I'm trying to customize major and minor tick labels on a log y axis where all labels are in %g
format.
When the minor 2s and 5s are labeled, and both major and minor grid lines are showing and the ticklabels show as expected.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
N = 100
x = np.linspace(0, 1, N)
np.random.seed(123)
y = np.random.uniform(0.1, 50, N)
fig, ax = plt.subplots()
ax.plot(x, y)
##### Eventually will roll this chunk into a formatter function
ax.set(yscale="log")
# Major ticks
major_ticks = [0.001, 0.01, 0.1, 1, 10, 100]
ax.set_yticks(major_ticks)
ax.yaxis.set_major_formatter(ticker.FormatStrFormatter("%g"))
# Minor ticks
minor_ticks = [0.002, 0.005, 0.02, 0.05, 0.2, 0.5, 2, 5, 20, 50]
minor_locator = ticker.LogLocator(base=10.0, subs=(0.2, 0.5), numticks=12)
def minor_tick_filter(val, pos):
if val in minor_ticks:
return '%g' % val
return ''
ax.yaxis.set_minor_locator(minor_locator)
ax.yaxis.set_minor_formatter(ticker.FuncFormatter(minor_tick_filter))
#####
ax.set(xlim=[0, 1], ylim=[0.1, 100])
plt.minorticks_on()
plt.show()
But if I want to plot the 3s, the label for 0.3 is missing. How can I fix this? Using matplotlib version 3.2.1. Yes it's old but it's a relic env I'm stuck with for this application.
minor_ticks = [0.003, 0.03, 0.3, 3, 30]
minor_locator = ticker.LogLocator(base=10.0, subs=[0.3], numticks=12)
This bug is related to floating point precision. Specifically, this membership test is the problem:
if val in minor_ticks:
This is because the value at minor tick position 9 is not 0.3, it is 0.30000000000000004, so because 0.30000000000000004 in minor_ticks
is False, it's being erased by the tick filter (you can also check that similar to 0.3, 0.6 and 0.7 don't pass the membership test either). To get the desired output, change the formatter function into:
def minor_tick_filter(val, pos):
# print(val) # <--- see the values passed
if round(val, 10) in minor_ticks: # <--- round to remove the error
return '%g' % val
return ''
Just with this change, I get the following figure: