Skip to content

Colorbar update error with clim change in multi_image.py example #17052

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
efiring opened this issue Apr 7, 2020 · 1 comment · Fixed by #19553
Closed

Colorbar update error with clim change in multi_image.py example #17052

efiring opened this issue Apr 7, 2020 · 1 comment · Fixed by #19553
Milestone

Comments

@efiring
Copy link
Member

efiring commented Apr 7, 2020

Bug report

Bug summary

In the multi_image example, the colorbar is responding correctly to set_clim only when called on the image to which the colorbar is directly attached.

Code for reproduction
This is just the example, https://matplotlib.org/gallery/images_contours_and_fields/multi_image.html, with manipulation of the clim at the bottom.

from matplotlib import colors
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(19680801)
Nr = 3
Nc = 2
cmap = "cool"

fig, axs = plt.subplots(Nr, Nc)
fig.suptitle('Multiple images')

images = []
for i in range(Nr):
    for j in range(Nc):
        # Generate data with a range that varies from one plot to the next.
        data = ((1 + i + j) / 10) * np.random.rand(10, 20) * 1e-6
        images.append(axs[i, j].imshow(data, cmap=cmap))
        axs[i, j].label_outer()

# Find the min and max of all colors for use in setting the color scale.
vmin = min(image.get_array().min() for image in images)
vmax = max(image.get_array().max() for image in images)
norm = colors.Normalize(vmin=vmin, vmax=vmax)
for im in images:
    im.set_norm(norm)

fig.colorbar(images[0], ax=axs, orientation='horizontal', fraction=.1)


# Make images respond to changes in the norm of other images (e.g. via the
# "edit axis, curves and images parameters" GUI on Qt), but be careful not to
# recurse infinitely!
def update(changed_image):
    for im in images:
        if (changed_image.get_cmap() != im.get_cmap()
                or changed_image.get_clim() != im.get_clim()):
            im.set_cmap(changed_image.get_cmap())
            im.set_clim(changed_image.get_clim())


for im in images:
    im.callbacksSM.connect('changed', update)

images[1].set_clim(1e-9, 2e-8)
fig.savefig('ax1_bad.png')
images[0].set_clim(1e-9, 2e-8)
fig.savefig('ax0_good.png')

Actual outcome
ax1_bad.png:

ax1_bad

Expected outcome
ax0_good.png:

ax0_good

Matplotlib version

  • Operating system: OSX
  • Matplotlib version: 3.1.2
  • Matplotlib backend (print(matplotlib.get_backend())): MacOSX, agg
  • Python version: 3.7
@anntzer
Copy link
Contributor

anntzer commented Apr 8, 2020

This is because the colorbar is listening to the "changed" event on images[0].callbacksSM, but that event is triggered when the image is directly manipulated (im.set_clim, etc.), but here they are not because it's the underlying norm object which is shared (and hence the "update" callback never fires because the clims on the image change directly via the norm object!).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants