ASKSAGE: Sage Q&A Forum - RSS feedhttps://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Wed, 22 Dec 2010 03:21:34 +0100Specific cmaphttps://ask.sagemath.org/question/7825/specific-cmap/Hello,
How would I create a specific cmap, which would have a separate color value for each matrix value? For example, could I make a cmap that specifies 0:'red', 1:'green', 2:'yellow', etc? The linear interpolation cmaps don't work as I want them to because they normalize to the given range of the matrix.
Thank you.Mon, 20 Dec 2010 00:18:36 +0100https://ask.sagemath.org/question/7825/specific-cmap/Answer by Jason Grout for <p>Hello,</p>
<p>How would I create a specific cmap, which would have a separate color value for each matrix value? For example, could I make a cmap that specifies 0:'red', 1:'green', 2:'yellow', etc? The linear interpolation cmaps don't work as I want them to because they normalize to the given range of the matrix.</p>
<p>Thank you.</p>
https://ask.sagemath.org/question/7825/specific-cmap/?answer=11888#post-id-11888You might check out the ``norm`` option to ``matrix_plot`` (see [the docs](http://www.sagemath.org/doc/reference/sage/plot/matrix_plot.html#sage.plot.matrix_plot.matrix_plot)), which takes a ``value`` argument that does away with scaling before applying a colormap. You can also specify a function that does the colormapping. See also the matplotlib [documentation](http://matplotlib.sourceforge.net/api/colors_api.html) for colormaps and the normalizing functions.Wed, 22 Dec 2010 03:21:34 +0100https://ask.sagemath.org/question/7825/specific-cmap/?answer=11888#post-id-11888Answer by kcrisman for <p>Hello,</p>
<p>How would I create a specific cmap, which would have a separate color value for each matrix value? For example, could I make a cmap that specifies 0:'red', 1:'green', 2:'yellow', etc? The linear interpolation cmaps don't work as I want them to because they normalize to the given range of the matrix.</p>
<p>Thank you.</p>
https://ask.sagemath.org/question/7825/specific-cmap/?answer=11881#post-id-11881Well, after writing this, I finally found out that we have this capability, though there are no examples in the `matrix_plot` doc (though it's mentioned).
sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=['red','green','blue'])
This relies on `get_cmap`, a very nice utility I had forgotten about! Read this:
sage: sage.plot.matrix_plot.get_cmap?
Still, I'll put some other interesting resources I found below, in case that is too easy, or you need more direction for how to create good colormaps..
[Here](http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps) is an example of how this might be done in pure Python, and [here](http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations) is a nice way to 'discretize' colormaps.
Now, these don't do exactly what you want, because the colormaps seem to mostly operate on the principle of the interval $(0,1)$. If we do
sage: import matplotlib
sage: matplotlib.colors?
A module for converting numbers or color arguments to *RGB* or *RGBA*
*RGB* and *RGBA* are sequences of, respectively, 3 or 4 floats in the
range 0-1.
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
``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 ``Colormap``.
Two are provided here: ``LinearSegmentedColormap``, which is used to
generate all the built-in colormap instances, but is also useful for
making custom colormaps, and ``ListedColormap``, which is used for
generating a custom colormap from a list of color specifications.
So here is something that might work:
sage: import matplotlib
sage: M = matplotlib.colors.ListedColormap([(0,1,1),(1,0,1),(1,1,0)],'M')
sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=M)
Mon, 20 Dec 2010 09:20:27 +0100https://ask.sagemath.org/question/7825/specific-cmap/?answer=11881#post-id-11881Comment by kcrisman for <p>Well, after writing this, I finally found out that we have this capability, though there are no examples in the <code>matrix_plot</code> doc (though it's mentioned). </p>
<pre><code>sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=['red','green','blue'])
</code></pre>
<p>This relies on <code>get_cmap</code>, a very nice utility I had forgotten about! Read this:</p>
<pre><code>sage: sage.plot.matrix_plot.get_cmap?
</code></pre>
<p>Still, I'll put some other interesting resources I found below, in case that is too easy, or you need more direction for how to create good colormaps..</p>
<p><a href="http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps">Here</a> is an example of how this might be done in pure Python, and <a href="http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations">here</a> is a nice way to 'discretize' colormaps. </p>
<p>Now, these don't do exactly what you want, because the colormaps seem to mostly operate on the principle of the interval $(0,1)$. If we do</p>
<pre><code>sage: import matplotlib
sage: matplotlib.colors?
A module for converting numbers or color arguments to *RGB* or *RGBA*
*RGB* and *RGBA* are sequences of, respectively, 3 or 4 floats in the
range 0-1.
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
``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 ``Colormap``.
Two are provided here: ``LinearSegmentedColormap``, which is used to
generate all the built-in colormap instances, but is also useful for
making custom colormaps, and ``ListedColormap``, which is used for
generating a custom colormap from a list of color specifications.
</code></pre>
<p>So here is something that might work:</p>
<pre><code>sage: import matplotlib
sage: M = matplotlib.colors.ListedColormap([(0,1,1),(1,0,1),(1,1,0)],'M')
sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=M)
</code></pre>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22379#post-id-22379And I do not believe matplotlib allows one to associate specific numbers with colors, only the range. The type of cmap this provides is discrete, though, so hopefully it should be good enough if you know what values to expect ahead of time. If that is random, you may have to generate the cmap on the fly. The links provided are just some of some great posts and explanations I found on the matplotlib and Scipy websites, so hopefully you'll find what you need if this isn't it.Mon, 20 Dec 2010 09:26:14 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22379#post-id-22379Comment by Eviatar Bach for <p>Well, after writing this, I finally found out that we have this capability, though there are no examples in the <code>matrix_plot</code> doc (though it's mentioned). </p>
<pre><code>sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=['red','green','blue'])
</code></pre>
<p>This relies on <code>get_cmap</code>, a very nice utility I had forgotten about! Read this:</p>
<pre><code>sage: sage.plot.matrix_plot.get_cmap?
</code></pre>
<p>Still, I'll put some other interesting resources I found below, in case that is too easy, or you need more direction for how to create good colormaps..</p>
<p><a href="http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps">Here</a> is an example of how this might be done in pure Python, and <a href="http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations">here</a> is a nice way to 'discretize' colormaps. </p>
<p>Now, these don't do exactly what you want, because the colormaps seem to mostly operate on the principle of the interval $(0,1)$. If we do</p>
<pre><code>sage: import matplotlib
sage: matplotlib.colors?
A module for converting numbers or color arguments to *RGB* or *RGBA*
*RGB* and *RGBA* are sequences of, respectively, 3 or 4 floats in the
range 0-1.
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
``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 ``Colormap``.
Two are provided here: ``LinearSegmentedColormap``, which is used to
generate all the built-in colormap instances, but is also useful for
making custom colormaps, and ``ListedColormap``, which is used for
generating a custom colormap from a list of color specifications.
</code></pre>
<p>So here is something that might work:</p>
<pre><code>sage: import matplotlib
sage: M = matplotlib.colors.ListedColormap([(0,1,1),(1,0,1),(1,1,0)],'M')
sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=M)
</code></pre>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22375#post-id-22375This fits my needs if normalized, but since user input will not necessarily be in order, the other solution works better.Mon, 20 Dec 2010 20:09:04 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22375#post-id-22375Comment by kcrisman for <p>Well, after writing this, I finally found out that we have this capability, though there are no examples in the <code>matrix_plot</code> doc (though it's mentioned). </p>
<pre><code>sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=['red','green','blue'])
</code></pre>
<p>This relies on <code>get_cmap</code>, a very nice utility I had forgotten about! Read this:</p>
<pre><code>sage: sage.plot.matrix_plot.get_cmap?
</code></pre>
<p>Still, I'll put some other interesting resources I found below, in case that is too easy, or you need more direction for how to create good colormaps..</p>
<p><a href="http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps">Here</a> is an example of how this might be done in pure Python, and <a href="http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations">here</a> is a nice way to 'discretize' colormaps. </p>
<p>Now, these don't do exactly what you want, because the colormaps seem to mostly operate on the principle of the interval $(0,1)$. If we do</p>
<pre><code>sage: import matplotlib
sage: matplotlib.colors?
A module for converting numbers or color arguments to *RGB* or *RGBA*
*RGB* and *RGBA* are sequences of, respectively, 3 or 4 floats in the
range 0-1.
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
``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 ``Colormap``.
Two are provided here: ``LinearSegmentedColormap``, which is used to
generate all the built-in colormap instances, but is also useful for
making custom colormaps, and ``ListedColormap``, which is used for
generating a custom colormap from a list of color specifications.
</code></pre>
<p>So here is something that might work:</p>
<pre><code>sage: import matplotlib
sage: M = matplotlib.colors.ListedColormap([(0,1,1),(1,0,1),(1,1,0)],'M')
sage: matrix_plot(matrix([[0,1],[1,2]]),cmap=M)
</code></pre>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22380#post-id-22380See also http://trac.sagemath.org/sage_trac/ticket/10503Mon, 20 Dec 2010 09:23:40 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22380#post-id-22380Answer by DSM for <p>Hello,</p>
<p>How would I create a specific cmap, which would have a separate color value for each matrix value? For example, could I make a cmap that specifies 0:'red', 1:'green', 2:'yellow', etc? The linear interpolation cmaps don't work as I want them to because they normalize to the given range of the matrix.</p>
<p>Thank you.</p>
https://ask.sagemath.org/question/7825/specific-cmap/?answer=11882#post-id-11882I seem to recall once having a slick workaround for this but for the life of me I can't find it now. Anyway, something like this should get the job done:
<pre><code># preamble
import matplotlib
# choose our preferred colour scheme, where None describes the exceptions
cdict = {0: 'red', 1: 'green', 2:'yellow', 3:'orange', 43+2*I: 'brown', None: 'purple'}
# choose some fixed order -- doesn't matter what -- for iterating the keys
ckeys, cvals = zip(*cdict.items())
# build a mapping function to turn the matrix elements into integers
# (would be faster to use a dict for lots of colours)
cmap_fn = lambda x: Integer(ckeys.index(x if x in cdict else None))
# generate a colormap with exactly the colours we want, in the right order
my_cmap = matplotlib.colors.ListedColormap(cvals)
# generate a test matrix
m = Matrix(lambda i,j: (i+j) if (i,j) != (6,6) else 43+2*I, nrows=10)
# plot it: apply the mapping function to the matrix and feed matrix_plot our colour map
matrix_plot(m.apply_map(cmap_fn), cmap=my_cmap)
</code>
</pre>
This should generate one very ugly graph: one red cell, two green cells, three yellow cells, four orange cells, and a brown cell at (6,6) in a purple sea. It's easy to bundle this into a function if you find yourself doing it frequently.
[update: modified to make it slightly more general: now you don't need any ordering relation defined on the matrix elements]Mon, 20 Dec 2010 09:32:26 +0100https://ask.sagemath.org/question/7825/specific-cmap/?answer=11882#post-id-11882Comment by kcrisman for <p>I seem to recall once having a slick workaround for this but for the life of me I can't find it now. Anyway, something like this should get the job done:</p>
<pre><code># preamble
import matplotlib
# choose our preferred colour scheme, where None describes the exceptions
cdict = {0: 'red', 1: 'green', 2:'yellow', 3:'orange', 43+2*I: 'brown', None: 'purple'}
# choose some fixed order -- doesn't matter what -- for iterating the keys
ckeys, cvals = zip(*cdict.items())
# build a mapping function to turn the matrix elements into integers
# (would be faster to use a dict for lots of colours)
cmap_fn = lambda x: Integer(ckeys.index(x if x in cdict else None))
# generate a colormap with exactly the colours we want, in the right order
my_cmap = matplotlib.colors.ListedColormap(cvals)
# generate a test matrix
m = Matrix(lambda i,j: (i+j) if (i,j) != (6,6) else 43+2*I, nrows=10)
# plot it: apply the mapping function to the matrix and feed matrix_plot our colour map
matrix_plot(m.apply_map(cmap_fn), cmap=my_cmap)
</code>
</pre>
<p>This should generate one very ugly graph: one red cell, two green cells, three yellow cells, four orange cells, and a brown cell at (6,6) in a purple sea. It's easy to bundle this into a function if you find yourself doing it frequently.</p>
<p>[update: modified to make it slightly more general: now you don't need any ordering relation defined on the matrix elements]</p>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22372#post-id-22372I've updated the relevant ticket to put this as an enhancement. DSM may want to put his/her real name on there to get some credit if this ever makes it into Sage, which seems like a good idea.Tue, 21 Dec 2010 09:04:18 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22372#post-id-22372Comment by DSM for <p>I seem to recall once having a slick workaround for this but for the life of me I can't find it now. Anyway, something like this should get the job done:</p>
<pre><code># preamble
import matplotlib
# choose our preferred colour scheme, where None describes the exceptions
cdict = {0: 'red', 1: 'green', 2:'yellow', 3:'orange', 43+2*I: 'brown', None: 'purple'}
# choose some fixed order -- doesn't matter what -- for iterating the keys
ckeys, cvals = zip(*cdict.items())
# build a mapping function to turn the matrix elements into integers
# (would be faster to use a dict for lots of colours)
cmap_fn = lambda x: Integer(ckeys.index(x if x in cdict else None))
# generate a colormap with exactly the colours we want, in the right order
my_cmap = matplotlib.colors.ListedColormap(cvals)
# generate a test matrix
m = Matrix(lambda i,j: (i+j) if (i,j) != (6,6) else 43+2*I, nrows=10)
# plot it: apply the mapping function to the matrix and feed matrix_plot our colour map
matrix_plot(m.apply_map(cmap_fn), cmap=my_cmap)
</code>
</pre>
<p>This should generate one very ugly graph: one red cell, two green cells, three yellow cells, four orange cells, and a brown cell at (6,6) in a purple sea. It's easy to bundle this into a function if you find yourself doing it frequently.</p>
<p>[update: modified to make it slightly more general: now you don't need any ordering relation defined on the matrix elements]</p>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22374#post-id-22374@kcrisman: yes, you just have to be careful to make sure that the matrix element still has the same type as [well, no, just 'still compares equal to'] the cdict key, else the cmap_fn will fail to find a match and fall back to the None colour.Mon, 20 Dec 2010 21:15:49 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22374#post-id-22374Comment by Eviatar Bach for <p>I seem to recall once having a slick workaround for this but for the life of me I can't find it now. Anyway, something like this should get the job done:</p>
<pre><code># preamble
import matplotlib
# choose our preferred colour scheme, where None describes the exceptions
cdict = {0: 'red', 1: 'green', 2:'yellow', 3:'orange', 43+2*I: 'brown', None: 'purple'}
# choose some fixed order -- doesn't matter what -- for iterating the keys
ckeys, cvals = zip(*cdict.items())
# build a mapping function to turn the matrix elements into integers
# (would be faster to use a dict for lots of colours)
cmap_fn = lambda x: Integer(ckeys.index(x if x in cdict else None))
# generate a colormap with exactly the colours we want, in the right order
my_cmap = matplotlib.colors.ListedColormap(cvals)
# generate a test matrix
m = Matrix(lambda i,j: (i+j) if (i,j) != (6,6) else 43+2*I, nrows=10)
# plot it: apply the mapping function to the matrix and feed matrix_plot our colour map
matrix_plot(m.apply_map(cmap_fn), cmap=my_cmap)
</code>
</pre>
<p>This should generate one very ugly graph: one red cell, two green cells, three yellow cells, four orange cells, and a brown cell at (6,6) in a purple sea. It's easy to bundle this into a function if you find yourself doing it frequently.</p>
<p>[update: modified to make it slightly more general: now you don't need any ordering relation defined on the matrix elements]</p>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22376#post-id-22376This is exactly what I wanted! Thank you! This should be built in to Sage.Mon, 20 Dec 2010 20:06:37 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22376#post-id-22376Comment by kcrisman for <p>I seem to recall once having a slick workaround for this but for the life of me I can't find it now. Anyway, something like this should get the job done:</p>
<pre><code># preamble
import matplotlib
# choose our preferred colour scheme, where None describes the exceptions
cdict = {0: 'red', 1: 'green', 2:'yellow', 3:'orange', 43+2*I: 'brown', None: 'purple'}
# choose some fixed order -- doesn't matter what -- for iterating the keys
ckeys, cvals = zip(*cdict.items())
# build a mapping function to turn the matrix elements into integers
# (would be faster to use a dict for lots of colours)
cmap_fn = lambda x: Integer(ckeys.index(x if x in cdict else None))
# generate a colormap with exactly the colours we want, in the right order
my_cmap = matplotlib.colors.ListedColormap(cvals)
# generate a test matrix
m = Matrix(lambda i,j: (i+j) if (i,j) != (6,6) else 43+2*I, nrows=10)
# plot it: apply the mapping function to the matrix and feed matrix_plot our colour map
matrix_plot(m.apply_map(cmap_fn), cmap=my_cmap)
</code>
</pre>
<p>This should generate one very ugly graph: one red cell, two green cells, three yellow cells, four orange cells, and a brown cell at (6,6) in a purple sea. It's easy to bundle this into a function if you find yourself doing it frequently.</p>
<p>[update: modified to make it slightly more general: now you don't need any ordering relation defined on the matrix elements]</p>
https://ask.sagemath.org/question/7825/specific-cmap/?comment=22377#post-id-22377Will that work even with Sage #s, like $4.3+2*I$?Mon, 20 Dec 2010 13:18:29 +0100https://ask.sagemath.org/question/7825/specific-cmap/?comment=22377#post-id-22377