I have data for which I would like to show two different scales. Matplotlib docs (such as this one) contain a few examples that twin either the x or y axes (not both), and none of these examples show how to manipulate the minor ticks of both x and y axes when log-scaled.
This is my question: how to format minor ticks on twin x and twin y axes, both of which are logarithmically scaled? In the example below, the conventional xy-axes are linearly-scaled (denoted by subscript i
), whereas the alternate/mirror/twin xy-axes are logarithmically scaled (denoted by subscript j
). The function twinboth
was borrowed from a similar question. Also, I am using LogLocator
instead of AutoMinorLocator
, as suggested in this post.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
## linear scale parameters
m, b = 0.5, np.pi
xi = np.arange(1, 11, 1).astype(int)
noisei = np.random.uniform(low=-0.5, high=0.5, size=xi.size)
yi = m * xi + b + noisei
## log scale parameters
xj = 2 ** xi
noisej = 2 ** noisei
yj = 2 ** yi
def twinboth(ax):
# Alternately, we could do `newax = ax._make_twin_axes(frameon=False)`
newax = ax.figure.add_subplot(ax.get_subplotspec(), frameon=False)
newax.xaxis.set(label_position='top')
newax.yaxis.set(label_position='right', offset_position='right')
newax.yaxis.get_label().set_rotation(-90) # Optional...
newax.yaxis.tick_right()
newax.xaxis.tick_top()
return newax
## initialize figure and linear axes
fig, axes = plt.subplots(nrows=2, ncols=2)
for axi in axes.ravel():
## plot linear
axi.scatter(xi, yi, color='r', alpha=0.5, label='linear')
axi.grid(color='k', alpha=0.3, linestyle=':')
## get twinned logarithmic axes
axj = twinboth(axi)
axj.set_xscale('log', basex=2)
axj.set_yscale('log', basey=2)
## whole number instead of sci-notation
axj.xaxis.set_major_formatter(ticker.ScalarFormatter())
axj.yaxis.set_major_formatter(ticker.ScalarFormatter())
## attempt log-scaled minor ticks on twin axes
axj.xaxis.set_minor_locator(ticker.LogLocator(base=2))
axj.yaxis.set_minor_locator(ticker.LogLocator(base=2))
axj.xaxis.set_minor_formatter(ticker.ScalarFormatter())
axj.yaxis.set_minor_formatter(ticker.ScalarFormatter())
## plot log-scale on twin axes
axj.scatter(xj, yj, color='b', alpha=0.5, label='log')
## get legend handles/labels from last iteration of for-loop above (avoid duplicates)
handlesi, labelsi = axi.get_legend_handles_labels()
handlesj, labelsj = axj.get_legend_handles_labels()
handles = handlesi + handlesj
labels = labelsi + labelsj
fig.subplots_adjust(bottom=0.2, wspace=0.3, hspace=0.3)
fig.legend(handles=handles, labels=labels, loc='lower center', mode='expand', ncol=2)
plt.show()
plt.close(fig)
This code generates the figure below, which shows NO minor ticks.
Your minor ticks are hidden by your major ticks.
axj.set_xscale('log', basex=2)
axj.set_yscale('log', basey=2)
Set scales of your "twin axes" to logarithm, and so with logarithm major ticks (4, 16, 64, 256, 1024
).
axj.xaxis.set_minor_locator(ticker.LogLocator(base=2))
axj.yaxis.set_minor_locator(ticker.LogLocator(base=2))
This, add minor ticks on logarithm locations which will be 4, 16, 64, 256, 1024
; the same that your major ticks.
What you want to do is either:
axi.xaxis.set_minor_locator(ticker.LogLocator(base=2))
axi.yaxis.set_minor_locator(ticker.LogLocator(base=2))
Adding minor logarithm ticks to your linear axis, or:
axj.xaxis.set_minor_locator(ticker.LinearLocator())
axj.yaxis.set_minor_locator(ticker.LinearLocator())
Adding minor linear ticks to your logarithm axis.