棒グラフを描く【Python】

ここではmatplotlibを用いて棒グラフを描く方法です。matplotlibで棒グラフを作成する際にはAxesオブジェクトのbarメソッドを用いますが、複数の棒グラフを重ねる場合(横並び・積み上げ)は棒グラフを描画する場所を自分で指定する必要があります。ここではその方法を説明していきます。

開発環境

  • matplotlib 3.3.4
  • Pandas 1.2.1
  • Python 3.7.9

棒グラフで1つのデータセットを描画する

Axesオブジェクトのbarメソッドで折れ線グラフを描画できます。(pyplotスタイルの場合は、pyplotのbar関数を用います)

基本的な使い方

まずは基本として、最もシンプルな描画方法を見ていきましょう。

barメソッドのx引数に横軸の値を、heightに棒グラフの高さをそれぞれリストやSeriesなど配列に類似するデータ構造で指定することで棒グラフを作成できます。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
height = [1, 2, 1, 2, 4, 5, 3, 7, 5, 9]
  
fig, ax = plt.subplots()
ax.bar(x, height)
plt.show()

棒グラフで複数のデータセットを描画する

横並び棒グラフを描画する

X軸の値ごとに2つのデータセットを横並びで表示させる方法で、2つの独立したデータセットを比較する場合によく用いられます。matplotlibのbarメソッドは複数のデータセットを引数で与えることはできないので、1つ1つの棒グラフをX軸の位置をずらして追加していくという手法をとる必要があります。

1つ1つ棒グラフを追加していく

まずは手作業で1つ1つ棒グラフを追加していく方法を見ていきましょう。

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(1, 11)
width = 0.3
height1 = [1, 2, 1, 2, 4, 5, 3, 7, 5, 9]
height2 = [1, 3, 2, 1, 2, 3, 5, 8, 6, 7]
  
fig, ax = plt.subplots()
ax.bar(x-width, height1, width, align='edge')
ax.bar(x, height2, width, align='edge')
plt.show()

barメソッドの引数として棒グラフの幅をwidthとして与え、10行目の方では棒グラフのX座標をwidthの分だけ引いています。なお、配列のすべての要素に対して同じ演算を行う(ブロードキャスト)ために、X軸の値はリストではなくndarrayとして与えています(4行目)。またbarメソッドのalign引数は’edge’を指定していますが、軸目盛りに対して棒グラフをどこに表示させるかの指定で、データセットの数が偶数なら’edge’、奇数なら’center’とするときれいに配置できます。

汎用的な関数を作成してみる

以上のように手作業でも横並び棒グラフを作成するのは難しいところはないのですが、棒グラフをずらす処理がやや煩雑ですよね?そこで以下の例では、データセットをリストとして渡せる汎用的な関数のbar_multiple関数を定義して、横並びの棒グラフを作成しています。

import numpy as np
import matplotlib.pyplot as plt

# 汎用的な関数を定義
def bar_multiple(axes, x, height_list):
    n = len(height_list)
    width = 0.8 / n
    
    if n % 2 == 0:
        diff = - (n / 2) * width
        for height in height_list:
            axes.bar(x + diff, height, width, align='edge')
            diff += width
    else:
        diff = - ((n - 1) / 2) * width
        for height in height_list:
            axes.bar(x + diff, height, width, align='center')
            diff += width

# 3つのデータセットを定義する
x = np.arange(1, 11)
height1 = [1, 2, 1, 2, 4, 5, 3, 7, 5, 9]
height2 = [1, 3, 2, 1, 2, 3, 5, 8, 6, 7]
height3 = [1, 3, 3, 6, 3, 7, 4, 6, 9, 8]

# グラフを描画する
fig, ax = plt.subplots()
bar_multiple(ax, x, (height1, height2, height3))
plt.show()

ここで定義したbar_multiple関数は引数に棒グラフを描画するAxesオブジェクトとX軸の値、棒グラフの高さのリスト(データセットのリスト)を指定します。なお、X軸の値はndarrayで指定する必要があります。このような関数を定義すれば簡単に横並びの棒グラフを作成できます。

積み上げ棒グラフを描画する

複数のデータセットをX軸の値ごとに積み重ねて表示させたものが積み上げ棒グラフで、X軸の値ごとの合計値も問題となる場合によく用いられます。matplotlibのbarメソッドは複数のデータセットを引数で与えることはできないので、1つ1つの棒グラフを高さを変えて描画していく必要があります。barメソッドのbottom引数で棒グラフの下の部分の高さを指定できます。

2つのデータセットを積み上げる

2つのデータセットを積み上げるだけなら、上側の棒グラフを描画する際にbarメソッドのbottom引数に下側の棒グラフの高さを指定するだけで描画できます。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
height1 = [1, 2, 1, 2, 4, 5, 3, 7, 5, 9]
height2 = [1, 3, 2, 1, 2, 3, 5, 8, 6, 7]
  
fig, ax = plt.subplots()
ax.bar(x, height1)
ax.bar(x, height2, bottom = height1)
plt.show()

3つ以上のデータセットを積み上げる

3つ以上のデータセットの場合も2つの場合と同じですが、barメソッドのbottom引数に指定する際に配列同士の足し算をできるように、データセットをリストではなくndarraySeriesで与えておくことがポイントです。

import numpy as np
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
height1 = np.array([1, 2, 1, 2, 4, 5, 3, 7, 5, 9])
height2 = np.array([1, 3, 2, 1, 2, 3, 5, 8, 6, 7])
height3 = np.array([1, 3, 3, 6, 3, 7, 4, 6, 9, 8])
  
fig, ax = plt.subplots()
ax.bar(x, height1)
ax.bar(x, height2, bottom = height1)
ax.bar(x, height3, bottom = height1 + height2)
plt.show()

100%積み上げ棒グラフを描画する

データセットの合計値を100%として、それぞれのX軸の値で各データセットの割合を示したものが100%積み上げ棒グラフです。実は100%積み上げ棒グラフを作成するための特別なことは何もなく、単純にそれぞれのX軸の値のデータの合計値が100%になるようにデータを書き換えてグラフを作成するだけになります。

配列同士の足し算やかけ算をできるように、データセットはリストではなくndarraySeriesで与えておきましょう。

import numpy as np
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
height1 = np.array([1, 2, 1, 2, 4, 5, 3, 7, 5, 9])
height2 = np.array([1, 3, 2, 1, 2, 3, 5, 8, 6, 7])
height3 = np.array([1, 3, 3, 6, 3, 7, 4, 6, 9, 8])
sum = height1 + height2 + height3
  
fig, ax = plt.subplots()
ax.bar(x, (height1 / sum) * 100)
ax.bar(x, (height2 / sum) * 100, bottom = (height1 / sum) * 100)
ax.bar(x, (height3 / sum) * 100, bottom = ((height1 + height2) / sum) * 100)
plt.show()

関連記事・スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)