1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonのmatplotlibの正負のある積み上げグラフ内のデータラベルを追加する.

Posted at

この記事が役に立つ人

  • Pythonのmatplotlibで正負混合のデータの積み上げグラフ内にラベルを入れたい人
  • 積み上げグラフの幅が狭いときラベルを省略したい人

ラベルの位置決め

正負混合のデータの積み上げグラフはpandasの描画機能で次のように作ることができます.

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

df = pd.DataFrame({'id':[1,2,3,4,5,6],
                   'f1':[30,45,10,15,4,30],
                   'f2': [20,-30,60,-40,45,-4],
                   'f3': [50,25,-30,45,15,2]})
df = df.set_index('id')
ax = plt.subplot()
df.plot.bar(stacked=True, legend=True, ax=ax)
ax.set_ylabel('value')

グラフは次のようになります.

graph1.png

正負混在しているグラフでは,描画されている矩形の位置が決まっていないので,参考資料にあるように位置に依存したテキストの描画ができません.

そのため,matplotlibのpatch情報を調べて矩形の描画位置を調べなければなりません.この場合のpatchはRectangleになります.Rectangleからは直接 y方向の描画位置がわかりません.

print (ax.patches[0])

>Rectangle(-0.25,0;0.5x30)

描画位置をとるには,get_bbox()を用います.これが,描画位置になります.

print (ax.patches[0].get_bbox())

>Bbox(x0=-0.25, y0=0.0, x1=0.25, y1=30.0)

patch情報は,配列として取得され,その順番は dataframe の並びに依存しています.この情報を用いて,次のようにテキストを描画できます.

yno = len(df)
xno = len(df.columns)

x_offset = 0.0
y_offset = 0.0

# for p in ax.patches:
for index, p in enumerate(ax.patches):

    (xn, yn) = divmod(index, yno)
    value = df.iloc[yn,xn]
    label = df.columns[xn]

    b = p.get_bbox()

    # ypos = (b.y0 + b.y1)/2
    ypos = min(b.y0, b.y1)

    ax.text( b.x0 + x_offset, ypos + y_offset, label)

graph2.png

ここでは,矩形の左隅に描画しています.

高さの小さい矩形のなかにはラベルを書かない処理

積み上げグラフで重要な項目はデータの大きなものです.この例ではデータの数が少ないですが,多い場合は不要なテキストの描画を避けるべきです.データの値によって選択することもできますが,データの値がわからないときは,描画位置から決めることができます.

次に一例をあげます.この例では,描画範囲の6%未満のデータにはテキストを書きません.

yno = len(dfs)
xno = len(dfs.columns)

# check max range of bar    
rmax = 0
rmin = 0
for index, p in enumerate(ax.patches):
    b = p.get_bbox()
    if (b.y1 > rmax):
        rmax = b.y1
    if (b.y0 > rmax):
        rmax = b.y0
    if (b.y1 < rmin):
        rmin = b.y1
    if (b.y0 < rmin):
        rmin = b.y0              
rrange = rmax-rmin

x_offset = 0.0
y_offset = 0.0
t_height = rrange*0.06  # condition for adding text

for index, p in enumerate(ax.patches):
    (xn, yn) = divmod(index, yno)
    value = dfs.iloc[yn,xn]
    label = dfs.columns[xn]

    b = p.get_bbox()

    height = abs (b.y1 - b.y0)

    if (height < t_height):	# 高さが小さいならスキップ
        continue
    ypos = min(b.y1, b.y0)
#   ypos = (b.y1 + b.y0)/2

    ax.text( b.x0 + x_offset, ypos + y_offset, label)

graph3.png

参考情報

Pythonのmatplotlibで積み上げ棒グラフを作成しデータラベルを追加してみた

Annotate bars with values on Pandas bar plots

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?