1
1
"""
2
- ===============
3
- Multiple images
4
- ===============
2
+ =================================
3
+ Multiple images with one colorbar
4
+ =================================
5
5
6
- Make a set of images with a single colormap, norm, and colorbar.
6
+ Use a single colorbar for multiple images.
7
+
8
+ Currently, a colorbar can only be connected to one image. The connection
9
+ guarantees that the data coloring is consistent with the colormap scale
10
+ (i.e. the color of value *x* in the colormap is used for coloring a data
11
+ value *x* in the image).
12
+
13
+ If we want one colorbar to be representative for multiple images, we have
14
+ to explicitly ensure consistent data coloring. The most important aspect
15
+ is the data normalization. By explicitly creating a norm and using that
16
+ for all images, we ensure that all images are scaled consistently.
7
17
"""
8
18
9
19
import matplotlib .pyplot as plt
12
22
from matplotlib import colors
13
23
14
24
np .random .seed (19680801 )
15
- Nr = 3
16
- Nc = 2
17
25
18
- fig , axs = plt .subplots (Nr , Nc )
26
+ datasets = [
27
+ (i + 1 )/ 10 * np .random .rand (10 , 20 )
28
+ for i in range (4 )
29
+ ]
30
+
31
+ fig , axs = plt .subplots (2 , 2 )
19
32
fig .suptitle ('Multiple images' )
20
33
21
- images = []
22
- for i in range (Nr ):
23
- for j in range (Nc ):
24
- # Generate data with a range that varies from one plot to the next.
25
- data = ((1 + i + j ) / 10 ) * np .random .rand (10 , 20 )
26
- images .append (axs [i , j ].imshow (data ))
27
- axs [i , j ].label_outer ()
34
+ # create a single norm to be shared across all images
35
+ norm = colors .Normalize (vmin = np .min (datasets ), vmax = np .max (datasets ))
28
36
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 )
37
+ images = []
38
+ for ax , data in zip (axs .flat , datasets ):
39
+ images .append (ax .imshow (data , norm = norm ))
35
40
36
41
fig .colorbar (images [0 ], ax = axs , orientation = 'horizontal' , fraction = .1 )
37
42
38
-
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!
42
- def update (changed_image ):
43
- for im in images :
44
- if (changed_image .get_cmap () != im .get_cmap ()
45
- or changed_image .get_clim () != im .get_clim ()):
46
- im .set_cmap (changed_image .get_cmap ())
47
- im .set_clim (changed_image .get_clim ())
48
-
49
-
50
- for im in images :
51
- im .callbacks .connect ('changed' , update )
52
-
53
43
plt .show ()
54
44
55
45
# %%
46
+ # The colors are now kept consistent across all images when changing the
47
+ # scaling, e.g. through zooming in the colorbar or via the "edit axis,
48
+ # curves and images parameters" GUI of the Qt backend. This is sufficient
49
+ # for most practical use cases.
50
+ #
51
+ # Advanced: Additionally sync the colormap
52
+ # ----------------------------------------
53
+ #
54
+ # While the norm is shared in the above example, the colormaps are not:
55
+ # Each image holds an independent reference to the colormap it wants to
56
+ # use. We implicitly rely on all images using the same colormap. This is
57
+ # often ok because colormaps are usually not changed dynamically. However,
58
+ # a user could change the colormap of an individual image through the
59
+ # "edit axis, curves and images parameters" GUI of the Qt backend.
60
+ # Unlike with a norm, it does not help to share colormaps between images.
61
+ # Changes to the norm limits modify the norm object in place and thus
62
+ # propagate to all images. But changing a colormap sets a new colormap
63
+ # object to the images and thus does not propagate to the other images.
64
+ # To make all other images follow, you could additionally sync the
65
+ # colormaps using the following code::
66
+ #
67
+ # def sync_cmaps(changed_image):
68
+ # for im in images:
69
+ # if changed_image.get_cmap() != im.get_cmap():
70
+ # im.set_cmap(changed_image.get_cmap())
71
+ #
72
+ # for im in images:
73
+ # im.callbacks.connect('changed', sync_cmaps)
74
+ #
56
75
#
57
76
# .. admonition:: References
58
77
#
@@ -63,6 +82,4 @@ def update(changed_image):
63
82
# - `matplotlib.figure.Figure.colorbar` / `matplotlib.pyplot.colorbar`
64
83
# - `matplotlib.colors.Normalize`
65
84
# - `matplotlib.cm.ScalarMappable.set_cmap`
66
- # - `matplotlib.cm.ScalarMappable.set_norm`
67
- # - `matplotlib.cm.ScalarMappable.set_clim`
68
85
# - `matplotlib.cbook.CallbackRegistry.connect`
0 commit comments