2014-01-28 5 views
9

Ich versuche, das folgende Bild in Matplotlib zu replizieren und es scheint barh ist meine einzige Option. Obwohl es scheint, dass Sie nicht barh Graphen stapeln können, so weiß ich nicht, wasstack bar plot in Matplotlib und fügen Sie Etikett zu jedem Abschnitt (und Anregungen)

enter image description here

tun, wenn Sie eine bessere Python-Bibliothek kennen diese Art der Sache zu ziehen, lassen Sie es mich wissen.

Das ist alles, was ich mit als Start einfiel:

import matplotlib.pyplot as plt; plt.rcdefaults() 
import numpy as np 
import matplotlib.pyplot as plt 

people = ('A','B','C','D','E','F','G','H') 
y_pos = np.arange(len(people)) 
bottomdata = 3 + 10 * np.random.rand(len(people)) 
topdata = 3 + 10 * np.random.rand(len(people)) 
fig = plt.figure(figsize=(10,8)) 
ax = fig.add_subplot(111) 
ax.barh(y_pos, bottomdata,color='r',align='center') 
ax.barh(y_pos, topdata,color='g',align='center') 
ax.set_yticks(y_pos) 
ax.set_yticklabels(people) 
ax.set_xlabel('Distance') 

plt.show() 

Ich würde dann Etiketten einzeln hinzufügen müssen ax.text verwendet, die langwierig sein würde. Im Idealfall möchte ich nur die Breite des einzufügenden Teils angeben und dann die Mitte dieses Abschnitts mit einer Zeichenfolge meiner Wahl aktualisieren. Die Etiketten auf der Außenseite (z. B. 3800) kann ich später selbst hinzufügen, es ist hauptsächlich die Beschriftung über den Balkenabschnitt selbst und das Erstellen dieser gestapelten Methode auf eine nette Art, mit der ich Probleme habe. Können Sie überhaupt eine "Entfernung", d. H. Eine Farbspanne, angeben?

enter image description here

+0

http://stackoverflow.com/a/16654564/380231 – tacaswell

Antwort

19

Edit 2: für heterogene Daten. (Ich habe das obige Verfahren verlassen, da ich es gewohnt arbeiten mit der gleichen Anzahl von Datensätzen pro Serie finden)

Beantwortung der beiden Teile der Frage:

a) barh einen Behälter mit Griffen wieder in alle Patches, die es gezeichnet hat. Sie können die Koordinaten der Patches verwenden, um die Textpositionen zu unterstützen.

b) Nach thesetwo Antworten auf die Frage, die ich festgestellt, vor (siehe Horizontal stacked bar chart in Matplotlib) können Sie Balkendiagramme stapeln sich horizontal durch den ‚linken‘ Eingangseinstellung.

und zusätzlich c) Umgang mit Daten, die in der Form weniger einheitlich sind.

Unten ist eine Art, wie Sie mit Daten umgehen können, die in der Form weniger einheitlich ist, einfach jedes Segment unabhängig zu verarbeiten.

import numpy as np 
import matplotlib.pyplot as plt 

# some labels for each row 
people = ('A','B','C','D','E','F','G','H') 
r = len(people) 

# how many data points overall (average of 3 per person) 
n = r * 3 

# which person does each segment belong to? 
rows = np.random.randint(0, r, (n,)) 
# how wide is the segment? 
widths = np.random.randint(3,12, n,) 
# what label to put on the segment 
labels = xrange(n) 
colors ='rgbwmc' 

patch_handles = [] 

fig = plt.figure(figsize=(10,8)) 
ax = fig.add_subplot(111) 



left = np.zeros(r,) 
row_counts = np.zeros(r,) 

for (r, w, l) in zip(rows, widths, labels): 
    print r, w, l 
    patch_handles.append(ax.barh(r, w, align='center', left=left[r], 
     color=colors[int(row_counts[r]) % len(colors)])) 
    left[r] += w 
    row_counts[r] += 1 
    # we know there is only one patch but could enumerate if expanded 
    patch = patch_handles[-1][0] 
    bl = patch.get_xy() 
    x = 0.5*patch.get_width() + bl[0] 
    y = 0.5*patch.get_height() + bl[1] 
    ax.text(x, y, "%d%%" % (l), ha='center',va='center') 

y_pos = np.arange(8) 
ax.set_yticks(y_pos) 
ax.set_yticklabels(people) 
ax.set_xlabel('Distance') 

plt.show() 

die eine graphische Darstellung wie diese heterogeneous hbars, mit einer unterschiedlichen Anzahl von Segmenten, die in jeder Serie produziert.

Beachten Sie, dass dies nicht besonders effizient ist, da jedes Segment einen individuellen Anruf an ax.barh verwendet. Es kann effizientere Verfahren geben (z. B. durch Auffüllen einer Matrix mit Segmenten mit einer Breite von null oder Nan-Werten), aber dies ist wahrscheinlich problemspezifisch und eine eindeutige Frage.


Bearbeiten: aktualisiert, um beide Teile der Frage zu beantworten.

import numpy as np 
import matplotlib.pyplot as plt 

people = ('A','B','C','D','E','F','G','H') 
segments = 4 

# generate some multi-dimensional data & arbitrary labels 
data = 3 + 10* np.random.rand(segments, len(people)) 
percentages = (np.random.randint(5,20, (len(people), segments))) 
y_pos = np.arange(len(people)) 

fig = plt.figure(figsize=(10,8)) 
ax = fig.add_subplot(111) 

colors ='rgbwmc' 
patch_handles = [] 
left = np.zeros(len(people)) # left alignment of data starts at zero 
for i, d in enumerate(data): 
    patch_handles.append(ax.barh(y_pos, d, 
     color=colors[i%len(colors)], align='center', 
     left=left)) 
    # accumulate the left-hand offsets 
    left += d 

# go through all of the bar segments and annotate 
for j in xrange(len(patch_handles)): 
    for i, patch in enumerate(patch_handles[j].get_children()): 
     bl = patch.get_xy() 
     x = 0.5*patch.get_width() + bl[0] 
     y = 0.5*patch.get_height() + bl[1] 
     ax.text(x,y, "%d%%" % (percentages[i,j]), ha='center') 

ax.set_yticks(y_pos) 
ax.set_yticklabels(people) 
ax.set_xlabel('Distance') 

plt.show() 

Sie entlang dieser Linien ein Ergebnis erzielen können (Anmerkung: Die Prozentsätze Ich habe nichts mit den Strichbreiten zu tun verwendet, wie die Beziehung im Beispiel scheint unklar):

example output

Einige Ideen zum Stapeln von horizontalen Balkenparzellen finden Sie unter Horizontal stacked bar chart in Matplotlib.


+0

Sie auf eine Frage verknüpfen, die die Verwendung von 'left' zum Stapeln zeigt, aber dann tun Sie es nicht in Ihrer Antwort verwenden. – tacaswell

+0

@tcaswell wahr. Das OP hat wirklich zwei Fragen: 1) Erstellen eines gestapelten Balkendiagramms; und 2) Hinzufügen von Etiketten zu Abschnitten eines gestapelten Balkendiagramms. Ich habe gerade 2) beantwortet und mögliche Lösungen zu 1) verknüpft. – Bonlenfum

+0

aktualisierte Lösung, um beide Teile der Frage jetzt zu lösen. Danke für die Rückmeldung! – Bonlenfum