Tick Label Text And Frequency In Matplotlib Plot
Solution 1:
Using Locator
we can define how many ticks shall be produced and where they should be placed. By sub-classing MaxNLocator
(this is essentially the default Locator) we can reuse the functionality and simply filter out unwanted ticks (e.g. ticks outside the label range). My approach could definitely be improved at this point, as sparse or non-equidistant x-range data would break my simple filtering solution. Also float values might be a challenge, but I'm certain such a data range could always be mapped to a convenient integer range if the above conditions do not apply. But this is beyond the scope of this question.
With Formatter
we can now simply lookup the corresponding labels in our label list to produce the correct tick label. For finding the closest matching value, we can efficiently utilize the bisect
module (related question). For static plots we could rely on the assumption that our Locator already produces indices we can directly use for our list access (avoiding unnecessary bisect operation). However, the dynamic view (see the bottom left corner in the screenshots) uses the Formatter to format non-tick position labels. Thus, using bisect is the more general and stable approach.
import matplotlib.pyplot as plt
import numpy as np
import bisect
from matplotlib.ticker import Formatter
from matplotlib.ticker import MaxNLocator
x = np.arange(0, 100, 1)
y = np.sin(x)
# custom labels, could by anything
l = ["!{}!".format(v) for v in x]
plt.plot(x, y)
ax = plt.gca()
classLookupLocator(MaxNLocator):
def__init__(self, valid_ticks, nbins='auto', min_n_ticks=0, integer=True):
MaxNLocator.__init__(self, integer=integer, nbins=nbins, min_n_ticks=min_n_ticks)
self._valid_ticks = valid_ticks
self._integer = integer
defis_tick_valid(self, t):
if self._integer:
return t.is_integer() andint(t) in self._valid_ticks
return t in self._valid_ticks
deftick_values(self, vmin, vmax):
returnfilter(self.is_tick_valid, MaxNLocator.tick_values(self, vmin, vmax))
classLookupFormatter(Formatter):
def__init__(self, tick_values, tick_labels):
Formatter.__init__(self)
self._tick_values = tick_values
self._tick_labels = tick_labels
def_find_closest(self, x):
# https://stackoverflow.com/questions/12141150/from-list-of-integers-get-number-closest-to-a-given-value
i = bisect.bisect_left(self._tick_values, x)
if i == 0:
return i
if i == len(self._tick_values):
return i - 1
l, r = self._tick_values[i - 1], self._tick_values[i]
if l - x < x - r:
return i
return i - 1def__call__(self, x, pos=None):
return self._tick_labels[self._find_closest(x)]
ax.xaxis.set_major_locator(LookupLocator(x))
ax.xaxis.set_major_formatter(LookupFormatter(x, l))
plt.show()
Post a Comment for "Tick Label Text And Frequency In Matplotlib Plot"