[解決!Python]Excelワークシートにドーナツグラフを作成するには(OpenPyXL)解決!Python

DoughnutChartクラスを使って、ドーナツグラフを作成したり、そこにパーセンテージ表示を加えたり、同心円状に複数の系列のデータを表示したりする方法を紹介する。

» 2022年04月05日 05時00分 公開
[かわさきしんじDeep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「解決!Python」のインデックス

連載目次

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

values = [
    ['Product', '2020', '2021'],
    ['A', 4000, 4500],
    ['B', 3000, 2500],
    ['C', 2000, 1800],
    ['D', 1000, 1200]
]

for v in values:
    ws.append(v)

wb.save('sample_chart.xlsx')

from openpyxl.chart import Reference, DoughnutChart

rmin = ws.min_row
rmax = ws.max_row
cmin = ws.min_column
cmax = ws.max_column

chart = DoughnutChart()
labels = Reference(ws, min_col=cmin, min_row=rmin+1, max_row=rmax)  # 'Product'
src = Reference(ws, min_col=cmin+1, min_row=rmin, max_row=rmax)  # '2020'列
chart.add_data(src, titles_from_data=True)
chart.set_categories(labels)
chart.title = 'sales'  # グラフタイトル
chart.anchor = 'A9'  # グラフの表示位置
chart.width = 16  # グラフのサイズ
chart.height = 8

ws.add_chart(chart)
wb.save('sample_chart.xlsx')

# ドーナツグラフから特定の構成要素を切り離して強調表示
from openpyxl.chart.series import DataPoint
slice = DataPoint(idx=2, explosion=10)
chart.ser[0].data_points = [slice]
wb.save('sample_chart.xlsx')

# パーセンテージの表示
from openpyxl.chart.label import DataLabel, DataLabelList
dLbls = [DataLabel(idx=idx, showPercent=True) for idx in range(rmax-rmin)]
dLbls = DataLabelList(dLbls)
chart.ser[0].dLbls = dLbls

wb.save('sample_chart.xlsx')

# パーセンテージ表示の文字色を変更する
from openpyxl.drawing.text import CharacterProperties, ParagraphProperties, Paragraph
from openpyxl.chart.text import RichText
char_props = CharacterProperties(solidFill='FFFFFF')
para_props = ParagraphProperties(defRPr=char_props)
para = Paragraph(pPr=para_props)
bodyPr = RichText(p=[para])
chart.ser[0].dLbls.textProperties = bodyPr

wb.save('sample_chart.xlsx')

# 同心円状にドーナツグラフを表示するように系列を追加
from openpyxl.chart import Series
src2 = Reference(ws, min_col=cmax, min_row=rmin, max_row=rmax)  # '2021'列
series2 = Series(src2, title_from_data=True)
series2.dLbls = dLbls
series2.dLbls.textProperties = bodyPr
chart.ser.append(series2)

wb.save('sample_chart.xlsx')

slice = DataPoint(idx=2, explosion=10)
chart.ser[1].data_points = [slice]

wb.save('sample_chart.xlsx')


サンプルのワークシート

 本稿では以下のコードで作成したワークシートを例に取る。

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

values = [
    ['Product', '2020', '2021'],
    ['A', 4000, 4500],
    ['B', 3000, 2500],
    ['C', 2000, 1800],
    ['D', 1000, 1200]
]

for v in values:
    ws.append(v)


 これをExcelで表示したものを以下に示す。

サンプルのワークシート サンプルのワークシート

ドーナツグラフ

 OpenPyXLを使ってドーナツグラフを作成するには、openpyxl.chart.DoughnutChartクラスを使用する。ドーナツグラフは円グラフとよく似ているが、中央が空いていて、見た目がドーナツに似ている。また、複数の系列のデータを同心円状に描画することで、特定の要素の増減をビジュアルに表現できる。作成の手順は以下の通り。

  • DoughnutChartクラスのインスタンス(グラフ)を生成する
  • Referenceクラスを使って、グラフ作成の基となる範囲を指定する
  • グラフにデータ(上で作成したReferenceクラスのインスタンス)を渡す
  • グラフのタイトルなどの設定を行う
  • ワークシートにグラフを挿入する

 ドーナツグラフ(DoughnutChart)で設定できる項目としては以下がある(一部)。

属性 説明
title属性 グラフのタイトル
anchor属性 グラフの挿入位置
width属性 グラフの横幅
height属性 グラフの高さ
ser属性 系列ごとのマーカーや線種の設定
ドーナツグラフに設定可能な項目(一部)

 ドーナツグラフを作成する基本的なコード例を以下に示す。

from openpyxl.chart import Reference, DoughnutChart

rmin = ws.min_row
rmax = ws.max_row
cmin = ws.min_column
cmax = ws.max_column

chart = DoughnutChart()
labels = Reference(ws, min_col=cmin, min_row=rmin+1, max_row=rmax)  # 'Product'
src = Reference(ws, min_col=cmin+1, min_row=rmin, max_row=rmax)  # '2020'
chart.add_data(src, titles_from_data=True)
chart.set_categories(labels)
chart.title = 'sales'  # グラフタイトル
chart.anchor = 'A9'  # グラフの表示位置
chart.width = 16  # グラフのサイズ
chart.height = 8

ws.add_chart(chart)


 この例では、最初にDoughnutChartクラスのインスタンスを生成し、その後'Product'列にある'A'〜'D'を項目名としてピックアップして変数labelsに格納し、'2020'列をドーナツグラフ描画の元データとして変数srcに格納している('2021'列は後で同心円状にドーナツグラフを描く際に使用する)。そして、add_dataメソッドで変数srcをグラフにデータとして追加して、set_categoriesメソッドで変数labelsを項目名としてセットしている。その後はラベルやグラフの表示位置とサイズを設定している。

 このコードを実行すると、次のようなグラフになる。

ドーナツグラフ ドーナツグラフ

 また、円グラフと同様に、ドーナツグラフの特定の要素を他の要素から切り離して、強調表示することも可能だ。これには、切り離したい要素のインデックス(0ベース)とどのくらい切り離すのかを指定して、DataPointクラスのインスタンスを生成し、それを系列の要素のdata_points属性に設定する(複数の要素を切り離したければ、インデックスと距離を指定したDataPointオブジェクトを複数用意して、それらを要素とするリストをdata_points属性に渡す)。

from openpyxl.chart.series import DataPoint
slice = DataPoint(idx=2, explosion=10# 3つ目の要素を切り離す
chart.ser[0].data_points = [slice]
wb.save('sample_chart.xlsx')


 これにより、グラフは次のようになる。

3つ目の要素が切り離された 3つ目の要素が切り離された

 上のコードではidxに2を指定しているが、0ベースなので、これは3つ目の要素を示している。そのため、上の画像では3つ目の要素がグラフの他の要素から切り離されている。なお、この設定は同心円状にした場合には無効化される。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。