-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Allow sharing locators across axises. #28429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
4bee35d
to
7b73776
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a reasonable and clever approach. It's worth pursuing, but we still should aim for removing the axis
state eventually to make to logic simpler again.
lib/matplotlib/ticker.py
Outdated
|
||
Note that the returned ticks depend on the axis assigned to the | ||
locator. If a given locator is used across multiple axises, make sure | ||
that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring ends prematurely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, fixed.
# note: some locators return data limits, other return view limits, | ||
# hence there is no *one* interface to call self.tick_values. | ||
raise NotImplementedError('Derived must override') | ||
|
||
def _call_with_axis(self, axis): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should get a docstring. If I understand it correctly, we always want to call this method instead of __call__
, which then makes the explicit self.axis
unused because it is always temporarily overwritten with the passed parameter.
We might choose to make this public as the new API, so people can use it directly (users wanting to evaluate, and locator authors implementing their logic directly here). We could then later deprecate __call__
and self.axis
/set_axis
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring added. Agreed that this should be the future public API, but I didn't want to commit yet to anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this should mostly not affect users, I think we should not introduce this silently, but together with the announcement and plan how to migrate to axis-independent locators. (And possibly similar for formatters).
if self.axes.yaxis._minor_tick_kw["gridOn"]: | ||
locs.extend(self.axes.yaxis.minor.locator()) | ||
locs.extend( | ||
self.axes.yaxis.minor.locator._call_with_axis(self.axis.yaxis)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo?
self.axes.yaxis.minor.locator._call_with_axis(self.axis.yaxis)) | |
self.axes.yaxis.minor.locator._call_with_axis(self.axes.yaxis)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, fixed
I suspect the long-term plan is that Locator.tick_values and Locator.__call__ should go away (as well as the axis attribute) and be replaced by Locator.position_ticks(axis) (name up to bikeshedding). But this feels like much larger surgery (especially if we want to do similar stuff on the formatters as well), whereas the PR here just fixes the actual underlying issue without touching the public API at all... |
It may be a bit artificial, but we're technically changing plot behavior by overriding the axis. A user could have done
Without having an env to check right now, but I suspect this ensures that the same locations are used on both axes. If my assumption is correct, we at least need to announce the change. |
Locally changing the assigned axis seems to be the most practical solution, if not the most elegant.
Sure, added a note. It's actually surprisingly difficult to explain this without getting bogged down in technical details, so if you can think of any better wording that would be welcome. |
How about:
We could add a warning to |
We can't add the warning at least until we provide a public API to _call_with_axis; otherwise, how can a third-party figure out where a custom, not-actually-installed locator would put ticks on an existing axis? (I guess they could do (Preferably, also all relevant Formatter methods should gain an axis kwarg as well before we start deprecating stuff: Formatter.format_data (or the newer Formatter.format_ticks) and Formatter.format_data_short all have good reasons to know what axis they are being called on too, e.g. to know cursor pointing precision to determine the number of significant digits.) |
Not sure I understand the use case. I believe we agree that there should not be any warnings when people just use Is this about a hypothetical case
Not sure if anybody needs this, but I think it's bearable for them to see the warning, or add a filter if they want to ignore the warning. That said, I believe it's reasonable change calling behavior, and deprecate It would be nice, but not strictly necessary to do the same for formatters at the same time. |
Sure, that's reasonable. However, I looked into deprecating Locator.set_axis and just setting an internal _axis attribute (temporarily mirrored externally via an axis property), but it turns out this is not so easy, due to the existence of wrapper locators: ThetaLocator (polar) and MicrosecondLocator (dates) currently both wrap another tick locator and propagate the axis to the internal locator by calling set_axis on that internal one. Sure, we could also change these wrapper locators to override _call_with_axis in a way to forward that temporary axis to the internal locator, but this feels like there's something more fundamentally wrong design-wise (e.g., third-parties could also want to write "wrapper locator" classes like ThetaLocator; should they be deprived of this mechanism? -- in other words, do we really want to have an escape hatch only available to builtin locators?) I don't think this is anything unfixable, but (unless I missed something) this isn't just a mechanical change either, and may require some more thoughts (if we indeed want to do the deprecation now). |
You might introduce a transition path where we move away from But for simplicity, I firmly believe we have to get rid of the state |
Locally changing the assigned axis seems to be the most practical solution, if not the most elegant.
See #13438 and related discussions. This PR mostly addresses that issue, although ultimately making locators (and formatters) not have an axis attribute at all (and requiring the axis to be passed as argument) is likely the cleanest long-term design. See also #13482 for an alternative ("more magical") approach.
PR summary
PR checklist