Skip to content

Twinning an axis resets tick visibility #15188

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

Closed
mwaskom opened this issue Sep 4, 2019 · 16 comments
Closed

Twinning an axis resets tick visibility #15188

mwaskom opened this issue Sep 4, 2019 · 16 comments
Labels
status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action

Comments

@mwaskom
Copy link

mwaskom commented Sep 4, 2019

Bug report

import matplotlib.pyplot as plt
with plt.rc_context({'ytick.left': False}):
    f, ax = plt.subplots()
    print(ax.yaxis.majorTicks[0].tick1line.get_visible())
    ax.twinx()
    print(ax.yaxis.majorTicks[0].tick1line.get_visible())

Actual outcome

False
True

Expected outcome

False
False

Matplotlib version

  • Operating system: MacOS
  • Matplotlib version: 3.1.1
  • Matplotlib backend (print(matplotlib.get_backend())): MacOSX
  • Python version: 3.7.4
  • Jupyter version (if applicable): N/A
  • Other libraries: N/A
@jklymak
Copy link
Member

jklymak commented Sep 4, 2019

This bisects to 525dcef, #10088

@ImportanceOfBeingErnest
Copy link
Member

I guess the underlying issue is not really what .tick1line.get_visible() returns, but if the ticks are drawn or not. As I see it they were always drawn, even in 2.0.

2.0.2 - True True Ticks drawn: Yes
2.1.2 - True True Ticks drawn: Yes
2.2.2 - True True Ticks drawn: Yes
3.0.0 - True True Ticks drawn: Yes
3.1.0 - False True Ticks drawn: Yes

The problem is that ax.twinx() calls self.yaxis.tick_left()

self.yaxis.tick_left()

and Axis.tick_left() simply ticks the left axis as expected. We do not have anything like Axis.tick_left_if_rc_allows_it().

@jklymak
Copy link
Member

jklymak commented Sep 4, 2019

OK, so #10088 just made ax.yaxis.majorTicks[0].tick1line.get_visible() conform with reality.

Do we know why twinx calls tick_left? Is it just to force the ticks over there so the right ticks can be placed? I guess thats OK? Or we could just not call this and let the user decide how to tick the original axis.

@ImportanceOfBeingErnest
Copy link
Member

Yes. twinx moves the tick(label)s to the left, even if they were on the right previously.

plt.rcParams.update({'ytick.left'      : False,
                     "ytick.labelleft" : False,
                     'ytick.right'     : True,
                     "ytick.labelright": True})

fig, ax = plt.subplots()
ax2 = ax.twinx()

results in a plot with ax's ticks on the left and ax2's ticks on the right. I would think this is somehow expected behaviour. But it inevitably leads to the problem above.

@mwaskom
Copy link
Author

mwaskom commented Sep 4, 2019

Isn't the problem that tick_left (or really, set_ticks_position) doesn't correctly propagate the information about the visibility of the original tick lines?

Part of the problem is the lack of a distinction in matplotlib between tick lines and, more generally, the demarcation of the axis that can include a line and/or label. When I call tick_left, I do expect the demarcator to move to the left, but I would expect it to be visually the same as it was before.

@jklymak
Copy link
Member

jklymak commented Sep 4, 2019

Thats fair enough - tick_left probably does too much. Whenever anyone delves into the code, they suggest it could all be done more clearly, but the back compatible issues are a bit overwhelming.

@mwaskom
Copy link
Author

mwaskom commented Sep 6, 2019

Fair enough

@mwaskom mwaskom closed this as completed Sep 6, 2019
@ImportanceOfBeingErnest
Copy link
Member

Indeed currently there is no way to distinguish between the case where labels/ticks are off because the user wanted to show them on the right instead or because they generally do not want any labels/ticks to be shown. A solution to this would be to have an additional parameter yaxis.decorators : {True/False/"both"} or similar, making everything much more complicated. Still it might be useful to think such solution through.

For now, would something like ax.twinx(restore_decorators=False) help here?

@mwaskom
Copy link
Author

mwaskom commented Sep 6, 2019

The docstring for tick_left says:

Move ticks and ticklabels (if present) to the left of the axes.

Therefore, I wouldn't expect it to change how the ticks/ticklines appear. I would just expect it to move them. So I don't really understand the problem as you see it.

@jklymak
Copy link
Member

jklymak commented Sep 6, 2019

FWIW, I added a note about this to the Matplotlib 4.0 roadmap. At some point I think Matplotlib should have a new version that allows some fundamental back compatibility breaks, (whether it's 4.0, or what) and allow us to re-engineer some of these things.

Not to preclude a more immediate solution if one can be devised.

I think the docstring should really be changed to say make the ticks and labels visible on the left side of the axes, and invisible on the right, since nothing is actually "moved"

@ImportanceOfBeingErnest
Copy link
Member

We could also argue that because backwards compatibility was broken with #9670 for ticklabels already, one can simply do the same for the ticks?

@mwaskom
Copy link
Author

mwaskom commented Sep 6, 2019

I don't really understand what the backwards compatibility concern is here.

I think it's fine to change the docstring of tick_{size} if you don't want to touch the code. But I would suggest that within the context of twin{ax}, it makes the most sense that the new axis either a) reflects the rc params or b) reflects the visual properties of its twin at the time of creation, neither of which is currently the case.

@jklymak
Copy link
Member

jklymak commented Sep 6, 2019

That change to twinx is just backwards incompatible simply because that is not currently what twinx does. Thats not necessarily a good reason to not change twinx; I agree that your expected behaviour is better, and I also agree that it probably wouldn't break much user code.

@jklymak jklymak reopened this Sep 6, 2019
@25shmeckles
Copy link

25shmeckles commented Oct 9, 2019

I want to point out a case in which the odd behavior of twinx() and twiny() makes hard to get a decent plot:

# Create some mock data
x1 = np.arange(0, 10, 1)
y1 = [random.randint(1,5) for n in x1]

x2 = np.arange(0, 100, 10)
y2 = [random.randint(10,50) for n in x2]

fig, ax1 = plt.subplots()

ax1.set_xlabel('x1', color='red')
ax1.set_ylabel('y1', color='red')
ax1.plot(x1, y1, color='red')
ax1.tick_params(axis='both', labelcolor='red')

ax2 = ax1.twinx().twiny() #4 different axes

ax2.set_xlabel('x2', color='blue')
ax2.set_ylabel('y2', color='blue') #where is the label?
ax2.plot(x2, y2, color='blue')
ax2.tick_params(axis='both', labelcolor='blue') #the color is not correct!

plt.show()

In this case, both label and color of the y2 axis are disappearing!

@github-actions
Copy link

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Jun 26, 2023
@github-actions github-actions bot added the status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. label Jul 28, 2023
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 28, 2023
@cdyellick
Copy link

This appears to still be an issue in matplotlib 3.8.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. status: inactive Marked by the “Stale” Github Action
Projects
None yet
Development

No branches or pull requests

5 participants