Cómo trazar varias barras en matplotlib, cuando intenté llamar a la función de la barra varias veces, se superponen y, como se ve en la siguiente figura, solo se puede ver el valor más alto en rojo. ¿Cómo puedo trazar las múltiples barras con fechas en los ejes x?
Hasta ahora, probé esto:
import matplotlib.pyplot as plt
import datetime
x = [
datetime.datetime(2011, 1, 4, 0, 0),
datetime.datetime(2011, 1, 5, 0, 0),
datetime.datetime(2011, 1, 6, 0, 0)
]
y = [4, 9, 2]
z = [1, 2, 3]
k = [11, 12, 13]
ax = plt.subplot(111)
ax.bar(x, y, width=0.5, color='b', align='center')
ax.bar(x, z, width=0.5, color='g', align='center')
ax.bar(x, k, width=0.5, color='r', align='center')
ax.xaxis_date()
plt.show()
Tengo esto:
Los resultados deberían ser algo así, pero con las fechas en los ejes xy las barras están una al lado de la otra:
python
matplotlib
John Smith
fuente
fuente
Respuestas:
import matplotlib.pyplot as plt from matplotlib.dates import date2num import datetime x = [ datetime.datetime(2011, 1, 4, 0, 0), datetime.datetime(2011, 1, 5, 0, 0), datetime.datetime(2011, 1, 6, 0, 0) ] x = date2num(x) y = [4, 9, 2] z = [1, 2, 3] k = [11, 12, 13] ax = plt.subplot(111) ax.bar(x-0.2, y, width=0.2, color='b', align='center') ax.bar(x, z, width=0.2, color='g', align='center') ax.bar(x+0.2, k, width=0.2, color='r', align='center') ax.xaxis_date() plt.show()
No sé qué significa "los valores y también se superponen", ¿el siguiente código resuelve su problema?
ax = plt.subplot(111) w = 0.3 ax.bar(x-w, y, width=w, color='b', align='center') ax.bar(x, z, width=w, color='g', align='center') ax.bar(x+w, k, width=w, color='r', align='center') ax.xaxis_date() ax.autoscale(tight=True) plt.show()
fuente
autofmt_xdate()
, que gira automáticamente las etiquetas.El problema de usar fechas como valores x es que si desea un gráfico de barras como en su segunda imagen, se equivocarán. Debes usar un gráfico de barras apiladas (colores uno encima del otro) o agrupar por fecha (una fecha "falsa" en el eje x, básicamente agrupando los puntos de datos).
import numpy as np import matplotlib.pyplot as plt N = 3 ind = np.arange(N) # the x locations for the groups width = 0.27 # the width of the bars fig = plt.figure() ax = fig.add_subplot(111) yvals = [4, 9, 2] rects1 = ax.bar(ind, yvals, width, color='r') zvals = [1,2,3] rects2 = ax.bar(ind+width, zvals, width, color='g') kvals = [11,12,13] rects3 = ax.bar(ind+width*2, kvals, width, color='b') ax.set_ylabel('Scores') ax.set_xticks(ind+width) ax.set_xticklabels( ('2011-Jan-4', '2011-Jan-5', '2011-Jan-6') ) ax.legend( (rects1[0], rects2[0], rects3[0]), ('y', 'z', 'k') ) def autolabel(rects): for rect in rects: h = rect.get_height() ax.text(rect.get_x()+rect.get_width()/2., 1.05*h, '%d'%int(h), ha='center', va='bottom') autolabel(rects1) autolabel(rects2) autolabel(rects3) plt.show()
fuente
datetime64
: ejemplo, un mes vale la pena:np.arange('2012-02', '2012-03', dtype='datetime64[D]')
. Es posible que deba pensar más sobre la mejor manera de representar estos datos si tiene 40 conjuntos de datos (según otro comentario) que abarcan más de 100 días.xaxis_date
pero tendrá que adaptar lo que he escrito para compensar sus valores de fecha (por ejemplo, por un número de horas usandotimedelta
) para cada serie para evitar que se superpongan. La otra respuesta hace exactamente esto, pero es posible que deba limpiar las etiquetas después.Sé que se trata
matplotlib
, pero usarpandas
yseaborn
puede ahorrarle mucho tiempo:df = pd.DataFrame(zip(x*3, ["y"]*3+["z"]*3+["k"]*3, y+z+k), columns=["time", "kind", "data"]) plt.figure(figsize=(10, 6)) sns.barplot(x="time", hue="kind", y="data", data=df) plt.show()
fuente
después de buscar una solución similar y no encontrar nada lo suficientemente flexible, decidí escribir mi propia función para ella. Le permite tener tantas barras por grupo como desee y especificar tanto el ancho de un grupo como los anchos individuales de las barras dentro de los grupos.
Disfrutar:
from matplotlib import pyplot as plt def bar_plot(ax, data, colors=None, total_width=0.8, single_width=1, legend=True): """Draws a bar plot with multiple bars per data point. Parameters ---------- ax : matplotlib.pyplot.axis The axis we want to draw our plot on. data: dictionary A dictionary containing the data we want to plot. Keys are the names of the data, the items is a list of the values. Example: data = { "x":[1,2,3], "y":[1,2,3], "z":[1,2,3], } colors : array-like, optional A list of colors which are used for the bars. If None, the colors will be the standard matplotlib color cyle. (default: None) total_width : float, optional, default: 0.8 The width of a bar group. 0.8 means that 80% of the x-axis is covered by bars and 20% will be spaces between the bars. single_width: float, optional, default: 1 The relative width of a single bar within a group. 1 means the bars will touch eachother within a group, values less than 1 will make these bars thinner. legend: bool, optional, default: True If this is set to true, a legend will be added to the axis. """ # Check if colors where provided, otherwhise use the default color cycle if colors is None: colors = plt.rcParams['axes.prop_cycle'].by_key()['color'] # Number of bars per group n_bars = len(data) # The width of a single bar bar_width = total_width / n_bars # List containing handles for the drawn bars, used for the legend bars = [] # Iterate over all data for i, (name, values) in enumerate(data.items()): # The offset in x direction of that bar x_offset = (i - n_bars / 2) * bar_width + bar_width / 2 # Draw a bar for every value of that type for x, y in enumerate(values): bar = ax.bar(x + x_offset, y, width=bar_width * single_width, color=colors[i % len(colors)]) # Add a handle to the last drawn bar, which we'll need for the legend bars.append(bar[0]) # Draw legend if we need if legend: ax.legend(bars, data.keys()) if __name__ == "__main__": # Usage example: data = { "a": [1, 2, 3, 2, 1], "b": [2, 3, 4, 3, 1], "c": [3, 2, 1, 4, 2], "d": [5, 9, 2, 1, 8], "e": [1, 3, 2, 2, 3], "f": [4, 3, 1, 1, 4], } fig, ax = plt.subplots() bar_plot(ax, data, total_width=.8, single_width=.9) plt.show()
Salida:
fuente
xticks
de la trama, por ejemploplt.xticks(range(5), ["one", "two", "three", "four", "five"])
Hice esta solución: si desea trazar más de una parcela en una figura, asegúrese de que antes de trazar las siguientes parcelas haya configurado correctamente la
matplotlib.pyplot.hold(True)
posibilidad de agregar otras parcelas.Con respecto a los valores de fecha y hora en el eje X, una solución que utiliza la alineación de barras funciona para mí. Cuando cree otro diagrama de barras con
matplotlib.pyplot.bar()
, solo usealign='edge|center'
y configurewidth='+|-distance'
.Cuando establezca todas las barras (gráficos) correctamente, verá las barras bien.
fuente
matplotlib.pyplot.hold
ha quedado obsoleto desde la versión 2.0, como se menciona en los documentos