Claude Media
Claudeでグラフの代替テキストと表データを付ける手順 — 色に頼らない凡例も

Claudeでグラフの代替テキストと表データを付ける手順 — 色に頼らない凡例も

グラフ画像やSVGに、短いalt・傾向の1文・データ表の3点をClaudeで一括して付ける手順です。色だけに頼らない凡例への直し方と、数値の検算スクリプトも載せます。

グラフ画像のaltに「売上推移のグラフ」とだけ書いても、画面を見られない人には何も伝わりません。グラフのaltは、短い説明と長い説明の二部構成にするのが基本です。長い説明の中身は、傾向を述べた1文とデータ表です。

この記事では、その3点セット(短いalt・傾向の1文・データ表)をClaudeに作らせ、HTMLに差し込み、数値を検算するまでを示します。写真や汎用画像のaltを一括で付ける場合はClaudeでaltテキストを画像から一括生成する手順が別にあります。グラフは「情報そのもの」を文字で出す必要があるぶん、扱いが違います。

グラフのaltは短い説明と長い説明の二部構成にする

W3CのWAIは、グラフや図表のように1文では伝えきれない画像を「複雑な画像」と呼びます。こうした画像には二部構成の代替テキストが必要です。

構成

グラフに付ける3つの文字情報

  • 短いalt

    グラフの種類と、何を表すかの識別だけを書きます。例は「2025年第1四半期のサイト1〜3の月別訪問者数を示す棒グラフ」です。

  • 傾向の1文

    読者に伝えたい読み取りを書きます。「サイト1は減少、サイト2は横ばい、サイト3は増加」のような一文です。

  • データ表

    軸の目盛り、系列ごとの値、単位を表にします。棒の並び順や使っている色のように、構造そのものが情報になる場合はそれも書きます。

長い説明は画像のリンク先に隠さず、本文の一部として全員に見せる形がW3Cのチュートリアルに載っています。複雑な図は、視覚に障害がない人にとっても読み解きにくいためです。本文側で「次のグラフは第1四半期に落ち込み、第2四半期に回復したことを示します」のように要点を添えるのも有効です。

色だけに頼らない凡例にする基準

WCAG 2.2の達成基準1.4.1(レベルA)は、色を「情報を伝える・操作を示す・視覚要素を区別する」ための唯一の手段にしないことを求めています。折れ線グラフで系列を色だけで見分ける凡例は、これに引っかかる典型です。

直し方は3通りです。

  • 系列ごとに線種(実線・破線・点線)やマーカー形状を変える
  • 線の末尾に系列名を直接ラベルとして置く
  • 色が見分けられなくても読めるデータ表を併記する

Claudeには、画像を見せて「色だけで区別している箇所はどこか」を挙げさせられます。ただし画像から読めるのは見た目の判定です。実際の色覚シミュレーションは別ツールで確かめます。

渡す材料は元データが先、画像は後

altを書かせる前に、元のCSVや集計表が手元にあるかを確かめます。あるなら、画像ではなくデータを渡して表と傾向文を作らせるのが最も確実です。画像から数値を読み取らせると、棒の高さや点の位置からの推定になり、誤読が混ざります。

Claudeの画像理解には、公式の制限事項として次のものが挙がっています。

  • 低品質・回転・200ピクセル未満の小さい画像では誤解釈や作り話をすることがある
  • 物の個数はおおよそで、小さいものが大量にあると不正確になりうる

棒グラフの値を画像だけから拾う運用は、まさにこの弱点に当たります。画像しか残っていない古い資料のときだけ、画像渡しに切り替えます。

使い分けは次のとおりです。

手元にあるもの渡すもの表の数値の信頼度
CSV・集計表がある渡すものデータ(+画像は凡例確認用)表の数値の信頼度元データのまま転記できる
SVGのソースがある渡すものSVGのテキストと凡例の文言表の数値の信頼度値が属性に入っていれば読める
PNG・JPEGだけ渡すもの画像表の数値の信頼度推定値。要目視確認

画像として送れる形式はJPEG・PNG・GIF・WebPです。SVGはこの形式に載っていないので、SVGはソースをテキストとして貼るか、PNGに変換して送ります。

元データから3点セットを作らせる

CSVがあるときの指示は、出力の形を固定するのがコツです。次の形でJSONを返させると、後工程でHTMLに差し込めます。

添付のCSVは、ある棒グラフの元データです。
次のJSONだけを返してください。
{
  "alt": "グラフの種類と対象。60字以内。傾向は書かない",
  "trend": "読み取れる傾向を1文で。データにある数値だけを使う",
  "table": [["列見出し", ...], ["行1", ...]],
  "legend_issues": []
}
- 数値はCSVの値をそのまま写し、丸めない
- CSVに無い数値(増加率など)を作らない
- 単位は列見出しに入れる

最後の2行が効きます。増加率のような計算値は、頼まなくても傾向文に混ざりやすいため、禁止するか、計算するなら式も書かせます。

画像に傾向文を足すだけなら、同じ指示で画像を添えます。このとき画像をテキストより前に置くと結果が安定しやすいという案内が、visionのドキュメントにあります。

画像だけが残っている場合のAPI呼び出し

PNGやJPEGしか無い場合は、画像ブロックの後ろに指示を置く形で送ります。次は百枚規模の一括処理に向く最小構成の例です。モデルIDは環境変数で渡します。

import base64, json, os, sys
import anthropic
 
client = anthropic.Anthropic()
PROMPT = open("chart_prompt.txt", encoding="utf-8").read()
 
def describe(path):
    data = base64.standard_b64encode(open(path, "rb").read()).decode()
    msg = client.messages.create(
        model=os.environ["MODEL_ID"],
        max_tokens=1500,
        messages=[{"role": "user", "content": [
            {"type": "image", "source": {
                "type": "base64",
                "media_type": "image/png",
                "data": data}},
            {"type": "text", "text": PROMPT},
        ]}],
    )
    return json.loads(msg.content[0].text)
 
for p in sys.argv[1:]:
    print(p, json.dumps(describe(p), ensure_ascii=False))

画像が大きすぎると縮小され、軸の目盛りの文字が読みにくくなります。縮小が始まる長辺はモデルで違い、Claude 4.7以降は2,576px、それ以前のモデルは1,568pxです。1枚あたりの寸法の上限は8000×8000px、サイズの上限はClaude APIで10MB(base64後)です。

目盛りが小さいグラフは、送る前に長辺を使うモデルの値以下へ自分で縮め、文字がつぶれていないかを目で確かめます。上限を超えた画像は自動で縮小されるため、送った画像と同じ見た目で読まれるとは限りません。JPEGの圧縮を何度も重ねると文字が読みづらくなり、性能が落ちる点もドキュメントに書かれています。

百枚規模の一括処理では、枚数と寸法の両方に上限があります。

  • 1リクエストの画像は、200kトークンのコンテキストウィンドウのモデルで100枚、それ以外のモデルで600枚まで
  • 1リクエストに21枚以上入れると、全画像に厳しい寸法上限がかかる。縦横とも2,000px以下に縮めるか、20枚以下に分ければ避けられる
  • リクエスト全体のサイズ上限は標準のエンドポイントで32MB。枚数の上限より先に当たることがある

一括処理は1画像1リクエストか、20枚以下ずつに分けるのが無難です。

HTMLに差し込む:figureの中に表を置く

W3Cの例は、figure の中に画像と長い説明をまとめ、role="group" を添えて古いブラウザにも対応させる形です。生成したJSONからは次のHTMLを組み立てます。

<figure role="group">
  <img src="sales-2025q1.png"
       alt="2025年第1四半期のサイト1〜3の月別訪問者数の棒グラフ。詳細は下の表">
  <figcaption>
    <p>サイト1は減少、サイト2は横ばい、サイト3は増加しています。</p>
    <table>
      <caption>月別訪問者数(単位: 千人)</caption>
      <tr><th>サイト</th><th>1月</th><th>2月</th><th>3月</th></tr>
      <tr><td>サイト1</td><td>120</td><td>110</td><td>95</td></tr>
    </table>
  </figcaption>
</figure>

数値は説明用の例です。表が必要になる理由は、aria-describedby で参照した要素が1つの連続した段落として読まれ、見出しや表の構造が失われるためです。W3Cはこの方法をテキストだけの説明向けとしており、表を含む長い説明には向きません。

SVGのグラフに名前と説明を付ける

SVGのソースが手元にあるなら、画像として送るよりテキストで貼るほうが値を正確に読ませられます。付ける側も同じで、SVGのグラフには title と desc の子要素で名前と説明を入れられます。SVG 2の仕様では、title は要素の短い代替テキスト、desc はより詳しい説明にあたります。役割は、先ほどの短いaltと長い説明の対応と同じ分け方です。

仕様には守る点が3つあります。

  • title と desc は、子要素として置いたときに親要素の名前と説明になる
  • 空の title や desc は置かない。名前のないオブジェクトとして支援技術に渡るため
  • 画面に見えるラベルがすでにあるなら、title に同じ文を重ねず aria-labelledby でそのラベルを指す

desc は支援技術向けの情報で、通常は他の利用者に見えません。仕様も、必須の指示に使わないよう注意しています。傾向の1文やデータ表は、SVGの外の本文に出す形のままにします。

Claudeには、SVGのソースを貼って次のように頼みます。

次のSVGのグラフに、アクセシブルな名前と説明を付けてください。
- title: グラフの種類と対象。60字以内。傾向は書かない
- desc: 軸、系列、読み取れる傾向。SVG内の数値だけを使う
- svg要素に role="img" と aria-labelledby を付け、
  title と desc のidを指す
- 元の図形は変更せず、追加した要素だけを示す

返ってくる差し込み例は次の形になります。

<svg role="img" aria-labelledby="t1 d1" viewBox="0 0 300 200">
  <title id="t1">2025年第1四半期のサイト1〜3の月別訪問者数の棒グラフ</title>
  <desc id="d1">横軸は月、縦軸は訪問者数(千人)。
    サイト1は減少、サイト2は横ばい、サイト3は増加。</desc>
  <!-- 以下、元の図形 -->
</svg>

role="img" はグラフ全体を1枚の画像として読ませるための選択で、仕様が求める書き方ではありません。<img src="chart.svg"> のようにファイルとして読み込む場合は、SVGの中身ではなくHTML側の alt が名前になるため、前節のfigureの形をそのまま使います。

グラフの種類で、altと傾向文に書くことは変わる

W3Cのチュートリアルの例は棒グラフだけで、折れ線や円の書き分けは載っていません。次の表は、altと傾向文の役割を種類別に分けた編集上の目安です。数値は説明用です。

グラフの種類altに書くこと傾向文に書くこと表に載せるもの
棒グラフaltに書くこと比べている対象と期間傾向文に書くこと最大・最小と、並びから分かる差表に載せるもの項目ごとの値と単位
折れ線altに書くこと系列の数と期間傾向文に書くこと上昇・下降の向きと転換点表に載せるもの時点ごとの値(系列別の列)
円・ドーナツaltに書くこと何の内訳か傾向文に書くこと最も大きい項目と、全体に占める割合表に載せるもの項目ごとの割合と合計
散布図altに書くこと2つの軸が何か傾向文に書くこと相関の向き(右上がり・無相関など)と外れ値の有無表に載せるもの点の座標。多いときは代表点と要約

たとえば円グラフなら、altは「2025年の流入経路の内訳を示す円グラフ」で十分です。「検索が60%を占め、最大」は傾向文に置きます。60%という数値は表にも載せるので、altには入れません。

散布図は点が密になると、表に全点を載せても読めません。この場合は相関の向きと外れ値だけを傾向文に書き、元データへのリンクを添える形になります。

生成結果を検算する

傾向文や表の数値は、公開前に必ず元データと突き合わせます。表のセルに現れる数値がすべて元CSVに存在するかは、数行のスクリプトで判定できます。

import csv, json, re, sys
 
source = {c for row in csv.reader(open(sys.argv[1], encoding="utf-8"))
          for c in row}
result = json.load(open(sys.argv[2], encoding="utf-8"))
 
def nums(text):
    return re.findall(r"\d+(?:\.\d+)?", text)
 
used = {n for row in result["table"][1:] for c in row[1:] for n in nums(c)}
used |= set(nums(result["trend"]))
missing = sorted(n for n in used if n not in source)
print("CSVに無い数値:", missing or "なし")

CSVに無い数値が出たら、計算値か誤読です。計算値で正しいなら、表の注に式を添えます。傾向文が「増加」と書いているのに表の数値が減っていないか、という意味の突き合わせは自動化しにくいので、目で見ます。

つまずきやすい点

落とし穴

同じ内容をaltと本文で二重に読ませる

長い説明を本文に出すなら、altに数値を詰めると音声で二度読まれます。altは識別だけに絞り、数値は表に任せます。

  • Claudeが画像に無い凡例の意味を補う: 色名と系列の対応を勝手に推測することがあります。凡例が画像内に無いときは、系列名を指示に書いて渡します
  • 件数が多いと見落としが増える: 点が密な散布図は個数や位置が不正確になりうるため、元データを必須にします
  • 装飾用のグラフ風画像: 情報を持たない飾りなら、グラフ用の3点セットではなく alt="" にします。判定の考え方は写真・汎用画像のalt生成の記事で扱っています
  • PRで機械検査も併用する: altの有無はaxeのようなツールで検査できます。表の中身の正しさは検査では分からないので、上の検算と併せます。CIでの組み込みはPlaywrightとaxeのCI検査にまとめています

グラフを新しく作る側の頼み方はClaudeにグラフを作らせる基本の頼み方を参照してください。作る時点で系列ごとの線種を指定しておけば、あとからaltで補う量が減ります。

まとめ

グラフのaltは、識別だけの短い文にして、傾向の1文とデータ表を本文側に置く構成が標準です。Claudeは元データから3点セットを作る用途に向き、画像からの数値読み取りは推定になります。生成後は、表の数値が元データに存在するかをスクリプトで確かめ、傾向文の方向だけ目で見る。この二段で、公開してよい水準に届きます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. platform.claude.com/docs/en/build-with-claude/vision
  2. w3.org/WAI/tutorials/images/complex
  3. w3.org/TR/WCAG22
  4. w3.org/TR/SVG2/struct.html
この記事を共有:XはてブLinkedIn