Skip to content
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

Y-axis value of a seaborn heatmap is reversed when home icon or H button is pushed #9863

Closed
cxrxixs opened this issue Nov 26, 2017 · 28 comments · Fixed by #9958
Closed

Y-axis value of a seaborn heatmap is reversed when home icon or H button is pushed #9863

cxrxixs opened this issue Nov 26, 2017 · 28 comments · Fixed by #9958

Comments

@cxrxixs
Copy link

cxrxixs commented Nov 26, 2017

Bug report

Bug summary
The value of Y-axis in a seaborn heatmap is reversed when home icon or H button is pushed.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

data = np.random.rand(10, 10)
sns.heatmap(data)
plt.show()

Actual outcome

Initial result on the Y-axis is from 9 to 0
After Home/H is pushed it will reverse the order from 0 to 9

Expected outcome

It should not reverse the order of Y-axis value
as tested on matplotlib 2.0.2

Matplotlib version

  • Operating system: Ubuntu 17.04
  • Matplotlib version: 2.1.0
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg
  • Python version: 3.6.1
  • Jupyter version (if applicable): N/A
  • Other libraries: Seaborn 0.8.1

Python3.6 is installed using APT, while matplotlib is installed via pip

@jklymak
Copy link
Member

jklymak commented Nov 26, 2017

Can you reproduce in matplotlib only?

@cxrxixs
Copy link
Author

cxrxixs commented Nov 27, 2017

It did not reverse the order when using purely matplotlib with the sample code below

import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(10, 10)
plt.imshow(data)
plt.show()

Is it because of seaborn? I did not have any issue before with seaborn 0.8.1 and matplotlib 2.0.2
By the way the icon of matplotlib plot is only a question mark on a grey background.

@mwaskom
Copy link

mwaskom commented Nov 27, 2017

seaborn.heatmap inverts the y axis to plot the heamatp in "matrix order". I don't know what the "H" button is supposed to do, though. If it resets the axes limits, this behavior makes sense and it's not a problem in matplotlib.

@cxrxixs
Copy link
Author

cxrxixs commented Nov 27, 2017

Initial plot result of seaborn heatmap (from the sample code) is from 9 ~ 0. I think that is what you mean by inverting matrix order. After pressing H or home icon, the Y axis of the plot changes to 0 ~ 9, this is the issue that I am reporting. The operation of Home/H will reset the plot to initial position after you zoom or pan on the plot.

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(10, 10)
fig, ax = plt.subplots()
ax.imshow(data)
ax.invert_yaxis()
plt.show()

This works fine in Master for macosx, Qt5Agg, and TkAgg backends on my machine (zoom, and then home button keeps the axis inverted). So either heatmap does something else than this minimal example or its been fixed in master...

@cxrxixs
Copy link
Author

cxrxixs commented Nov 27, 2017

It's working fine also on my machine with matplotlib 2.1.0. The issue occurs when heatmap is generated using seaborn. I guess this is an issue for seaborn ? But why is it working fine with older version of matplotlib 2.0.2 using the same seaborn 0.8.1 version?

@mwaskom
Copy link

mwaskom commented Nov 27, 2017

Heatmap uses pcolormesh...

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

And inverts the y axis?

Replacing imshow with pcolormesh above inverts the axis, but the behaviour still works fine. Maybe the bug was in 2.0.2?

import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
import numpy as np
data = np.random.rand(10, 10)
fig, ax = plt.subplots()
ax.pcolormesh(data)
ax.invert_yaxis()
plt.show()

figure_1

@cxrxixs
Copy link
Author

cxrxixs commented Nov 27, 2017

That's what I am thinking also that maybe the bug is in old version. But for a user perspective if I pushed home button the expected result is that it will take me to where I came from, which for this case is the initial view of my plot.
I also tried it in my macosx python3.6, matplotlib 2.1.0, and seaborn 0.8.1. The behavior is the same, it changes the order of Y-axis after home or H is pushed.
By the way can you try the code above the one with seaborn to see if the behavior is the same with your master version of matplotlib.

@cxrxixs
Copy link
Author

cxrxixs commented Nov 27, 2017

For visualization
This is the initial plot image generated using seaborn ( Y-axis is from 9 ~ 0) Which is the expected result.
initial

This is after pressing home/H button (Y-axis is reversed from the initial plot, it became 0 ~ 9)
after

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

I can reproduce your reported behaviour using seaborn. No idea what seaborn does though in heatmap, so its hard to see if we have a bug or seaborn does. I'll leave open, but mark it as needing a downstream fix/investigation. Feel free to reference this Issue when you report to them.

@mwaskom
Copy link

mwaskom commented Nov 27, 2017

OK. I figured it out. Here's a minimal example that distills the seaborn _Heatmapper.plot method:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.rand(10, 10)

f, ax = plt.subplots()
ax.pcolormesh(x)
ax.figure.draw(ax.figure.canvas.get_renderer())
ax.invert_yaxis()

plt.show()

The resetting happens when figure.draw is called before invert_yaxis but not if the order of hte calls is reversed. This script is consistent across backends (but a simpler script that doesn't force a draw was not, as previously noted).

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

Thanks, that seems to be the problem. I'm not sure why figure.draw() would cause this behaviour.

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2017

That's because the "home" position is defined the first time the canvas is drawn (when else could it be?) and just stores the limits as they are (whether the limits are inverted are part of the position).

I actually think this is the correct behavior (there's nothing in matplotlib that directly stores whether an axis is inverted, it's just that you can set xlow>xhigh). So I'm tempted to close this as "not a bug" (or rather, should be fixed on seaborn's side).

For seaborn's specific case, I don't think there's any gain to calling draw before calling invert_yaxis (you'll have to redraw the whole thing anyways).

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

Ooops, I was just typing that!

I agree that seaborn should reconsider issuing a "draw" request, at least before the axis is inverted.

OTOH, all the programatic ways to change the xlimits, ylimits, etc do not register in the stack. One could argue that the toolbar stack should only be filled when "show" is called. I couldn't quite follow the trail to see where the "Home" was defined to see what changed.

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2017

Not everyone calls show() (for example, when embedding matplotlib in a GUI where you manage widget visibility yourself), but everyone has to call draw(), so I maintain that it's the correct place to do it.

@mwaskom
Copy link

mwaskom commented Nov 27, 2017

seaborn has to force a draw to get the tick labels, but there's probably no compelling reason to delay inverting the axis.

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

@anntzer Agreed. But, it'd be nice to know what changed...

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2017

#6598 is what changed (but see also #9359).

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

@anntzer Thanks, and, I'm fine w/ that logic. But....

If the first "draw" event gets registered onto the stack, why aren't subsequent ones? i.e. in the above snippet, draw is called twice (once explictly, and once in show), and you, fairly enough, register the first as "Home". But I'd expect to be able to get back to the second draw as well using the arrow keys. Instead that state is lost.

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2017

I think it's fine to register later draws as well (the reason it isn't is because I copied the old logic, which similarly also only registered the first view (specifically, at the time a pan/zoom button was pressed for the first time)).

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

OK, but thinking about it, isn't that the better behaviour? i.e. only save the initial state when the user starts interacting w/ the figure? What was #6598 trying to fix?

@jklymak
Copy link
Member

jklymak commented Nov 27, 2017

I played with registering later draws, but of course you are also drawing when zooming and panning, so its hard to just do that....

Anyway, I don't know that this is a huge deal, but I've noted a few people wondering about the behaviour of zoom and pan. I wonder if this change has some connection. @efiring I think was one of them.

@anntzer
Copy link
Contributor

anntzer commented Nov 27, 2017

#6598 was handling the case of the limits being changed by the figure options tool (but I guess the other way to do it would be to register the initial position when any UI tool is triggered for the first time).

@efiring
Copy link
Member

efiring commented Nov 27, 2017

That makes sense to me. The point of the navigation buttons is to move among configurations generated via the UI tools, so starting with the plot as first seen when a UI tool is clicked seems like the correct behavior.

@jklymak
Copy link
Member

jklymak commented Dec 7, 2017

@anntzer were you going to work on this? I could take a stab. I see what you changed, and I see how to get it back to the old behaviour w/o reverting everything you did (I think)..

@anntzer
Copy link
Contributor

anntzer commented Dec 7, 2017

Not right now, got for it!

@jklymak
Copy link
Member

jklymak commented Dec 7, 2017

Well, I won't do it right now ;-), but over the next week or so...

@jklymak jklymak self-assigned this Dec 7, 2017
@QuLogic QuLogic added this to the v2.2 milestone Dec 9, 2017
@QuLogic QuLogic modified the milestones: needs sorting, v2.2.0 Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants