web-dev-qa-db-ja.com

より効率的なmatplotlib積み上げ棒グラフ-底値の計算方法

python matlibplotで積み上げ棒グラフのセットを作成するのにいくつかの助けが必要です。私の基本的なコードは以下ですが、私の問題はbottomの値を生成する方法です2番目の要素を超えた要素efficiently。サンプルグラフを正しくスタックできます(常に下から上にa、b、c、d)。

import numpy as np
import matplotlib.pyplot as plt

ind = np.arange(3)

a = [3,6,9]
b = [2,7,1]
c = [0,3,1]
d = [4,0,3]

p1 = plt.bar(ind, a, 1, color='#ff3333')
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=a)
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=[a[j] +b[j] for j in range(len(a))])
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=[a[j] +b[j] +c[j] for j in range(len(a))])

plt.show()

私の最終的なコードには非常に多くのバーが含まれる可能性があり、常に拡張する関数bottom = [...]は最善の解決策にはなりません。価値を引き出す方法についても説明していただければ幸いです。派手な機能はありますか?.

どうもありがとうございました!!! PS私は答えを探しましたが、何が見つかるかわかりませんでした。

19
2705114-john

最近、同じ問題に直面しました。その後、すべてをニースのクラスにまとめることにしました。興味のある方は、ここに積み上げ棒グラフクラスの実装を取得します。

https://github.com/minillinim/stackedBarGraph

それは、スケーリングされた積み上げグラフ、およびバーの幅と高さの設定(スケーリングされた内部で)を可能にします。

次のようなデータセットがあるとします。

    d = np.array([[101.,0.,0.,0.,0.,0.,0.],
                  [92.,3.,0.,4.,5.,6.,0.],
                  [56.,7.,8.,9.,23.,4.,5.],
                  [81.,2.,4.,5.,32.,33.,4.],
                  [0.,45.,2.,3.,45.,67.,8.],
                  [99.,5.,0.,0.,0.,43.,56.]])

    d_heights = [1.,2.,3.,4.,5.,6.]
    d_widths = [.5,1.,3.,2.,1.,2.]
    d_labels = ["fred","julie","sam","peter","rob","baz"]
    d_colors = ['#2166ac',
                '#fee090',
                '#fdbb84',
                '#fc8d59',
                '#e34a33',
                '#b30000',
                '#777777']

次のような画像を作成できます。

stacked bar graph

愛を込めたGPLv3。

29
minillinim

値をnumpy配列に変換すると、作業が楽になります。

data = np.array([a, b, c, d])
bottom = np.cumsum(data, axis=0)
colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff')

plt.bar(ind, data[0], color=colors[0])
for j in xrange(1, data.shape[0]):
    plt.bar(ind, data[1], color=colors[j], bottom=bottom[i-1])

または、最初のバーの厄介な特定のケースを取り除くには:

data = np.array([a, b, c, d])
bottom = np.vstack((np.zeros((data.shape[1],), dtype=data.dtype),
                    np.cumsum(data, axis=0)[:-1]))
colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff')
for dat, col, bot in Zip(data, colors, bottom):
    plt.bar(ind, dat, color=col, bottom=bot)
14
Jaime
_[sum(values) for values in Zip(a, b, c)]
_

Python 2では、

_map(sum, Zip(a, b, c))
_

しかしPython 3は

_list(map(sum, Zip(a, b, c)))
_

あまりいい感じではありません。


これをカプセル化できます:

_def sumzip(*items):
    return [sum(values) for values in Zip(*items)]
_

そして次に

_p1 = plt.bar(ind, a, 1, color='#ff3333')
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sumzip(a))
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sumzip(a, b))
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sumzip(a, b, c))
_

あまりにも。


abcおよびdがnumpy配列の場合は、sum([a, b, c])も実行できます。

_a = np.array([3,6,9])
b = np.array([2,7,1])
c = np.array([0,3,1])
d = np.array([4,0,3])

p1 = plt.bar(ind, a, 1, color='#ff3333')
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sum([a]))
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sum([a, b]))
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sum([a, b, c]))
_
5
Veedrac

私はそれを次のように解決しました:

import numpy as np

dates = # somehow get a list of dates
labels = # a list of various labels
colors = # somehow get a list of colors

margin_bottom = np.zeros(dates)

for index, label in enumerate(labels):
    values = # get your values for the label at index-th position from somewhere
    ax.bar(
        dates, values, 
        align='center', label=label, color=colors[index], bottom=margin_bottom
    )
    margin_bottom += values # here you simply add it to the previous margin
    # margin_bottom is a numpy array, adding a list will not change that

これは他のいくつかのソリューションと似ていますが、常にすべてのマージンを保存する必要はありません。代わりに、スタックを下から上に「構築」し、反復ごとにマージンを増やしていきます。

2