Como definir a escala de escala como a potência de 2 em matplotlib? [duplicado]
Quero traçar uma figura cujos valores de xtick crescem na potência de 2.
Por exemplo,
import pandas as pd
data = pd.DataFrame({
'x': [2, 4, 8, 16, 32, 64],
'y': [1, 2, 3, 4, 5, 6]
})
O que eu espero é uma figura como esta,
Para dados organizados como o exemplo acima, posso apenas criar uma coluna auxiliar x2de 1 ~ 6 neste dataframe e definir os xticklabels da figura como 2 ^ 1 ~ 2 ^ 6. No entanto, esta solução alternativa não se aplica a situações com outros valores como 3, 7 ou 30.
Parece que matplotlib suporta apenas uma escala logarítmica. Como posso atingir um tique com uma escala de potência de 2?
Respostas
Esta é uma pergunta particularmente capciosa (que eu não esperava que fosse ^^).
OK, vamos começar com algumas dicas para leitura: Você deseja definir a escala x / y: .matplotlib.axes.Axes.set_yscale () . Embora existam algumas escalas padrão (o padrão é obviamente 'liner', pode-se definir uma escala personalizada. Aqui estão alguns bons exemplos.
Basicamente, você define duas funções com a transformação direta e com o inverso dela. Depois, você precisa definir os ticks corretamente (porque você aplica a transformação após a plotagem, os ticks permanecem os mesmos (mas não na mesma posição devido à transformação). Um tem duas opções para isso:
- definir os carrapatos manualmente
matplotlib.axes.Axes.set_xticks(), ou - definindo o localizador do eixo:
matplotlib.axes.Axes.xaxis.set_major_locator(). Isso é recomendado se você usar grades. Mas como meu conhecimento é limitado, agradeço uma explicação mais detalhada (porque agora também estou curioso sobre este recurso ^^)
E agora vem a parte complicada: formatar os rótulos de escala para representar um '2^x'. Não tive uma ideia melhor do que defini-los explicitamente como strings. Parece que só se pode mudar o formato geral dentro de limites restritos, veja matplotlib.pyplot.ticklabel_format(), onde se pode escolher se e quando uma notação científica deve ser usada (ou seja, exibindo um '10^x'no canto inferior direito). Deixe-me saber se existe uma solução mais genérica para isso.
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.ticker import FixedLocator
# create dummy data
df = pd.DataFrame({
'x': [2**x for x in range(1,10)],
'y': list(range(1,10))
})
def forward(x):
return np.log2(x)
def inverse(x):
return 2**x
# open figure
fig, ax = plt.subplots(2,2)
axs = ax.flatten()
for i in range(0,4):
# plot data
axs[i].plot(df['x'],df['y'])
if i > 0:
# set scale function
axs[i].set_xscale('function', functions=(forward,inverse))
if i > 1:
# set ticks
# - OPTION 1
axs[i].set_xticks(df['x'])
# - OPTION 2
axs[i].xaxis.set_major_locator(FixedLocator(2**np.arange(1,10)))
if i > 2:
# est tick labels
axs[i].set_xticklabels( [f"2^{j:.0f}" for j in np.log2(df['x'])] )
plt.show()