DOC: draft of a full explanation of norm + colormap interactions #18487
Conversation
80b7c57
to
9d22732
| scaled = (resampled - .1) * (data_max - data_min) + data_min | ||
|
|
||
| For "most" user data is OK, but can fail in interesting ways. First, | ||
| if range of the input data is large, but the range the user actually |
jpivarski
Oct 7, 2020
"if the range"
"if the range"
|
So far, it looks like this includes pretty useful info at good places in the docs. However, I suggest being more colloquial. I guess you could describe a colormap as a 1-D path through R^3 space, but maybe "a list of N colors specified as RGB" will be more accessible? It took me a while to understand what you were trying to say, and my undergrad degree was Mathematics and Physics, albeit a few years ago ;-) |
| the data <sphx_glr_tutorials_colors_colormaps.py>` but in general | ||
| "good" colormaps smoothly and continuously change their RGB values as | ||
| a function of the input data. By looking at the RGB values as we go | ||
| through the full range of the user data (e.g. a colorbar) we can trace |
QuLogic
Oct 8, 2020
Member
Not sure what a colorbar has to do with this sentence.
Not sure what a colorbar has to do with this sentence.
story645
Oct 9, 2020
Member
Also the "good" in parenthesis is probably a stand in for some precise term and otherwise not true for categorical data and questionable on discrete data.
Also the "good" in parenthesis is probably a stand in for some precise term and otherwise not true for categorical data and questionable on discrete data.
| max of the data are drastically different than the vmin / vmax of the | ||
| norm we use a data range expanded from vmin/vmax in the rescaling. |
QuLogic
Oct 8, 2020
Member
This sentence kind of runs on.
This sentence kind of runs on.
| class in `~.cm` and the `~.Normalize` and `~.Colormap` classes in | ||
| `~.colors` (this module). | ||
|
|
||
| At the core, colormapping is going from a scalar value to a RGB tuple |
jklymak
Oct 8, 2020
Contributor
I still feel this is more complicated than it needs to be, and not even particularly true if you want to be mathematically rigorous; colormaps are finite discrete ordered points in R^3, not a smooth curve or path, so I find taking about it like this distracting. The first step is normalizing the data between vmin and vmax to the range 0-1, perhaps using a non-linear function, and secondly, using a linear lookup table to find the RGBA color closest to that value between 0 and 1.
I still feel this is more complicated than it needs to be, and not even particularly true if you want to be mathematically rigorous; colormaps are finite discrete ordered points in R^3, not a smooth curve or path, so I find taking about it like this distracting. The first step is normalizing the data between vmin and vmax to the range 0-1, perhaps using a non-linear function, and secondly, using a linear lookup table to find the RGBA color closest to that value between 0 and 1.
jklymak
Oct 8, 2020
•
Contributor
I always like code examples to make the abstract concrete:
A color mapping from floating point data values to colors takes place in two steps.
First the data is normalized between 0 and 1. This requires a `vmin` and `vmax` the define
which values are mapped to 0 and 1, respectively, and it requires a function that defines the
mapping between these two values. The simplest case is a linear map ::
import matplotlib.colors as mcolors
norm = mcolors.Normalize(vmin=100, vmax=300)
norm([100, 200, 300]) # returns 0.0, 0.5, 1.0
but a logarithmic norm is also possible ::
norm = mcolors.LogNorm(vmin=10, vmax=1000)
norm([10, 100, 1000]) # returns 0.0, 0.5, 1.0
Once the data has been normalized between 0 and 1, it can be passed to a colormap
to return RGB(A) values ::
cmap = cm.viridis
cmap([0.0, 0.5, 1.0])
# returns RGBA array with the first three colors of viridis colormap.
# array([[0.267004, 0.004874, 0.329415, 1. ],
# [0.127568, 0.566949, 0.550556, 1. ],
# [0.993248, 0.906157, 0.143936, 1. ]])
I always like code examples to make the abstract concrete:
A color mapping from floating point data values to colors takes place in two steps.
First the data is normalized between 0 and 1. This requires a `vmin` and `vmax` the define
which values are mapped to 0 and 1, respectively, and it requires a function that defines the
mapping between these two values. The simplest case is a linear map ::
import matplotlib.colors as mcolors
norm = mcolors.Normalize(vmin=100, vmax=300)
norm([100, 200, 300]) # returns 0.0, 0.5, 1.0
but a logarithmic norm is also possible ::
norm = mcolors.LogNorm(vmin=10, vmax=1000)
norm([10, 100, 1000]) # returns 0.0, 0.5, 1.0
Once the data has been normalized between 0 and 1, it can be passed to a colormap
to return RGB(A) values ::
cmap = cm.viridis
cmap([0.0, 0.5, 1.0])
# returns RGBA array with the first three colors of viridis colormap.
# array([[0.267004, 0.004874, 0.329415, 1. ],
# [0.127568, 0.566949, 0.550556, 1. ],
# [0.993248, 0.906157, 0.143936, 1. ]])
tacaswell
Oct 8, 2020
Author
Member
We use discrete colormaps as an implementation detail (both for performance and because we are targeting 8bit RGB which is inherently discrete), but if we had infinite precision floats and an analytic function for the colormap the whole system would still hold together.
I think the correct solution is to include both versions :)
We use discrete colormaps as an implementation detail (both for performance and because we are targeting 8bit RGB which is inherently discrete), but if we had infinite precision floats and an analytic function for the colormap the whole system would still hold together.
I think the correct solution is to include both versions :)
This make it clearer that we only need this in one of the code paths and avoids creating the un-used ScalarMappable in the png savefig code path.
Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
55c6446
to
cbe0c6e
PR Summary
This is the start of the documentation I said I would write on the call about float issues in resampling / normalizing / colormapping images, but I got distracted making sure that we had this well documented.
The text at https://matplotlib.org/3.3.1/tutorials/colors/colormapnorms.html is correct, but terse. The code at https://matplotlib.org/3.3.1/gallery/userdemo/colormap_normalizations.html is almost the same but even less text. https://matplotlib.org/3.3.1/tutorials/colors/colormaps.html is mostly about how to pick the right color map, and https://matplotlib.org/3.3.1/tutorials/colors/colormap-manipulation.html is about working with colormap objects once you have them.
I think the second one should probably go away and the first should link back to this new text.