Dar formato al eje y como porcentaje

114

Tengo una trama existente que se creó con pandas como este:

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

El eje y tiene el formato flotante y quiero cambiar el eje y a porcentajes. Todas las soluciones que encontré usan la sintaxis ax.xyz y solo puedo colocar el código debajo de la línea de arriba que crea el gráfico (no puedo agregar ax = ax a la línea de arriba).

¿Cómo puedo formatear el eje y como porcentajes sin cambiar la línea de arriba?

Aquí está la solución que encontré pero requiere que redefina 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()

Enlace a la solución anterior: Pyplot: usando porcentaje en el eje x

Chris
fuente
¿Podría cambiar su respuesta aceptada al enfoque implementado de forma nativa en matplotlib? stackoverflow.com/a/36319915/1840471
Max Ghenis

Respuestas:

128

Esto es unos meses tarde, pero he creado PR # 6251 con matplotlib para agregar una nueva PercentFormatterclase. Con esta clase, solo necesita una línea para reformatear su eje (dos si cuenta la importación de matplotlib.ticker):

import ...
import matplotlib.ticker as mtick

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

PercentFormatter()acepta tres argumentos, xmax, decimals, symbol. xmaxle permite establecer el valor que corresponde al 100% en el eje. Esto es bueno si tiene datos de 0.0 a 1.0 y desea mostrarlos de 0% a 100%. Solo hazlo PercentFormatter(1.0).

Los otros dos parámetros le permiten establecer el número de dígitos después del punto decimal y el símbolo. Por defecto son Noney '%', respectivamente. decimals=Noneestablecerá automáticamente el número de puntos decimales en función de la cantidad de ejes que esté mostrando.

Actualizar

PercentFormatter se introdujo en Matplotlib propiamente dicho en la versión 2.1.0.

Físico loco
fuente
@MateenUlhaq Por favor, no introduzca modificaciones de código significativas en sus ediciones. Replicó el código en mi respuesta sin ninguna necesidad. No fue una buena edición.
Mad Physicist
Mi mal, por alguna extraña razón, leí eso from matplotlib.ticker import mticky asumí que el mtick"módulo" fue eliminado.
Mateen Ulhaq
125

pandas dataframe plot devolverá el axpor usted, y luego puede comenzar a manipular los ejes lo que quiera.

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

ingrese la descripción de la imagen aquí

Jianxun Li
fuente
5
Esto tendrá efectos no deseados tan pronto como
desplace
3
¡Millones de veces más fácil que intentar usar matplotlib.tickerformateadores de funciones!
Jarad
¿Cómo se limita entonces el eje y para decir (0,100%)? ¡Probé ax.set_ylim (0,100) pero eso no parece funcionar!
mpour
@mpour solo se cambian las etiquetas de los yticks, por lo que los límites todavía están en unidades naturales. Configurar ax.set_ylim (0, 1) hará el truco.
Joeran
79

La solución de Jianxun hizo el trabajo por mí, pero rompió el indicador de valor y en la parte inferior izquierda de la ventana.

Terminé usando en su FuncFormatterlugar (y también eliminé los ceros finales innecesarios como se sugiere aquí ):

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

En términos generales, recomendaría usarlo FuncFormatterpara formatear etiquetas: es confiable y versátil.

ingrese la descripción de la imagen aquí

erwanp
fuente
19
Se puede simplificar el código aún más: ax.yaxis.set_major_formatter(FuncFormatter('{0:.0%}'.format)). AKA no es necesario el lambda, deje que el formato haga el trabajo.
Daniel Himmelstein
@DanielHimmelstein, ¿puedes explicar esto un poco? Particularmente dentro del {}. No estoy seguro de cómo mi 0.06 se convierte en 6% usando eso con el formato Python. También es una gran solución. Parece funcionar de manera mucho más confiable que usar .set_ticklabels
DChaps
3
@DChaps '{0:.0%}'.formatcrea una función de formateo . El 0antes de los dos puntos le dice al formateador que reemplace las llaves y su contenido con el primer argumento pasado a la función. La parte que sigue a los dos puntos, .0%indica al formateador cómo representar el valor. El .0especifica 0 lugares decimales y %especifica la representación como porcentaje.
Daniel Himmelstein
31

Para aquellos que buscan una frase rápida:

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

O si está utilizando Latex como formateador de texto del eje, debe agregar una barra invertida '\'

plt.gca().set_yticklabels(['{:.0f}\%'.format(x*100) for x in plt.gca().get_yticks()]) 
np8
fuente
Para mí, la respuesta de Daniel Himmelstein funcionó, mientras que esta respuesta cambió la escala
R. Cox
2

Propongo un método alternativo usando seaborn

Código de trabajo:

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)

ingrese la descripción de la imagen aquí

Dr. Arslan
fuente
0

Llego tarde al juego, pero me doy cuenta de esto: axse puede reemplazar con plt.gca()para aquellos que no están usando ejes y solo subtramas.

Haciendo eco de la respuesta de @Mad Physicist, usando el paquete PercentFormattersería:

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
Gato mai
fuente