¿Cómo establecer la escala de ticks como la potencia de 2 en matplotlib? [duplicar]

Dec 16 2020

Quiero trazar una figura cuyos valores de xtick crezcan a la potencia de 2.

Por ejemplo,

import pandas as pd
data = pd.DataFrame({
    'x': [2, 4, 8, 16, 32, 64],
    'y': [1, 2, 3, 4, 5, 6]
})

Lo que espero es una figura como esta,

Para datos ordenados como el ejemplo anterior, puedo crear una columna auxiliar x2de 1 ~ 6 en este marco de datos y luego establecer las xticklabels de la figura en 2 ^ 1 ~ 2 ^ 6. Sin embargo, esta solución alternativa no se aplica a situaciones con otros valores como 3, 7 o 30.

Parece que matplotlib solo admite una escala logarítmica. ¿Cómo puedo conseguir un tick con una escala de potencia de 2?

Respuestas

max Dec 16 2020 at 17:20

Esta es una pregunta particularmente engañosa (que no esperaba que fuera ^^).

Bien, comencemos con algunas sugerencias para la lectura: desea establecer la escala x / y: .matplotlib.axes.Axes.set_yscale () . Si bien hay un par de escalas estándar (la predeterminada es obviamente 'liner', se puede establecer una escala personalizada. Aquí hay algunos buenos ejemplos.

Básicamente, define dos funciones con la transformación hacia adelante y con la inversa . Luego, debe configurar los ticks correctamente (debido a que aplica la transformación después de trazar, los ticks permanecen iguales (pero no en la misma posición debido a la transformación). Uno tiene dos opciones para esto:

  • configurar las garrapatas manualmente matplotlib.axes.Axes.set_xticks(), o
  • estableciendo el localizador del eje: matplotlib.axes.Axes.xaxis.set_major_locator(). Esto se recomienda si usa cuadrículas. Pero como mi conocimiento es limitado, agradezco una explicación más detallada (porque ahora también tengo curiosidad por esta característica ^^)

Y ahora viene la parte complicada: formatear las etiquetas de verificación para representar a '2^x'. No encontré una mejor idea que establecerlos explícitamente como cadenas. Parece que se puede cambiar el formato general sólo dentro de límites restringidos, ver matplotlib.pyplot.ticklabel_format(), donde se puede elegir si se debe usar una notación científica y cuándo (es decir, mostrar una '10^x'en la parte inferior derecha). Avíseme si hay una solución más genérica para esto.

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