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


¿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.


@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í


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í


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

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í


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.