Como plotar várias barras em matplotlib, quando tentei chamar a função de barra várias vezes, elas se sobrepõem e, como pode ser visto na figura abaixo, o maior valor vermelho pode ser visto apenas. Como posso plotar as várias barras com datas nos eixos x?
Até agora, tentei isto:
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()
Eu tenho esse:
Os resultados devem ser algo como, mas com as datas no eixo x e as barras próximas umas das outras:
python
matplotlib
John smith
fonte
fonte
Respostas:
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()
Não sei o que significa "os valores y também estão sobrepostos", o código a seguir resolve seu 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()
fonte
autofmt_xdate()
, que gira automaticamente os rótulos.O problema de usar datas como valores x é que, se você quiser um gráfico de barras como em sua segunda imagem, eles estarão errados. Você deve usar um gráfico de barras empilhadas (cores umas sobre as outras) ou agrupar por data (uma data "falsa" no eixo x, basicamente agrupando os pontos de dados).
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()
fonte
datetime64
: por exemplo, vale a pena Um mês:np.arange('2012-02', '2012-03', dtype='datetime64[D]')
. Você pode precisar pensar mais sobre a melhor maneira de representar esses dados se tiver 40 conjuntos de dados (conforme outro comentário) abrangendo mais de 100 dias.xaxis_date
mas você precisará adaptar o que escrevi para compensar seus valores de data (por exemplo, por um número de horas usandotimedelta
) para cada série para evitar que se sobreponham. A outra resposta faz exatamente isso, mas você pode precisar mexer com os rótulos depois.Eu sei que se trata
matplotlib
, mas usarpandas
eseaborn
pode poupar muito tempo: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()
fonte
depois de procurar uma solução semelhante e não encontrar nada flexível o suficiente, decidi escrever minha própria função para ela. Ele permite que você tenha quantas barras por grupo desejar e especifique a largura de um grupo, bem como as larguras individuais das barras dentro dos grupos.
Apreciar:
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()
Resultado:
fonte
xticks
do gráfico, por exemploplt.xticks(range(5), ["one", "two", "three", "four", "five"])
Eu fiz esta solução: se você quiser plotar mais de um gráfico em uma figura, certifique-se antes de plotar os próximos gráficos que você definiu corretamente
matplotlib.pyplot.hold(True)
para poder adicionar outros gráficos.Em relação aos valores de data e hora no eixo X, uma solução usando o alinhamento de barras funciona para mim. Ao criar outro gráfico de barra com
matplotlib.pyplot.bar()
, basta usaralign='edge|center'
e definirwidth='+|-distance'
.Quando você definir todas as barras (plotagens) corretamente, verá que as barras estão bem.
fonte
matplotlib.pyplot.hold
está obsoleto desde a v2.0, conforme mencionado nos documentos