2
2
``matplotlib.image ``
3
3
********************
4
4
5
- .. currentmodule :: matplotlib.image
6
-
7
5
.. automodule :: matplotlib.image
8
6
:no-members:
9
7
:no-inherited-members:
@@ -42,21 +40,107 @@ resampling process can introduce a variety of artifacts and the
42
40
default interpolation is chosen to avoid aliasis in common cases (see
43
41
:doc: `/gallery/images_contours_and_fields/image_antialiasing `).
44
42
45
- Floating point and you
46
- ----------------------
43
+ Colormapping
44
+ ~~~~~~~~~~~~
47
45
48
46
The processing steps for rendering a pseudo color image are:
49
47
50
48
1. rasample to user input to the required dimensions
51
49
2. normalize the user data via a `~.colors.Normalize ` instance
52
- 3. color map from the normalized data to RGBA via a `~.colors.ColorMap ` instance
50
+ 3. colormap from the normalized data to RGBA via a `~.colors.Colormap ` instance
51
+
52
+ Prior to Matplotlib 2.0 we did the normalization and colormapping
53
+ first and then resampled to fit the screen. However this can produce
54
+ artifacts in the visualization when the data is changing close to the
55
+ full range on the scale of a few pixels with most colormaps due to the
56
+ interpolation in RGB space producing colors that are not in the
57
+ colormap.
58
+
59
+
60
+ Floating point and you
61
+ ~~~~~~~~~~~~~~~~~~~~~~
62
+
63
+ Floating point numbers, despite being ubiquitous, are not fully
64
+ understood by most practitioners. For a through review of how
65
+ floating point numbers work see `Goldberg, ACM Computing
66
+ Surveys (1991) 10.1145/103162.103163
67
+ <https://doi.org/10.1145/103162.103163> `__ or the `IEEE Standard for
68
+ Floating Point Arithmetic ( IEEE std 754) 10.1109/IEEESTD.2008.4610935
69
+ <https://doi.org/10.1109/IEEESTD.2008.4610935> `__ (both behind
70
+ paywalls). For the purposes of this discussion we need to know:
71
+
72
+ 1. There are only a finite number "floating point numbers" (that is
73
+ values that can be represented by a IEEE float in the computer) and
74
+ hence can not exactly represent all Real Numbers. Between those
75
+ two Real Numbers there is an infinite number of Real numbers, hence
76
+ the floating point numbers and computation expressed in a computer
77
+ are an approximation of the Real Numbers.
78
+ 2. The absolute distance between adjacent floating point numbers
79
+ scales with the magnitude, while the relative distance remains
80
+ the same. This is a consequence of the implementation of IEEE
81
+ floats.
82
+ 3. During computation results are rounded to the nearest
83
+ represent-able value. Working with numbers that are either almost
84
+ identical or vastly different orders of magnitude exasperates the
85
+ errors due to this rounding.
86
+
87
+ This is relevant to images because, as an implementation detail, we
88
+ make use of the GAG library to do the resampling from the data space
89
+ to screen space and that code clips all input values to the range
90
+ :math: `[0 , 1 ]`. In addition to the mapping the colors "in range" we also
91
+ map over, under, and bad values (see :ref: `norms_and_colormaps `) which need to be
92
+ preserved through the resampling process. Thus, we:
93
+
94
+ 1. scale the data to :math: `[.1 , .9 ]`
95
+ 2. pass the data to AGG to resample the pixels
96
+ 3. scale back to the original data range
97
+
98
+ and then resume going through the user supplied normalization and colormap.
99
+
100
+ Naively, this could be expressed as ::
101
+
102
+ data_min, data_max = data.min, data.max
103
+ # scale to [.1, .9]
104
+ rescaled = .1 + .8 * (data - data_min) / (data_max - data_min)
105
+ # get the correct number of pixels
106
+ resampled = resample(scaled)
107
+ # scale back to original data range
108
+ scaled = (resampled - .1) * (data_max - data_min) + data_min
109
+
110
+ For "most" user data is OK, but can fail in interesting ways. First,
111
+ if range of the input data is large, but the range the user actually
112
+ cares about is small this will effectively map all of the interesting
113
+ data to the same value! To counter act this, we have a check min /
114
+ max of the data are drastically different than the vmin / vmax of the
115
+ norm we use a data range expanded from vmin/vmax in the rescaling.
116
+ This was addressed in and :ghissue: `10072 `, :ghpull: `10133 `, and
117
+ :ghpull: `11047 `.
118
+
119
+ The second is that due floating point math being an approximation of
120
+ the exact infinite precision computation not all values "round trip"
121
+ identically. This cause the rescaling to move values in the input
122
+ data that are very close to the values of vmin or vmax to the other
123
+ side. In the default case, when the over and under colors are equal
124
+ to the top and bottom colors of the colormap respectively this is not
125
+ visually apparent, however if the user sets a different color for
126
+ over/under this is extremely apparent. The solution is to also
127
+ rescale the vmin and vmax values. Despite accumulating errors, the
128
+ float operations will preserve the relative ordering of values under
129
+ :math: `\geq ` and :math: `\leq `. This was reported in :ghissue: `16910 ` and
130
+ fixed in :ghpull: `17636 `.
131
+
132
+ The third issue we had was that due to rescaling the vmin and vmax,
133
+ under certain conditions the sign of the vmin may change. In the case
134
+ of a linear `~.colors.Normalize ` this is not a problem, but in the case of a
135
+ `~.colors.LogNorm ` we check that both vmin and vmax are greater than 0. This
136
+ was reported in :ghissue: `18415 ` and fixed in :ghpull: `18458 ` by
137
+ special casing `~.colors.LogNorm ` and clipping vmin to be greater than 0.
53
138
54
- Prior to Matplotlib 2.0 we re
55
139
56
140
57
141
58
142
Helper functions
59
- ~~~~~~~~~~~~~~~~
143
+ ----------------
60
144
61
145
62
146
@@ -75,8 +159,8 @@ Image I/O functions
75
159
76
160
This functions can be used to read, save, and generate thumbnails of
77
161
files on disk. These are here for historical reasons, and while it is
78
- unlikely we will remove them, please prefer to use a dedicated image
79
- I/O library (such as `imageio <https://imageio.github.io/ >`__, `pillow
162
+ unlikely we will remove them, please use a dedicated image I/O library
163
+ (such as `imageio <https://imageio.github.io/ >`__, `pillow
80
164
<https://pillow.readthedocs.io/en/stable/> `__, or `tifffile
81
165
<https://pypi.org/project/tifffile/> `__) instead.
82
166
0 commit comments