Как установить шкалу тика как степень 2 в matplotlib? [дубликат]

Dec 16 2020

Я хочу построить фигуру, значения xtick которой растут со степенью 2.

Например,

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

Я ожидаю такой фигуры,

Для аккуратных данных, подобных приведенному выше образцу, я могу просто создать вспомогательный столбец x2размером 1 ~ 6 в этом фрейме данных, а затем установить xticklabels рисунка на 2 ^ 1 ~ 2 ^ 6. Однако этот обходной путь не применяется к ситуациям с другими значениями, такими как 3, 7 или 30.

Кажется, что matplotlib поддерживает только шкалу журнала. Как добиться отметки со шкалой мощности 2?

Ответы

max Dec 16 2020 at 17:20

Это особенно сложный вопрос (которого я не ожидал ^^).

Хорошо, давайте начнем с нескольких советов для чтения: вы хотите установить масштаб x / y: .matplotlib.axes.Axes.set_yscale () . Хотя есть несколько стандартных масштабов (очевидно 'liner', по умолчанию , можно установить собственный масштаб. Вот несколько хороших примеров.

По сути, вы определяете две функции с прямым преобразованием и с обратным ему. После этого вам необходимо правильно установить метки (поскольку вы применяете преобразование после построения графика, метки остаются прежними (но не в том же положении из-за преобразования). Для этого есть два варианта:

  • установка галочки вручную matplotlib.axes.Axes.set_xticks(), или
  • установив локатор оси: matplotlib.axes.Axes.xaxis.set_major_locator(). Это рекомендуется, если вы используете сетки. Но поскольку мои знания ограничены, я ценю более подробное объяснение (потому что теперь мне также интересно узнать об этой функции ^^)

А теперь самое сложное: форматирование меток для представления файла '2^x'. Я не нашел лучшей идеи, чем явно задавать их как строки. Кажется, что можно изменить общий формат только в ограниченных пределах, см. matplotlib.pyplot.ticklabel_format(), Где можно выбрать, следует ли и когда использовать научную нотацию (например, отображение символа '10^x'в правом нижнем углу). Сообщите мне, есть ли для этого более общее решение.

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