TL'DR, les diagrammes à barres verticales sont représentés de manière conventionnelle - les éléments sont alignés de gauche à droite. Toutefois, lorsqu’il est converti en histogramme horizontal (de bar
à barh
), tout est inversé. En d'autres termes, pour un diagramme à barres groupées, non seulement l'ordre des barres est erroné, mais l'ordre de chaque groupe est également incorrect.
Par exemple, le graphique de http://dwheelerau.com/2014/05/28/pandas-data-analysis-new-zealanders-and-their-sheep/
Si vous regardez de plus près, vous constaterez que la barre et la légende sont dans l'ordre inverse. Beef apparaît en haut de la légende mais en bas du graphique.
Comme démonstration la plus simple, j'ai changé kind='bar',
en kind='barh',
De ce graphique https://plot.ly/pandas/bar-charts/#pandas-grouped-bar-chart } _ et le résultat ressemble à ceci: https://plot.ly/7/~xpt/
C'est-à-dire que les barres du graphique à barres groupées horizontales sont ordonnées à l'envers.
Comment le réparer?
EDIT: @Ajean, en fait, non seulement l'ordre des barres groupées est incorrect, mais l'ordre de chaque groupe est également incorrect. Le graphique de Personnalisation simple du diagramme à barres matplotlib/pandas (étiquettes, ticks, etc.) } le montre clairement:
Nous pouvons voir que l'ordre est également non conventionnel, car les gens s'attendent à ce que le graphique soit top-down, avec "AAA" en haut, pas en bas.
Si vous recherchez "Excel à l'envers", vous constaterez que les gens se plaignent à ce sujet dans Excel un peu partout. Microsoft Excel a un correctif, est-ce que Matplotlib/Panda/Searborn/Ploty/etc a un correctif?
Je crois que le mauvais ordre conjoint des groupes et des sous-groupes se résume à une seule caractéristique: que l’axe y
augmente vers le haut, comme dans un graphique ordinaire. Essayez d’inverser l’axe y
de vos axes comme dans cet exemple sans pandas:
import numpy as np
import matplotlib.pyplot as plt
x=range(5)
y=np.random.randn(5)
#plot1: bar
plt.figure()
plt.bar(x,y)
#plot2: barh, wrong order
plt.figure()
plt.barh(x,y)
#plot3: barh with correct order: top-down y axis
plt.figure()
plt.barh(x,y)
plt.gca().invert_yaxis()
Je crois que la solution la plus simple à ce problème consiste à inverser le cadre de données des pandas avant de tracer. Par exemple:
df = df.iloc[::-1]
df.plot.barh(stacked=True);
A mon avis, c'est un bug dans la fonction des Pandas Barh. Au moins, les utilisateurs devraient pouvoir passer un argument tel que reverse_order = True, etc.
Je considérerai cela comme un bogue, c’est-à-dire que la position y des barres n’est pas affectée correctement. Le patch est cependant relativement simple:
Ceci est seulement un bon ordre de barres, et cela s'appelle ..., le bon ordre. Tout ce qui n'est pas dans le bon ordre est donc un ordre de buggy. : p
In [63]:
print df
Total_beef_cattle Total_dairy_cattle Total_sheep Total_deer \
1994 0.000000 0.000000 0.000000 0.000000
2002 -11.025827 34.444950 -20.002034 33.858009
2003 -8.344764 32.882482 -20.041908 37.229441
2004 -11.895128 34.207998 -20.609926 42.707754
2005 -12.366101 32.506699 -19.379727 38.499840
Total_pigs Total_horses
1994 0.000000 0.000000
2002 -19.100637 11.811093
2003 -10.766476 18.504488
2004 -8.072078 13.376472
2005 -19.230733 -100.000000
In [64]:
ax = df.plot(kind='barh', sort_columns=True)
#Get the actual bars
bars = [item for item in ax.get_children() if isinstance(item, matplotlib.patches.Rectangle)]
bars = bars[:df.size]
#Reset the y positions for each bar
bars_y = [plt.getp(item, 'y') for item in bars]
for B, Y in Zip(bars, np.flipud(np.array(bars_y).reshape(df.shape[::-1])).ravel()):
B.set_y(Y)
La solution générale est simple:
handles, labels = axis.get_legend_handles_labels()
# reverse to keep order consistent
axis.legend(reversed(handles), reversed(labels), loc='upper left')