This is a particularly trick question (which I did not expected to be ^^).
OK, let's start with a few hints for reading: You want to set the x/y scale: .matplotlib.axes.Axes.set_yscale(). While there are a couple of standard scales (the default is obviously 'liner'
, one can set a custom scale. Here are some nice examples.
Basically, you define two functions with the forward transformation and with the inverse of it.
Afterwards you need to set the ticks correctly (because you apply the transformation after plotting, the ticks remain the same (but not at the same position due to the transformation). One has two options for this:
- setting the ticks manually
matplotlib.axes.Axes.set_xticks()
, or
- by setting the locator of the axis:
matplotlib.axes.Axes.xaxis.set_major_locator()
. This is recommended if you use grids. But as my knowledge is limited, I appreciate a more detailed explanation (because now I am also curious about this feature ^^)
And now comes the tricky part: formatting the tick-labels to represent a '2^x'
. I didn't came across a better idea than setting them explicitly as strings. It seems that one can change the general format only within restricted limits, see matplotlib.pyplot.ticklabel_format()
, where one can choose if and when a scientific notation should be used (i.e. displaying a '10^x'
at the bottom right). Let me know if there is a more generic solution for this.
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()