-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
BUG: Prevent Tick params calls from overwriting visibility without being told to #12839
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
Conversation
lib/matplotlib/axis.py
Outdated
for d in dicts: | ||
if reset: | ||
d.clear() | ||
blacklist_dicts.append( | ||
{k: d.pop(k) for k in blacklist if k in d.keys()} |
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.
First, either this line seems to be indented too far or the line above isn't indented enough? Second, I'm curious about if there is a better way to write this without using .pop
and iterating through d.keys()
for every single lookup?
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.
I'll note that the iteration is only over the keys in the blacklist (total of 5 items), k in d.keys()
is an O(1) check since keys view objects are set-like and hashable.
The second iteration could actually be rolled into this conditional, to prevent things from being popped then added back with updates, rather than popping indiscriminately and then iterating over the kwtrans keys.
fig, ax = plt.subplots() | ||
plt.plot([0, 1, 2], [0, -1, 4]) | ||
plt.setp(ax.get_yticklabels(), visible=False) | ||
ax.tick_params(axis="y", which="both", length=0) |
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.
I think this test could be easily done without an image comparison by just checking the visibility of the ticks?
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.
The tricky bit is that one of the common ways in tests of checking wheter the ticks are visible was lying to you prior to this PR, (though if you went to the individual ticks, it would be correct) As such, I was looking to make sure it translated to the image generated.
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.
You can instead save to svg and use some long-ish strings as labels, and check that the labels don't appear as substrings in the svg file.
lib/matplotlib/axis.py
Outdated
for d in dicts: | ||
if reset: | ||
d.clear() | ||
blacklist_dicts.append( |
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.
I find this pretty opaque, and don’t really understand why these kwargs are different than the other kwargs (other than that they control visibility). This could really use a comment explaining what it does and why. As it stands, I’m not clear at all that this is the proper solution, and maybe there is something more fundamental that is at fault.
So the bug comes from the fact that plt.setp(... visible=False) set the visibility by calling tick.set_visible(False), which used to override tick_params() which would set reset label1On to True; but after #10088 label1On maps to set_visible and thus the call to tick_params undoes the call to set_visible(False). I think a correct fix would be somewhere along the lines of
plus some wrangling with the rest of the codebase to keep track of label1On-ness. Release critical as a regression. |
If I recall correctly, I had tried something like the simpler diff you presented here, but got several new test failures as a result. It may very well be easy to track those down in a cleaner way, though my inital efforts focused on fixing the problem fairily locally. |
I think a simpler approach may be possible but this looks generally ok as a stopgap if nothing better is proposed before 3.1. |
lib/matplotlib/axis.py
Outdated
blacklist_dicts.append( | ||
{ | ||
k: d.pop(k) for k in blacklist | ||
if k in d.keys() and k not in kwtrans.keys() |
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.
k in d
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.
Strongly suggest not adding a baseline image per https://github.com/matplotlib/matplotlib/pull/12839/files#r255441630.
I am concerned about this fix. The underlying issue here is that the tick system has an internal set of defaults that it uses to create new ticks, but by using ax.tick_params(axis="y", which="both", label1On=False)
ax.tick_params(axis="y", which="both", length=0) works as expected. I am 👎 on merging this. The correct fix is to track on the tick objects what state has been touch independently by the user and then not update that property. I am also concerned that this will not work in the case where we generate more tick objects later so you will end up with mixed state. |
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.
I do not think this is the correct fix to the problem (which is that we do not track if users have mutated objects that the axis thinks it is managing).
It might be possible to use the |
To be clear, this is just taking out arguments only in the case that they were not asked for explicitly and simply not trying to change it. If the user is modifying the state using this function, those changes are propegated. That said, I make no illusions, this is a hack, and there are certainly cleaner solutions, including changing my own library code such that the The point about mixed state is a good one, however, if users intentionally got a mixed state (I would tend to avoid this myself, but still) The code without this patch will override that mixed state, even when the arguments that are written have nothing to do with visibility. The way this is implemented preserves mixed state if it exists, but makes it easy to get back to a consistent state. |
Sorry, being thrashy about milestones / tags... Still thinking about this. |
I have now pushed a commit to this branch.
I applied half of the diff suggested in the comments by @anntzer (we still want to update the default settings for new ticks) but only apply the passed-in kwargs to the existing ticks.
@ksunden what tests failed for you locally with this change? Went back and forth a bit on trying to understand what the intent of this method is (as it could be argued that the correct behavior is to re-apply the standard style to all of the ticks), but the presence of the |
I am not getting any local test failures now, I recall trying this back in november, but don't recall why I ultimately moved on from it. All looks good on my end now. |
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.
Please try to not include a baseline image per https://github.com/matplotlib/matplotlib/pull/12839/files#r255441630. (I'm not 100% sure this will work, but is at least worth a try.)
Saving 15Kb on a file is not worth the complexity of checking the text of an svg (discussed on phone call)
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.
I'm ok with adding another baseline image. It's only 15kb, and the alternative would actually be something out of line from the rest of the test suite and require more effort to understand what's going on.
…rwriting visibility without being told to
Something went wrong ... Please have a look at my logs. |
…839-on-v3.1.x Backport PR #12839 on branch v3.1.x (BUG: Prevent Tick params calls from overwriting visibility without being told to)
After matplotlib/matplotlib#12839 axis ticks showed up along all the edges of the plot panel and theming of tick labels was finicky. The solution is we have to be careful in how we toggle the visibility of these elements. If not careful, merely setting the tick/tick labels could switch on the visibility. This could interfere with theme. closes #278
PR Summary
Prevents a regression bisected to #10088, which caused subsequent calls to
tick_params
to overwrite the visibility of tick labels (et al.) when those calls did not set visibility themselves.Just pops a subset of the kwargs out of the dictionary and replaces them after the call to
_apply_params
is made, so that they are there for other parts of the codebase (including tests).The test included here passes on current release (v3.0.2), but fails on current master (
936855c).
PR Checklist