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

Deleting axis in matplotlib > v1.2.1 does not work similar to v1.1.1 #2688

Closed
xo-HADES-xo opened this issue Dec 18, 2013 · 7 comments · Fixed by #3110
Closed

Deleting axis in matplotlib > v1.2.1 does not work similar to v1.1.1 #2688

xo-HADES-xo opened this issue Dec 18, 2013 · 7 comments · Fixed by #3110

Comments

@xo-HADES-xo
Copy link

This issue is described in this Stackoverflow question:

http://stackoverflow.com/questions/17052380/deleting-axis-in-matplotlib-v1-2-1-does-not-work-similar-to-v1-1-1

I am using matplotlib (python win32 v2.7.5) to plot contour plots with color bars that are animated or the contour gets updated. In order to update the plot, I delete the color bar axis while keeping the original plot axis untouched. In version 1.1.1 of matplotlib, the program was working okay, however, when I upgraded to 1.2.1 (and higher) of matplotlib I started to notice my plot is getting squashed to the left.

The following code demos the issues. Run it in version 1.1.1 and then in 1.2.1 to see the differences.

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.mlab import bivariate_normal
from matplotlib.colors import LogNorm

delta = 0.5
x = np.arange(-3.0, 4.001, delta)
y = np.arange(-4.0, 3.001, delta)
X, Y = np.meshgrid(x, y)
Z = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
fig  = plt.figure()
fig.subplots_adjust(left=0.1, bottom=0.1, right=0.97, top=0.92)
ax   = fig.add_subplot(1,1,1)
axim = ax.imshow(Z,norm = LogNorm())
cb   = fig.colorbar(axim)

##Note:  These are not replicated, I put them here to show how a refresh of the 
##          contour plot multiple times will look like
fig.delaxes(fig.axes[1])
fig.subplots_adjust(left=0.1, bottom=0.1, right=0.97, top=0.92)
cb   = fig.colorbar(axim)

fig.delaxes(fig.axes[1])
fig.subplots_adjust(left=0.1, bottom=0.1, right=0.97, top=0.92)
cb   = fig.colorbar(axim)

plt.show()

If i delete ALL axis and re-create them each time, then it looks ok even in new version, but I am thinking that this is not efficient process with animation.

@tacaswell
Copy link
Member

I have not sorted out if this is a regression or not, but it is better to not delete any axes. fig.colorbar takes a cax kwarg (doc) which allows you to set which the axes that the colorbar should be drawn to:

cax = cb.ax
...
cb = fig.colorbar(axim, cax=cax)
...

@KevKeating
Copy link
Contributor

This bug is biting us as well. We're using the same Figure to display data with and without a colorbar at different times, so reusing an existing the existing colorbar axes isn't ideal (since we want the ability to completely delete the colorbar when necessary and later add another colorbar). I did a bit of digging, and it appears that the bug is actually due to a change in subplots_adjust() behavior.

The following script demonstrates the bug:

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy
import sys

fig = plt.figure()
plot = fig.add_subplot(111)
scatter = plot.scatter([1, 2], [3, 4], cmap=cm.spring, color="red")
scatter.set_array(numpy.array([5, 6]))

for i in range(10):
    cb = fig.colorbar(scatter)
    fig.delaxes(cb.ax)
fig.subplots_adjust()
fig.savefig(sys.argv[1])

This creates and deletes a colorbar ten times, calls subplots_adjust(), and then saves the resulting image. In matplotlib 1.1.1, this produces
repeated_subplots_adjust-1 1 1
but in matplotlib 1.2.1, this produces the incorrect results:
repeated_subplots_adjust-1 2 1

Modifying the script to remove the subplots_adjust()

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy
import sys

fig = plt.figure()
plot = fig.add_subplot(111)
scatter = plot.scatter([1, 2], [3, 4], cmap=cm.spring, color="red")
scatter.set_array(numpy.array([5, 6]))

for i in range(10):
    cb = fig.colorbar(scatter)
    fig.delaxes(cb.ax)
# fig.subplots_adjust()
fig.savefig(sys.argv[1])

removes the differences. Both versions produce a shrunken plot. matplotlib 1.1.1:
no_subplots_adjust-1 1 1
matplotlib 1.2.1
no_subplots_adjust-1 2 1

The change in subplots_adjust() behavior between 1.1.1 and 1.2.1 is not entirely negative. Calling subplots_adjust() without deleting the colorbar

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy
import sys

fig = plt.figure()
plot = fig.add_subplot(111)
scatter = plot.scatter([1, 2], [3, 4], cmap=cm.spring, color="red")
scatter.set_array(numpy.array([5, 6]))

cb = fig.colorbar(scatter)
fig.subplots_adjust()
fig.savefig(sys.argv[1])

shows incorrect behavior in matplotlib 1.1.1:
dont_delete_cb-1 1 1
but is correct in matplotlib 1.2.1:
dont_delete_cb-1 2 1

I just ran git diff on figure.py to compare the 1.1.x and 1.2.x branches, but there aren't any differences in the subplots_adjust() method itself. Presumably, something it calls or accesses has changed (subplotpars.update() or ax.update_params()?). I can play with things a bit more and see if there's a good solution.

@tacaswell tacaswell added this to the v1.4.0 milestone May 28, 2014
@tacaswell
Copy link
Member

I seem to be adding bugs to 1.4.0 faster than we are removing them.

I would point out that this as a compatibility break that is very old and we are not providing patches for either 1.1 or 1.2 anymore. I suspect the bug is in delaxes not cleaning up after it's self.

@tacaswell
Copy link
Member

And this is reproducible on close-to-master.

@KevKeating
Copy link
Contributor

I don't need a fix for either 1.1 or 1.2; I just wanted to play around with versions shortly before and shortly after the bug started occurring. Once I track things down a little more, I'll switch to master for further work.

@KevKeating
Copy link
Contributor

I did some more digging, and it looks like the issue is that the default value for the use_gridspec argument to fig.colorbar changed between 1.1.1 and 1.2.1. In 1.1.1, the default value was False. In 1.2.1 and newer, the default value is True. If I add an explicit use_gridspec=True or use_gridspec=False to the three scripts in my earlier comment, then versions 1.1.1, 1.2.1, and 1.3.1 will all produce identical output. (I haven't gotten a 1.4.x build working just yet.) When use_gridspec is True, matplotlib.colorbar.make_axes_gridspec is called, which calls set_subplotspec so that fig.subplots_adjust will know to allocate space for the colorbar. If the colorbar is then deleted using fig.delaxes, the subplotspec will not be reverted to its previous value. As a result, fig.subplots_adjust will continue to allocate space for the non-existent colorbar.

I'm not entirely sure what the best way is to solve this is, but I'll keep looking into it.

@pelson
Copy link
Member

pelson commented Jun 4, 2014

I seem to be adding bugs to 1.4.0 faster than we are removing them.

@tacaswell - putting out a release isn't about creating a bug free version of matplotlib (or even a known-bug free version) - it is about drawing a line in the sand and getting people to make use of fixed bugs, future proofed APIs and added functionality. There is no harm in accepting there are issues, and ensuring that user's time isn't wasted in bug-tracking by providing appropriate documentation about known issues.

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.

4 participants