論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
複合グラフ
Composite Chart / 組み合わせグラフ
可視化
別称: 組み合わせグラフ / コンビネーションチャート

🔖 キーワード索引

#複合グラフ#棒+折れ線#2軸#twinx#matplotlib#可視化

複合グラフ(composite chart)」は、 棒グラフと折れ線グラフなど異なる種類のグラフを1つの図に重ねて表示する可視化手法。 本ページでは複合グラフを取り巻く中核キーワードをチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

複合グラフ2軸グラフSSDSE-B-2026スケール調整適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「複合グラフの理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

このページで扱う考えを、先に一覧にしておきます。 どれも「二軸を使ってよいか」を判断するための道具です。

用語このページでの意味
複合グラフ棒と線など異なる形の系列を 1 枚に重ねた図。多くは二軸を伴う
二軸(twinx)左右に無関係な単位の軸を置くこと。右軸の範囲は作図者が自由に決められる
第 2 軸(secondary axis)右軸が左軸の関数で決まる読み替え。恣意性がない
写像式 $\ell(r)$右軸の値が図上のどの高さに置かれるかを決める 1 次関数
交点棒と線が交わる点。右軸の範囲次第で任意の位置に動くため情報を持たない
指数化基準年を 100 にそろえる変換。二軸の第一の代替案
スモールマルチプル重ねずに縦に並べ、横軸だけ共有する図
足せる量/足せない量人数・件数は棒、率・強度は線。形と意味を一致させる原則
水準の相関/差分の相関前者は共通トレンドで膨らむ。後者で本当の連動を確かめる
見せかけの回帰両系列が時間で単調に動くだけで相関が大きく出る現象
パレート図右軸を 0〜100% の累積比率に固定した、恣意性のない複合グラフ
zorder描画の前後関係。twinx では既定で線が棒の前に来る

💡 30秒で分かる結論

🍰 まずはやさしく

2種類のグラフを重ねたものです。

違う単位のデータを同時に見せるために使います。

テストの点数と正解率を一緒に並べるようなものです。

この章では複合グラフの基本を学びます。

複合グラフ:異なるグラフ種を1図に重ね、 異質な指標を同時に見せる

📍 文脈ボックス

🍰 まずはやさしく

データの見せ方のひとつです。

分析レポートなどで正しく伝えるために使います。

部活の人数と勝ち率をまとめて出す時に便利です。

このページでは定義から作り方までを解説します。

この用語は 可視化 カテゴリに属します。 関連する別称・略号:組み合わせグラフ・コンビネーションチャート。 単位の異なる2系列を左右軸で重ねる形は特に 2軸グラフ と呼ばれます。

論文・実務レポートで 複合グラフ が登場したら、 まず本ページの「30秒で分かる結論」と「直感で掴む」を読めば、 その文脈で何を言っているか把握できます。

本ページでは「複合グラフ」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「複合グラフ」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む

🍰 まずはやさしく

2つの情報を1枚にまとめた地図のようなものです。

バラバラなデータを比べて、関係を見つけるために使います。

スマホの利用時間と成績の変化を重ねて見ます。

なぜグラフを重ねるのか、その理由を説明します。

都道府県別の 総人口(棒)高齢化率(折れ線) を1枚に重ねる。 棒の高さで「その県の人口規模」、 折れ線の上下で「高齢化の進み具合」が同時に読める ── これが 複合グラフ。 人口は「万人」、 高齢化率は「%」で単位が違うため、 左軸を人口、 右軸を%にした 2軸グラフ にするのが定石。

なぜ重ねるのか: 東京都は人口 1,409 万人と巨大だが高齢化率は 22.8% と全国最低クラス。 秋田県は人口 91 万人と小さいが高齢化率 39.1% と全国最高。 棒だけ・折れ線だけを別々の図にすると、 読者は2枚を視線で往復して対応づけねばならない。 複合グラフなら「人口が大きい大都市ほど高齢化率が低い」という逆の関係が1枚で浮かび上がる。

積み上げ棒グラフとの違い: 積み上げ棒は「同じ単位のカテゴリ(年少/生産/高齢)を1本の棒に積む」。 複合グラフは「単位の違う指標(人口=棒/高齢化率=折れ線)を左右軸で重ねる」。 両者とも「複数情報を1図に集約」する点は同じだが、 積み上げは構成比、 複合グラフは異質指標の同時比較、 と使い分ける。

表 1. 複合グラフでよく組み合わせる2系列(SSDSE-B-2026)
棒(左軸・量)折れ線(右軸・率/変化)読み取れること
総人口 A1101高齢化率 A1303/A1101人口規模と高齢化の関係
出生数 A4101合計特殊出生率 A4103実数と比率の乖離
総人口 A1101年平均気温 B4101規模と気候の対応(相関の当たり)

なぜ「桁が違う」と重ねられないのか — 26 倍と 1.7 倍

複合グラフが必要になる状況を、SSDSE-B-2026 の 2023 年データで具体的に見ます。 47 都道府県の総人口高齢化率を、同じ 1 本の縦軸に描こうとするとどうなるか。

項目最大最小最大 ÷ 最小
総人口(人)東京都 14,086,000鳥取県 537,00026.2 倍
高齢化率(%)秋田県 39.06東京都 22.751.72 倍

総人口の軸は 0〜1,400 万まで伸びます。その軸に高齢化率 39.06 を打つと、 軸の高さの 39.06 ÷ 14,086,000 ≒ 0.00028 % —— つまり底辺にぴったり張り付いた、区別のつかない一本の線になります。 秋田(39.06)と東京(22.75)の差はグラフ上で 1 ピクセルにもなりません。 これが「二軸を使いたくなる」典型的な動機です。

ただし気をつけてください。この動機は「二軸が正しい」ことを意味しません。 意味するのは「この 2 つは単位も桁も違う、別種の量である」という事実だけです。 別種の量を 1 枚の絵に載せた瞬間、読み手は「同じ図にあるのだから比べられるはずだ」と誤解します。 複合グラフの技術的な問題は解けても、この認知的な問題は残り続けます。

3 つの登場人物:棒・線・面

複合グラフの部品には、それぞれ読み手が無意識に期待する意味があります。 この期待に逆らうと、正しいデータでも誤読されます。

読み手が期待する意味適した量・SSDSE での例
量そのもの。長さを比べる。ゼロから始まる総人口、出生数、婚姻件数、着工新設住宅戸数(足し算に意味がある量
連続的な推移。傾きを読む。ゼロ始まりでなくてよい高齢化率、合計特殊出生率、年平均気温(比率・強度など足せない量
面(塗り)累積・構成。全体に占める割合15 歳未満/15〜64 歳/65 歳以上の積み上げ

原則棒は「足せる量」、線は「足せない量」。 たとえば高齢化率を棒で描くと、読み手は無意識に「47 本の棒を足したら全国の高齢化率」と感じてしまいます。 実際には 47 県の高齢化率の単純平均(31.59%)と、全国の高齢化率(29.13%)は一致しません。 人口の大きい東京(22.75%)の重みが単純平均では無視されるからです。 率を棒にしただけで、この 2.5 ポイントのずれが見えなくなります。

複合グラフの標準形が「棒+線」なのは偶然ではありません。 左軸に足せる量(実数)を棒で、右軸に足せない量(率)を線で置く—— この組み合わせは形と意味が一致しているので、比較的誤読が少ないのです。 逆に「棒+棒」の二軸(左右で違う単位の棒を並べる)は、 読み手が長さを直接比べてしまうため最も危険な形です。

歴史的な背景 — なぜ二軸は「悪者」になったのか

複合グラフ自体は 19 世紀から使われてきた古い形式で、 もともとは限られた紙面に複数の情報を詰め込むための工夫でした。 印刷が高価だった時代、図を 2 枚に分けることには実質的なコストがあり、 軸を 2 本にして 1 枚にまとめる合理性がありました。

状況が変わったのは、表計算ソフトが「第 2 軸」をボタン 1 つで追加できるようになってからです。 コストがゼロになった結果、必要のない場面でも二軸が使われるようになりました。 同時に、右軸の範囲を自動設定に任せる習慣が広まり、 作図者自身が「自分が何を選んだか」を自覚しないまま図が量産される状態が生まれます。 可視化の教科書が二軸に厳しいのは、二軸そのものが悪いからではなく、 この「無自覚な選択」を問題視しているからです。

一方で、画面の解像度が上がり、図を何枚並べても追加コストがかからない現代では、 スモールマルチプルという選択肢が事実上タダで手に入ります。 19 世紀に二軸を正当化していた制約は、もう存在しません。 にもかかわらず二軸を選ぶなら、それは「1 枚にまとめたほうが読み手にとって良い」という 積極的な判断でなければならない、というのが現在の標準的な立場です。

もう一つ、日本の統計資料には「棒+線の複合グラフ」が定型として深く根づいているという事情もあります。 白書や自治体の統計年鑑では、実数を棒・率を線で示す形が半ば様式化しており、 読み手の側もその読み方に慣れています。 読み手が慣れている形式には、それ自体に伝達上の価値があります。 本ページで挙げた注意点は「二軸を使うな」という主張ではなく、 慣習に乗るときこそ、右軸の範囲と主張の限定を意識的に選べという話だと受け取ってください。

📐 定義・数式

🍰 まずはやさしく

グラフの目盛りを調整する仕組みです。

単位が違うデータを同じ高さに収めるために使います。

買い物で、金額と個数を同時にグラフにする時に必要です。

目盛りをどうやって決めるのか、仕組みを解説します。

【第2軸スケーリング】
$$ s = \frac{\max_i x_i}{\max_i y_i}, \qquad \tilde y_i = y_i \cdot s $$

棒の系列 $x_i$(例: 人口)と折れ線の系列 $y_i$(例: 高齢化率)は単位が違う。 折れ線を棒と同じ高さ帯に収めるには、 両系列の最大値の比 $s$ を掛けて $\tilde y_i$ に変換する。 実務では ax.twinx()第2軸そのものを別スケールにするため、 この $s$ を明示的に計算せずとも matplotlib が自動で対応づける。 右軸の目盛りが元の $y_i$(%)のまま読める点が2軸グラフの利点。

二軸の対応づけを式で書く

複合グラフの本質は「2 本目の軸をどう 1 本目に写像するか」です。これは 1 次関数で書けます。 左軸の値域を $[L_{\min}, L_{\max}]$、右軸の値域を $[R_{\min}, R_{\max}]$ とすると、 右軸の値 $r$ は描画上、左軸のどの高さ $\ell(r)$ に置かれるかが決まります。

$$\ell(r) = L_{\min} + \frac{r - R_{\min}}{R_{\max} - R_{\min}} \cdot (L_{\max} - L_{\min})$$

そして「2 本の線が交わる点」は $\ell(r) = b$($b$ は左軸の系列の値)を解いた

$$r^{*} = R_{\min} + \frac{b - L_{\min}}{L_{\max} - L_{\min}} \cdot (R_{\max} - R_{\min})$$

で与えられます。ここが決定的です。$R_{\min}, R_{\max}$ は作図者が自由に決められるので、 交点の位置も、線が棒の上に来るか下に来るかも、作図者が自由に決められます。 データは 1 ミリも変えずに、です。 複合グラフに「正しい交点」という概念は存在しません。 これが $\ell$ がデータではなく作図者の選択の関数である、という意味です。

唯一の例外は、2 つの軸が意味のある変換で結ばれている場合です。たとえば

$$\text{高齢化率}(\%) = \frac{P_{65+}}{P_{\text{total}}} \times 100$$

のように、右軸が左軸の値から一意に決まるなら、二軸は単なる目盛りの読み替えであり恣意性はありません (摂氏と華氏、円とドル、人数と割合など)。 matplotlib の secondary_yaxis(functions=(f, g)) はこの用途のための機能で、 本来の意味での「二軸」はこちらです。恣意的な二軸(twinx)とは別物として区別してください。

この節のまとめ

数式の側から見た複合グラフの本質は、たった 1 行に凝縮できます—— 右軸の値 $r$ が図上のどこに描かれるかは、$r$ だけでは決まらない。 $R_{\min}$ と $R_{\max}$ というデータの外側にある 2 つの数が必ず介在します。 左軸(棒)は「ゼロ始まり」という規範が $L_{\min} = 0$ を固定してくれるのに対し、 右軸にはそれに相当する規範がありません。この非対称性が、複合グラフの危うさの正体です。

逆に言えば、$R_{\min}, R_{\max}$ を決めるルールを先に固定してしまえば、 複合グラフは十分に信用できる図になります。 パレート図が「右軸は 0〜100% の累積比率」と決め打ちしているのが、その成功例です。 自分で二軸を作るときも「右軸はデータの実測範囲に合わせる」といった 自分なりのルールを先に決め、図の脚注に書く—— これだけで、恣意性の批判はほぼ回避できます。

🔬 数式を言葉で読み解く

数式に出てくる記号の意味を 1 つずつ確認しましょう。

$x_i$
棒で描く系列(例: $i$ 県の総人口)。 左軸に対応。
$y_i$
折れ線で描く系列(例: $i$ 県の高齢化率)。 右軸に対応。
$s$
スケール係数。 折れ線を棒の高さ帯へ揃える倍率。
twinx
左軸を共有し右側に独立した第2軸を作る matplotlib 操作。

複合グラフの本質は「2つの独立したスケールを x 軸だけ共有させる」こと。 スケール係数 $s$ は概念理解のための式で、 実装では第2軸に元の単位(%)をそのまま表示させるのが読み手に親切です。 どこを揃え(x 軸)、 どこを分けるか(y 軸) を意識するのが読解の要点です。

記号を 1 つずつ、実際の数値に置き換える

前節の写像式 $\ell(r) = L_{\min} + \dfrac{r - R_{\min}}{R_{\max} - R_{\min}}(L_{\max} - L_{\min})$ を、 全国の総人口(棒・左軸)と高齢化率(線・右軸)の図で読み解きます。

記号言葉での意味この図での値と、決めたのは誰か
$L_{\min}$左軸の下端0(万人)。棒グラフなのでゼロ始まりが必須——ここは作図者の自由ではない
$L_{\max}$左軸の上端14,000(万人)。データの最大 12,759 万人を少し超える値。慣習的に決まる
$R_{\min}$右軸の下端作図者が完全に自由に決める。0 でも 24 でも 28 でもよい
$R_{\max}$右軸の上端同上
$r$右軸の系列の値高齢化率。2012 年 24.13、2023 年 29.13(データが決める
$\ell(r)$図の上での高さ$R_{\min}, R_{\max}$ 次第でいくらでも動く合成物

表を縦に眺めると、データ由来の量は $r$ ただ 1 つで、 残りはすべて作図者の選択であることが分かります。 左軸(棒)は「ゼロ始まり」という強い規範があるので自由度が低いのに対し、 右軸(線)にはそれに相当する規範がありません。 複合グラフの非対称な危うさは、この一点に集約されます。

実際に代入してみます。$L_{\min}=0$, $L_{\max}=14000$, $R_{\min}=24$, $R_{\max}=30$, $r=29.13$ なら

$$\ell(29.13) = 0 + \frac{29.13 - 24}{30 - 24} \times 14000 = \frac{5.13}{6} \times 14000 = 11{,}970$$

つまり 2023 年の高齢化率の点は、左軸で読むと「11,970 万人」の高さに打たれます。 同じ年の総人口の棒は 12,435 万人。 線は棒のすぐ下、ほとんど頭が触れる位置に来ます。 読み手はここから「高齢化率が総人口に追いつきそうだ」という、 意味のまったくない印象を受け取ります。 $R_{\min}$ を 0 に変えれば $\ell = 0 + (29.13/30) \times 14000 = 13{,}594$ となり、 今度は線が棒を追い越します。データは同じです。

「交点」に意味がないことの証明

複合グラフの解説でよく「線が棒を上回った年が転換点」といった読み方をされますが、 これは式から見て無意味です。 交点の位置 $r^{*} = R_{\min} + \dfrac{b - L_{\min}}{L_{\max} - L_{\min}}(R_{\max} - R_{\min})$ に $b$(棒の高さ)が入っている一方、$R_{\min}, R_{\max}$ も入っています。 後者は作図者が決めるので、「交点をどの年に持ってくるか」を先に決めてから $R$ を逆算できてしまうのです。 グラフから読み取ってよいのはそれぞれの系列の傾き(自分の軸に対する変化)だけで、 2 本の線の上下関係・交点・距離には情報がありません

🧮 実値で計算してみる

🧮 数式に値を入れて手で計算する: 棒+折れ線の2軸スケーリング

①目的:単位の違う「売上(棒)」と「利益率(折れ線)」を1図に重ねるには、 折れ線を棒の高さ帯へ揃えるスケール係数を求める必要がある。 合成データで手計算し、 Python 出力と一致するか確かめる。

Step 1: 月別データ

売上利益率 [%]
1月10020
2月15015
3月20025
4月18018
5月25022

Step 2: 2軸スケーリング (売上 max / 利益率 max)

売上 max = 250, 利益率 max = 25 スケール係数 = 250 / 25 = 10 利益率を 10 倍した値なら棒と同じ高さ帯に描ける

🐍 Python で再現

②橋渡し:上の手計算(係数 10)を numpy で確かめる。 sales.max() / profit_rate.max() が係数、 それを利益率に掛けた配列が「棒と同軸で描ける折れ線の高さ」になる。

1
2
3
4
5
6
7
import numpy as np
sales = np.array([100, 150, 200, 180, 250])
profit_rate = np.array([20, 15, 25, 18, 22])
scale = sales.max() / profit_rate.max()
scaled = profit_rate * scale
print(f"スケール係数: {scale}")
print(f"スケーリング後: {scaled}")

📤 実行結果

スケール係数: 10.0 スケーリング後: [200. 150. 250. 180. 220.]

④読み取り:手計算 (Step 2) の係数 10 と Python 出力が完全一致。 利益率 20%→200、 25%→250 と、 折れ線が棒(売上 100〜250)と同じ高さ帯に収まった。 実務では係数を手で掛ける代わりに ax.twinx() で右軸を別スケールにするが、 「揃える倍率」の正体はこの $s$ である。

実データで作ってみる — 全国の総人口(棒)と高齢化率(線)

複合グラフがいちばん活きるのは、単位も桁もまったく違う 2 つの量を、同じ時間軸で並べたいときです。 SSDSE-B-2026 の全国合計(47 都道府県を足し上げたもの)で、2012〜2023 年の実測値を見てみます。

年度総人口(人)出生数(人)高齢化率(%)
2012127,589,0001,037,16524.13
2015127,094,7451,005,66826.33
2018126,748,000918,36128.07
2021125,500,000811,61128.86
2023124,353,000727,26929.13

総人口は 1 億 2 千万台、高齢化率は 20 台の数字です。桁が 7 つ違うので、 同じ軸に描くと高齢化率の線は完全に潰れて水平にしか見えません。 ここで左軸に総人口(棒)、右軸に高齢化率(線)を割り当てるのが複合グラフです。

ただし、この図を見せる前に必ず確認すべきことがあります。それぞれの変化率です。

指標20122023変化率
総人口127,589,000124,353,000−2.5%
出生数1,037,165727,269−29.9%
高齢化率24.13%29.13%+20.7%

💬 ここが要点:総人口はこの 11 年で 2.5% しか減っていません。 棒グラフで描くとほとんど変化していないように見えます。 一方で出生数は 3 割減、高齢化率は 2 割増と、桁違いに大きく動いています。 複合グラフで「総人口(棒)と高齢化率(線)」を並べると、 変化していない棒の横で線だけが急上昇する図になり、 見る人は「人口は横ばいなのに高齢化だけが進んでいる」と読みます。 これは実際そのとおりで、この場合の複合グラフは正しく機能しています

二軸は「相関を作り出せる」— 目盛りを変えるだけで印象が変わる

複合グラフの最大の危険は、2 本目の軸の範囲を描き手が自由に決められることです。 同じデータでも、右軸の下限・上限をどう取るかで、2 本の線は「ぴったり重なる」ようにも 「まったく無関係」にも見せられます。

右軸(高齢化率)の取り方見え方読み手が受ける印象
0〜100%(ゼロ起点)線がほぼ水平に見える「高齢化はあまり進んでいない」
24〜30%(実データの範囲)線が右肩上がりに大きく伸びる「高齢化が急進行している」
28〜30%(さらに拡大)直近の停滞まで誇張される「最近は頭打ち」

データは 1 つも変えていません。変えたのは軸の目盛りだけです。 それでも「急進行」「横ばい」「頭打ち」という 3 通りの結論が作れてしまいます。 棒グラフは原則ゼロ起点という規則は広く知られていますが、 二軸の 2 本目については明確な規則がありません。だからこそ悪用されやすいのです。

もう一つの操作が「交点をずらす」手口です。 2 本の線が交わる位置は軸の取り方で自由に動かせるため、 「ここで逆転しました」という物語を、実体のないところに作れてしまいます。 複合グラフを見たら、まず右軸の目盛りの下限を確認する癖をつけてください。 自分が作るときは、軸の範囲を選んだ理由を図の注釈に書くのが誠実なやり方です。

全国 12 年分の元データ(すべて SSDSE-B-2026 の 47 都道府県合計)

以降の計算はすべてこの表から出ています。丸めのない元の値を先に置きます。

年度総人口(人)出生数婚姻件数着工新設住宅戸数高齢化率(%)
2012127,589,0001,037,165668,870893,00224.13
2013127,414,0001,029,763660,622987,25425.04
2014127,238,0001,003,544643,783880,47025.93
2015127,094,7451,005,668635,225920,53726.33
2016127,044,000977,177620,707974,13727.23
2017126,920,000946,095606,952946,39627.69
2018126,748,000918,361586,481952,93628.07
2019126,555,000865,212599,007883,68728.36
2020126,146,099840,808525,507812,16428.01
2021125,500,000811,611501,138865,90928.86
2022124,946,000770,750504,930860,82829.00
2023124,353,000727,269474,741800,22629.13

高齢化率は「65 歳以上人口 ÷ 総人口 × 100」で計算しています。 たとえば 2023 年は $36{,}229{,}000 \div 124{,}353{,}000 \times 100 = 29.13$。 2020 年だけ高齢化率が前年より下がっている(28.36 → 28.01)ことに注意してください。 この年は 65 歳以上人口が 35,886,000 → 35,335,805 と実際に減少した唯一の年で、 翌 2021 年には 36,215,000 に戻っています。 高齢者が本当に減ったというより、2020 年が国勢調査年で、 推計値から実測値へ切り替わった段差と見るのが自然です。 複合グラフでこの 1 点だけ線が凹むと、読み手は「政策の効果が出た」と誤読しかねません。 系列の途中で定義や集計方法が変わる年には、必ず注記を入れてください。

「連動している」は差分をとると消える

複合グラフで 2 本の線が同じ向きに動いていると、つい「連動している」と言いたくなります。 本当に連動しているかは、水準(レベル)ではなく変化量(差分)で相関を見ると分かります。 上の表から前年差をとって計算した結果です。

組み合わせ水準の相関差分の相関解釈
総人口 と 高齢化率−0.824+0.361符号すら逆転。水準の強い相関は共通トレンドの産物
出生数 と 婚姻件数+0.972−0.169「婚姻が減ると出生も減る」は年単位の変化では見えない

💬 これが本ページで最も重要な数字です。 出生数と婚姻件数の水準相関 +0.972 は、教科書に載るような「ほぼ完全な正の相関」です。 複合グラフで並べれば、2 本の線は見事に重なって下がっていきます。 ところが前年差でとると −0.169——ほぼ無相関、しかも符号が逆です。 つまり「婚姻件数が多く減った年に、出生数も多く減った」という関係はデータに存在しません。 どちらも 12 年かけて別々の理由でじりじり減っただけです。 複合グラフが見せていたのは「関係」ではなく「同じ方向の時間経過」でした。

もちろん、婚姻が出生に効くとしても数年の遅れがあるはずなので、 同年の差分相関がゼロでも因果がないとは言い切れません。 言えるのは「複合グラフの見た目からは何も結論できない」という一点です。 12 時点しかない系列で因果を論じるのは、そもそも無理があります。

時系列でない複合グラフ — 都道府県を横軸にとる場合

複合グラフは時系列専用ではありません。 横軸をカテゴリ(都道府県)にして、棒=総人口、線=高齢化率という図もよく作られます。 2023 年の人口上位 10 県の実データです。

順位都道府県総人口(棒・左軸)高齢化率(線・右軸)
1東京都14,086,00022.75%
2神奈川県9,229,00025.90%
3大阪府8,763,00027.66%
4愛知県7,477,00025.72%
5埼玉県7,331,00027.45%
6千葉県6,257,00028.06%
7兵庫県5,370,00029.96%
8福岡県5,103,00028.45%
9北海道5,092,00033.01%
10静岡県3,555,00030.97%

この形には、時系列版にはない強みと弱みがあります。

強み:横軸が時間でないので、見せかけの回帰の問題が起きません。 実際、この 10 県での相関は r = −0.867、47 県全体の順位相関は ρ = −0.711(p = 2.2×10⁻⁸)で、統計的にも意味のある地域差です。 「人口の多い県ほど高齢化率が低い」——これは時間経過の産物ではなく、 若年層が都市部へ移動した結果として実在する構造です。

弱み横軸の並べ方が結論を左右します。 上の表は人口の降順に並べたので、線(高齢化率)が右上がりに見えて 「人口が減ると高齢化する」という物語が自然に立ち上がります。 ところが 9 位の北海道(33.01%)は 8 位の福岡(28.45%)より 4.6 ポイントも高く、 順序どおりには並んでいません。 もし五十音順に並べ替えれば、線はギザギザになり、同じ構造がまったく見えなくなります。 カテゴリ軸の複合グラフでは、「並べ方」が二軸の範囲と同じくらい強力な操作だと覚えてください。

💬 結論:この関係を本気で示したいなら、 棒+線ではなく横軸に総人口(対数目盛)、縦軸に高齢化率をとった散布図にすべきです。 47 点すべてを表示でき、並べ方の恣意性もなく、 北海道のような外れ方をする県も一目で見つかります。 複合グラフはあくまで「上位 10 県の顔ぶれを見せる」ための図であって、 関係を証明する図ではありません

🐍 Python 実装

①目的:SSDSE-B-2026 の実データで、 人口上位7都府県の 総人口(棒)高齢化率(折れ線) を2軸の複合グラフにする。 「大都市ほど高齢化率が低い」傾向を1枚で示すのが狙い。

②橋渡し:cp932 で CSV を読み、 先頭列 SSDSE-B-2026(=年度)で 2023 年に絞る。 skiprows=[1] で日本語見出し行を飛ばす。 高齢化率は A1303÷A1101×100 で作り、 ax1(左軸)に人口の棒、 ax2 = ax1.twinx()(右軸)に高齢化率の折れ線を描く。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) 北海道 5,092,000 1,681,000 東京都 14,086,000 3,205,000 沖縄県 1,468,000 350,000 …(全 47 行)
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
df['高齢化率'] = df['A1303'] / df['A1101'] * 100
top = df.sort_values('A1101', ascending=False).head(7)
fig, ax1 = plt.subplots(figsize=(11, 6))
ax1.bar(top['Prefecture'], top['A1101'] / 10000, color='#4DB6AC', label='総人口')
ax2 = ax1.twinx()
ax2.plot(top['Prefecture'], top['高齢化率'], color='#E65100', marker='o', label='高齢化率')
ax1.set_ylabel('総人口(万人)'); ax2.set_ylabel('高齢化率(%)')
fig.legend(loc='upper right'); plt.tight_layout(); plt.show()

④読み取り:棒(左軸・万人)は東京→神奈川→大阪…と規模順に低くなり、 折れ線(右軸・%)は東京 22.8% から大阪 27.7% へと逆に上がる。 棒が高い県ほど折れ線が低いという「逆相関」が視覚化される。 軸が2本あるので、 どちらの系列がどちらの軸かを凡例・軸ラベルで必ず明示する。

数値も確認する

図の背後の実数を print で出しておくと、 図と本文の食い違いを防げる。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) 北海道 5,092,000 1,681,000 東京都 14,086,000 3,205,000 沖縄県 1,468,000 350,000 …(全 47 行)
1
2
3
4
5
6
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
df['高齢化率'] = (df['A1303'] / df['A1101'] * 100).round(2)
big = df.sort_values('A1101', ascending=False).head(5)
print(big[['Prefecture', 'A1101', '高齢化率']].to_string(index=False))

📤 実行結果

Prefecture A1101 高齢化率 東京都 14086000 22.75 神奈川県 9229000 25.90 大阪府 8763000 27.66 愛知県 7477000 25.72 埼玉県 7331000 27.45

④読み取り:人口最大の東京都が高齢化率は最小(22.75%)、 という複合グラフの主張が数値でも裏づく。 折れ線の値は右軸目盛りとこの表を突き合わせて読む。

右軸の範囲がどれだけ印象を変えるかを、数値で確かめる

このコードでやること:SSDSE-B-2026 から全国の高齢化率の推移を計算し、 右軸の範囲を 3 通りに変えたとき、同じ 2 点が図のどの高さに描かれるかを数値で出します。 グラフを描く前に、二軸がどれほど恣意的かを数字で理解するためのコードです。

📥 入力データ(SSDSE-B-2026、564 行 = 47 都道府県 × 12 年):

地域コード 都道府県 年度 総人口 65歳以上人口 ... R01000 北海道 2023 5,092,000 1,703,000 ... R13000 東京都 2023 14,086,000 3,204,000 ...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 右軸の範囲を変えるだけで「同じデータ」がどう見えるか
import pandas as pd

df = pd.read_csv("data/raw/SSDSE-B-2026.csv", encoding="cp932", header=1)
df = df[df["地域コード"].astype(str).str.match(r"^R\d{5}$", na=False)].copy()
for c in ["総人口", "出生数", "65歳以上人口"]:
    df[c] = pd.to_numeric(df[c], errors="coerce")
df["年度"] = pd.to_numeric(df["年度"], errors="coerce")

# 全国合計(47 都道府県を足し上げる)
nat = df.groupby("年度").agg(総人口=("総人口", "sum"),
                             高齢者=("65歳以上人口", "sum")).reset_index()
nat["高齢化率"] = nat["高齢者"] / nat["総人口"] * 100

first, last = nat["高齢化率"].iloc[0], nat["高齢化率"].iloc[-1]
print(f"高齢化率(実データ): 2012 年 {first:.2f}%  →  2023 年 {last:.2f}%")
print("この 1 つの事実が、右軸の取り方でどう見えるか:")
print()

# 右軸を [lo, hi] にしたとき、線は図の高さの何 % の位置に描かれるか
for lo, hi, name in [(0, 100, "A: 0〜100%(原点をとる)"),
                     (24, 30, "B: 24〜30%(データに密着)"),
                     (28, 30, "C: 28〜30%(上端だけ切り出す)")]:
    y0 = (first - lo) / (hi - lo) * 100
    y1 = (last  - lo) / (hi - lo) * 100
    print(f"{name:26s} 2012 {y0:7.1f}%  2023 {y1:7.1f}%  上昇 {y1 - y0:6.1f} ポイント")

📤 実行すると次の出力が得られます:

高齢化率(実データ): 2012 年 24.13% → 2023 年 29.13% この 1 つの事実が、右軸の取り方でどう見えるか: A: 0〜100%(原点をとる) 2012 24.1% 2023 29.1% 上昇 5.0 ポイント B: 24〜30%(データに密着) 2012 2.2% 2023 85.6% 上昇 83.3 ポイント C: 28〜30%(上端だけ切り出す) 2012 -193.3% 2023 56.7% 上昇 250.0 ポイント

💬 読み方:実データの事実は「24.13% → 29.13%、5 ポイントの上昇」ただ 1 つです。 ところが図の上での見え方は 5.0 ポイント(A)/83.3 ポイント(B)/250.0 ポイント(C) と、 50 倍も変わります。 C にいたっては 2012 年の点が図の下端の外(−193.3%)に飛び出すので、 読み手には「2012 年からいきなり急上昇した」ようにしか見えません。 棒(総人口)は一切いじっていないのに、線との位置関係も交点も自在に動きます。

実務での使い方:複合グラフを作ったら、必ずこの 3 通りを自分で描いて見比べてください。 そのうえで「なぜこの範囲にしたか」を図の注釈に書けないなら、その二軸はやめたほうがよいという判断基準になります。

matplotlib で複合グラフを描くときの実務メモ

やりたいこと書き方注意
右軸を追加するax2 = ax1.twinx()左右で単位が無関係。恣意性が入る
単位換算の第 2 軸ax1.secondary_yaxis(functions=(f, g))こちらは恣意性なし。使えるならこちらを使う
棒が線を隠すax1.set_zorder(1) + ax1.patch.set_visible(False)twinx は既定で ax2 が上。棒を前に出すとこの操作が要る
凡例を 1 つにまとめるh1,l1 = ax1.get_legend_handles_labels() を ax2 の分と連結別々に legend() を呼ぶと凡例が 2 個出て重なる
横向きの棒にするax.barh(...)orientation="horizontal" は matplotlib 3.10 以降のみ。可搬性が落ちる
目盛りラベルを付けるplt.xticks(pos, labels)tick_labels= は新しい版でしか通らない

最後に、色の選び方。棒と線を「赤と緑」にすると、 日本人男性のおよそ 5% にあたる色覚特性のある読み手には区別できません。 青系(棒)+オレンジ/濃赤系(線)のように、明度差も付けた組み合わせにしてください。 さらに線にはマーカー(marker="o")を付けると、白黒印刷でも棒と区別できます。

二軸をやめる — 指数化を実際に計算する

このコードでやること:全国の 4 系列(総人口・出生数・婚姻件数・着工新設住宅戸数)を 2012 年 = 100 に変換します。二軸どころか 1 本の軸で 4 系列を扱えることを、実データで確かめます。

📥 入力データ(変換前の全国合計、2012 年):

総人口 127,589,000 人 / 出生数 1,037,165 件 婚姻件数 668,870 件 / 着工新設住宅戸数 893,002 戸 → 単位も桁もバラバラ。このままでは 1 本の軸に載らない
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 二軸をやめて指数化する(2012 年 = 100)
import pandas as pd

df = pd.read_csv("data/raw/SSDSE-B-2026.csv", encoding="cp932", header=1)
df = df[df["地域コード"].astype(str).str.match(r"^R\d{5}$", na=False)].copy()
cols = ["総人口", "出生数", "婚姻件数", "着工新設住宅戸数"]
for c in cols:
    df[c] = pd.to_numeric(df[c], errors="coerce")
df["年度"] = pd.to_numeric(df["年度"], errors="coerce")

nat = df.groupby("年度")[cols].sum()      # 全国合計(47 都道府県の和)
idx = nat / nat.loc[2012] * 100           # 2012 年を 100 とした指数

print("2012 年 = 100 とした指数")
print(idx.round(1).to_string())
print()
print(f"2023 年の指数の幅: {idx.loc[2023].min():.1f}{idx.loc[2023].max():.1f}")
print("→ 単位も桁も消えたので、4 系列すべてを 1 本の軸に載せられる")

📤 実行すると次の出力が得られます:

2012 年 = 100 とした指数 総人口 出生数 婚姻件数 着工新設住宅戸数 年度 2012 100.0 100.0 100.0 100.0 2013 99.9 99.3 98.8 110.6 2014 99.7 96.8 96.2 98.6 2015 99.6 97.0 95.0 103.1 2016 99.6 94.2 92.8 109.1 2017 99.5 91.2 90.7 106.0 2018 99.3 88.5 87.7 106.7 2019 99.2 83.4 89.6 99.0 2020 98.9 81.1 78.6 90.9 2021 98.4 78.3 74.9 97.0 2022 97.9 74.3 75.5 96.4 2023 97.5 70.1 71.0 89.6 2023 年の指数の幅: 70.1 〜 97.5 → 単位も桁も消えたので、4 系列すべてを 1 本の軸に載せられる

💬 読み方:4 系列すべてが 70〜111 の範囲に収まりました。 軸は 1 本、範囲は自動的に決まるので作図者が操作できる余地がありません。 しかも複合グラフでは見えなかった事実がはっきりします—— 出生数(70.1)と婚姻件数(71.0)はほぼ同じ速さで 3 割減ったのに対し、 着工新設住宅戸数(89.6)は 2013 年に 110.6 まで増えてから減った総人口(97.5)はほとんど動いていない。 「日本の人口減少」という一括りの言葉のなかに、 まったく速さの違う 4 つの現象が入っていることが 1 枚で分かります。

複合グラフでこれをやろうとすると、2 系列ずつ 6 枚の図が必要で、 しかも 6 枚それぞれで右軸の範囲を決めなければなりません。 指数化なら 1 枚、恣意性ゼロ。 「二軸にするしかない」と思ったら、まずこの変換を試してください。

ただし指数化にも弱点があります。元の水準が消えることです。 上の図からは「出生数が 70.1 まで減った」ことは分かっても、 それが 103 万件から 73 万件なのか、1,030 件から 730 件なのかは読めません。 指数の図には必ず「基準年の実数」を注記として添えてください。 また基準年(ここでは 2012)がたまたま異常値だと全系列が歪むので、 重要な図では基準年を変えた版も作って結論が変わらないことを確認します。

⚠️ よくある落とし穴

この用語を使うときに陥りがちな失敗パターン。 経験者ほどここに 1 度はハマっています。

❌ 2軸のスケールで印象を操作
左右軸の範囲を恣意的に選ぶと、 折れ線と棒の交差点を自在に動かせる。 「相関しているように見せる」誤導の温床。 軸範囲の根拠を明示する。
❌ どちらの系列がどちらの軸か不明
凡例と軸ラベルを省くと、 棒と折れ線がどちらの軸に対応するか読めない。 軸ラベルに色を対応させると親切。
❌ 交点に意味があると誤読させる
2軸グラフの棒と折れ線の交差点はスケール次第で移動するため、 それ自体に意味はない。 「交わった=一致」と読ませない。
❌ 系列を増やしすぎる
棒+折れ線 2 本まではよいが、 3 軸・4 系列になると解読不能。 3 系列以上は small multiples(分割図)を検討。

複合グラフの落とし穴 — 実データでの具体例つき

落とし穴何が起きるか対処
右軸の恣意性 高齢化率 24.13→29.13% の同じ事実が、右軸の取り方で図上 5.0/83.3/250.0 ポイントの上昇に見える(本ページの実測) 右軸の範囲を注記に明記する。可能なら指数化に置き換える
交点の誤読 「線が棒を追い越した年」に意味を見いだしてしまう。$R_{\min}$ を動かせば交点は任意の年に置ける 交点に注釈をつけない。むしろ「交点に意味はない」と図中に書く
見せかけの連動 全国 12 年で 総人口 vs 高齢化率 r = −0.824。強い相関に見えるが、両方が時間で単調に動いているだけ 断面(2023 年の 47 県、r = −0.710)や差分系列で確かめる
率を棒で描く 47 県の高齢化率の単純平均 31.59% と、全国の高齢化率 29.13% は 2.5 ポイントずれる。棒だと「足せる」錯覚が生じる 率・比・強度は線かドットで。棒は実数(人数・件数)に限る
棒が線を隠す twinx() は既定で ax2(線)が前面。棒を太くすると線の一部が見えなくなる図もある 棒の透明度を下げる(alpha=0.6)か zorder を明示する
凡例の二重出現 ax1 と ax2 で別々に legend() を呼ぶと凡例枠が 2 つ重なり、どちらの軸かが分からなくなる ハンドルを連結して 1 つにまとめ、ラベルに単位を書く(「総人口(万人・左軸)」)
3 系列目の追加 軸は 2 本しかないので、3 本目は既存のどちらかに相乗りするしかなく、必ず潰れる 系列が 3 つ以上なら複合グラフをあきらめ、指数化かスモールマルチプルへ
色の選択 赤(線)と緑(棒)は色覚特性のある読み手に区別できない。白黒印刷でも同じ濃さになる 青系+濃いオレンジ/赤系にして明度差もつける。線にはマーカーを付ける

いちばん多い失敗は「二軸そのもの」ではなく、二軸で作った図に 「連動している」「同時に悪化している」という言葉を添えてしまうことです。 図が示せるのは各系列の推移だけで、連動の有無は図の外側—— 相関回帰分析——で 別途検証しなければ言えません。

図の脚注に書くべき 5 行 — そのまま使えるひな形

複合グラフを提出物に載せるとき、次の 5 行を脚注に添えるだけで、 指摘されうる論点のほとんどを先回りで潰せます。 本ページの全国の総人口+高齢化率の図を例に、実際に埋めたものを示します。

書く項目記入例
1. 出典と範囲SSDSE-B-2026(47 都道府県 × 2012〜2023 年、564 行)を全国合計に集計。
2. 左軸総人口(万人)、0〜14,000。棒。ゼロ始まり。
3. 右軸高齢化率=65 歳以上人口÷総人口×100(%)、24〜30。線。データの実測範囲 24.13〜29.13 に合わせて設定
4. 主張の限定本図は 2 系列それぞれの推移を示すものであり、両者の関係については何も示していない。交点および両線の上下関係に意味はない。
5. 注意すべき点2020 年は国勢調査年にあたり、高齢者人口が前年比で減少(35,886 千人 → 35,336 千人)している。系列の段差に注意。

このうち4 番目がいちばん重要で、そしていちばん書かれていない項目です。 「連動を示していない」と明記することは、自分の図の価値を下げる行為に見えるかもしれません。 しかし実際には逆で、何を示していないかを言える人だけが、示していることを信用してもらえます

3 番目の「右軸の範囲とその理由」も、書こうとすると意外に難しいはずです。 「データの実測範囲に合わせた」と書ければ十分ですが、 もし理由が「そのほうが見栄えがよいから」しか思いつかないなら、それは操作をしているサインです。 そのときは指数化に切り替えてください。 脚注が書けるかどうかは、二軸を使ってよいかどうかの実用的なテストになります。

🗺 概念マップ

「複合グラフ」を中心に、 2軸スケーリング・棒と折れ線の役割分担・軸ラベル対応・スケール誤導回避・系列数の抑制・積み上げ棒との使い分け の 6 論点を並べた俯瞰図。 異なる単位の同時提示という本質を読み解く地図。

複合グラフ 2軸スケーリング 棒と折れ線の分担 軸ラベル対応 スケール誤導回避 系列数の抑制 積み上げ棒と使い分け

上の概念マップは「複合グラフ」を中心に、 2軸スケーリング・棒と折れ線の役割分担・軸ラベル対応・スケール誤導回避・系列数の抑制・積み上げ棒との使い分け という 6 論点を並べた俯瞰図である。 x 軸を共有しつつ左右で別スケールを持たせ、 「量(棒)」と「率・変化(折れ線)」を同時に伝える二面性が複合グラフの本質であり、 ここを誤って恣意的な軸範囲を選ぶと誤導グラフに転落する。

位置づけを言葉で確認する

複合グラフは「グラフの種類」というより、「1 枚の図に軸を 2 本置く」という決断です。 上の図で中心にあるのはその決断で、そこから 3 方向に道が伸びています。

方向行き先選ぶ条件
そのまま進む棒+線の二軸グラフ系列 2 つ、量と率、推移を見せるだけ、右軸の範囲を説明できる
軸を 1 本に戻す指数化・スモールマルチプル系列 3 つ以上、または変化の速さを比べたい
時間軸を捨てる散布図・相関・回帰「連動している」を主張したい

3 つ目の道がいちばん見落とされます。 複合グラフを作りたくなる動機の多くは「2 つの量に関係があることを見せたい」ですが、 それは複合グラフが原理的にできないことです。 動機がそちらにあると気づいたら、迷わず散布図に切り替えてください。

🔗 隣接手法への橋渡し

「複合グラフ」は棒と折れ線など異種グラフを1図に重ねる手法で、 上流の系列そろえ(単位・粒度の整形)と下流の軸設計(スケール・ラベル)を組まないと、 読者が2系列の関係を誤読する。

上流で2系列の単位を整え、 並列の棒単独・折れ線単独と比較し、 下流で軸ラベルと凡例を整えれば、 人口規模と高齢化率のような異質な2指標を 1 枚で説明できる。

二軸をやめる 3 つの代替案 — 実データで比べる

「桁が違うから二軸にするしかない」と考えがちですが、多くの場合より誠実で読みやすい代替案があります。 先ほどの全国データで、3 つの方法を実際に試します。

代替案 1:指数化(基準年を 100 にそろえる)

すべての系列を「2012 年 = 100」に変換すると、単位も桁も消えて同じ 1 本の軸に載せられます。 SSDSE-B-2026 の全国合計での実測値です。

年度総人口出生数高齢化率婚姻件数
2012100.0100.0100.0100.0
201599.697.0109.195.0
201899.388.5116.387.7
202198.478.3119.674.9
202397.570.1120.771.0

軸は 1 本、範囲は 70〜121。4 つの系列を同時に、目盛りの操作なしで比較できます。 しかも「総人口はほぼ動かず(97.5)、出生数と婚姻件数だけが 3 割減(70.1・71.0)」という 複合グラフでは読み取りにくかった事実が一目で分かります。 変化の向きと大きさを比べたいなら、二軸より指数化のほうがほぼ常に優れています。

注意点は基準年の選び方で印象が変わることです。 たまたま基準年が異常値だと、その後の系列がすべて歪んで見えます。 基準年を変えた図も並べて、結論が変わらないことを確かめてください。

代替案 2:小分割(スモールマルチプル)

2 つの図を縦に並べ、横軸(時間)だけをそろえる方法です。 軸を重ねないので目盛りの操作が起きようがなく、それぞれの系列を自然な範囲で描けます。 欠点は「同時に 1 点を読む」のがやや面倒なこと。 利点は系列が 3 つ以上になっても破綻しないことです。 二軸は原理的に 2 系列までですが、小分割なら 6 つでも 8 つでも並べられます。

代替案 3:散布図にする(時間を点の並びで表す)

2 つの量の関係そのものを見たいなら、時間軸を捨てて散布図にするのが最も率直です。 全国 12 年分で相関係数を計算すると次のようになります。

組み合わせ(全国・12 時点)相関係数 r解釈上の注意
総人口 と 高齢化率−0.824どちらも時間とともに単調変化しているだけ
出生数 と 高齢化率−0.898同上。因果ではない
婚姻件数 と 出生数+0.972実質的な関係はありうるが、これも共通の時間傾向を含む

💬 重要な警告:この 3 つの相関係数は、いずれも 0.8 を超える強い値に見えます。 しかし時系列どうしの相関は、両方が時間とともに一方向に動いているだけで簡単に大きくなります (見せかけの回帰)。「総人口が減ると高齢化率が上がる」のは定義上ほぼ自明であって、発見ではありません。 二軸グラフで 2 本の線が同じ向きに動いているのを見せられると、 読み手は勝手に因果を読み取ります。複合グラフが批判されるいちばんの理由がこれです。 関係を主張したいなら、時系列の相関ではなく、 相関回帰分析のページにあるとおり、 差分をとる・共通のトレンドを除く・断面(同一時点の 47 県)で見るといった処理が要ります。

実際、同じ「総人口と高齢化率」を 2023 年の 47 都道府県という断面で計算すると r = −0.710 でした。時系列の −0.824 とは別の意味を持つ数字です。 前者は「人口の多い県ほど高齢化率が低い」という地域差の話、 後者は「年を追うごとに両者が逆方向に動いた」という時間変化の話。 複合グラフは後者しか描けないのに、読み手はしばしば前者として受け取ります。

よくある質問

Q. 上司から「二軸で作って」と言われました。断るべきですか?
A. 断る必要はありません。二軸版と指数化版の 2 枚を作って持っていくのが実務的な最善手です。 多くの場合、指数化版のほうが言いたいことが伝わるので、そちらが採用されます。 採用されなくても、二軸版の右軸範囲を自分で説明できる状態になっています。

Q. Excel の「第 2 軸」も同じ問題を抱えていますか?
A. 同じです。Excel は右軸の範囲を自動で決めますが、 その自動値は「両系列が図の中央付近で交差する」ように選ばれがちで、 結果として「連動しているように見える」図が既定で出てきます。 自動設定だから中立、ということはありません。範囲は必ず自分で確認してください。

Q. 右軸を必ず 0 から始めれば公平ですか?
A. 公平にはなりますが、読めない図になることが多いです。 本ページの実測では、右軸 0〜100% にすると高齢化率の 5 ポイントの上昇が 図の高さのわずか 5.0% にしか現れず、ほぼ水平線に見えました。 「0 始まりが常に正しい」のは棒グラフの規範であって、 率の折れ線には当てはまりません。 正しい対処は「0 から始める」ではなく「範囲を明記する」または「指数化する」です。

Q. 3 つ目の軸を右側にもう 1 本追加できますか?
A. matplotlib では ax3 = ax1.twinx()ax3.spines["right"].set_position(("outward", 60)) を組み合わせれば技術的には可能です。しかし読み手が 3 本の軸と 3 本の線を正しく対応づけられる見込みはほぼありません。 系列が 3 つ以上になった時点で、指数化かスモールマルチプルに切り替えてください。

Q. 論文やレポートで二軸を使うと査読で指摘されますか?
A. 分野によりますが、指摘されることは珍しくありません。 指摘を避けるには、図の脚注に (1) 左右それぞれの軸の範囲、(2) その範囲を選んだ理由、 (3) 両系列の関係を主張していないこと——この 3 点を書いておけば、 ほとんどの場合で十分です。逆にこの 3 点が書けないなら、その図は使わないほうが安全です。

🌳 意思決定ツリー:複合グラフを使うべきか

「複合グラフ(2軸)を使う」前に、 本当に適切かを 5 段階の質問で確認します。

段階 質問 分岐
2系列の単位は違うか?Yes → 2軸を検討/No → 同軸で重ねるだけで十分
片方は「量」、 もう片方は「率・変化」か?Yes → 棒+折れ線が最適/No → 用途を再確認
系列は 2 本以下か?Yes → 複合グラフ/No → small multiples に分割
軸範囲の根拠を示せるか?Yes → 採用/No → 誤導リスク。 単軸2枚を検討
読者に「関係」を伝えたいか?Yes → 複合グラフ+相関値/No → 単独グラフで可

5 つの質問で決める — 複合グラフを使ってよい場合

上から順に答えていき、1 つでも「いいえ」があれば複合グラフはやめるのが安全側の運用です。

質問「いいえ」なら理由
Q1系列はちょうど 2 つか?指数化 or スモールマルチプル軸は 2 本しかない。3 本目は必ず潰れる
Q22 つは単位も桁も違うか?1 本の軸に重ねる同じ単位なら二軸は害しかない
Q3一方は足せる量(人数・件数)、他方は足せない量(率)か?散布図 or 表棒=量、線=率の対応が崩れると誤読が増える
Q4言いたいのは「それぞれの推移」か?(「連動」ではなく)散布図+相関の検証複合グラフは連動を示せない(本ページの実測どおり)
Q5右軸の範囲を説明できるか?指数化説明できない範囲=恣意的な範囲

たとえば「全国の総人口(人)と高齢化率(%)の 12 年推移」は Q1〜Q3 と Q5 は通りますが、Q4 で「両者の連動を示したい」と考えているなら不合格です。 それぞれの推移を独立に見せたいだけなら合格。 同じデータでも、言いたいことによって合否が変わるのがこの表の要点です。

目的別・早見表

言いたいこと最適な図SSDSE での作例
量と率の推移を 1 枚で見せたい複合グラフ(棒+線)総人口(棒)+高齢化率(線)、右軸の範囲を注記
どれが速く減ったかを比べたい指数化した折れ線2012=100 で 総人口 97.5/出生数 70.1/婚姻 71.0
系列が 3 つ以上あるスモールマルチプル総人口・出生数・婚姻件数・着工戸数を縦に 4 段
2 つの量の関係を主張したい散布図相関2023 年 47 県で 総人口 vs 高齢化率、r = −0.710
内訳の変化を見せたい積み上げ面グラフ15 歳未満/15〜64 歳/65 歳以上の 3 区分
正確な値を読ませたい本ページの 12 年分データ表
地域差を見せたいドットプロット/ランキング高齢化率 秋田 39.06% 〜 東京 22.75%

最下段の「表」を軽視しないでください。 12 点しかない系列を図にする必然性はほとんどありません。 値を正確に読ませたいなら表が最強で、しかも二軸の恣意性が入り込む余地がゼロです。 複合グラフを選ぶ前に「表ではだめか」を一度は自問してください。

チェックリスト — 提出前の 8 項目

複合グラフを含む資料を出す前に、次の 8 項目を上から確認してください。 本ページで扱った内容を、そのまま作業手順に落としたものです。

確認項目満たせないときの対処
1系列は 2 つ以内か指数化かスモールマルチプルに変更
2棒は足せる量、線は足せない量か形を入れ替える。率を棒にしない
3左軸(棒)はゼロから始まっているかゼロ始まりに直す。棒では例外なし
4右軸の範囲を一言で説明できるか説明できないなら指数化へ
5凡例は 1 つにまとまり、単位と軸が書いてあるかハンドルを連結し「(万人・左軸)」等を追記
6色は明度差があり、線にマーカーがあるか青系+濃赤系に変更、marker="o" を追加
7本文に「連動」「相関」と書いていないか書くなら差分の相関などで別途検証する
8系列に定義変更・集計方法変更の年はないか該当年に注記を入れる(例: 2020 年の国勢調査)

経験上、引っかかりやすいのは 4 と 7 です。 4 は「なんとなく見栄えで決めた」まま提出されがちで、 7 は本文を書いた人と図を作った人が別だと高い確率で発生します。 図と本文を必ず同じ人が最後に読み合わせる——それだけで大半の事故は防げます。