Mettre en forme l'axe y en pourcentage

114

J'ai un complot existant qui a été créé avec des pandas comme celui-ci:

df['myvar'].plot(kind='bar')

L'axe y est au format flottant et je veux changer l'axe y en pourcentages. Toutes les solutions que j'ai trouvées utilisent la syntaxe ax.xyz et je ne peux placer du code que sous la ligne ci-dessus qui crée le tracé (je ne peux pas ajouter ax = ax à la ligne ci-dessus.)

Comment puis-je formater l'axe des y sous forme de pourcentages sans changer la ligne ci-dessus?

Voici la solution que j'ai trouvée mais nécessite que je redéfinisse l'intrigue :

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mtick

data = [8,12,15,17,18,18.5]
perc = np.linspace(0,100,len(data))

fig = plt.figure(1, (7,4))
ax = fig.add_subplot(1,1,1)

ax.plot(perc, data)

fmt = '%.0f%%' # Format you want the ticks, e.g. '40%'
xticks = mtick.FormatStrFormatter(fmt)
ax.xaxis.set_major_formatter(xticks)

plt.show()

Lien vers la solution ci-dessus: Pyplot: utilisation du pourcentage sur l'axe des x

Chris
la source
Pourriez-vous s'il vous plaît changer votre réponse acceptée à l'approche implémentée nativement dans matplotlib? stackoverflow.com/a/36319915/1840471
Max Ghenis

Réponses:

128

C'est quelques mois de retard, mais j'ai créé PR # 6251 avec matplotlib pour ajouter une nouvelle PercentFormatterclasse. Avec cette classe, vous n'avez besoin que d'une ligne pour reformater votre axe (deux si vous comptez l'importation de matplotlib.ticker):

import ...
import matplotlib.ticker as mtick

ax = df['myvar'].plot(kind='bar')
ax.yaxis.set_major_formatter(mtick.PercentFormatter())

PercentFormatter()accepte trois arguments, xmax, decimals, symbol. xmaxvous permet de définir la valeur qui correspond à 100% sur l'axe. C'est bien si vous avez des données de 0,0 à 1,0 et que vous souhaitez les afficher de 0% à 100%. Fais juste PercentFormatter(1.0).

Les deux autres paramètres vous permettent de définir le nombre de chiffres après la virgule décimale et le symbole. Ils sont respectivement par défaut Noneet '%'. decimals=Nonedéfinit automatiquement le nombre de points décimaux en fonction de la quantité d'axes que vous affichez.

Mettre à jour

PercentFormatter a été introduit dans Matplotlib proprement dit dans la version 2.1.0.

Physicien fou
la source
@MateenUlhaq Veuillez ne pas introduire de modifications de code significatives dans vos modifications. Vous avez répliqué le code dans ma réponse sans aucun besoin. Ce n'était pas un bon montage.
Mad Physicist
Mon mauvais, pour une raison étrange, j'ai lu cela comme from matplotlib.ticker import mticket supposé que le mtick"module" était supprimé.
Mateen Ulhaq le
125

pandas dataframe plot renverra le axpour vous, et vous pourrez alors commencer à manipuler les axes comme vous le souhaitez.

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(100,5))

# you get ax from here
ax = df.plot()
type(ax)  # matplotlib.axes._subplots.AxesSubplot

# manipulate
vals = ax.get_yticks()
ax.set_yticklabels(['{:,.2%}'.format(x) for x in vals])

entrez la description de l'image ici

Jianxun Li
la source
5
Cela aura des effets indésirables dès que vous effectuez un panoramique / zoom sur le graphique de manière interactive
hitzg
3
Des millions de fois plus facile que d'essayer d'utiliser matplotlib.tickerdes formateurs de fonctions!
Jarad
Comment limitez-vous alors l'axe des y pour dire (0,100%)? J'ai essayé ax.set_ylim (0,100) mais cela ne semble pas fonctionner !!
mpour
@mpour seuls les libellés des yticks sont modifiés, les limites sont donc toujours en unités naturelles. Définir ax.set_ylim (0, 1) fera l'affaire.
Joeran
79

La solution de Jianxun a fait le travail pour moi mais a cassé l'indicateur de valeur y en bas à gauche de la fenêtre.

J'ai fini par utiliser à la FuncFormatterplace (et j'ai également supprimé les zéros de fin non nécessaires comme suggéré ici ):

import pandas as pd
import numpy as np
from matplotlib.ticker import FuncFormatter

df = pd.DataFrame(np.random.randn(100,5))

ax = df.plot()
ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y))) 

De manière générale, je recommanderais d'utiliser FuncFormatterpour le formatage des étiquettes: c'est fiable et polyvalent.

entrez la description de l'image ici

Erwanp
la source
19
Vous pouvez simplifier le code encore plus: ax.yaxis.set_major_formatter(FuncFormatter('{0:.0%}'.format)). AKA pas besoin de lambda, laissez le format faire le travail.
Daniel Himmelstein
@DanielHimmelstein pouvez-vous expliquer cela un peu? Particulièrement à l'intérieur du {}. Je ne sais pas comment mon 0,06 est transformé en 6% en utilisant cela avec le format python. Aussi une excellente solution. Semble fonctionner de manière beaucoup plus fiable que l'utilisation de .set_ticklabels
DChaps
3
@DChaps '{0:.0%}'.formatcrée une fonction de formatage . Le 0signe avant les deux points indique au formateur de remplacer les accolades et son contenu par le premier argument passé à la fonction. La partie après les deux points,, .0%indique au formateur comment rendre la valeur. Le .0spécifie 0 décimale et %spécifie le rendu en pourcentage.
Daniel Himmelstein
31

Pour ceux qui recherchent le one-liner rapide:

plt.gca().set_yticklabels(['{:.0f}%'.format(x*100) for x in plt.gca().get_yticks()]) 

Ou si vous utilisez Latex comme formateur de texte d'axe, vous devez ajouter une barre oblique inverse '\'

plt.gca().set_yticklabels(['{:.0f}\%'.format(x*100) for x in plt.gca().get_yticks()]) 
np8
la source
Pour moi, la réponse de Daniel Himmelstein a fonctionné alors que cette réponse a changé l'échelle
R. Cox
2

Je propose une méthode alternative utilisant seaborn

Code de travail:

import pandas as pd
import seaborn as sns
data=np.random.rand(10,2)*100
df = pd.DataFrame(data, columns=['A', 'B'])
ax= sns.lineplot(data=df, markers= True)
ax.set(xlabel='xlabel', ylabel='ylabel', title='title')
#changing ylables ticks
y_value=['{:,.2f}'.format(x) + '%' for x in ax.get_yticks()]
ax.set_yticklabels(y_value)

entrez la description de l'image ici

Dr Arslan
la source
0

Je suis en retard dans le jeu mais je me rends juste compte de ceci: axpeut être remplacé par plt.gca()pour ceux qui n'utilisent pas d'axes et juste des sous-intrigues.

En écho à la réponse de @Mad Physicist, en utilisant le package, PercentFormatterce serait:

import matplotlib.ticker as mtick

plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter(1))
#if you already have ticks in the 0 to 1 range. Otherwise see their answer
Chat Mai
la source