2013-09-27 13 views
15

Ich brauche Hilfe bei der Erstellung einer Reihe von gestapelten Balkendiagramme in Python mit Matlibplot. Mein grundlegender Code ist unten, aber meine Probleme sind, wie man den Wert für unteren für jedes mögliches Element über dem 2. effizient erzeugt. Ich kann das Beispiel Graphen erhalten, richtig zu stapeln (immer a, b, c, d von unten nach oben)Effizienter Matplotlib gestapelt Balkendiagramm - wie unteren Werte zu berechnen

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

Mein letzten Code könnte sehr große Anzahl von Bars hat und die immer größer werdende Funktion unten = [.. .] kann nicht die beste Lösung sein. Es wäre großartig, wenn Sie auch erklären könnten, wie ich den Wert ableiten muss. Gibt es eine anzahl Funktion?

Vielen Dank !!! PS Ich habe nach einer Antwort gesucht, aber ich habe nicht verstanden, was ich finden konnte.

Antwort

28

Ich habe gerade das gleiche Problem konfrontiert. Danach habe ich beschlossen, alles in einer netten Klasse zu verpacken. Für alle Interessierten Sie eine Implementierung eines gestapelten Balkendiagramm Klasse bekommen hier:

https://github.com/minillinim/stackedBarGraph

Es ermöglicht skaliert gestapelten Graphen sowie die Einstellung Strichbreiten und stellen Höhen (mit skalierten inners).

einen Datensatz wie folgt gegeben:

stacked bar graph

GPLv3 mit der Liebe:

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'] 

Es Bilder wie diese machen.

+0

Danke - wie bekomme ich Leerzeichen zwischen den Balken? – Matt

+0

Ich habe den Code aktualisiert, um Lücken zu ermöglichen. Es ist eigentlich ziemlich einfach, wenn Sie einen festen Betrag von den Breiten der Balken abziehen, dann schrumpft es sie effektiv. Danach geht es nur noch darum, mit den Xlims zu spielen. Der Hauptfunktionsaufruf hat jetzt zwei neue Parameter, Lücken und EndGaps. Die unteren beiden Bilder zeigen Beispiele davon. – minillinim

+0

Liebe @ minillinim Paket. Es fühlte sich zu einfach an. Um eine Legende hinzuzufügen, wenn Sie die Farben mit einem Array wie 'stacked_colors = ['# 2166ac', '# fee090', '# fdbb84']' und 'cols = stacked_colors' festlegen, ist es einfach, eine Legende hinzuzufügen eine grafische Darstellung von einem pandas Datenrahmen aus: 'Legenden = [] i = 0 für Spalte in df.columns: legends.append (mpatches.Patch (color = stacked_colors [i], Etikett = Spalte)) i + = 1 plt.legend (handles = legends) ' –

5
[sum(values) for values in zip(a, b, c)] 

In Python 2 Sie können auch

map(sum, zip(a, b, c)) 

tun, aber Python 3 würde

list(map(sum, zip(a, b, c))) 

benötigen, die weniger schön ist.


Sie könnten diese einkapseln:

def sumzip(*items): 
    return [sum(values) for values in zip(*items)] 

und tun dann

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

auch.


Wenn a, b, c und d sind numpy Arrays können Sie auch sum([a, b, c]) tun:

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])) 
14

Ihre Werte konvertieren Arrays numpy wird Ihr Leben leichter machen:

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

Alternativ, um den fiesen besonderen Fall für den ersten Balken loszuwerden:

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) 
+4

Wenn Sie matplotlib verwenden, endet alles als ndarray unter _anyway_. Es könnte auch Ihr Leben angenehm machen;) – tacaswell

+0

danke, wie kann ich Etiketten hinzufügen? Ich habe eine Liste mit Label/Namen für jede der Serien, die ich staple, aber obwohl ich es versucht habe, kann ich sie nicht richtig hervorbringen. Ich habe auch versucht, eine einfache Legende wie die unten zu laufen, aber es hat nicht wirklich funktioniert .: 'code'plt.legend ((pl [0], pm [0], ph [0], pa [0]) , ('L', 'M', 'H', 'At'), bbox_to_anchor = [1.05, 0.5], loc = 'zentrum') –

1

ich es wie folgt gelöst:

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 ist ähnlich wie einige andere Lösungen, aber es jederzeit gespeichert werden nicht alle die Margen erfordern wird. Stattdessen "baut" er die Stapel von unten nach oben auf und fügt mit jeder Iteration mehr und mehr Rand hinzu.