Более эффективная гистограмма диаграммы matplotlib - как рассчитать нижние значения
Мне нужна помощь в создании набора штабелированных графиков в python с помощью matlibplot. Мой базовый код ниже, но мои проблемы в том, как сгенерировать значение bottom для любого элемента за 2-й эффективный . Я могу получить примерный граф для правильного стека (всегда 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 = [...] не может быть лучшим решением. Было бы здорово, если бы вы также могли объяснить, как мне нужно получить ценность. Есть функция numpy.
Большое спасибо!!!
PS Я искал ответ, но я не понимал, что я могу найти.
Ответы
Ответ 1
Недавно я столкнулся с той же проблемой. Впоследствии я решил обернуть все в класс. Для всех, кого это интересует, вы получаете реализацию класса столбчатых столбцов:
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 с любовью.
Ответ 2
Преобразование ваших значений в массивы 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)
Ответ 3
[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)]
а затем do
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))
тоже.
Если a
, b
, c
и 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]))
Ответ 4
Я решил это так:
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
Он похож на некоторые другие решения, но он не требует, чтобы все поля сохранялись в любое время. Вместо этого он "строит" стеки снизу вверх, добавляя все больше и больше полей с каждой итерацией.