Skip to content
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

DOC: draft of a full explanation of norm + colormap interactions #18487

Open
wants to merge 11 commits into
base: master
from

Conversation

@tacaswell
Copy link
Member

@tacaswell tacaswell commented Sep 15, 2020

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.

@tacaswell tacaswell added this to the v3.4.0 milestone Sep 15, 2020
@story645 story645 self-assigned this Sep 15, 2020
@tacaswell tacaswell force-pushed the tacaswell:doc_floating_point_and_you branch 2 times, most recently from 80b7c57 to 9d22732 Oct 7, 2020
@tacaswell tacaswell marked this pull request as ready for review Oct 7, 2020
@tacaswell tacaswell requested review from jklymak and anntzer and removed request for anntzer Oct 7, 2020
doc/api/image_api.rst Outdated Show resolved Hide resolved
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

This comment has been minimized.

@jpivarski

jpivarski Oct 7, 2020

"if the range"

@jklymak
Copy link
Contributor

@jklymak jklymak commented Oct 7, 2020

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 ;-)

doc/api/colors_api.rst Outdated Show resolved Hide resolved
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

This comment has been minimized.

@QuLogic

QuLogic Oct 8, 2020
Member

Not sure what a colorbar has to do with this sentence.

This comment has been minimized.

@story645

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.

doc/api/colors_api.rst Outdated Show resolved Hide resolved
doc/api/colors_api.rst Outdated Show resolved Hide resolved
doc/api/colors_api.rst Outdated Show resolved Hide resolved
doc/api/image_api.rst Outdated Show resolved Hide resolved
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.
Comment on lines +114 to +118

This comment has been minimized.

@QuLogic

QuLogic Oct 8, 2020
Member

This sentence kind of runs on.

doc/api/image_api.rst Outdated Show resolved Hide resolved
doc/api/image_api.rst Outdated Show resolved Hide resolved
doc/api/image_api.rst Outdated Show resolved Hide resolved
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

This comment has been minimized.

@jklymak

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.

This comment has been minimized.

@jklymak

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.      ]])

This comment has been minimized.

@tacaswell

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 :)

tacaswell and others added 11 commits Sep 20, 2020
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>
@tacaswell tacaswell force-pushed the tacaswell:doc_floating_point_and_you branch from 55c6446 to cbe0c6e Oct 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
You can’t perform that action at this time.