本記事では、ExcelをPythonで操作する「openpyxl」ライブラリの解説をしていきます。
Excelには多くの機能が搭載されておりますので、ひと記事ですべてを網羅的に解説することはできません。大項目(機能)ごとに分けて連載記事【Python×Excel】としてまとめています。
前回の記事(連載7回)では、openpyxlによる「グラフの作成手順の概要」と「グラフを構成する要素のクラスやオブジェクト」について紹介しました。
今回からは【実践編】としてサンプルコードを交えて、より具体的にグラフ作成の手順を解説していきます。openpyxlを使うことで、驚くほど簡単に実用的なグラフを描画できることを実感してみてください。
この記事を読むことで、次のようなことが「できる・わかる」ようになりますので最後までお付き合いください。
なお、本記事ではPythonプログラムでグラフを作成する際のキーポイントや特殊属性(プロパティ)について解説していきます。グラフそのももの説明は各種Excelの専門書を参考にして下さい。
本サイトでの紹介例は一例です。また、関数などの省略可能なオプション引数などについては割愛していますので、詳細や不明点などは必要に応じて公式サイトなどを参照してください。
【公式サイト】https://openpyxl.readthedocs.io/en/stable/index.html
1. 「棒グラフ」の作成手順について
oenpyxlでグラフ作成をする手順(フロー)について解説します。
折れ線、棒グラフなど、各系列によって同じ項目(X軸の値)を共有するタイプのグラフは、全ての系列データをまとめて「Referenceオブジェクト」として一括参照できます。図2にフロー全体を体系化しました。
図2のブロック(➀~➆)について解説します。
➀.【Chartオブジェクトを取得する】
Chartオブジェクト はグラフ本体(フレームワーク)となります。
グラフのタイプごとに専用のクラスが用意されています。今回の「棒グラフ」であれば BarChartクラス からBarChartオブジェクトを取得します。
➁.【Chartオブジェクトにグラフの要素を追加する】
グラフを構成する要素には、タイトル、凡例、軸のタイトルなどがあります。
これらは、Chartオブジェクト 配下の属性(プロパティ)によって追加・設定します。
➂.【データの参照情報をReferenceオブジェクトとして定義する】
グラフが参照するセル範囲を Referenceオブジェクト として定義します。参照するセル範囲は、「系列名を含めたデータ領域」と「項目名」の2つです。(図3) Referenceクラス は<関連記事>を参照願います。
➃.【Chartオブジェクトにデータを設定する】
➂で定義したデータ領域を指す Referenceオブジェクト を add_data() でChartオブジェクトに追加します。
➄.【Chartオブジェクトに項目名(カテゴリ)を設定する】
➂で定義した項目名(カテゴリ)を指す Referenceオブジェクト を set_categories() でChartオブジェクトに追加します。
➅.【系列データごとに装飾効果を適用する】
グラフの個々の系列データは Seriesオブジェクト として管理されています。マーカーやライン、塗り潰しなどプロットエリア内の装飾効果は、Seriesオブジェクト配下の属性にて設定します。
Seriesオブジェクトは、Chartオブジェクトの seriesプロパティ で取得できます。
➆.【Worksheetにグラフを挿入する】
最後にWorksheetオブジェクトの add_chart() の引数に、これまでに定義してきたChartオブジェクトとグラフの挿入位置(セルアドレス)を指定してワークシートに挿入します。
以上がグラフ作成の手順となります。
次節からは、具体的なサンプルコードを交えながら詳細解説していきます。今回は、「棒グラフ(BarChart)」の作例を紹介します。
2. openpyxlによる「縦棒/横棒グラフ」について
「棒グラフ」とは、X軸(項目名)とY軸(値)の対となるデータの絶対量をバー(棒線)で表現し、項目間、系列間の比較が、一目で確認できる形態のグラフです。データの参照情報は、全ての系列データをReferenceオブジェクト として一括にまとめまて管理します。
同じようなグラフに「散布図」がありますが、違いはX軸の値(カテゴリ)を各系列間で共有する点にあります。
棒グラフの本体(Chartオブジェクト)を提供するクラスは、グラフの次数により、平面(2D)ではBarChartクラス と立体(3D)では BarChart3Dクラス の2種類があります。
また、BarChart(3D)オブジェクト がもつ grouping属性 によって、グラフの形態を「”standard“(標準)」「”stacked“(積み上げ)」「 “percentStacked“(100%積み上げ)」の3つの中から選択することができます。さらに、type属性 によりバーの向きを「“col”(縦方向)」「“bar”(横方向)」で指定することができます。
棒グラフの次数と形態・バーの向き、それぞれの特徴は図4に示すとおりです。
プロットエリアの構成要素には、バー(棒)がありますが、内部を任意のパターンで塗り潰す、間隔の調整やラベルを付与するといったことができます。
これらは、系列ごとに Seriesオブジェクト として管理されています。
以上、棒グラフ(BarChart(3Dを含む)オブジェクト)の概要についてでした。次節からは具体的なサンプルコードを示しながらグラフの作成手順をステップごとに解説していきます。
3. 棒グラフ(BarChart)の実装
それでは、次のような仕様をもつ棒グラフの実装例をステップごとに順番に解説していきます。
3.1 「棒グラフ」の概要を定義する【Step.1】
はじめに、必要なクラスのインポートから、グラフ本体となる BarChartオブジェクト、それからタイトルや凡例などのグラフエリアを構成する要素を次の<List1>で定義します。
このプログラムで使用するブック(.xlsx)ファイルは以下からダウンロードできます。
# モジュール・クラス群のインポート-------------------------------------------
from openpyxl import load_workbook
# 棒グラフ作成(グラフ本体、データ参照情報の定義)に必要となるクラス
from openpyxl.chart import BarChart, Reference, Series
# パターン(模様)塗り潰しに必要なクラス
from openpyxl.drawing.fill import PatternFillProperties, ColorChoice
# 個別データ(項目名・カテゴリ名)情報の定義に必要なクラス
from openpyxl.chart.marker import DataPoint
# データラベル情報の定義に必要なクラス
from openpyxl.chart.label import DataLabel, DataLabelList
# ファイル(シート)読込--------------------------------------------------------
wb = load_workbook('Graph_DataSource.xlsx') # Excelファイル(元データ)の読込み
ws = wb.worksheets[0] # Worksheetオブジェクトの取得
# [A] グラフ本体と構成要素の準備 ----------------------------------------------
# Chartオブジェクト(棒グラフの本体)を取得
c1 = BarChart()
# グラフの大きさを調整する
c1.width = 18 # デフォルト(15cm)
c1.height = 10 # デフォルト(7cm)
# グラフのタイトルを設定(メイン、軸)
c1.title = "Bar Chart" # メインタイトル
c1.x_axis.title = 'Month' # X軸のタイトル
c1.y_axis.title = 'Precipitation' # Y軸のタイトル
# グラフの凡例
c1.legend.position = 'b' # 凡例の配置位置
#---------------------------------------------
# <List2>へ続く
それでは、ポイントを解説します。
15行目までは、棒グラフの本体機能を提供する BarChartクラス や棒(バー)の装飾(※)に必要となるクラス群をインポートしています。※後半の各系列データの個別設定で使用します。
また、26行目で BarChartオブジェクト を取得(変数c1に格納)しています。以降の処理では、このBarChartオブジェクト配下のメソッドや属性(プロパティ)を使ってグラフを構築していきます。
ここまでのコードを実行しても図5のようにグラフエリアの枠以外は何も表示されません。次項の<List2>でプロットエリアを定義した後に、軸や凡例が反映されます。
3.2 「棒グラフ」の参照情報を定義する【Step.2】
<List1>に引き続き<List2>を追記してください。<List2>では「BarChartオブジェクト」にデータの参照情報を追加しています。
# [B] データの参照情報を取得する --------------------------------------------------
# データ(系列名を含めた)となるセル範囲の参照オブジェクトを取得
# 3(C)列-5(E)列、4行目-8行目を参照
data = Reference(ws, min_col=3, max_col=5, min_row=4, max_row=8)
# 項目名(カテゴリ)となる列の参照オブジェクトを取得
# 2(B)列、5行目-8行目を参照
category = Reference(ws, min_col=2, max_col=2, min_row=5, max_row=8)
# Chartオブジェクトにデータと項目を設定する
c1.add_data(data, titles_from_data=True) # 第2引数にTrueを指定して先頭要素を系列名とする
c1.set_categories(category) # 項目(カテゴリ)を設定
#---------------------------------------------
# <List3>へ続く
まず、5行目ではデータの参照情報を Referenceオブジェクト として定義します。(図6の赤の枠内)
その際、系列名となるセル範囲(図6の青の枠内)も含めた範囲を指定するようにします。
次に9行目では項目名(カテゴリ)となる参照情報の Referenceオブジェクト も同じように定義します。
そして、12行目の add_data()メソッド でデータ情報を、13行目の set_categories()メソッド で項目(カテゴリ)をそれぞれ BarChartオブジェクト に設定します。また、add_data()メソッドでは、引数:title_from_data に”True“を設定することで、データ領域の先頭行の要素(※)を系列名と認識するようにします。
※ 引数:titles_form_data で系列名を指定できるのはあくまで先頭行の要素です。先頭列ではありませんので、元となるテーブルは図6のように配置しておかなければなりません。
3.3 棒グラフの形態と向きを指定する【Step.2】
<List2>に続き<List3>を追加して下さい。<List3>では、棒グラフの大まかな形態や見栄えを整えています。
# [C] 棒グラフ(BarChart)の形態タイプと見栄えの設定 -----------------------------
# 棒グラフのテーマカラーの設定
c1.style = 7 # テーマカラーを整数で設定
# バーの向き(縦、横)を設定する
# "col":縦棒グラフ , "bar":横棒グラフ(デフォルトは"col")
c1.type = "col"
# グラフの形態を設定する
# "standard"(標準), "stacked"(積み上げ),"percentStacked"(100%積み上げ)
c1.grouping = "standard"
# カテゴリ集合の間隔を調整する
c1.gapWidth = 200
#---------------------------------------------
# <List4>へ続く
3.4 系列に書式を設定する【Step.4-1】
<List3>に続いて<List4>を追記してください。<List4>では、各系列に対して、塗りつぶし効果を適用させます。具体的には、2つの系列データ(札幌・仙台)に対して、「単色塗りつぶし」「パターン塗りつぶし」を設定します。
塗りつぶし効果については、こちらの<Fillオブジェクト>も参考にして下さい。
# [D] 各系列ごとにバーの装飾を設定する
# <系列1>のバーの装飾 -----------------------------------------------------------
# Seriesオブジェクトの取得
ser1=c1.series[0]
# 単一色による塗り潰し
# ➀ RGB Hex表記による色指定
# ser1.graphicalProperties.solidFill = "FF0000"
# ➁ ColorChoiceオブジェクトによる指定
ser1.graphicalProperties.solidFill = ColorChoice(prstClr="cornflowerBlue")
# <系列2>のバーの装飾 -----------------------------------------------------------
# Seriesオブジェクトの取得
ser2=c1.series[1]
# パターン(模様)の定義
# (PatternFillPropertiesオブジェクトの定義)
# 【その➀ 属性による指定】
# ➀-1 縦縞模様の塗り潰し
fill = PatternFillProperties(prst="dkVert")
# ➀-2 foreground属性で前景色を指定(赤)
fill.foreground = ColorChoice(prstClr="red")
# ➀-3 background属性で背景色を指定(青)
fill.background = ColorChoice(prstClr="blue")
# 【その➁引数による指定】
# fill = PatternFillProperties(prst="dkVert", fgClr=ColorChoice(prstClr="red"), bgClr=ColorChoice(prstClr="blue"))
# SeriesオブジェクトのpattFill属性に、パターン定義(PatternFillPropertiesオブジェクト)を設定する
ser2.graphicalProperties.pattFill = fill
#---------------------------------------------
# <List5>へ続く
6行目で、<系列1>の Seriesオブジェクト を取得します。14行目までは、この<系列1>のバーに対する処理を行います。
ColorChoiceクラス の書式は以下の通りです。「組込み(prstColor)」「RGB形式(srgbColor)」「システム(sysColor)」「テーマ(shemeColor)」などのタイプに応じた指定が可能です。詳しくは公式ドキュメントを参考にして下さい。
続く19行目で<系列2>の Seriesオブジェクト を取得します。以降、30行目まで、この<系列2>のバーに対する処理を行います。
パターン塗りつぶしは、最終的に37行目で graphicalproperties属性 に pattFill属性 を続けて適用することになりますが、その前に、網掛けするパターンの定義情報である PatternFillpropertiesオブジェクト を定義する必要があります。
3.5 系列に書式を設定する【Step.4-2】
<List4>に続いて<List5>を追記してください。<List4>では系列全体に対する処理でしたが、<List5>は同じ系列の特定の項目に対して書式を適用する応用例となります。
# [E] 系列3の指定した項目(カテゴリ)のみ装飾を施す
# <系列3>のバーの装飾 -----------------------------------------------------------
# Seriesオブジェクトの取得
ser3=c1.series[2]
# 特定の項目情報はDataPointオブジェクトで管理
# 引数のidxは項目のインデックスをを指定
pt = DataPoint(idx=3)
# DataPointオブジェクトに施す、書式を設定する(この場合は、パターン網掛け)
pt.graphicalProperties.pattFill = PatternFillProperties(prst="ltHorz")
# Seriesオブジェクトに、DataPointオブジェクトを適用する
# 適用する方法は以下の3通りあり、どれでも構わない
#ser3.dPt.append(pt) # appendメソッドで追加(1)
#ser3.data_points.append(pt) # appendメソッドで追加(2)
ser3.data_points = [pt] # リストで設定
# [F] 系列3のバーに「データラベル」を施す-----------------------------------------
# ➀全ての項目(カテゴリ)にラベルを表示する場合
# ➀-1 DataLabelListオブジェクトの取得
#lbl = DataLabelList(showVal=True)
# ➁特定の項目を指定してラベルを表示する場合
# ➁-1 DataLabelオブジェクトを取得する(引数idxは項目のインデクスを指定)
lb = DataLabel(idx=1, showVal=True)
# ➁-2 DataLabelListオブジェクトに追加する
lbl = DataLabelList(dLbl=[lb])
# 系列3のSeriesオブジェクトにラベル(DataLabelListオブジェクト)を設定する
#ser3.dLbls=lbl # ➂-1
ser3.labels=lbl # ➂-2
# Chartオブジェクトをシートに追加して保存 -----------------------------------------
ws.add_chart(c1, "B13") # B13セルを左上にグラフを貼り付ける
wb.save('BarChart_example1_standard.xlsx')
6行目で<系列3>の Seriesオブジェクト を取得します。以降38行目までは、<系列3>のバーに対する処理を行います。
また、補足として系列のすべての項目に対してラベルを設定する場合は、27行目のように「DataLabelListコレクション」に対して 引数:showval を有効にします。(➀–1)
サンプルコードの解説は以上となります。<List1>~<List5>をすべて連結、実行した結果は図9のようになりました(以下からダウンロードできます)。タイトルやバーの塗りつぶし、それから特定の項目に対して、パターンやデータラベルが表示されることが確認できます。
4. 棒グラフの種別について<補足>
2節の<図4>のように、棒グラフ(BarChart)は、「バーの向き」と「グラフの種別」を組合わせて描画します。本節では、これらを設定するための属性と適用例を紹介します。
4.1 バーの向き
バーの向きは、type属性 によって縦棒“col”もしくは横棒”bar”(横棒)の指定ができます。容易に切り替えることができますが、両者の設定でカテゴリの並びが反転してしまう点には留意しましょう。
<List3>の8行目を<List6>を差し替えることで縦棒から横棒にバーの向きが変更されました。(図10)
# バーの向き(縦、横)を設定する
# "col":縦棒グラフ , "bar":横棒グラフ(デフォルトは"col")
c1.type = "bar"
4.2 棒グラフの形態
グラフの形態は、grouping属性 によって”standard“(標準), “stacked”(積み上げ),”percentStacked“(100%積み上げ)の3つの中から選択できます。
<List3>の12行目を<List7>の3行目に差し替えるだけで変更することができます。(図11)
# グラフの形態を設定する
# "standard"(標準), "stacked"(積み上げ),"percentStacked"(100%積み上げ)
c1.grouping = "stacked" # 積み上げ棒グラフ
# 隣接する辺の共有度合いを調整する(積み上げタイプのみ設定が可能)
# 100がデフォルト、小さくするごとに上下のバーがズレていく(-100~100の間で設定可能)
c1.overlap = 0
また、“積み上げ”タイプの棒グラフについては、overlap属性 の設定が有効となり、隣接する辺の共有度合いを調整することができます。「100」で完全に隣接し、小さくするほど離れていきます。「-100~100」の範囲で指定します。<List7>の8行目
以上1~3節が「棒グラフ(BarChart)」に関する一連の解説となりますが、棒グラフにはもう一つ立体(3D)タイプもありますので最後に少しだけ触れておきます。
5. 立体(3D)棒グラフ(BarChart3D)について
<2.項>冒頭でも触れましたが、棒グラフには、立体(3D)表現することができる BarChart3Dクラス が用意されています。
3D棒ブラフは、<List8>のように「BarChart3Dクラス」からChartオブジェクトを取得し平面グラフと同じように参照先情報や属性を設定していきます。
# 3D棒グラフ本体を定義するクラス
from openpyxl.chart import BarChart3D, Reference, Series
# Chartオブジェクト(3D棒グラフの実体)を取得
c1 = BarChart3D()
基本的な属性は平面(2次)のものと共通ですが、立体(3次)では次数が増えますので、設定可能な属性もその分増えることになります。ただ、特にこだわりがないのであればどの属性に関してもデフォルト設定(特に設定する必要はない)のままで構わないと思いますが、いくつか立体グラフ特有の属性もあります。<表1>
【Chartオブジェクトの属性】 | 【機能】 | 【詳細】 |
---|---|---|
backWall | 背面の設定 | (調査中) |
floor | 床面の設定 | (調査中) |
sideWall | 側面の設定 | (調査中) |
view3D | 立体の視点を調整 | (調査中) |
gapDepth | 床面の奥行を調整 | 0~500の範囲で設定する |
shape | バーの形状を指定 | {‘pyramid’, ‘pyramidToMax’, ‘coneToMax’, ‘cylinder’, ‘box’, ‘cone’} |
次の<List9>は<表1>の中から、バーの形状を指定できる shape属性 と床面の奥行を調整する gapDepth属性 を設定したコードの抜粋です。
# バーの形状をshape属性で指定
# {‘pyramid','pyramidToMax','coneToMax','cylinder',box',cone’}
c1.shape = "cylinder" # 円柱
# 床面の奥行を指定する(0~500)
c1.gapDepth = 250
<List8><List9>を反映させたグラフは以下のようになりました。
「shape属性」に「円柱」を意味する“cylinder”を指定しているのでバーが円柱表記になっています。また、「gapDepth属性」によって奥行が調整できることも確認いただけます。
以上が、立体(3D)棒グラフの作成方法を平面グラフとの差分でした。繰り返しますが、基本的なコードは同じなため、共通するコードの解説は割愛します。
6. まとめ
いかがでしたでしょうか?
Excelを操作する外部ライブラリ「openpyxl」を使用して、棒グラフの作成手順を実例を交えて紹介しました。
前回のクラスやオブジェクトの説明だけでは分かりずらい点もあったかもしれませんが、実際のコードを読むことで理解が深まったと感じて頂けたのではないでしょうか。
また、グラフ作成のコードにはある程度パターンがあるので紹介したサンプルコードを参考にアレンジしてみて下さい。
Excelのグラフには、「棒グラフ」のほかにもさまざまなタイプがあります。
「折れ線グラフ」「散布図」「バブルチャート」など良く使われるタイプを中心に解説していますので、是非そちらも参考にして下さい。
ここまでの内容をまとめておきましょう。
1. 棒グラフのような系列ごとに同じ項目(カテゴリ)を共有するグラフの「Chartオブジェクト」を生成する際の注意点は以下の2つがあります。
- 「Referenceオブジェクト」となるデータの参照情報は、複数の系列まとめて取得する
- 系列ごとにオブジェクトを追加していくようなことはできない
2. バーに装飾(塗りつぶし効果やデータラベルなど)を施す場合は「Seriesオブジェクト」を取得したのち、配下の属性で設定する
- 塗りつぶし効果については、graphicalproperties.solidFill属性 で設定する
- データラベルについては labels属性 に DataLabelオブジェクト を設定する
最後までお読みいただきありがとうございました。