Formatar o eixo y como porcentagem

114

Tenho um enredo criado com pandas assim:

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

O eixo y está formatado como flutuante e quero alterar o eixo y para porcentagens. Todas as soluções que encontrei usam a sintaxe ax.xyz e só posso colocar o código abaixo da linha acima que cria o gráfico (não posso adicionar ax = ax à linha acima).

Como posso formatar o eixo y como porcentagens sem alterar a linha acima?

Aqui está a solução que encontrei, mas requer que eu redefina o gráfico :

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

Link para a solução acima: Pyplot: usando porcentagem no eixo x

Chris
fonte
Você poderia mudar sua resposta aceita para a abordagem implementada nativamente no matplotlib? stackoverflow.com/a/36319915/1840471
Max Ghenis

Respostas:

128

Isso está alguns meses atrasado, mas criei PR # 6251 com matplotlib para adicionar uma nova PercentFormatterclasse. Com esta classe, você só precisa de uma linha para reformatar seu eixo (duas se você contar a importação de matplotlib.ticker):

import ...
import matplotlib.ticker as mtick

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

PercentFormatter()aceita três argumentos, xmax, decimals, symbol. xmaxpermite que você defina o valor que corresponde a 100% no eixo. Isso é bom se você tiver dados de 0,0 a 1,0 e quiser exibi-los de 0% a 100%. Apenas faça PercentFormatter(1.0).

Os outros dois parâmetros permitem definir o número de dígitos após o ponto decimal e o símbolo. O padrão é Nonee '%', respectivamente. decimals=Noneirá definir automaticamente o número de casas decimais com base em quantos eixos você está mostrando.

Atualizar

PercentFormatter foi introduzido no Matplotlib na versão 2.1.0.

Físico Louco
fonte
@MateenUlhaq Por favor, não introduza modificações significativas no código em suas edições. Você replicou o código em minha resposta sem necessidade. Não foi uma boa edição.
Mad Physicist
Que pena, por algum motivo estranho, li isso como from matplotlib.ticker import mticke assumi que o mtick"módulo" foi removido.
Mateen Ulhaq
124

O gráfico do dataframe do pandas retornará o axpara você, e então você pode começar a manipular os eixos como quiser.

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

insira a descrição da imagem aqui

Jianxun Li
fonte
5
Isso terá efeitos indesejados assim que você
aplicar
3
Milhões de vezes mais fácil do que tentar usar matplotlib.tickerformatadores de função!
Jarad de
Como você limita o eixo y para dizer (0,100%)? Eu tentei ax.set_ylim (0,100) mas não parece funcionar !!
mpour de
@mpour apenas os rótulos dos yticks são alterados, então os limites ainda estão em unidades naturais. Definir ax.set_ylim (0, 1) resolverá o problema.
Joeran,
79

A solução de Jianxun funcionou para mim, mas quebrou o indicador de valor y no canto inferior esquerdo da janela.

Acabei usando em FuncFormattervez disso (e também retirei os zeros à direita desnecessários, conforme sugerido aqui ):

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 modo geral, eu recomendo usar FuncFormatterpara formatação de etiqueta: é confiável e versátil.

insira a descrição da imagem aqui

Erwanp
fonte
18
Você pode simplificar o código ainda mais: ax.yaxis.set_major_formatter(FuncFormatter('{0:.0%}'.format)). Também conhecido como, não há necessidade de lambda, deixe o formato fazer o trabalho.
Daniel Himmelstein
@DanielHimmelstein você pode explicar isso um pouco? Particularmente dentro do {}. Não sei como meu 0,06 foi transformado em 6% usando isso com o formato python. Também é uma ótima solução. Parece funcionar de maneira muito mais confiável do que usar .set_ticklabels
DChaps de
3
@DChaps '{0:.0%}'.formatcria uma função de formatação . O 0antes dos dois pontos informa ao formatador para substituir as chaves e seu conteúdo pelo primeiro argumento passado para a função. A parte após os dois pontos,, .0%informa ao formatador como renderizar o valor. O .0especifica 0 casas decimais e %especifica a renderização como uma porcentagem.
Daniel Himmelstein de
31

Para aqueles que procuram uma linha rápida:

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

Ou se você estiver usando Latex como o formatador de texto do eixo, você deve adicionar uma barra invertida '\'

plt.gca().set_yticklabels(['{:.0f}\%'.format(x*100) for x in plt.gca().get_yticks()]) 
np8
fonte
Para mim, a resposta de Daniel Himmelstein funcionou, enquanto essa resposta mudou a escala
R. Cox
2

Eu proponho um método alternativo usando seaborn

Código de trabalho:

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)

insira a descrição da imagem aqui

Dr. Arslan
fonte
0

Estou atrasado para o jogo, mas acabei de perceber isso: axpode ser substituído plt.gca()por aqueles que não estão usando eixos e apenas subtramas.

Ecoando a resposta do @Mad Physicist, usando o pacote PercentFormatterseria:

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
Cat Mai
fonte