| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
There was a problem hiding this comment.
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.
Sorry, something went wrong.
|
|
||
| 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.
Docstring ends prematurely.
Sorry, something went wrong.
There was a problem hiding this comment.
oops, fixed.
Sorry, something went wrong.
| # 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.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
Docstring added. Agreed that this should be the future public API, but I didn't want to commit yet to anything.
Sorry, something went wrong.
There was a problem hiding this comment.
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).
Sorry, something went wrong.
| 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.
Typo?
| self.axes.yaxis.minor.locator._call_with_axis(self.axis.yaxis)) | |
| self.axes.yaxis.minor.locator._call_with_axis(self.axes.yaxis)) |
Sorry, something went wrong.
There was a problem hiding this comment.
oops, fixed
Sorry, something went wrong.
|
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... |
Sorry, something went wrong.
It may be a bit artificial, but we're technically changing plot behavior by overriding the axis. A user could have done ax.yaxis.get_major_locator().set_axis(ax.xaxis) 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. |
Sorry, something went wrong.
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. |
Sorry, something went wrong.
|
How about:
We could add a warning to locator.set_axis() that fires on any user-call but not on our own (temporary manipulation). |
Sorry, something went wrong.
|
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 old_loc = axis.get_major_locator(); axis.set_major_locator(custom_loc); locs = custom_loc(); axis.set_major_formatter(old_loc) but that's much nastier than custom_loc.set_axis(axis); custom_loc().) (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.) |
Sorry, something went wrong.
Not sure I understand the use case. I believe we agree that there should not be any warnings when people just use set_locator(). There's usually no need for users to call set_axis(). But if they've done this previously any locator __call__ - including our internal ones would use the new axis. Your replacing direct internal __call__ by _call_with_axis may break these people since they may be assuming that their set_axis is honored. That's why I want to warn on set_axis - something like "You can use this for manual __call__s but it is overridden for any internal usage.` Is this about a hypothetical case fig, ax = plt.subplots() loc = LogLocator() loc.set_axis(ax.xaxis) positions = loc() 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 set_axis in one go because the changed calling behavoir has the above mentioned side-effect on set_axis. I think this should also be straight forwarnd for locator - we only have to decide on a name for _call_with_axis. It would be nice, but not strictly necessary to do the same for formatters at the same time. |
Sorry, something went wrong.
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). |
Sorry, something went wrong.
|
You might introduce a transition path where we move away from set_axis internally (e.g. through a separate _set_axis or and _axis attribute). This means set_axis would only be used by external users, and if given, that axis would still take precedence over the _call_with_axis-axis. This ensures full backward-compatibility for existing users of set_axis. At the same time, it allows sharing locators if they haven't been explicitly assigned an axis via set_axis. - I believe the intersection between both cases is tiny. So you can have both worlds soon. You do not yet have to introduce new public API or deprecate anything. But for simplicity, I firmly believe we have to get rid of the state self.axis eventually. The two worlds from above can coexist reasonably well, but "locators can be shared, if they don't have an axis assigned explicitly" is still quirky, has a more complicated implementation and will lead to confusion in very rare edge cases (Why can I share a ScalarLocator, but not a ThetaLocator). |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
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