问题
In matplotlib
, when I use a log
scale on one axis, it might happen that that axis will have no major ticks, only minor ones. So this means no labels are shown for the whole axis.
How can I specify that I need labels also for minor ticks?
I tried:
plt.setp(ax.get_xticklabels(minor=True), visible=True)
... but it didn't do the trick.
回答1:
I've tried many ways to get minor ticks working properly in log plots. If you are fine with showing the log of the value of the tick you can use matplotlib.ticker.LogFormatterExponent. I remember trying matplotlib.ticker.LogFormatter but I didn't like it much: if I remember well it puts everything in base^exp
(also 0.1, 0, 1). In both cases (as well as all the other matplotlib.ticker.LogFormatter*
) you have to set labelOnlyBase=False
to get minor ticks.
I ended up creating a custom function and use matplotlib.ticker.FuncFormatter. My approach assumes that the ticks are at integer values and that you want a base 10 log.
from matplotlib import ticker
import numpy as np
def ticks_format(value, index):
"""
get the value and returns the value as:
integer: [0,99]
1 digit float: [0.1, 0.99]
n*10^m: otherwise
To have all the number of the same size they are all returned as latex strings
"""
exp = np.floor(np.log10(value))
base = value/10**exp
if exp == 0 or exp == 1:
return '${0:d}$'.format(int(value))
if exp == -1:
return '${0:.1f}$'.format(value)
else:
return '${0:d}\\times10^{{{1:d}}}$'.format(int(base), int(exp))
subs = [1.0, 2.0, 3.0, 6.0] # ticks to show per decade
ax.xaxis.set_minor_locator(ticker.LogLocator(subs=subs)) #set the ticks position
ax.xaxis.set_major_formatter(ticker.NullFormatter()) # remove the major ticks
ax.xaxis.set_minor_formatter(ticker.FuncFormatter(ticks_format)) #add the custom ticks
#same for ax.yaxis
If you don't remove the major ticks and use subs = [2.0, 3.0, 6.0]
the font size of the major and minor ticks is different (this might be cause by using text.usetex:False
in my matplotlibrc
)
回答2:
You can use set_minor_tickformatter
on the corresponding axis:
from matplotlib import pyplot as plt
from matplotlib.ticker import FormatStrFormatter
axes = plt.subplot(111)
axes.loglog([3,4,7], [2,3,4])
axes.xaxis.set_minor_formatter(FormatStrFormatter("%.2f"))
plt.xlim(1.8, 9.2)
plt.show()

回答3:
I think it is worth mentioning the option "minor_thresholds" introduced in matplotlib version 2.0 (docs link). It's a parameter in the form of a pair (subset, all) of the class LogFormatter that allows you to specify when a (fixed) subset of minor ticklabels should be shown and when all minor ticklabels should be shown (explanation of what this means is at the bottom).
In the following code I show the effect by using the same parameter values ((2, 0.4) in this case) but changing the limits of the x-axis:
import matplotlib.pyplot as plt
from matplotlib.ticker import LogFormatter
import numpy as np
fig, axes = plt.subplots(4, figsize=(12, 24))
dt = 0.01
t = np.arange(dt, 20.0, dt)
# first plot doesn't use a formatter
axes[0].semilogx(t, np.exp(-t / 5.0))
axes[0].set_xlim([0, 25])
axes[0].grid()
xlims = [[0, 25], [0.2, 8], [0.6, 0.9]]
for ax, xlim in zip(axes[1:], xlims):
ax.semilogx(t, np.exp(-t / 5.0))
formatter = LogFormatter(labelOnlyBase=False, minor_thresholds=(2, 0.4))
ax.get_xaxis().set_minor_formatter(formatter)
ax.set_xlim(xlim)
ax.grid()
plt.show()
This results in the following plot:
You see that in the second row the ticklabels are the same as in the first row where we didn't use a formatter. This is because the log of the view-range is more than 2 (the first value of the parameter pair) or to put it differently, the view spans a range that is bigger than a range between two major ticklabels. In the third row the view is smaller than 2 but bigger than 0.4 (the second value of the parameter pair), so we see a subset of the minor ticklabels. Finally, in the last row the view spans less than 0.4 of the space between two major ticklabels, so all minor ticklabels are shown.
来源:https://stackoverflow.com/questions/17165435/matplotlib-show-labels-for-minor-ticks-also