una - python graficos 2d
Gráfico de barras apiladas matplotlib más eficientes: cómo calcular los valores mínimos (4)
Necesito ayuda para hacer un conjunto de gráficos de barras apiladas en python con matlibplot. Mi código básico está a continuación, pero mi problema es cómo generar el valor de abajo para cualquier elemento más allá del 2º de manera eficiente . Puedo obtener el gráfico de ejemplo para apilar correctamente (siempre a, b, c, d de abajo hacia arriba)
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()
Mi código final podría tener una gran cantidad de barras y la función de expansión constante bottom = [...] no puede ser la mejor solución. Sería genial si también pudieras explicar cómo necesito obtener el valor. ¿Hay una función numpy?
¡¡¡Muchas gracias!!! PD. He buscado una respuesta, pero no entendí qué podría encontrar.
La conversión de sus valores a matrices numpy hará su vida más fácil:
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])
Alternativamente, para deshacerse del desagradable caso particular de la primera barra:
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)
[sum(values) for values in zip(a, b, c)]
En Python 2 también puedes hacer
map(sum, zip(a, b, c))
pero Python 3 necesitaría
list(map(sum, zip(a, b, c)))
que es menos agradable
Podrías encapsular esto:
def sumzip(*items):
return [sum(values) for values in zip(*items)]
y luego hacer
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))
también.
Si a
, b
, c
y d
son matrices numpy, también puedes hacer 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]))
Recientemente me he enfrentado al mismo problema. Después, decidí envolverlo todo en una clase agradable. Para cualquier persona interesada, obtenga una implementación de una clase de gráfico de barras apiladas aquí:
https://github.com/minillinim/stackedBarGraph
Permite gráficos apilados a escala, así como establecer anchos de barra y establecer alturas (con internos escalados).
Dado un conjunto de datos como este:
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'']
Puede hacer imágenes como esta:
GPLv3 con amor.
Lo solucioné así:
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
Es similar a algunas otras soluciones, pero no requiere que todos los márgenes se almacenen en todo momento. En su lugar, "construye" las pilas de abajo hacia arriba, agregando más y más margen con cada iteración.