Description
Problem
As of matplotlib 3.7.1, matplotlib.colors.SymLogNorm
doesn't produce any minor tick (that doesn't overlap with major ticks). I understand that default minor tick locations are absolutely not obvious in the general case and, where the log base can be any real number, however, I think there's a case to be had regarding the special (and very useful) case of integer log bases (10 and 2 are probably among the most useful bases all domains considered), in which the interval between two major ticks n and n+1 can be divided by the interval between ticks n-1 and n (where n+1 is farthest from 0).
If fact matplotlib.colors.LogNorm
uses log10 and produces minorticks by default. The difference in behaviour is perhaps best illustrated in a case where everything else is identical
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import SymLogNorm, LogNorm
prng = np.random.RandomState(0)
data = 50 * (prng.random_sample((10, 10)))
fig, axs = plt.subplots(ncols=2, figsize=(10,3))
for ax, norm in zip(axs, [LogNorm(), SymLogNorm(base=10, linthresh=1)]):
im = ax.imshow(data, cmap="viridis_r", norm=norm)
cb = fig.colorbar(im, ax=ax)
cb.minorticks_on()
sfile = "/tmp/test.png"
print(f"saving to {sfile}")
fig.savefig(sfile)
Here's my attempt to reproduce what's happening internally (within cb.minorticks_on()
) with a more minimal example
import matplotlib.ticker as mticker
log_t = mticker.LogLocator(base=10, subs=None)
symlog_t = mticker.SymmetricalLogLocator(linthresh=1, base=10, subs=None)
print(log_t.tick_values(vmin=1, vmax=100))
print(symlog_t.tick_values(vmin=1, vmax=100))
outputs
[2.e-01 3.e-01 4.e-01 5.e-01 6.e-01 7.e-01 8.e-01 9.e-01 2.e+00 3.e+00
4.e+00 5.e+00 6.e+00 7.e+00 8.e+00 9.e+00 2.e+01 3.e+01 4.e+01 5.e+01
6.e+01 7.e+01 8.e+01 9.e+01 2.e+02 3.e+02 4.e+02 5.e+02 6.e+02 7.e+02
8.e+02 9.e+02 2.e+03 3.e+03 4.e+03 5.e+03 6.e+03 7.e+03 8.e+03 9.e+03]
[ 1. 10. 100.]
I think that it is reasonable to expect SymmetricalLogLocator
and LogLocator
to produce identica ticks in this case (for values above linthresh
), and this behaviour could be generalised to any integer base.
Proposed solution
At the moment I don't have a working patch for this. What I do not understand is how major ticks are sorted out from minor ticks in the case LogLocator
. With a better understanding of the internals I'm willing to bet that the behaviour I expect should be easy to implement, and I'm more than willing to contribute it, but I may need some guidance.