Formatta l'asse y come percentuale


114

Ho una trama esistente che è stata creata con i panda in questo modo:

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

L'asse y è formato come float e voglio cambiare l'asse y in percentuali. Tutte le soluzioni che ho trovato utilizzano la sintassi ax.xyz e posso solo posizionare il codice sotto la riga sopra che crea la trama (non posso aggiungere ax = ax alla riga sopra).

Come posso formattare l'asse y come percentuali senza modificare la linea sopra?

Ecco la soluzione che ho trovato ma richiede di ridefinire la trama :

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

Collegamento alla soluzione precedente: Pyplot: utilizzando la percentuale sull'asse x


Potresti cambiare la tua risposta accettata all'approccio implementato nativamente in matplotlib? stackoverflow.com/a/36319915/1840471
Max Ghenis

Risposte:


128

Questo è in ritardo di alcuni mesi, ma ho creato PR # 6251 con matplotlib per aggiungere una nuova PercentFormatterclasse. Con questa classe hai solo bisogno di una riga per riformattare il tuo asse (due se conti l'importazione di matplotlib.ticker):

import ...
import matplotlib.ticker as mtick

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

PercentFormatter()accetta tre argomenti, xmax, decimals, symbol. xmaxpermette di impostare il valore che corrisponde al 100% sull'asse. Questo è utile se hai dati da 0.0 a 1.0 e vuoi visualizzarli da 0% a 100%. Fallo e basta PercentFormatter(1.0).

Gli altri due parametri consentono di impostare il numero di cifre dopo il punto decimale e il simbolo. L'impostazione predefinita è Nonee '%', rispettivamente. decimals=Noneimposterà automaticamente il numero di punti decimali in base alla quantità di assi mostrati.

Aggiornare

PercentFormatter è stato introdotto in Matplotlib nella versione 2.1.0.


@MateenUlhaq Per favore, non introdurre modifiche significative al codice nelle tue modifiche. Hai replicato il codice nella mia risposta senza alcun bisogno. Non era una buona modifica.
Mad Physicist

Colpa mia, per qualche strana ragione, l'ho letto e ho from matplotlib.ticker import mtickpensato che il mtick"modulo" fosse stato rimosso.
Mateen Ulhaq

125

pandas dataframe plot restituirà il axper te, quindi puoi iniziare a manipolare gli assi come preferisci.

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

inserisci qui la descrizione dell'immagine


5
Ciò avrà effetti indesiderati non appena si
esegue una

3
Milioni di volte più facile che provare a utilizzare i matplotlib.tickerformattatori di funzioni!
Jarad

Come si limita quindi l'asse y a dire (0,100%)? Ho provato ax.set_ylim (0,100) ma non sembra funzionare !!
Verso il

@mpour vengono modificate solo le etichette degli ytick, quindi i limiti sono ancora in unità naturali. L'impostazione di ax.set_ylim (0, 1) farà il trucco.
Joeran

79

La soluzione di Jianxun ha funzionato per me, ma ha rotto l'indicatore del valore y in basso a sinistra nella finestra.

Ho finito per usare FuncFormatterinvece (e ho anche rimosso gli zeri finali non necessari come suggerito qui ):

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

In generale, ne consiglio l'utilizzo FuncFormatterper la formattazione dell'etichetta: è affidabile e versatile.

inserisci qui la descrizione dell'immagine


19
È possibile semplificare il codice ancora di più: ax.yaxis.set_major_formatter(FuncFormatter('{0:.0%}'.format)). AKA non c'è bisogno di lambda, lascia che il formato faccia il lavoro.
Daniel Himmelstein

@DanielHimmelstein puoi spiegarlo un po '? In particolare all'interno di {}. Non sono sicuro di come il mio 0,06 venga trasformato nel 6% usando quello con il formato python. Ottima anche la soluzione. Sembra funzionare in modo molto più affidabile rispetto all'utilizzo di .set_ticklabels
DC Forse il

3
@DChaps '{0:.0%}'.formatcrea una funzione di formattazione . La 0prima dei due punti indica al formattatore di sostituire le parentesi graffe e il suo contenuto con il primo argomento passato alla funzione. La parte dopo i due punti,, .0%indica al formattatore come eseguire il rendering del valore. La .0specifica 0 cifre decimali e %specifica di rendering come percentuale.
Daniel Himmelstein

31

Per coloro che cercano il one-liner veloce:

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

Oppure, se stai usando Latex come formattatore del testo dell'asse, devi aggiungere una barra rovesciata '\'

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

Per me, la risposta di Daniel Himmelstein ha funzionato mentre questa risposta ha cambiato la scala
R. Cox il

2

Propongo un metodo alternativo utilizzando seaborn

Codice di lavoro:

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)

inserisci qui la descrizione dell'immagine


0

Sono in ritardo per il gioco ma me ne rendo conto: axpuò essere sostituito con plt.gca()per coloro che non utilizzano assi e solo sottotrame.

Facendo eco alla risposta di @Mad Physicist, usando il pacchetto PercentFormattersarebbe:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.