-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Improve symlog axis ticks #27310
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?
Improve symlog axis ticks #27310
Conversation
The new locator is based on LogLocator in such a way that it should give identical results if the data is only in a logarithmic part of the axis. It is extended to the linear part in a (hopefully) reasonable manner.
We will use it in the formatter, too.
Very cramped ticks are already avoided by choice of the first decade.
Ah, about the tests: Not all tests ran succesfully on my machine, but all the ones that fail also do so on |
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.
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks.
You can also join us on gitter for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide
We strive to be a welcoming and open project. Please follow our Code of Conduct.
Leaving this comment to ping you guys, as it's been more than a week since I opened this PR. :-) |
Leaving another ping-comment, as it's been almost six weeks. |
Sorry there hasn't been much discussion here. I've put this on the agenda for tomorrow's meeting. |
Sorry I meant to comment last week after the meeting, but it seemed to have been left here without going through. In general, we are in favour of this change. However, we would like to see that it be behind a flag of some sort, either a) an argument to the class init, or b) an rcParam, or c) both. Sometime in the future, it may make sense to flip that flag (which I would be in favour of), but it should be tested out a bit first.
I think I've seen an issue related to this somewhere and will try to find it.
It was probably an artifact of whoever implemented things, but then was refactored to share code and now it seems inconsistent. But now it can't easily change for backwards compatibility reasons.
Unfortunately we do, so it will have to be reverted. In some cases, we might want to start making arguments keyword-only, but that does require going through a deprecation cycle.
It's probably fine here, but if you have some easy way to show that difference outside of the other changes, it might be quicker for review as a separate PR.
This is set by the classic style, which is the default for all tests, though new tests should start using
I think this might have moved here. @story645 I guess we need to update the pull request template for some of the recent refactors? |
is something like this clearer? if not or you have a suggestion, please let me know at #27641 |
Thanks for your comments! I think I have everything to make final adjustments now. I'm quite busy at the moment, but I will try and get that done soon. |
Does this also close #10369? |
PR summary
In the current implementation,
symlog
axes only get major ticks by default. Depending on the data range, this can lead to too few or even no ticks at all. When "subticks" between decades are specified manually, those are sometimes labeled in an unintended manner (when they are at a decade).This PR re-implements the tick placement and formatting for
symlog
axes to remedy these problems. If I am not mistaken, this closes #17402, closes #18757 and closes #25994.I am submitting this as a PR now to get some general feedback on the approach and pointers if I need to consider anything regarding style or conventions that I missed. If I get a thumbs up, I would polish some things off (like making
_SymmetricalLogUtil
's methods work withnp.array
s and have.firstdec()
cache results) before merging.My approach for the tick locator
I was aiming for
SymmetricalLogLocator
to behave identically toLogLocator
as long as the data range is outside of the linear part of the scale and extend this reasonably to the linear part if it's present. What I came up with is this (I'm describing the positive half axis here for simplicity, everything works the same on the negative side):LogLocator
, the only caveat being that 0 should always receive a tick if it is in the range.LogFormatter
(which is also used forsymlog
axes) is adapted accordingly._firstsublabels
for placing sublabels below the first decade.log
axes it can sometimes happen that there is only one major tick with unlabeled minor ticks around it. This is fine (one can still identify the unlabeled positions) as long as the major tick is at some decade and not at 0, which can happen withsymlog
axes. In that case, we need to label at least one of the minor ticks to allow reading values off the axis.Since both the locator and the formatter need the calculation of the first decade I placed the code regarding this into a helper class
_SymmetricalLogUtil
.Finally,
SymmetricalLogScale
is adapted to actually use the new functionality by default.I checked all parameter ranges I could think of and this seems to work out quite nicely.
This is how it looks.
For comparison, this is how it used to look.
Code to reproduce.
Requested feedback
There are some details regarding which I would like feedback/guidance from you.
stride
(i.e. the number of decades between major ticks) a possible forced tick at 0 is not considered. This may lead to an off-by-one error regardingnumticks
(i.e. astride
value smaller by one would have been possible) but I feel like preventing this is not worth the complication of taking it into account. Do you agree?subs=None
is equivalent tosubs='auto'
inLogLocator
but tosubs=(1.0,)
inSymmetricalLogLocator
. Is that on purpose? I left it like that.base
came afterlinthresh
inSymmetricalLogLocator
's signature, contrary to most other occurences. In addinglinscale
I reordered those. While this is strictly a backwards incompatible change (whereas I just appendedlinscale
everywhere else), I don't expect it to have ever been used in an incompatible way: providingbase
only make sense whentransform
(the first argument) is not given, so it's most probably always been don by keyword argument, though it is in principle possible to saySymmetricalLogLocator(None, None, 2, 10)
to getSymmetricalLogLocator(linthresh=2, base=10)
. Should I switch it back for backwards compatibility or do we care more about consistent argument order?LogFormatter
threw away the sign of any value, even though it is used for negative values withsymlog
axes. This was no problem becauseLogFormatterMathtext
overwrites__call__
and preserves the sign, so it didn't actually show up on any axis (with the default configuration). I fixed this. Is it fine to just leave it in this PR or should it be a separate one?test_ticker.py
the testTestSymmetricalLogLocator.test_extending()
relies onrcParams['axes.autolimit_mode']
being set toround_numbers
but this is not set up in the test itself. I assume that this configuration is left in place by some previous test, though I can't tell where. Is this by design or should anrc_context
be used, like in some other tests?linscale
argument to the locator and the formatter as well as the changed default value ofSymmetricalLogScale
'ssubs
argument qualify as, I think) with a directive and release note, but the linked section does not seem to exist. What do I need to do?PR checklist