Python matplotlib çoklu çubuklar


92

Matplotlib'de birden çok çubuk nasıl çizilir, çubuk işlevini birden çok kez çağırmaya çalıştığımda, bunlar üst üste biniyor ve aşağıdaki şekilde görüldüğü gibi en yüksek değer kırmızı sadece görülebiliyor. X eksenlerinde tarih bulunan birden çok çubuğu nasıl çizebilirim?

Şimdiye kadar bunu denedim:

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()

Bunu anladım:

görüntü açıklamasını buraya girin

Sonuçlar aşağıdaki gibi olmalıdır, ancak tarihler x eksenlerinde ve çubuklar yan yana:

görüntü açıklamasını buraya girin


x değerlerini değiştirmeniz gerekiyor
jterrace

2
Ne demek istiyorsun ? X değerleri tarihlerdir ...
John Smith

4
bu neden matplotlib tarafından desteklenmiyor ?!
ihadanny

Yanıtlar:


115
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()

görüntü açıklamasını buraya girin

"Y değerleri de çakışıyor" ne anlama geliyor bilmiyorum, aşağıdaki kod sorununuzu çözüyor mu?

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()

görüntü açıklamasını buraya girin


Teşekkürler, ama 3 çubuğum varsa iyi görünüyor. 40 bar gibi denediğimde ortalığı karıştırıyor. Çözümünüzü daha ölçeklenebilir olması için güncelleyebilir misiniz?
John Smith

"Dağınıklık" demek mi? Üst üste gelen X etiketleri autofmt_xdate(), etiketleri otomatik olarak döndüren kullanılarak düzeltilebilir .
John Lyon

Sorun X etiketlerinin örtüşmesi değil, y değerlerinin de örtüşmesidir. Nasıl düzeltilir?
John Smith

ve ayrıca genişlik = 0,2 büyük bir zaman aralığı için çok küçüktür. Daha büyük değerler kullanırsam aynı sonucu almam.
John Smith

Başka bir şey de, baştaki ve sondaki boşluklar. Boşluklar nasıl kaldırılır ve doğrudan ilk tarih nasıl başlatılır ve benzer şekilde son tarihi boşluk veya daha az boşluk olmadan nasıl sonlandırılır.
John Smith

61

Tarihleri ​​x değerleri olarak kullanmanın sorunu, eğer ikinci resminizdeki gibi bir çubuk grafik istiyorsanız, bunların yanlış olacağıdır. Ya yığılmış bir çubuk grafik (renkler üst üste) kullanmalı ya da tarihe göre gruplamalısınız (x ekseninde "sahte" bir tarih, temelde sadece veri noktalarını gruplandırarak).

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()

görüntü açıklamasını buraya girin


x ekseninde 100 gün gibi göstermek istersem, bunları nasıl yerleştirirsiniz?
John Smith

1
Kolayca numpy en gereklidir tarihleri yaratabilecek datetime64bir ay değerinde örneğin: np.arange('2012-02', '2012-03', dtype='datetime64[D]'). 100 günden fazla yayılan 40 veri kümeniz (başka bir yoruma göre) varsa, bu verileri temsil etmenin en iyi yolu hakkında daha fazla düşünmeniz gerekebilir.
John Lyon

Ayrıca, ax.xaxis_date () kullanmak çok avantajlıdır, çünkü tarihlerinizi x eksenlerine sığdırır.
John Smith

3
Neden önce sen gitmiyorsun? Öğrenmenize yardımcı olmaya çalışıyorum, kodunu sizin için yazmam. Eminim bununla yapabilirsiniz, xaxis_dateancak timedeltaher seri için tarih değerlerinizi dengelemek için yazdıklarımı uyarlamanız gerekir (örneğin, kullanarak birkaç saat ). Diğer cevap tam da bunu yapıyor, ancak daha sonra etiketlerle uğraşmanız gerekebilir.
John Lyon

tamam, ancak np.arange ('2012-02', '2012-03, dtype =' datetime64 [D] ') çalıştırdığımda şunu alıyorum: -:' str 've' için desteklenmeyen işlenen türleri str '
John Smith

25

Bunun hakkında olduğunu biliyorum matplotlib, ancak kullanmak pandasve seabornsize çok zaman kazandırabilir:

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()

görüntü açıklamasını buraya girin


Harika cevap, ancak x ekseni nedeniyle biraz eksik. Daha prezentabl yapabilir misin?
Spinor8

Sanırım pandalar ve matplotlib ile de yapabilirsin
Vicki B

18

Benzer bir çözüm aradıktan ve yeterince esnek bir şey bulamadıktan sonra, onun için kendi işlevimi yazmaya karar verdim. Grup başına istediğiniz kadar çubuğa sahip olmanıza ve hem bir grubun genişliğini hem de gruplar içindeki çubukların ayrı genişliklerini belirlemenize olanak tanır.

Zevk almak:

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()

Çıktı:

görüntü açıklamasını buraya girin


Bunu x eksenine etiket eklemek için nasıl değiştirebiliriz? Her bar grubunda olduğu gibi mi?
x89

xticksarsayı değiştirin , örneğinplt.xticks(range(5), ["one", "two", "three", "four", "five"])
pascscha

güzel işlev, çok yardımcı, teşekkürler. Değiştirdiğim tek şey, barplot çağrısına label = data.keys [i] koyarsanız ve çubuklar listesini oluşturmanıza gerek kalmazsa, efsanenin daha kolay olacağını düşünüyorum.
Adrian Tompkins

0

Bu çözümü yaptım: Bir şekilde birden fazla arsa çizmek istiyorsanız, sonraki arsaları çizmeden önce matplotlib.pyplot.hold(True) başka arsa ekleyebilmek için doğru ayarladığınızdan emin olun .

X eksenindeki tarih saat değerleri ile ilgili olarak, çubukların hizalanmasını kullanan bir çözüm benim için çalışıyor. İle başka bir çubuk grafiği oluşturduğunuzda matplotlib.pyplot.bar(), sadece kullanın align='edge|center've ayarlayın width='+|-distance'.

Tüm çubukları (grafikleri) doğru ayarladığınızda, çubukları iyi göreceksiniz.


Docsmatplotlib.pyplot.hold
engineervix
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.