Skip to content

Commit 4c56dcb

Browse files
committed
update multi_image example
1 parent 78ef64e commit 4c56dcb

File tree

1 file changed

+73
-26
lines changed

1 file changed

+73
-26
lines changed

examples/images_contours_and_fields/multi_image.py

+73-26
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,92 @@
11
"""
2-
===========
3-
Multi Image
4-
===========
2+
==================================
3+
Multiple images sharing a colorbar
4+
==================================
55
6-
Make a set of images with a single colormap, norm, and colorbar.
7-
"""
6+
A colorbar is always connected to a single image (more precisely, to a single
7+
`.ScalarMappable`). If we want to use multiple images with a single colorbar,
8+
we have to create a colorbar for one of the images and make sure that the
9+
other images use the same color mapping, i.e. the same Colormap and the same
10+
`.Normalize` instance.
811
12+
"""
913
from matplotlib import colors
1014
import matplotlib.pyplot as plt
1115
import numpy as np
1216

1317
np.random.seed(19680801)
14-
Nr = 3
15-
Nc = 2
16-
cmap = "cool"
18+
nrows = 3
19+
ncols = 2
20+
cmap = "plasma"
21+
22+
data = [((1 + i) / 10) * np.random.rand(11, 21) * 1e-6
23+
for i in range(nrows * ncols)]
24+
25+
#############################################################################
26+
#
27+
# All data available beforehand
28+
# -----------------------------
29+
#
30+
# In the most simple case, we have all the image data sets available, e.g.
31+
# in a list, before we start to plot. In this case, we create a common
32+
# `.Normalize` instance scaling to the global min and max by passing all data
33+
# to the *data* argument of Normalize. We then use this and a common colormap
34+
# when creating the images.
35+
36+
fig, axs = plt.subplots(nrows, ncols, sharex=True, sharey=True)
37+
fig.suptitle('Multiple images sharing a colorbar')
38+
39+
norm = colors.Normalize(data=data)
40+
images = [ax.imshow(data, cmap=cmap, norm=norm)
41+
for data, ax in zip(data, axs.flat)]
42+
fig.colorbar(images[0], ax=axs, orientation='horizontal', fraction=.06)
43+
plt.show()
44+
45+
#############################################################################
46+
#
47+
# Not all data available beforehand
48+
# ---------------------------------
49+
#
50+
# Things get a bit more complicated, if we don't have all the data beforehand,
51+
# e.g. when we generate or load the data just before each plot command. In
52+
# this case, the common norm has to be created and set afterwards. We can use
53+
# a small helper function for that.
54+
55+
def normalize_images(images):
56+
"""Normalize the given images to their global min and max."""
57+
vmin = min(image.get_array().min() for image in images)
58+
vmax = max(image.get_array().max() for image in images)
59+
norm = colors.Normalize(vmin=vmin, vmax=vmax)
60+
for im in images:
61+
im.set_norm(norm)
62+
1763

18-
fig, axs = plt.subplots(Nr, Nc)
19-
fig.suptitle('Multiple images')
64+
fig, axs = plt.subplots(nrows, ncols, sharex=True, sharey=True)
65+
fig.suptitle('Multiple images sharing a colorbar')
2066

2167
images = []
22-
for i in range(Nr):
23-
for j in range(Nc):
68+
for i in range(nrows):
69+
for j in range(ncols):
2470
# Generate data with a range that varies from one plot to the next.
25-
data = ((1 + i + j) / 10) * np.random.rand(10, 20) * 1e-6
71+
data = ((1 + i + j) / 10) * np.random.rand(11, 21) * 1e-6
2672
images.append(axs[i, j].imshow(data, cmap=cmap))
27-
axs[i, j].label_outer()
28-
29-
# Find the min and max of all colors for use in setting the color scale.
30-
vmin = min(image.get_array().min() for image in images)
31-
vmax = max(image.get_array().max() for image in images)
32-
norm = colors.Normalize(vmin=vmin, vmax=vmax)
33-
for im in images:
34-
im.set_norm(norm)
73+
normalize_images(images)
74+
fig.colorbar(images[0], ax=axs, orientation='horizontal', fraction=.06)
3575

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

77+
#############################################################################
78+
#
79+
# Dynamically adapting to changes of the norm and cmap
80+
# ----------------------------------------------------
81+
#
82+
# If the images norm or cmap can change later on (e.g. via the
83+
# "edit axis, curves and images parameters" GUI on Qt), one can propagate
84+
# these changes to all images by connecting to the 'changed' callback.
85+
#
86+
# Note: It's important to have the ``if`` statement to check whether there
87+
# are really changes to apply. Otherwise, you would run into an infinite
88+
# recursion with all images notifying each other infinitely.
3889

39-
# Make images respond to changes in the norm of other images (e.g. via the
40-
# "edit axis, curves and images parameters" GUI on Qt), but be careful not to
41-
# recurse infinitely!
4290
def update(changed_image):
4391
for im in images:
4492
if (changed_image.get_cmap() != im.get_cmap()
@@ -50,7 +98,6 @@ def update(changed_image):
5098
for im in images:
5199
im.callbacksSM.connect('changed', update)
52100

53-
plt.show()
54101

55102
#############################################################################
56103
#

0 commit comments

Comments
 (0)