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

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

言語 JA

ツリーマップ

中級

06.1.2

ツリーマップ

最終更新 2020-02-12 読了時間 5 分
まとめ
ツリーマップは、全体を 1 枚の長方形とみなし、各カテゴリの値に比例した面積の矩形に分割して見せる図です。squarify.plot(sizes, color=colors, label=labels) に値のリストを渡すだけで、10・20・30・40 の 4 つの値が 1 : 2 : 3 : 4 の面積の矩形になります。面積にはサイズ、色には別の量(損益率など)を割り当てられるので、保有株を「現在価額の大きさ」と「評価損益の正負と大きさ」で同時に見る finviz 風のヒートマップが描けます。日経平均や S&P 500 の銘柄マップが代表例で、円グラフより多くのカテゴリ(10〜50 個)を 1 枚に収められます。

直感 #

6 銘柄を持つポートフォリオで、「どの銘柄に資産が偏っているか」と「どれが儲かってどれが損しているか」を同時に知りたいとします。ツリーマップは、画面全体を資産の合計とみなして、各銘柄の現在価額に比例した面積の矩形に切り分けます。GOOG が 1,588 なら PBR(130)の 12 倍の面積になります。そして矩形の色に損益率を割り当て、利益なら緑、損なら赤にし、+224% のように率が大きいほど明るくします。面積で「どこに資産があるか」、色で「どこで儲けたか」の 2 つの量が 1 枚に乗ります。このページでは squarify を使い、代表例として finviz の S&P 500 マップ のようなものを作ります。

ツリーマップは plotly でも作成できます。階層の深いデータや対話的なドリルダウンが必要なら Treemap charts with Python - Plotly を参照してください。

基本の 4 分割を描く #

次のコードは 10・20・30・40 の 4 つの値を、1 : 2 : 3 : 4 の面積比の矩形に分割し、赤の濃淡で塗ります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import numpy as np
import matplotlib.pyplot as plt
import squarify

np.random.seed(0)  # 乱数を固定する

labels = ["A" * i for i in range(1, 5)]
sizes = [i * 10 for i in range(1, 5)]
colors = ["#%02x%02x%02x" % (i * 50, 0, 0) for i in range(1, 5)]

plt.figure(figsize=(5, 5))
squarify.plot(sizes, color=colors, label=labels)
plt.axis("off")
plt.show()

ツリーマップの図

実行結果の読み方 #

最も大きい AAAA(40)の矩形が左半分近くを占め、A(10)の矩形は右下の小さな一角になります。面積比はちょうど 1 : 2 : 3 : 4 です。色は値に連動して AAAA が最も明るい赤なので、この例では面積と色が同じ情報を 2 重に伝えています。

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

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

見るポイント:構成比は件数ではなく割合で比べる。積み上げると全体(100%)に占める大きさが面積になる。

ポートフォリオを可視化する #

ここからは、持っている銘柄ごとの取得価額・現在価額のデータから、finviz のようなヒートマップを作ります。面積に現在価額、色に評価損益率を割り当てるので、1 枚の図に 2 つの量が載ります。

データを作成する #

次のコードは、csv から読み込んだと想定した 6 銘柄の取得価額と現在価額を DataFrame にし、差額の列「評価損益」を足します。

※ここに示しているのは架空のデータです

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pandas as pd

data = [
    ["PBR", 80.20, 130.00],
    ["GOOG", 1188.0, 1588.0],
    ["FLNG", 70.90, 230.00],
    ["ZIM", 400.22, 630.10],
    ["GOGL", 120.20, 90.90],
    ["3466\nラサールロジ", 156.20, 147.00],  # 日本語表示のテスト用
]

df = pd.DataFrame(data)
df.columns = ["銘柄名", "取得価額", "現在の価額"]
df["評価損益"] = df["現在の価額"] - df["取得価額"]
df.head(6)

plt.show()

銘柄名取得価額現在の価額評価損益
0PBR80.20130.049.80
1GOOG1188.001588.0400.00
2FLNG70.90230.0159.10
3ZIM400.22630.1229.88
4GOGL120.2090.9-29.30
53466\nラサールロジ156.20147.0-9.20

ツリーマップの色を指定する #

次のコードは評価損益率(損益 ÷ 取得価額 × 100)を計算し、利益なら緑、損なら赤で、率が大きいほど濃くなる色を銘柄ごとに作ります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
colors = []
percents = []
for p_or_l, oac in zip(df["評価損益"], df["取得価額"]):
    percent = p_or_l / oac * 100

    if p_or_l > 0:
        g = np.min([percent * 255 / 100 + 100, 255.0])
        color = "#%02x%02x%02x" % (0, int(g), 0)
        colors.append(color)
    else:
        r = np.min([-percent * 255 / 100 + 100, 255])
        color = "#%02x%02x%02x" % (int(r), 0, 0)
        colors.append(color)

    percents.append(percent)

print(df["銘柄名"].values)
print(colors)
print(percents)

plt.show()
['PBR' 'GOOG' 'FLNG' 'ZIM' 'GOGL' '3466\nラサールロジ']
['#00ff00', '#00b900', '#00ff00', '#00f600', '#a20000', '#730000']
[62.094763092269325, 33.670033670033675, 224.4005641748942, 57.43840887511868, -24.376039933444257, -5.8898847631241935]

ツリーマップを表示する #

次のコードは現在価額を面積、先ほどの色を塗り、銘柄名と損益率を各矩形に書いたツリーマップを描きます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
current_prices = [cp for cp in df["現在の価額"]]
labels = [
    f"{name}\n{np.round(percent, 2)}%".replace("-", "▼")
    for name, percent in zip(df["銘柄名"], percents)
]

plt.figure(figsize=(10, 10))
plt.rcParams["font.size"] = 18
squarify.plot(current_prices, color=colors, label=labels)
plt.axis("off")
plt.show()

ポートフォリオのツリーマップ

実行結果の読み方 #

GOOG の緑の矩形が全体の半分以上を占め、資産がこの 1 銘柄に偏っていることが面積から読めます。右側の小さな赤い矩形 2 つが GOGL(▼24.38%)と 3466(▼5.89%)で、損失が出ているのは資産全体の 8% ほどだと分かります。FLNG は面積こそ 8% ですが最も明るい緑で、率では 224% と最大の利益を出しています。面積(どこに資産があるか)と色(どこで儲けたか)を別々に読むのがツリーマップの使い方です。

キャッシュの表示を追加する #

次のコードは、株式 6 銘柄に現金 3,500 をグレーの矩形として足し、資産全体の中での現金比率を見せます。

1
2
3
4
5
6
7
plt.figure(figsize=(10, 10))
plt.rcParams["font.size"] = 18
squarify.plot(
    current_prices + [3500], color=colors + ["#ccc"], label=labels + ["キャッシュ"]
)
plt.axis("off")
plt.show()

色はグレーにしますの図

使いどころと落とし穴 #

銘柄別の時価総額、部門別の予算、ディレクトリ別のディスク使用量のように、10〜50 個のカテゴリの大きさを 1 枚で俯瞰したいときに向いています。円グラフでは 6 個以上の扇形が読めなくなりますが、ツリーマップなら矩形の面積と色で数十個を収められ、色に第 2 の量(損益率・成長率)を載せられます。一方、面積 8% と 10% のようなわずかな差を人の目は正確に判別できないので、厳密な数値比較が目的なら棒グラフを、階層構造そのものを見せたいなら サンバーストチャート を選びます。

落とし穴は 2 つあります。面積の微妙な差は読めないので、重要な値は label に「62.09%」のように数値を入れて補います。階層が 3 以上になると内側の矩形が極端に小さくなるので、squarify では 1〜2 階層にとどめ、事業部 → 部門 → チームのような深い階層は plotly の treemap でドリルダウンできる対話版にします。