Pythonとopenpyxlで実現する高度なグラフ描画:ManualLayout活用術

openpyxl

「PythonとopenpyxlでExcelレポートを自動作成しているけど、グラフの位置やサイズが微妙にずれてしまう…」「複数のグラフを意図通りにきれいに並べたいのに、うまくいかない!」

そんな悩みを抱えていませんか?openpyxlは非常に便利なライブラリですが、グラフのレイアウト調整は少し癖があり、思い通りの見た目に仕上げるのが難しい場合があります。

この記事を読めば、その悩みを解決できます。openpyxl.chart.layout.ManualLayout を使うことで、グラフの位置とサイズを絶対値で正確にコントロールし、誰が見ても美しいExcelレポートを自動生成する方法がわかります。

もう手動でのグラフ調整作業に時間を奪われることはありません。ManualLayoutをマスターして、ワンランク上のExcel操作自動化を実現しましょう。

openpyxlのグラフ描画とレイアウトの課題

まずは結論です。openpyxlで通常の方法でグラフを追加すると、そのレイアウトはグラフを配置したセルの大きさに影響されてしまいます。

worksheet.add_chart() を使ってグラフを配置する際、A1E5のようにアンカーとなるセルを指定します。これは「グラフをこのセルに結びつけて配置する」という意味になり、非常に直感的です。

しかし、この方法はセルの結合状態や、後から行の高さや列の幅を変更した場合に、グラフのサイズや位置が意図せず変わってしまう原因になります。

特に、以下のようなケースで問題となりがちです。

  • 定型レポートの自動生成: 毎回同じ見た目のレポートを作りたいのに、データ量によって列幅が変わるとグラフのレイアウトも崩れてしまう。
  • 複数のグラフの整列: 複数のグラフをきれいに並べたいのに、基準となるセルのサイズが異なると、グラフの大きさがバラバラになってしまう。
  • 細かなレイアウト調整: あと数ピクセルだけ右に動かしたい、といった微調整が難しい。

これらの課題を解決してくれるのが、今回ご紹介する ManualLayout です。

ManualLayoutとは?グラフ配置を自由自在にする機能

ManualLayoutを一言で説明すると、グラフをセルのアンカーから切り離し、絶対的な位置とサイズで配置するための機能です。

ManualLayoutを使うと、グラフはもはや特定のセルに縛られません。ワークシートという大きなキャンバスの上に、自由な座標と大きさでグラフを描画するイメージです。

主なメリットは以下の通りです。

  • ピクセルレベルでの厳密な制御: グラフの左上の座標、幅、高さを数値で直接指定できます。
  • セル変更からの独立: 行の高さや列の幅を変更しても、グラフのレイアウトには一切影響しません。
  • レポートの再現性向上: いつ、どんなデータで実行しても、完全に同じレイアウトのレポートを生成できます。

これまでのように「だいたいこの辺り」で配置するのではなく、「ここからここまで」と正確に指定できるため、レポート自動化の品質が格段に向上します。

ManualLayoutの基本的な使い方(サンプルコード付き)

それでは、実際の使い方を見ていきましょう。 結論から言うと、ManualLayoutオブジェクトを作成し、グラフオブジェクトのlayoutプロパティに設定するだけで利用できます。

ここでは、簡単な棒グラフを作成し、特定の位置に指定したサイズで配置する手順を3ステップで解説します。このコードはopenpyxl 3.0以降のバージョンで動作します。

Step1. 準備:グラフの元となるデータとグラフオブジェクトを作成する

まず、グラフの元になるデータを持つExcelファイルと、グラフオブジェクトを作成します。

import openpyxl
from openpyxl.chart import BarChart, Reference

# 1. 新しいExcelブックを作成
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "ManualLayout_Sample"

# 2. グラフの元になるサンプルデータを書き込む
rows = [
    ["Category", "Value"],
    ["A", 150],
    ["B", 230],
    ["C", 180],
    ["D", 120],
]

for row in rows:
    ws.append(row)

# 3. グラフオブジェクトを作成 (ここでは棒グラフ)
chart = BarChart()
chart.title = "サンプル棒グラフ"
chart.style = 10

# 4. グラフのデータ範囲とカテゴリを指定
data = Reference(ws, min_col=2, min_row=1, max_row=5)
cats = Reference(ws, min_col=1, min_row=2, max_row=5)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)

ここまでは通常のグラフ作成手順と同じです。この時点では、まだグラフはシートに追加されていません。

Step2. ManualLayoutで位置とサイズを定義する

次に、この記事の主役である ManualLayout を使って、グラフの配置情報を定義します。

ManualLayoutには、主に4つの重要なプロパティがあります。これらは0から1の間の小数で指定し、シート全体に対する比率で位置や大きさを決めます。

  • x: シートの左端からの距離の比率(0.0が左端、1.0が右端)
  • y: シートの上端からの距離の比率(0.0が上端、1.0が下端)
  • w (width): シートの幅に対するグラフの幅の比率
  • h (height): シートの高さに対するグラフの高さの比率
from openpyxl.chart.layout import ManualLayout

# ManualLayoutオブジェクトを作成
# x=0.1: 左から10%の位置に配置
# y=0.1: 上から10%の位置に配置
# w=0.5: シートの幅の50%の幅を持つグラフ
# h=0.5: シートの高さの50%の高さを持つグラフ
manual_layout = ManualLayout(
    x=0.1, 
    y=0.1,
    w=0.5,
    h=0.5
)

Step3. グラフにManualLayoutを適用し保存する

最後に、作成したManualLayoutオブジェクトを、グラフオブジェクトのlayoutプロパティに設定し、シートにグラフを追加します。

このとき、ws.add_chart()の第2引数(アンカーセルの位置)はどこでも構いませんが、慣例的に左上のA1などを指定しておくと分かりやすいでしょう。ManualLayoutが適用されている場合、このセルの位置は無視されます。

以下に、Step1からStep3までを統合した完全なサンプルコードを示します。

import openpyxl
from openpyxl.chart import BarChart, Reference
from openpyxl.chart.layout import ManualLayout

# --- Step1: 準備 ---
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "ManualLayout_Sample"

rows = [
    ["Category", "Value"],
    ["A", 150],
    ["B", 230],
    ["C", 180],
    ["D", 120],
]

for row in rows:
    ws.append(row)

chart = BarChart()
chart.title = "サンプル棒グラフ"
chart.style = 10

data = Reference(ws, min_col=2, min_row=1, max_row=5)
cats = Reference(ws, min_col=1, min_row=2, max_row=5)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)

# --- Step2: ManualLayoutで位置とサイズを定義 ---
# 左から10%, 上から10%の位置に、幅50%, 高さ50%のグラフを配置
manual_layout = ManualLayout(
    x=0.1, 
    y=0.1,
    w=0.5,
    h=0.5
)

# --- Step3: グラフにManualLayoutを適用 ---
chart.layout = manual_layout

# シートにグラフを追加 (アンカーセルはA1とするが、ManualLayoutにより無視される)
ws.add_chart(chart, "A1")

# Excelファイルを保存
wb.save("manual_layout_basic_sample.xlsx")

print("グラフを含むExcelファイルを作成しました。")

このコードを実行して生成されたExcelファイルを開くと、シートの左上から少し離れた位置に、指定した比率の大きさでグラフが配置されていることが確認できます。

【応用】ManualLayoutを活用した高度なレイアウトテクニック

ManualLayoutの基本をマスターすれば、応用は簡単です。 結論として、ManualLayoutのプロパティ値をプログラムで計算することで、複数のグラフを正確に整列させるなど、より高度なレイアウトが実現可能になります。

複数のグラフを隙間なく横に並べる

例えば、2つのグラフをきれいに横に並べたい場合を考えます。 1つ目のグラフの x 座標と幅 w が分かっていれば、2つ目のグラフの x 座標は x + w で計算できます。

import openpyxl
from openpyxl.chart import BarChart, PieChart, Reference
from openpyxl.chart.layout import ManualLayout

# ... (ブックとシート、データ準備は上記と同様) ...
# (ここでは簡単のため、データ準備部分を省略します)
# wb, ws を作成し、データが書き込まれていると仮定します。

# --- ダミーのデータとシートを作成 ---
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "MultiChart_Sample"
rows = [["Category", "Value1", "Value2"], ["A", 150, 80], ["B", 230, 120]]
for row in rows:
    ws.append(row)
# -----------------------------------


# --- 1つ目のグラフ(棒グラフ)を作成 ---
chart1 = BarChart()
data1 = Reference(ws, min_col=2, min_row=1, max_row=3)
cats1 = Reference(ws, min_col=1, min_row=2, max_row=3)
chart1.add_data(data1, titles_from_data=True)
chart1.set_categories(cats1)
chart1.title = "データ1"

# 1つ目のグラフのレイアウトを定義
chart1_x = 0.05  # 左から5%
chart1_y = 0.1   # 上から10%
chart1_w = 0.4   # 幅40%
chart1_h = 0.6   # 高さ60%
chart1.layout = ManualLayout(x=chart1_x, y=chart1_y, w=chart1_w, h=chart1_h)


# --- 2つ目のグラフ(円グラフ)を作成 ---
chart2 = PieChart()
data2 = Reference(ws, min_col=3, min_row=1, max_row=3)
labels = Reference(ws, min_col=1, min_row=2, max_row=3)
chart2.add_data(data2, titles_from_data=True)
chart2.set_categories(labels)
chart2.title = "データ2"

# 2つ目のグラフのレイアウトを計算
gap = 0.05 # グラフ間の隙間を5%に設定
chart2_x = chart1_x + chart1_w + gap # 1つ目のグラフの右隣に配置
chart2_y = chart1_y                   # 高さは同じ
chart2_w = chart1_w                   # 幅も同じ
chart2_h = chart1_h                   # 高さも同じ
chart2.layout = ManualLayout(x=chart2_x, y=chart2_y, w=chart2_w, h=chart2_h)


# --- シートにグラフを追加 ---
ws.add_chart(chart1, "A1")
ws.add_chart(chart2, "H1") # アンカーはどこでもOK

wb.save("manual_layout_multi_sample.xlsx")
print("複数のグラフを整列させたExcelファイルを作成しました。")

このように、レイアウト情報を変数で管理し計算することで、まるでCSSでWebページのレイアウトを組むかのように、Excelシート上のグラフ配置を柔軟にコントロールできます。

グラフの重ね順(Z-order)とManualLayout

ManualLayoutで座標が重なるようにグラフを配置した場合、その重ね順(Z-order)は ws.add_chart()で後から追加したものが上 になります。この仕様を利用して、意図的にグラフを重ねて表現することも可能です。

xModeとyModeで基点を変更する

ManualLayoutには、xModeyModeという、さらに高度なプロパティも存在します。これは、x, y座標の基点をどこに置くかを設定するものです。

  • edge(デフォルト): オブジェクトの左上端を基点とします。
  • factor: オブジェクトの中心を基点とします(x=0.5で中央揃え、といった指定が可能)。

通常はデフォルトのedgeで十分ですが、グラフをシートの中央に厳密に配置したい場合などにfactorが役立ちます。

まとめ

今回は、Pythonのopenpyxlライブラリでグラフのレイアウトを自在に操るManualLayout機能について、基本的な使い方から応用テクニックまでを解説しました。

最後に、この記事の重要なポイントを振り返ります。

  • openpyxlのデフォルトのグラフ配置は、セルのサイズに依存してしまい、レイアウトが崩れることがある。
  • ManualLayoutを使うことで、セルから独立した絶対的な位置・サイズ指定が可能になる。
  • 基本はx, y, w, hの4つのプロパティに0から1の比率を指定するだけ。
  • プロパティ値を計算で求めることで、複数のグラフもきれいに整列できる。

ManualLayoutを使いこなせば、これまで手作業での微調整が必要だったExcelレポートの作成を完全に自動化し、いつでも完璧なレイアウトの資料を生成できるようになります。

ぜひ、あなたのPython Excel自動化スクリプトにManualLayoutを取り入れて、レポート作成のレベルを一段階引き上げてください。

コメント

タイトルとURLをコピーしました