K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

カテゴリ別の散布図に注釈を追加

中級

06.5.6

カテゴリ別の散布図に注釈を追加

最終更新 2020-04-08 読了時間 2 分
まとめ
カテゴリ別の注釈付き散布図は、グループごとに色を分けた散布図に、全体平均の基準線と矢印付きのテキストを足して「どこを見てほしいか」を図の中に書き込む手法です。色分けは ax.scatter をグループの数だけ呼んで label を付け、基準線は ax.axvline(np.mean(x)) と ax.axhline(np.mean(y))、注釈は ax.annotate(text, xy=矢印の先, xytext=文字の位置) で描きます。この章では A・B・C の 3 グループ 210 点を描き、平均線で 4 つの象限に区切り、右上の C グループに「高スコア帯」の注釈を添えます。読み終えると、分析者が見つけた結論を図の上で第三者に伝える 3 つの道具(色・基準線・注釈)の使い分けと、注釈を 1〜2 個に絞る理由が分かります。

先に 散布図の基本形 で 1 グループの点の打ち方を見ておくと、この章は「色分け・基準線・注釈の 3 つを足す」だけの拡張だと分かります。

直感 #

3 つのグループの評価指標 X と Y を 210 点の散布図にすると、分析者には「C グループが右上に固まっている」と見えても、初めて図を見る人は 210 個の点を眺めるだけで終わります。そこで 3 つの道具を足します。まずグループごとに青・緑・橙で色を分け、次に X と Y の全体平均に破線を引いて図を「平均より上か下か」の 4 象限に切り、最後に右上の塊へ「高スコア帯」と矢印を打ちます。点の配置は変えていないのに、読者の目は矢印の先へ誘導され、「C は X も Y も平均より高いグループだ」という結論が 3 秒で伝わります。

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:r は「直線に沿う強さ」。曲線的な関係や外れ値があると、r だけでは関係を見誤る。

Python で描く #

次のコードは、中心の違う 3 つの正規分布から A(80 点)・B(70 点)・C(60 点)を作り、グループごとに ax.scatter で色を分けて描きます。その上に平均を通る破線 2 本と、(66, 84) を指す矢印付きの注釈「高スコア帯」を加えます。

 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
27
28
29
30
31
32
33
34
import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(0)
cluster = np.concatenate([np.full(80, "A"), np.full(70, "B"), np.full(60, "C")])
x = np.concatenate([rng.normal(40, 6, 80), rng.normal(55, 5, 70), rng.normal(65, 4, 60)])
y = np.concatenate([rng.normal(70, 5, 80), rng.normal(60, 6, 70), rng.normal(80, 5, 60)])
palette = {"A": "#2563eb", "B": "#10b981", "C": "#f97316"}

fig, ax = plt.subplots(figsize=(6, 4))
for cat in np.unique(cluster):
    mask = cluster == cat
    ax.scatter(x[mask], y[mask], label=f"グループ {cat}", color=palette[cat], alpha=0.75, edgecolors="white", s=60)

ax.axvline(np.mean(x), color="#9ca3af", linestyle="--", linewidth=1)
ax.axhline(np.mean(y), color="#9ca3af", linestyle="--", linewidth=1)

ax.annotate(
    "高スコア帯",
    xy=(66, 84),
    xytext=(72, 90),
    arrowprops=dict(arrowstyle="->", color="#1f2937"),
    fontsize=11,
)

ax.set_xlabel("評価指標 X")
ax.set_ylabel("評価指標 Y")
ax.set_title("カテゴリ別散布図と注釈")
ax.legend()
ax.grid(alpha=0.3)

fig.tight_layout()

plt.show()

注目してほしい領域をテキストで示すと伝わりやすくなりますの図

実行結果の読み方 #

青の A は左上(X 約 40、Y 約 70)、緑の B は中央下(X 約 55、Y 約 60)、橙の C は右上(X 約 65、Y 約 80)に固まります。灰色の破線は X の全体平均(約 52)と Y の全体平均(約 70)を通り、C だけが「X も Y も平均より高い」右上の象限にほぼ全員入っていることが読めます。矢印付きの「高スコア帯」はその C の塊を指しており、読者はまずそこを見てから他の 2 グループに目を移します。A は X が低く、B は Y が低い、という対比も象限の位置から読めます。

使いどころと落とし穴 #

この手法が向くのは、分析者がすでに結論(「C が高スコア帯」)を持っていて、それを第三者に図で納得させるプレゼンや報告書の場面です。基準線は全体平均のほかに目標値や業界平均でもよく、axhline(80) のように固定値を渡します。凡例の順番を「重視順」や「規模順」に並べ替えると説明の流れに沿います。落とし穴の 1 つ目は注釈の付けすぎで、210 点すべてや 10 か所に矢印を打つと情報過多で何も伝わらないため、本当に見せたい 1〜2 か所に絞ります。2 つ目はラベルの重なりで、数十点に名前を付けると文字どうしが重なって読めなくなるので、adjustText ライブラリで自動的にずらすか、xytext を手で調整します。全点の値を確認したい用途なら、静止画ではなく Plotly などのホバー表示付きの図に切り替えるほうが向いています。