Matplotlibで魅せるデータ可視化:table.table()活用術

2025-05-31

matplotlib.pyplot.table()matplotlib.axes.Axes.table() とは

MatplotlibはPythonでグラフを描画するためのライブラリですが、データの可視化に加えて、そのデータに関連する情報を表形式で表示する機能も提供しています。その中心となるのが table() 関数です。

  • matplotlib.axes.Axes.table(): Axes オブジェクトのメソッドとして呼び出します。より詳細な制御が必要な場合や、複数のサブプロットを扱う場合に利用します。fig, ax = plt.subplots() のように ax オブジェクトを作成した場合に ax.table() として使います。
  • matplotlib.pyplot.table(): pyplot モジュールを通して、現在のAxes(サブプロット)に直接テーブルを追加する際に使用します。手軽にテーブルを作成したい場合に便利です。

どちらの関数も基本的な引数は同じで、テーブルのデータ、列・行のラベル、配置などを指定できます。

主な引数

table() 関数でよく使われる引数は以下の通りです。

  • edges:
    • 説明: セルの境界線のスタイルを指定。'closed' (全ての境界線), 'open' (境界線なし), 'horizontal' (水平線のみ), 'vertical' (垂直線のみ) や、'BRTL' のサブストリング(Bottom, Right, Top, Left)で個別に指定することもできます。デフォルトは 'closed'。
  • bbox:
    • 説明: テーブルを描画するバウンディングボックスを指定するリスト [xmin, ymin, width, height]loc よりも優先されます。
  • loc:
    • 説明: Axes(サブプロット)内でのテーブルの配置。'bottom', 'top', 'center' などが指定できます。デフォルトは 'bottom'。
  • colLoc:
    • 説明: 列ヘッダーのテキストの配置('left', 'center', 'right')。デフォルトは 'center'。
  • colColours:
    • 説明: 列ヘッダーの背景色を指定するリスト。
  • colLabels:
    • 説明: 列ヘッダー(上側のラベル)のテキストを指定するリスト。
  • rowLoc:
    • 説明: 行ヘッダーのテキストの配置('left', 'center', 'right')。デフォルトは 'left'。
  • rowColours:
    • 説明: 行ヘッダーの背景色を指定するリスト。
  • rowLabels:
    • 説明: 行ヘッダー(左側のラベル)のテキストを指定するリスト。
  • colWidths:
    • 説明: 各列の幅を指定するリスト(axes単位)。指定しない場合、列の数に応じて均等に幅が割り振られます。
  • cellLoc:
    • 説明: セル内のテキストの配置('left', 'center', 'right')。デフォルトは 'right'。
  • cellColours:
    • 説明: セルの背景色を指定する2次元リスト。cellText と同じ構造で色を指定します。
    • : [['lightblue', 'lightgreen'], ['yellow', 'lightcoral']]
  • cellText:
    • 説明: テーブルのセルに表示するテキストの2次元リスト(またはNumPy配列、Pandas DataFrame)。外側のリストが行、内側のリストが列を表します。
    • : [['データA1', 'データA2'], ['データB1', 'データB2']]
import matplotlib.pyplot as plt

# データの準備
data = [
    ['リンゴ', 100, 200],
    ['バナナ', 150, 250],
    ['オレンジ', 120, 180]
]
row_labels = ['フルーツA', 'フルーツB', 'フルーツC']
col_labels = ['種類', '2023年売上', '2024年売上']

# グラフとAxesの作成
fig, ax = plt.subplots(figsize=(8, 4))

# 軸を非表示にする(テーブルだけを表示する場合)
ax.axis('off')
ax.set_frame_on(False) # 軸の枠も非表示にする

# table() 関数を使ってテーブルを作成
table = ax.table(
    cellText=data,
    rowLabels=row_labels,
    colLabels=col_labels,
    loc='center', # テーブルを中央に配置
    cellLoc='center', # セル内のテキストを中央揃え
    colColours=['lightgray', 'lightgreen', 'lightgreen'] # 列ヘッダーの色
)

# テーブルのサイズを自動調整
table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1.2, 1.2) # テーブル全体のサイズを拡大

# タイトルを追加
ax.set_title('年間売上データ', fontsize=14)

plt.show()
  • グラフとテーブルの併用: table() は既存のグラフの上にテーブルを重ねて表示することもできます。その場合、locbbox 引数を使ってテーブルの位置を調整し、グラフと重ならないように配置するのが一般的です。
  • スタイルのカスタマイズ: table.get_celld() を使うことで、各セル(matplotlib.table.Cell オブジェクト)にアクセスし、個別に背景色、フォントサイズ、境界線などを細かく設定することも可能です。
  • Pandas DataFrameとの連携: Pandas DataFrameを cellText に直接渡すことで、より簡単にテーブルを作成できます。その際、DataFrameのインデックスやカラム名が自動的に rowLabelscolLabels になります。


テーブルが表示されない、または一部しか表示されない

最もよくある問題の一つです。特にグラフと併用する場合や、多くの行・列を持つテーブルの場合に発生しやすいです。

考えられる原因と解決策

  • tight_layout() の問題
    • 原因
      plt.tight_layout() を使うと、サブプロット間の間隔が自動調整されますが、テーブルがこの調整の対象外になることがあり、結果としてテーブルがはみ出すことがあります。
    • 解決策
      fig.tight_layout() を呼び出す前にテーブルを配置し、それでも問題が解決しない場合は、tight_layout() を使わずに手動で subplots_adjustbbox でレイアウトを調整することを検討します。
  • テーブルの位置(locまたはbbox)が適切でない
    • 原因
      loc 引数で指定した位置が、グラフのプロット領域と重なり、テーブルが見えなくなっている場合があります。特にax.axis('off')などで軸を非表示にしている場合、Axesのデフォルト領域にテーブルが配置され、それが視覚的に適切でないことがあります。
    • 解決策
      • loc='center' を試して、Axesの中央に配置してみます。
      • bbox=[xmin, ymin, width, height] を使って、テーブルの正確な位置とサイズをAxes座標で指定します。これにより、テーブルの表示領域を細かく制御できます。
      import matplotlib.pyplot as plt
      import numpy as np
      
      data = np.random.rand(3, 3)
      fig, ax = plt.subplots(figsize=(6, 4))
      ax.axis('off')
      
      # Axesの左下隅から(0.1, 0.1)の位置に、幅0.8、高さ0.5のテーブルを配置
      ax.table(cellText=np.round(data, 2), bbox=[0.1, 0.1, 0.8, 0.5])
      plt.show()
      
  • bbox_inches='tight' を使用している場合
    • 原因
      plt.savefig()bbox_inches='tight' を指定すると、グラフの境界線に合わせて出力サイズが調整されますが、テーブルがこの自動調整の範囲外に配置されていると、一部が切り取られることがあります。
    • 解決策
      bbox_inches='tight' を削除するか、テーブルの位置を明示的に調整するために bbox 引数を使用します。
  • 図のサイズが足りない
    • 原因
      作成したFigure(図全体)のサイズが、テーブルの内容を表示するのに十分でないために、テーブルが途中で途切れたり、まったく表示されなかったりすることがあります。
    • 解決策
      plt.figure(figsize=(幅, 高さ)) でFigureのサイズを大きくします。テーブルの行数や列数に応じて適切なサイズを設定してください。
      import matplotlib.pyplot as plt
      import numpy as np
      
      data = np.random.rand(10, 3) # 10行3列のデータ
      fig, ax = plt.subplots(figsize=(6, 4)) # 図のサイズを調整
      
      ax.axis('off')
      ax.table(cellText=np.round(data, 2), loc='center')
      plt.show()
      

考えられる原因と解決策

セルの書式設定(色、サイズ、配置など)がうまくいかない

table()関数の引数を間違えているか、詳細なカスタマイズ方法を理解していない場合に発生します。

考えられる原因と解決策

  • 列幅の自動調整がうまくいかない
    • 原因
      colWidths を指定しない場合、Matplotlibはテキストの長さに応じて列幅を自動調整しようとしますが、期待通りの結果にならないことがあります。
    • 解決策
      colWidths 引数で各列の幅を明示的に指定します。これはAxesの幅に対する比率で指定します。
      import matplotlib.pyplot as plt
      
      data = [['長いテキストの列', '短い', 'もっと長いテキストの列です']]
      fig, ax = plt.subplots(figsize=(8, 2))
      ax.axis('off')
      
      # 1列目に多くの幅、2列目に少し、3列目にまた多くの幅を割り当てる
      ax.table(cellText=data, loc='center', colWidths=[0.4, 0.15, 0.45])
      plt.show()
      
  • 個々のセルのプロパティ変更
    • 原因
      table()関数自体で指定できるカスタマイズは限定的で、個々のセルの背景色やフォントなどを細かく設定したい場合に困ることがあります。
    • 解決策
      tableオブジェクトが返された後、table.get_celld() メソッドを使って個々のセルにアクセスし、そのプロパティを変更します。
      import matplotlib.pyplot as plt
      import numpy as np
      
      data = [['A', 10], ['B', 20], ['C', 30]]
      fig, ax = plt.subplots(figsize=(4, 3))
      ax.axis('off')
      
      table = ax.table(cellText=data, loc='center', cellLoc='center')
      
      # 特定のセルの背景色を変更
      table[(0, 0)].set_facecolor('red') # 0行0列のセル
      table[(1, 1)].set_facecolor('lightblue') # 1行1列のセル
      
      # ヘッダー行の背景色を変更
      for (row, col), cell in table.get_celld().items():
          if row == 0: # 1行目(ヘッダー行)
              cell.set_facecolor('lightgray')
          if col == -1: # 行ラベルの列
              cell.set_facecolor('lightgreen')
          if row == -1: # 列ラベルの行
              cell.set_facecolor('lightcoral')
      
      # フォントサイズを大きくする
      table.auto_set_font_size(False)
      table.set_fontsize(12)
      table.scale(1, 1.5) # 高さを1.5倍に拡大
      
      plt.show()
      
  • 引数の指定間違い
    • 原因
      cellTextrowLabelscolLabels の次元や型が一致していない。cellColours などで色のリストを間違えている。
    • 解決策
      Matplotlibの公式ドキュメントや例をよく参照し、引数の型と構造を確認します。例えば、cellText は2次元リスト、rowLabelscolLabelsは1次元リストである必要があります。

テーブルがグラフと重なってしまう

グラフデータとテーブルを同じAxes内に表示する場合によく発生します。

考えられる原因と解決策

  • bbox を使った微調整
    • 原因
      loc だけでは適切な位置に配置できない場合。
    • 解決策
      bbox=[xmin, ymin, width, height] を使用して、Axes座標でテーブルの正確な位置とサイズを決定します。これにより、グラフとテーブルの配置を細かく調整できます。
  • loc の指定ミス
    • 原因
      テーブルの loc 引数が、グラフのプロット領域と重なるように設定されている。
    • 解決策
      loc'bottom', 'top', 'right', 'left' など、グラフと重ならない位置に設定します。

import matplotlib.pyplot as plt import numpy as np

    x = np.linspace(0, 10, 100)
    y = np.sin(x)

    fig, ax = plt.subplots(figsize=(8, 6))
    ax.plot(x, y, label='sin(x)')
    ax.set_title('グラフとテーブル')
    ax.legend()
    ax.grid(True)

    # テーブルデータ
    table_data = [
        ['Min', f'{np.min(y):.2f}'],
        ['Max', f'{np.max(y):.2f}']
    ]

    # テーブルをグラフの下部に配置(Axesの左下隅から0.1, 0.02の位置に、幅0.3, 高さ0.1のサイズで)
    table = ax.table(cellText=table_data, loc='bottom', bbox=[0.1, 0.02, 0.3, 0.1])
    table.auto_set_font_size(False)
    table.set_fontsize(10)

    plt.show()
    ```

table() 関数が古いバージョンで動作しない、または期待と異なる挙動をする

Matplotlibのバージョンアップにより、一部のAPIが変更されたり、機能が追加・修正されたりすることがあります。

  • 非推奨の機能を使用している
    • 原因
      過去のバージョンでは動作したが、現在のバージョンでは非推奨になった引数やメソッドを使用している。
    • 解決策
      最新のドキュメントを参照し、推奨される方法でコードを修正します。
  • Matplotlibのバージョンが古い
    • 原因
      実行しているMatplotlibのバージョンが古く、使用したい機能がサポートされていない、または引数の仕様が異なる。
    • 解決策
      Matplotlibを最新バージョンにアップデートします。
      pip install --upgrade matplotlib
      
  1. エラーメッセージをよく読む
    Pythonのエラーメッセージは、問題の箇所と原因を示す重要な情報源です。特にTypeError, ValueError, IndexError などに注目し、どの引数やデータが問題を引き起こしているかを特定します。
  2. 最小限の再現コードを作成する
    問題が発生したコード全体ではなく、table()関数とその関連部分のみを抜き出して、最小限のコードで同じ問題を再現できるか試します。これにより、問題の原因を絞り込むことができます。
  3. 公式ドキュメントを参照する
    Matplotlibの公式ドキュメントは非常に詳細で、各関数の引数、返り値、使用例が豊富に掲載されています。問題に直面したら、まず公式ドキュメントでtable関数のページを確認することをお勧めします。
  4. 環境を確認する
    Pythonのバージョン、Matplotlibのバージョン、OSなどを確認し、それらの組み合わせが問題を引き起こしている可能性がないか検討します。特に、特定のOSでのみ発生するフォントの問題などは、環境依存の可能性が高いです。


基本的なテーブルの作成

最もシンプルな例で、データとヘッダー(列・行ラベル)を指定してテーブルを作成します。

import matplotlib.pyplot as plt
import numpy as np

# テーブルのデータ
data = [
    [100, 200, 300],
    [150, 250, 350],
    [120, 180, 220]
]

# 行ラベルと列ラベル
row_labels = ['製品A', '製品B', '製品C']
col_labels = ['2023年', '2024年', '2025年']

# FigureとAxes(サブプロット)を作成
fig, ax = plt.subplots(figsize=(7, 4)) # 図のサイズを調整

# Axesの軸を非表示にする(テーブルだけを表示する場合)
ax.axis('off')
ax.set_frame_on(False) # 軸の枠も非表示にする

# table() 関数を使ってテーブルを作成
# cellText: セルに表示するデータ
# rowLabels: 行のヘッダー
# colLabels: 列のヘッダー
# loc: Axes内でのテーブルの配置 ('center' は中央)
table = ax.table(
    cellText=data,
    rowLabels=row_labels,
    colLabels=col_labels,
    loc='center'
)

# テーブルのフォントサイズを自動調整し、少し大きくする
table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1.2, 1.2) # テーブル全体のサイズをX軸方向に1.2倍、Y軸方向に1.2倍に拡大

# タイトルを追加
ax.set_title('製品別年間売上推移', fontsize=14)

plt.show()

解説

  • table.auto_set_font_size(False)table.set_fontsize() でフォントサイズを明示的に指定し、table.scale() でテーブル全体のサイズを調整しています。
  • loc='center' でAxesの中央にテーブルを配置します。
  • ax.table()cellText でデータを、rowLabelscolLabels でそれぞれのラベルを渡します。
  • plt.subplots() でFigureとAxesを作成します。テーブルだけを表示する場合は、ax.axis('off')ax.set_frame_on(False) で軸と枠を非表示にすると綺麗に見えます。

Pandas DataFrame を使ったテーブルの作成

Pandas DataFrame を cellText に直接渡すと、DataFrameのインデックスやカラム名が自動的に行・列ラベルとして使用されるため、非常に便利です。

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# Pandas DataFrameを作成
df = pd.DataFrame(
    np.random.randint(100, 500, size=(4, 3)), # 100から500のランダムな整数を4行3列で生成
    index=['支店A', '支店B', '支店C', '支店D'],
    columns=['商品X', '商品Y', '商品Z']
)

fig, ax = plt.subplots(figsize=(8, 5))
ax.axis('off')
ax.set_title('月間売上データ(Pandas使用)', fontsize=16)

# Pandas DataFrameを直接 cellText に指定
table = ax.table(
    cellText=df.values, # DataFrameのデータ部分
    rowLabels=df.index, # DataFrameのインデックスが行ラベル
    colLabels=df.columns, # DataFrameのカラム名が列ラベル
    loc='center',
    cellLoc='center', # セル内のテキストを中央揃え
    colColours=['lightgray', 'lightgray', 'lightgray'] # 列ヘッダーの背景色
)

# フォントサイズとスケール調整
table.auto_set_font_size(False)
table.set_fontsize(12)
table.scale(1.2, 1.3) # 拡大

plt.show()

解説

  • colColours で列ヘッダーの背景色を一括で指定しています。
  • cellLoc='center' でセルのテキストを中央揃えにしています。
  • df.values でDataFrameの数値データ部分を cellText に、df.index でインデックスを行ラベルに、df.columns でカラム名を列ラベルに設定しています。

セルやヘッダーの色のカスタマイズ

各セル、行ヘッダー、列ヘッダーに個別の色を設定する方法です。

import matplotlib.pyplot as plt

# データとラベル
data = [
    [75, 88, 92],
    [60, 70, 85],
    [95, 80, 78]
]
row_labels = ['学生1', '学生2', '学生3']
col_labels = ['数学', '科学', '国語']

# 各セルの背景色(例: 点数に応じて色分け)
cell_colors = [
    ['lightcoral' if cell < 70 else 'lightgreen' if cell >= 90 else 'lightblue' for cell in row]
    for row in data
]

# 行ヘッダーの色
row_colors = ['#FFFF99', '#CCEEFF', '#FFCCCC'] # 薄い黄色、水色、ピンク

# 列ヘッダーの色
col_colors = ['#DCDCDC', '#DCDCDC', '#DCDCDC'] # 灰色

fig, ax = plt.subplots(figsize=(7, 5))
ax.axis('off')
ax.set_title('学生の成績表', fontsize=16)

table = ax.table(
    cellText=data,
    cellColours=cell_colors, # 各セルの背景色
    rowLabels=row_labels,
    rowColours=row_colors, # 行ヘッダーの背景色
    colLabels=col_labels,
    colColours=col_colors, # 列ヘッダーの背景色
    loc='center',
    cellLoc='center',
    rowLoc='center', # 行ヘッダーのテキストを中央揃え
    colLoc='center'  # 列ヘッダーのテキストを中央揃え
)

table.auto_set_font_size(False)
table.set_fontsize(11)
table.scale(1.1, 1.5) # テーブルの幅と高さを調整

plt.show()

解説

  • rowLoccolLoc で行・列ヘッダーのテキスト配置も指定できます。
  • 16進数カラーコード(例: #FFFF99)も使用できます。
  • rowColourscolColours には1次元リストで色を指定します。
  • cellColours には cellText と同じ構造の2次元リストで色を指定します。

グラフとテーブルを併用する例

テーブルは、グラフの詳細な情報や要約を提示するのに非常に役立ちます。ここでは、棒グラフの下にテーブルを追加する例を示します。

import matplotlib.pyplot as plt
import numpy as np

# グラフのデータ
categories = ['A', 'B', 'C', 'D']
values = [85, 60, 92, 78]

# テーブルのデータ(グラフの要約)
table_data = [
    ['カテゴリ', '値'],
    ['平均', f'{np.mean(values):.2f}'],
    ['最大', np.max(values)],
    ['最小', np.min(values)]
]

fig, ax = plt.subplots(figsize=(8, 6))

# 棒グラフを描画
ax.bar(categories, values, color=['skyblue', 'lightcoral', 'lightgreen', 'gold'])
ax.set_title('カテゴリ別売上', fontsize=16)
ax.set_ylabel('売上', fontsize=12)
ax.set_ylim(0, 100) # Y軸の範囲を設定

# テーブルをグラフの下部に配置
# bbox=[xmin, ymin, width, height] でAxes座標系での位置とサイズを細かく指定
# xmin, yminはAxesの左下からの相対座標(0.0~1.0)
# width, heightもAxesの幅・高さに対する比率(0.0~1.0)
table = ax.table(
    cellText=table_data,
    loc='bottom', # Axesの底部に配置
    bbox=[0.1, -0.3, 0.8, 0.2], # [x座標, y座標, 幅, 高さ]
    cellLoc='center'
)

# テーブルのフォントサイズ調整
table.auto_set_font_size(False)
table.set_fontsize(10)

# テーブルがグラフと重ならないように、サブプロットの下部余白を調整
plt.subplots_adjust(bottom=0.25) # 下部の余白を増やす

plt.show()

解説

  • plt.subplots_adjust(bottom=0.25) は、テーブルが表示されるスペースを確保するために、サブプロットの下部余白を増やしています。これにより、テーブルがグラフに重なるのを防ぎます。
  • 重要
    bbox 引数を使って、テーブルの正確な位置とサイズをAxes座標系で指定しています。[0.1, -0.3, 0.8, 0.2] は、Axesの左端から10%の位置、Axesの下端から-30%(つまりAxesの下にはみ出す)、幅80%、高さ20%の領域にテーブルを配置するという意味です。
  • ax.table() でテーブルを作成し、loc='bottom' でAxesの底部に配置します。
  • ax.bar() で通常の棒グラフを作成します。

table.get_celld() メソッドを使って、テーブル内の各セル(matplotlib.table.Cell オブジェクト)にアクセスし、より詳細なカスタマイズを行うことができます。

import matplotlib.pyplot as plt

data = [
    ['項目A', 150],
    ['項目B', 250],
    ['項目C', 100]
]
col_labels = ['名称', '値']

fig, ax = plt.subplots(figsize=(6, 4))
ax.axis('off')
ax.set_title('詳細カスタマイズテーブル', fontsize=16)

table = ax.table(
    cellText=data,
    colLabels=col_labels,
    loc='center',
    cellLoc='left' # デフォルトは左揃え
)

# テーブル全体のフォントサイズを調整
table.auto_set_font_size(False)
table.set_fontsize(12)

# 各セルにアクセスしてプロパティを変更
for (row, col), cell in table.get_celld().items():
    if row == 0: # 列ヘッダー行
        cell.set_facecolor('darkblue') # 背景色
        cell.set_text_props(color='white', weight='bold') # テキストの色と太さ
        cell.set_height(0.1) # セルの高さ
        cell.set_width(0.3) # セルの幅

    elif row > 0: # データ行
        cell.set_edgecolor('gray') # 境界線の色
        cell.set_linewidth(1.5) # 境界線の太さ

        if col == 1: # 2列目のデータ(値の列)
            cell.set_text_props(ha='right') # 右揃え
            # 特定の値に基づいて色を変更
            value = data[row-1][col] # row-1はデータ配列のインデックス
            if value < 120:
                cell.set_facecolor('pink')
            elif value > 200:
                cell.set_facecolor('lightgreen')
            else:
                cell.set_facecolor('lightblue')
        else: # 1列目のデータ(名称の列)
            cell.set_facecolor('whitesmoke')

# テーブルの境界線を全て表示
table.set_edges('closed')

plt.show()
  • table.set_edges('closed') で、テーブル全体の境界線を明示的に表示しています。
  • cell.set_edgecolor()cell.set_linewidth() でセルの境界線をカスタマイズできます。
  • cell.set_facecolor() でセルの背景色、cell.set_text_props() でテキストの色や太さ、配置を変更できます。
  • table.get_celld().items() を使って、各セルとそのインデックス((row, col))を取得します。


table.table() の代替方法

主に、以下の2つのアプローチがあります。

  1. Matplotlibの他の描画プリミティブを使用する: table.table() ほど構造化されていなくても、テキストや線を使って手動でテーブルのようなものを描画する。
  2. 別のライブラリを使用する: Matplotlib以外で、より特化した表作成機能を持つライブラリを利用し、必要に応じてその出力をMatplotlibと組み合わせる。

Matplotlibの他の描画プリミティブを使用する

これは、table.table() の機能が重すぎる、または特定の部分だけをカスタマイズしたい場合に有効です。

a. ax.text() を使用してテキストを配置する

最も基本的な方法で、個々のセルやラベルを自由に配置できます。

利点:

  • 各テキスト要素のフォント、色、配置などを個別に制御できる。
  • 非常に柔軟性が高く、完全に自由にテキストを配置できる。

欠点:

  • 罫線や背景色などの描画は別途行う必要がある。
  • テーブルの構造(行、列、セル間の間隔)を手動で計算して配置する必要があり、手間がかかる。

コード例:

import matplotlib.pyplot as plt

data = [
    ['Header A', 'Header B', 'Header C'],
    ['Value 1A', 'Value 1B', 'Value 1C'],
    ['Value 2A', 'Value 2B', 'Value 2C']
]

fig, ax = plt.subplots(figsize=(6, 4))
ax.axis('off') # 軸を非表示

# テーブルの開始座標
x_start, y_start = 0.1, 0.8
row_height = 0.1
col_widths = [0.3, 0.3, 0.3] # 各列の相対幅

# セル間の間隔
x_padding = 0.02
y_padding = 0.02

current_y = y_start

for r_idx, row_data in enumerate(data):
    current_x = x_start
    for c_idx, cell_text in enumerate(row_data):
        # セルの背景を描画(例: ヘッダー行のみ背景色をつける)
        if r_idx == 0:
            rect = plt.Rectangle((current_x, current_y - row_height + y_padding/2),
                                 col_widths[c_idx] - x_padding, row_height - y_padding,
                                 facecolor='lightgray', edgecolor='black', linewidth=1)
            ax.add_patch(rect)

        # テキストを配置
        ax.text(current_x + col_widths[c_idx] / 2, # 中央揃えのためにX座標を調整
                current_y - row_height / 2, # Y座標を調整
                cell_text,
                ha='center', va='center', # 水平・垂直中央揃え
                fontsize=10,
                bbox=dict(facecolor='white' if r_idx > 0 else 'none', edgecolor='none', boxstyle='square,pad=0.5')) # セルの背景(ヘッダー以外)

        current_x += col_widths[c_idx]
    current_y -= row_height

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("ax.text() を使用したテーブル風表示")
plt.show()

b. ax.add_patch()ax.text() を組み合わせて罫線や背景を自由に描画する

ax.text() だけでは罫線や背景の描画が面倒ですが、matplotlib.patches.Rectangle などのパッチを使って四角形を描画し、その上にテキストを重ねることで、よりテーブルらしい見た目を作成できます。

利点:

  • セルの背景色や罫線を細かく制御できる。
  • 見た目の自由度が非常に高い。

欠点:

  • 座標計算が手動になり、レイアウト変更に手間がかかる。
  • table.table() に比べてコードが複雑になりやすい。

これは上記の ax.text() の例に plt.Rectangle を追加したもので、より詳細なカスタマイズが可能です。

Matplotlibの機能を補完するため、または完全に別の目的で表を作成するために、特化したライブラリを使用します。

a. Pandas DataFrame の表示機能を利用する

Pandas DataFrame は、そのもの自体が表形式のデータ構造であり、Jupyter Notebookなどでは非常に綺麗に表示されます。これを画像として保存することも可能です。

利点:

  • df.style を使うことで、条件付き書式設定や背景色、フォントなどを高度にカスタマイズできる。
  • df.to_html() などでHTML形式に変換して、Webページなどに埋め込むことができる。
  • Jupyter Notebookでのインタラクティブな表示が強力。
  • DataFrameのデータをそのまま表として表示できる。

欠点:

  • グラフと同時に表示するには、レイアウトの調整が必要。
  • MatplotlibのFigure内に直接埋め込むのは難しい(画像として保存してからax.imshow()で表示するなどの工夫が必要)。

コード例 (Jupyter Notebookでの表示):

import pandas as pd
import numpy as np

df = pd.DataFrame(
    np.random.rand(5, 3),
    index=[f'Row {i}' for i in range(1, 6)],
    columns=['Column A', 'Column B', 'Column C']
)

# スタイルを適用
styled_df = df.style.background_gradient(cmap='Blues') \
                    .format(precision=2) \
                    .set_caption("Pandas DataFrame with Styles") \
                    .highlight_max(axis=0, color='yellow')

# Jupyter Notebookで実行すると、スタイルが適用されたHTMLテーブルとして表示される
styled_df

Matplotlib Figure内への埋め込み (間接的な方法): PandasのDataFrameを画像として保存し、それをMatplotlibのAxesに読み込む方法です。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import dataframe_image as dfi # dfiをインストールする必要がある: pip install dataframe-image

# データフレームの作成
df = pd.DataFrame(
    np.random.randint(10, 100, size=(5, 4)),
    index=[f'製品{i}' for i in range(1, 6)],
    columns=['Q1', 'Q2', 'Q3', 'Q4']
)

# データフレームのスタイル設定(オプション)
styled_df = df.style.background_gradient(cmap='YlGn')\
                    .set_caption("四半期売上データ")

# DataFrameを画像ファイルとして保存
# Chrome/Chromiumブラウザまたはwkhtmltopdfが必要
try:
    dfi.export(styled_df, 'styled_dataframe.png')
    print("DataFrameが画像として保存されました: styled_dataframe.png")
except Exception as e:
    print(f"DataFrameを画像として保存できませんでした。Chrome/Chromiumまたはwkhtmltopdfがインストールされているか確認してください: {e}")
    # 代替として、シンプルなテーブルを作成するなどのフォールバック処理
    fig, ax = plt.subplots(figsize=(6, 4))
    ax.axis('off')
    ax.text(0.5, 0.5, "DataFrameを画像に変換できませんでした。\nMatplotlibのtable()を使用してください。",
            ha='center', va='center', fontsize=12)
    plt.show()
    exit() # 処理を終了するか、他の代替手段に進む

# 保存した画像をMatplotlibで読み込み、表示
fig, ax = plt.subplots(figsize=(8, 6))

try:
    img = mpimg.imread('styled_dataframe.png')
    ax.imshow(img)
    ax.axis('off') # 画像なので軸は不要
    ax.set_title("DataFrameを画像としてMatplotlibに表示", fontsize=16)
except FileNotFoundError:
    print("画像ファイルが見つかりません。")

plt.show()

注意: dataframe-image ライブラリは、内部でウェブレンダリングエンジン(Chrome/Chromiumブラウザまたはwkhtmltopdf)を使用するため、それらがシステムにインストールされている必要があります。

b. 専用のレポート生成ライブラリを利用する

Pythonには、より複雑なレポートやドキュメントを生成するためのライブラリが多数存在します。これらは、単なるグラフの描画を超えて、表、テキスト、画像などを統合したドキュメントを作成することに特化しています。

  • WeasyPrint: HTML/CSSをPDFに変換するライブラリ。PandasのHTML出力と組み合わせることで、美しいPDFレポートを作成できます。
  • Pandoc + LaTeX/HTML: MarkdownやreStructuredTextで記述した内容を、Pandocを使ってLaTeX(PDF出力)やHTMLに変換し、その中にテーブルやグラフを埋め込む方法。テーブルの記述はMarkdownのシンタックスを利用できるため比較的簡単です。
  • ReportLab: PDFドキュメント生成ライブラリ。詳細なテーブルレイアウトや複雑なドキュメント作成に適しています。Matplotlibのグラフを埋め込むことも可能。

利点:

  • Matplotlibのグラフも組み込みやすい。
  • テーブルのレイアウトやデザインを高度に制御できる。
  • 複雑なドキュメントやレポートの作成に特化している。

欠点:

  • MatplotlibのFigure内に直接テーブルを描画する目的とは少し異なる。
  • 学習コストが高い場合がある。
  • データフレームを美しく表示したい、またはHTML/PDFレポートの一部として表を作成したい: Pandasの表示機能やdataframe-image、あるいはReportLabなどの専用ライブラリが適しています。
  • 非常に細かくレイアウトを制御したい、またはtable()のデフォルトの動作が合わない: ax.text()ax.add_patch() を使って手動で構築する方法も検討できますが、手間がかかります。
  • シンプルな表をMatplotlibグラフ内に直接描画したい: matplotlib.pyplot.table() または matplotlib.axes.Axes.table() が最も直接的で推奨される方法です。