Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DOC: colormap-manipulation tutorial #11905

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

Merged
merged 6 commits into from
Aug 25, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ per-file-ignores =
tutorials/advanced/transforms_tutorial.py: E402, E501
tutorials/colors/colormaps.py: E501
tutorials/colors/colors.py: E402
tutorials/colors/colormap-manipulation.py: E402
tutorials/intermediate/artists.py: E402, E501
tutorials/intermediate/constrainedlayout_guide.py: E402, E501
tutorials/intermediate/gridspec.py: E402, E501
Expand Down Expand Up @@ -114,6 +115,7 @@ per-file-ignores =
examples/color/color_demo.py: E402
examples/color/colorbar_basics.py: E402
examples/color/colormap_reference.py: E402
examples/color/custom_cmap.py: E402
examples/color/named_colors.py: E402
examples/event_handling/data_browser.py: E501
examples/event_handling/path_editor.py: E501
Expand All @@ -129,7 +131,6 @@ per-file-ignores =
examples/images_contours_and_fields/contourf_demo.py: E402, E501
examples/images_contours_and_fields/contourf_hatching.py: E402
examples/images_contours_and_fields/contourf_log.py: E402
examples/images_contours_and_fields/custom_cmap.py: E402
examples/images_contours_and_fields/demo_bboximage.py: E402
examples/images_contours_and_fields/image_clip_path.py: E402
examples/images_contours_and_fields/image_demo.py: E402
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Creating a colormap from a list of colors
=========================================

For more detail on creating and manipulating colormaps see
:doc:`/tutorials/colors/colormap-manipulation`.

Creating a :doc:`colormap </tutorials/colors/colormaps>`
from a list of colors can be done with the
:meth:`~.colors.LinearSegmentedColormap.from_list` method of
Expand Down
9 changes: 7 additions & 2 deletions lib/matplotlib/cm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
"""
Builtin colormaps, colormap handling utilities, and the `ScalarMappable` mixin.

See :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps.
See :doc:`/tutorials/colors/colormaps` for an in-depth discussion of colormaps.
- See :doc:`/gallery/color/colormap_reference` for a list of builtin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't indent bullet points. RestructuredText interprets this as a blockquote. This leads to over-indented bullet points in the HTML.

grafik

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem - shoudl this be a seealso::?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you could make this a seealso::.

If you switch to seealso:: the following is just for information: Make sure to write bullet lists exactly like this:

    Some paragraph:

    - Some long text that is continued on
      the next line.
    - Some other text.

    Normal paragraph again.
  1. No indent of the bullets with respect to the surronding paragraphs (that's fixed now).
  2. Continued bulleted lines have to have the text alinged with the text after the bullet (you had extra indentation here.
  3. There needs to be an empty line before and after the bullet list.

I know this is a bit picky, but that's how restructered text wants it.

colormaps.
- See :doc:`/tutorials/colors/colormaps` for an in-depth discussion of
choosing colormaps.
- See :doc:`/tutorials/colors/colormap-manipulation` for an in-depth
discussion of how to manipulate colormaps.

"""

import functools
Expand Down
27 changes: 19 additions & 8 deletions lib/matplotlib/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@

This module includes functions and classes for color specification
conversions, and for mapping numbers to colors in a 1-D array of colors called
a colormap. Colormapping typically involves two steps: a data array is first
mapped onto the range 0-1 using an instance of :class:`Normalize` or of a
subclass; then this number in the 0-1 range is mapped to a color using an
instance of a subclass of :class:`Colormap`. Two are provided here:
:class:`LinearSegmentedColormap`, which is used to generate all the built-in
colormap instances, but is also useful for making custom colormaps, and
:class:`ListedColormap`, which is used for generating a custom colormap from a
list of color specifications.
a colormap.

Mapping data onto colors using a colormap typically involves two steps:
a data array is first mapped onto the range 0-1 using a subclass of
:class:`Normalize`, then this number is mapped to a color using
a subclass of :class:`Colormap`. Two are provided here:
:class:`LinearSegmentedColormap`, which uses piecewise-linear interpolation
to define colormaps, and :class:`ListedColormap`, which makes a colormap
from a list of colors.

.. seealso::

:doc:`/tutorials/colors/colormap-manipulation` for examples of how to
make colormaps and

:doc:`/tutorials/colors/colormaps` for a list of built-in colormaps.

:doc:`/tutorials/colors/colormapnorms` for more details about data
normalization

The module also provides functions for checking whether an object can be
interpreted as a color (:func:`is_color_like`), for converting such an object
Expand Down
198 changes: 198 additions & 0 deletions tutorials/colors/colormap-manipulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
"""
********************************
Creating Colormaps in Matplotlib
********************************

Matplotlib colormaps are implimented as a class, which makes them quite
flexible, but opaque to users as to how to create and/or
manipulate them. This opacity is not helped in the library by the fact that
the named colormaps are accessed via `.matplotlib.cm.get_cmap` module, whereas
the colormap class itself is defined in `.matplotlib.colors.Colormap`!

Fortunately, the way to create colormaps is quite straight forward, by creating
an instance of class `.ListedColormap` using a Nx4 numpy array of values
between 0 and 1 to represent the RGBA values of the colormap.

Getting colormaps and accessing their values
============================================

First, getting a named colormap, most of which are listed in
:doc:`/tutorials/colors/colormaps` requires the use of
`.matplotlib.cm.get_cmap`, which returns a
:class:`.matplotlib.colors.ListedColormap` object. The second argument gives
the size of the list of colors used to define the colormap, and below we
use a modest value of 12 so there are not a lot of values to look at.
"""

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from collections import OrderedDict

viridis = cm.get_cmap('viridis', 12)
print(viridis)

##############################################################################
# The object ``viridis`` is a callable, that when passed a float between
# 0 and 1 returns an RGBA value from the colormap:

print(viridis(0.56))

##############################################################################
# The list of colors that comprise the colormap can be directly accessed using
# the ``colors`` property,
# or it can be acccessed indirectly by calling ``viridis`` with an array
# of values matching the length of the colormap. Note that the returned list
# is in the form of an RGBA Nx4 array, where N is the length of the colormap.

print('viridis.colors', viridis.colors)
print('viridis(range(12))', viridis(range(12)))
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))

##############################################################################
# The colormap is a lookup table, so "oversampling" the colormap returns
# nearest-neighbor interpolation (note the repeated colors in the list below)

print('viridis(np.linspace(0, 1, 15))', viridis(np.linspace(0, 1, 15)))

##############################################################################
# Creating a new ListedColormap
# =============================
#
# This is essential the inverse operation of the above where we supply a
# Nx4 numpy array with all values between 0 and 1,
# to `.ListedColormap` to make a new colormap. This means that
# any numpy operations that we can do on a Nx4 array make carpentry of
# new colormaps from existing colormaps quite straight forward.
#
# Suppose we want to make the first 25 entries of a 256-length "viridis"
# colormap pink for some reason:

viridis = cm.get_cmap('viridis', 256)
newcolors = viridis(np.linspace(0, 1, 256))
pink = np.array([248/256, 24/256, 148/256, 1])
newcolors[:25, :] = pink
newcmp = ListedColormap(newcolors)


def plot_examples(cms):
"""
helper function to plot two colormaps
"""
np.random.seed(19680801)
data = np.random.randn(30, 30)

fig, axs = plt.subplots(1, 2, figsize=(6, 3), constrained_layout=True)
for [ax, cmap] in zip(axs, cms):
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
fig.colorbar(psm, ax=ax)
plt.show()

plot_examples([viridis, newcmp])

##############################################################################
# We can easily reduce the range of a colormap; here we choose the middle
# 0.5 of the colormap.

viridis = cm.get_cmap('viridis', 256)
newcmp = ListedColormap(viridis(np.linspace(0.25, 0.75, 256)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this have over-sampling issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, yes it will. Not really noticeable at 256 resolution, but would certainly be a problem for small colormaps. Changed to

# We can easily reduce the dynamic range of a colormap; here we choose the middle
# 0.5 of the colormap.  However, we need to interpolate from a larger
# colormap, otherwise the new colormap will have repeated values.

viridisBig = cm.get_cmap('viridis', 512)
newcmp = ListedColormap(viridisBig(np.linspace(0.25, 0.75, 256)))
plot_examples([viridis, newcmp])

plot_examples([viridis, newcmp])

##############################################################################
# and we can easily concatenate two colormaps:

top = cm.get_cmap('Oranges_r', 128)
bottom = cm.get_cmap('Blues', 128)

newcolors = np.vstack((top(np.linspace(0, 1, 128)),
bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plot_examples([viridis, newcmp])

##############################################################################
# Of course we need not start from a named colormap, we just need to create
# the Nx4 array to pass to `.ListedColormap`. Here we create a
# brown colormap that goes to white....

N = 256
vals = np.ones((N, 4))
vals[:, 0] = np.linspace(90/256, 1, N)
vals[:, 1] = np.linspace(39/256, 1, N)
vals[:, 2] = np.linspace(41/256, 1, N)
newcmp = ListedColormap(vals)
plot_examples([viridis, newcmp])

##############################################################################
# LinearSegmented colormaps
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Would call this "Creating a new LinearSegmentedColormap" in resemblence to "Creating a new ListedColormap".

  2. Not sure if we need the "new" in the title.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retitled

# =========================
#
# `.LinearSegmentedColormap` have an alternate way to specify colormaps that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative wording:

LinearSegmentedColormap specifies the colors using anchor points. The RGB(A) color values for positions in between the anchor points are linearly interpolated from the anchor point RGB(A) values.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewritten...

# specify anchor points for linear ramps for each of RGB, and optionally, alpha
# (RGBA).
#
# The format to specify these colormaps is a bit complicated to allow
# discontinuities at the anchor points. First, with no discontinuities:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the format needs a description here, or at least a "See LinearSegmentedColormap for a description of the format."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new version describes the format.


cdict = {'red': [[0.0, 0.0, 0.0],
[0.5, 1.0, 1.0],
[1.0, 1.0, 1.0]],
'green': [[0.0, 0.0, 0.0],
[0.25, 0.0, 0.0],
[0.75, 1.0, 1.0],
[1.0, 1.0, 1.0]],
'blue': [[0.0, 0.0, 0.0],
[0.5, 0.0, 0.0],
[1.0, 1.0, 1.0]]}


def plot_linearmap(cdict):
newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
rgba = newcmp(np.linspace(0, 1, 256))
fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
col = ['r', 'g', 'b']
for xx in [0.25, 0.5, 0.75]:
ax.axvline(xx, color='0.7', linestyle='--')
for i in range(3):
ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
ax.set_xlabel('index')
ax.set_ylabel('RGB')
plt.show()

plot_linearmap(cdict)

#############################################################################
# However, consider the case where the third column is different than the
# second. The linear interpolation between red[i, 0] and red[i+1, 0] is
# from red[i, 2] to red[i+1, 1]. This format allows us to have
# discontinuities in the colormap at the anchor points; in this case
# between 0 and 0.5, the linear interpolation goes from 0.3 to 1, and
# between 0.5 and 1 it goes from 0.9 to 1. Note that red[0, 1], and red[2, 2]
# are both superfluous to the interpolation, which happens between the last
# element of the first anchor and the first element of the second anchor.

cdict['red'] = [[0.0, 0.0, 0.3],
[0.5, 1.0, 0.9],
[1.0, 1.0, 1.0]]
plot_linearmap(cdict)


#############################################################################
#
# ------------
#
# References
# """"""""""
#
# The use of the following functions, methods, classes and modules is shown
# in this example:

import matplotlib
matplotlib.axes.Axes.pcolormesh
matplotlib.figure.Figure.colorbar
matplotlib.colors
matplotlib.colors.LinearSegmentedColormap
matplotlib.colors.ListedColormap
matplotlib.cm
matplotlib.cm.get_cmap