matplotlibでティックスケールを2の累乗として設定するにはどうすればよいですか?[複製]

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

これは特にトリックの質問です(私はそうなるとは思っていませんでした^^)。

OK、読むためのいくつかのヒントから始めましょう:x / yスケールを設定したい:.matplotlib.axes.Axes.set_yscale()。いくつかの標準スケールがありますが(デフォルトは明らか'liner'にですが、カスタムスケールを設定できます。ここにいくつかの良い例があります。

基本的に、変換とその変換を使用して2つの関数を定義します。その後、ティックを正しく設定する必要があります(プロットに変換を適用するため、ティックは同じままです(ただし、変換のために同じ位置にはありません)。これには2つのオプションがあります。

  • ティックを手動で設定する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()