Jak wykreślić wiele słupków w matplotlib, kiedy próbowałem wielokrotnie wywołać funkcję słupka, nakładają się one i jak widać na poniższym rysunku, najwyższa wartość jest czerwona. Jak narysować wiele słupków z datami na osiach X?
Do tej pory próbowałem tego:
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()
Mam to:
Wyniki powinny wyglądać mniej więcej tak, ale z datami są na osiach x, a słupki obok siebie:
python
matplotlib
John Smith
źródło
źródło
Odpowiedzi:
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()
Nie wiem, co oznacza „wartości y również się nakładają”, czy poniższy kod rozwiązuje problem?
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()
źródło
autofmt_xdate()
, która automatycznie obraca etykiety.Problem z używaniem dat jako wartości x polega na tym, że jeśli chcesz mieć wykres słupkowy taki jak na drugim zdjęciu, będą one błędne. Należy użyć skumulowanego wykresu słupkowego (kolory nakładające się na siebie) lub grupować według daty („fałszywa” data na osi X, w zasadzie tylko grupowanie punktów danych).
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()
źródło
datetime64
: Np jednomiesięcznej wartości:np.arange('2012-02', '2012-03', dtype='datetime64[D]')
. Być może będziesz musiał dokładniej przemyśleć najlepszy sposób przedstawienia tych danych, jeśli masz 40 zestawów danych (jak w innym komentarzu) obejmujących ponad 100 dni.xaxis_date
ale musisz dostosować to, co napisałem, aby przesunąć wartości dat (np. O liczbę godzin używaniatimedelta
) dla każdej serii, aby zapobiec ich nakładaniu się. Druga odpowiedź właśnie to robi, ale być może później będziesz musiał pogrzebać z etykietami.Wiem, że o to chodzi
matplotlib
, ale używaniepandas
iseaborn
pozwala zaoszczędzić sporo czasu: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()
źródło
szukając podobnego rozwiązania i nie znajdując niczego wystarczająco elastycznego, postanowiłem napisać dla niego własną funkcję. Pozwala na utworzenie dowolnej liczby słupków w grupie i określenie zarówno szerokości grupy, jak i indywidualnych szerokości słupków w ramach grup.
Cieszyć się:
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()
Wynik:
źródło
xticks
działkę, np.plt.xticks(range(5), ["one", "two", "three", "four", "five"])
Zrobiłem to rozwiązanie: jeśli chcesz wykreślić więcej niż jedną działkę na jednym rysunku, upewnij się, że przed wykreśleniem kolejnych wykresów ustawiłeś prawo
matplotlib.pyplot.hold(True)
do dodawania kolejnych wykresów.Jeśli chodzi o wartości daty i godziny na osi X, rozwiązanie wykorzystujące wyrównanie słupków działa dla mnie. Kiedy tworzysz kolejny wykres słupkowy za pomocą
matplotlib.pyplot.bar()
, po prostu użyjalign='edge|center'
i ustawwidth='+|-distance'
.Kiedy ustawisz wszystkie słupki (wykresy) w prawo, zobaczysz słupki w porządku.
źródło
matplotlib.pyplot.hold
została wycofana od wersji 2.0, jak wspomniano w dokumentacji