The issue with FixedFormatter is due to the fact that FixedFormatters are really only designed to work together with FixedLocator. It's not even clear to me what kind of other behavior you'd expect...
The second one can be fixed with a slightly more careful implementation of MultipleLocator.tick_values, which currently does not respect the tick limits. The following patch against master should do:
diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py
index 84192c7..2bd27db 100644
--- a/lib/matplotlib/ticker.py
+++ b/lib/matplotlib/ticker.py
@@ -1614,10 +1614,10 @@ class MultipleLocator(Locator):
def tick_values(self, vmin, vmax):
if vmax < vmin:
vmin, vmax = vmax, vmin
- vmin = self._base.ge(vmin)
base = self._base.get_base()
- n = (vmax - vmin + 0.001 * base) // base
- locs = vmin - base + np.arange(n + 3) * base
+ nmin = round(self._base.ge(vmin) / base)
+ nmax = round(self._base.le(vmax) / base)
+ locs = np.arange(nmin, nmax + 1) * base
return self.raise_if_exceeds(locs)
def view_limits(self, dmin, dmax):
I would have expected the 3 strings to be assigned to the 3 ticks. Is there any usage restriction indicated somewhere in the documentation (didn't find any) ?
Just to clarify, we agree that my patch fixes the behavior with MultipleLocator, and we're talking about the first example, right?
I guess you are confused because you expect the call to set_xlim(0, 2) to given an axes with ticks at 0, 1, 2? But note that FixedFormatter takes strings... they may as well be "a", "b", "c"; they are completely unrelated to whatever set_xlim does (you can check that by plotting say plot([0, 1, 2], [0, 1, 2], "o")). I guess what you really want is
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
ax.xaxis.set_major_locator(plt.FixedLocator([0, 1, 2]))
ax.xaxis.set_major_formatter(plt.FixedFormatter(["0", "1", "2"]))
ax.set_xlim(0, 2)
plt.show()
(by the way, note that the relevant classes are conveniently exported in the plt namespace as well.)
Yes, I was referring to the second point. I agree to what you explain but I think the combination of MultipleLocator and FixedFormatter is still weird. I now understand the second example I posted works as expected but the third example produces three ticks and the first label of the FixedFormatter is not used.
While the first examples are expected behaviour, nothing has changed with the third example, which you can see from the tick formatter example that @rougier contributed.
Activity
anntzer commented on Sep 16, 2016
The issue with FixedFormatter is due to the fact that FixedFormatters are really only designed to work together with FixedLocator. It's not even clear to me what kind of other behavior you'd expect...
The second one can be fixed with a slightly more careful implementation of MultipleLocator.tick_values, which currently does not respect the tick limits. The following patch against master should do:
diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 84192c7..2bd27db 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -1614,10 +1614,10 @@ class MultipleLocator(Locator): def tick_values(self, vmin, vmax): if vmax < vmin: vmin, vmax = vmax, vmin - vmin = self._base.ge(vmin) base = self._base.get_base() - n = (vmax - vmin + 0.001 * base) // base - locs = vmin - base + np.arange(n + 3) * base + nmin = round(self._base.ge(vmin) / base) + nmax = round(self._base.le(vmax) / base) + locs = np.arange(nmin, nmax + 1) * base return self.raise_if_exceeds(locs) def view_limits(self, dmin, dmax):rougier commented on Sep 16, 2016
I would have expected the 3 strings to be assigned to the 3 ticks. Is there any usage restriction indicated somewhere in the documentation (didn't find any) ?
rougier commented on Sep 16, 2016
BTW, you should propose a PR with your fix to multiple locator.
anntzer commented on Sep 16, 2016
That's because the first tick is at 0 and thus not visible. (This is no longer the case with 2.0 where the ticks are outside of the axes by default.)
When I post a patch it means "I'm too lazy to make a PR but it's up for grabs" :-)
rougier commented on Sep 19, 2016
Sorry I dont' get tick. Even if the tick at zero is not visible and the first label from the FixedFormatter should use this position, no ?
If it can only be used with FixedLocator, this should be mentioned in the documentation (or is it already ?)
anntzer commented on Sep 19, 2016
Just to clarify, we agree that my patch fixes the behavior with MultipleLocator, and we're talking about the first example, right?
I guess you are confused because you expect the call to set_xlim(0, 2) to given an axes with ticks at 0, 1, 2? But note that FixedFormatter takes strings... they may as well be "a", "b", "c"; they are completely unrelated to whatever set_xlim does (you can check that by plotting say plot([0, 1, 2], [0, 1, 2], "o")). I guess what you really want is
(by the way, note that the relevant classes are conveniently exported in the plt namespace as well.)
rougier commented on Sep 19, 2016
Yes, I was referring to the second point. I agree to what you explain but I think the combination of MultipleLocator and FixedFormatter is still weird. I now understand the second example I posted works as expected but the third example produces three ticks and the first label of the FixedFormatter is not used.
efiring commented on May 23, 2019
Quite a bit has changed in the last couple of years, so I suspect this is out of date. Reopen if warranted.
QuLogic commented on May 24, 2019
While the first examples are expected behaviour, nothing has changed with the third example, which you can see from the tick formatter example that @rougier contributed.
efiring commented on May 24, 2019
Maybe the solution is to block use of FixedFormatter with anything other than FixedLocator.
anntzer commented on Jul 20, 2020
Effectively closed by #15507, I believe.