stapeln Sie Balkendiagramm in Matplotlib und fügen Sie jedem Abschnitt eine Beschriftung hinzu

Lesezeit: 8 Minuten

stapeln Sie Balkendiagramm in Matplotlib und fugen Sie jedem Abschnitt
Griff

Ich versuche, das folgende Bild in Matplotlib zu replizieren, und es scheint barh ist meine einzige Möglichkeit. Obwohl es scheint, dass Sie nicht stapeln können barh Diagramme, also weiß ich nicht, was ich tun soll

Geben Sie hier die Bildbeschreibung ein

Wenn Sie eine bessere Python-Bibliothek kennen, um so etwas zu zeichnen, lassen Sie es mich bitte wissen.

Das ist alles, was mir als Anfang einfallen würde:

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 müsste dann Labels einzeln mit hinzufügen ax.text was langweilig wäre. Idealerweise möchte ich nur die Breite des einzufügenden Teils angeben, dann wird die Mitte dieses Abschnitts mit einer Zeichenfolge meiner Wahl aktualisiert. Die Beschriftungen auf der Außenseite (z. B. 3800) kann ich später selbst hinzufügen, es ist hauptsächlich die Beschriftung über dem Balkenabschnitt selbst und das Erstellen dieser Stapelmethode auf eine schöne Weise, mit der ich Probleme habe. Können Sie überhaupt einen „Abstand“, dh eine Farbspanne, angeben?

Geben Sie hier die Bildbeschreibung ein

1644106026 700 stapeln Sie Balkendiagramm in Matplotlib und fugen Sie jedem Abschnitt
Bonnenfum

Bearbeiten 2: für heterogenere Daten. (Ich habe die obige Methode verlassen, da ich es üblicher finde, mit der gleichen Anzahl von Datensätzen pro Serie zu arbeiten.)

Beantwortung der beiden Teile der Frage:

ein) barh gibt einen Container mit Handles für alle gezeichneten Patches zurück. Sie können die Koordinaten der Patches verwenden, um die Textpositionen zu unterstützen.

b) Nach diesen beiden Antworten auf die Frage, die ich zuvor notiert habe (siehe Horizontal gestapeltes Balkendiagramm in Matplotlib), können Sie Balkendiagramme horizontal stapeln, indem Sie den ‘linken’ Eingang setzen.

und zusätzlich c) Handhabung von Daten, die eine weniger einheitliche Form haben.

Im Folgenden finden Sie eine Möglichkeit, mit weniger einheitlichen Daten umzugehen, indem Sie einfach jedes Segment einzeln 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 (xrange in py2.7, range for py3)
labels = range(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()

Was eine solche Grafik erzeugt heterogene hbarswobei in jeder Serie eine unterschiedliche Anzahl von Segmenten vorhanden ist.

Beachten Sie, dass dies nicht besonders effizient ist, da jedes Segment einen individuellen Anruf verwendet ax.barh. Möglicherweise gibt es effizientere Methoden (z. B. durch Auffüllen einer Matrix mit Segmenten mit einer Breite von Null oder Nan-Werten), aber dies ist wahrscheinlich problemspezifisch und eine andere 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 range(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 können ein Ergebnis in dieser Richtung erzielen (Anmerkung: Die Prozentangaben, die ich verwendet habe, haben nichts mit den Balkenbreiten zu tun, da das Verhältnis im Beispiel unklar erscheint):

Beispielausgabe

Siehe Horizontal gestapeltes Balkendiagramm in Matplotlib für einige Ideen zum Stapeln von horizontalen Balkendiagrammen.


stapeln Sie Balkendiagramm in Matplotlib und fugen Sie jedem Abschnitt
Trenton McKinney

Importiert und testet DataFrame

import pandas as pd
import numpy as np

# create sample data as shown in the OP
np.random.seed(365)
people = ('A','B','C','D','E','F','G','H')
bottomdata = 3 + 10 * np.random.rand(len(people))
topdata = 3 + 10 * np.random.rand(len(people))

# create the dataframe
df = pd.DataFrame({'Female': bottomdata, 'Male': topdata}, index=people)

# display(df)
   Female   Male
A   12.41   7.42
B    9.42   4.10
C    9.85   7.38
D    8.89  10.53
E    8.44   5.92
F    6.68  11.86
G   10.67  12.97
H    6.05   7.87

Aktualisiert mit matplotlib v3.4.2

ax = df.plot(kind='barh', stacked=True, figsize=(8, 6))

for c in ax.containers:
    
    # customize the label to account for cases when there might not be a bar section
    labels = [f'{w:.2f}%' if (w := v.get_width()) > 0 else '' for v in c ]
    
    # set the bar label
    ax.bar_label(c, labels=labels, label_type="center")

    # uncomment and use the next line if there are no nan or 0 length sections; just use fmt to add a % (the previous two lines of code are not needed, in this case)
#     ax.bar_label(c, fmt="%.2f%%", label_type="center")

# move the legend
ax.legend(bbox_to_anchor=(1.025, 1), loc="upper left", borderaxespad=0.)

# add labels
ax.set_ylabel("People", fontsize=18)
ax.set_xlabel("Percent", fontsize=18)
plt.show()
  • Die Diagramme entsprechen den unten gezeigten.

Anmerkungsressourcen – von matplotlib v3.4.2

  • Hinzufügen von Wertbeschriftungen zu einem Matplotlib-Balkendiagramm
  • So kommentieren Sie jedes Segment eines gestapelten Balkendiagramms
  • Gestapeltes Balkendiagramm mit zentrierten Beschriftungen
  • So zeichnen und kommentieren Sie mehrere Datenspalten in einem Seaborn-Balkendiagramm
  • So kommentieren Sie ein seegeborenes Balkendiagramm mit dem aggregierten Wert
  • So fügen Sie einem Balkendiagramm mehrere Anmerkungen hinzu
  • So zeichnen und kommentieren Sie ein gruppiertes Balkendiagramm

Ursprüngliche Antwort – vorher matplotlib v3.4.2

  • Der einfachste Weg, einen horizontal oder vertikal gestapelten Balken zu zeichnen, besteht darin, die Daten in a zu laden pandas.DataFrame
    • Dadurch wird korrekt geplottet und kommentiert, selbst wenn alle Kategorien ('People'), haben nicht alle Segmente (z. B. ist ein Wert 0 oder NaN)
  • Sobald sich die Daten im Datenrahmen befinden:
    1. Es ist einfacher zu manipulieren und zu analysieren
    2. Es kann mit geplottet werden matplotlib Motor, mit:
  • Diese Methoden geben a zurück matplotlib.axes.Axes oder ein numpy.ndarray von ihnen.
  • Verwendung der .patches Methode entpackt eine Liste von matplotlib.patches.Rectangle Objekte, eines für jeden Abschnitt der gestapelten Leiste.
    • Jeder .Rectangle verfügt über Methoden zum Extrahieren der verschiedenen Werte, die das Rechteck definieren.
    • Jeder .Rectangle ist in der reihenfolge von links nach rechts und von unten nach oben, also alle .Rectangle Objekte für jede Ebene erscheinen beim Durchlaufen der Reihe nach .patches.
  • Die Etiketten werden mit einem erstellt f-Saite, label_text = f'{width:.2f}%'sodass bei Bedarf zusätzlicher Text hinzugefügt werden kann.

Zeichnen und kommentieren

  • Das Zeichnen des Balkens ist 1 Linie, der Rest ist das Kommentieren der Rechtecke
# plot the dataframe with 1 line
ax = df.plot.barh(stacked=True, figsize=(8, 6))

# .patches is everything inside of the chart
for rect in ax.patches:
    # Find where everything is located
    height = rect.get_height()
    width = rect.get_width()
    x = rect.get_x()
    y = rect.get_y()
    
    # The height of the bar is the data value and can be used as the label
    label_text = f'{width:.2f}%'  # f'{width:.2f}' to format decimal values
    
    # ax.text(x, y, text)
    label_x = x + width / 2
    label_y = y + height / 2
    
    # only plot labels greater than given width
    if width > 0:
        ax.text(label_x, label_y, label_text, ha="center", va="center", fontsize=8)

# move the legend
ax.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0.)

# add labels
ax.set_ylabel("People", fontsize=18)
ax.set_xlabel("Percent", fontsize=18)
plt.show()

Geben Sie hier die Bildbeschreibung ein

Beispiel mit fehlendem Segment

# set one of the dataframe values to 0
df.iloc[4, 1] = 0
  • Beachten Sie, dass sich die Anmerkungen alle an der richtigen Stelle befinden df.

Geben Sie hier die Bildbeschreibung ein

.

789830cookie-checkstapeln Sie Balkendiagramm in Matplotlib und fügen Sie jedem Abschnitt eine Beschriftung hinzu

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy