Michael Rawlins, on 2011-01-05 08:44,  wrote:
> How does one define a range of colors for a custom user-defined
> colormap?  I'm fairly new to matplotlib and have been using
> standard colormaps.  Below is a sample program that makes a
> color bar based on the hot colormap.  I'd like to have a
> colormap like hot, but that starts at, say, orange (near 14%),
> and runs to black (40%).
 
Hi Michael,

first a quick aside: your reversing of the colormap is
unnecessary - just change the colordict assignment line to be:

  colordict=cm.hot_r._segmentdata.copy()

and get rid of the two nested for loops. Or better still, get rid
of colordict altogether and just use

  maprev = cm.hot_r

Ok, as far as your question - I'm not certain that this is what
you're asking for - but if you want to construct a colormap that
"stretches" the portion of your plot that goes from 14 to 40
"percent" (as labeled), to be the entire range of a colormap -
use the following:

All colormaps take as input a value from 0.0-1.0, and give you
back an rgba tuple. You already have a normalization 'norm' in
there which maps an arbitrary interval (0-40 in your case) to the
0.0-1.0 interval. So you like the color value at 14 - let's find
out what the scalar value for 14 is, once it's mapped to the
0.0-1.0 interval.

In [68]: norm(14)
Out[68]: 0.34999999999999998

So that's the value we will pass to cm.hot_r to get the color at
14.  Let's verify that this is actually what's going on - I'll
create a new figure and plot just one big dot on there of what
should hopefully be the same color.

In [69]: f, ax = plt.subplots(1,1)
In [70]: plt.scatter(0,0,c=cm.hot_r(norm(14)),s=1000) # c is color, s is size
Out[70]: <matplotlib.collections.CircleCollection object at 0xae9002c>

Ok, that looks good. We can repeat the procedure for the 40
"percent" case

In [89]: norm(40)
Out[89]: 1.0
In [90]: plt.scatter(0,0,c=cm.hot_r(norm(40)),s=1000)
Out[90]: <matplotlib.collections.CircleCollection object at 0xae97c4c>

No surprises there (it's black). Now let's create our own
segmented map. You can look at the documentation and an example:
http://matplotlib.sourceforge.net/api/colors_api.html#matplotlib.colors.LinearSegmentedColormap
http://matplotlib.sourceforge.net/examples/pylab_examples/custom_cmap.html

but a LinearSegmentedColormap just splits deals with the rgb
channels seperately, and for each color, defines transition
points in the 0.0-1.0 interval which are refered to as 'x' in the
links above, as well as the color to use before the transition
point ('y0'), and the color to use after the point ('y1'). Here's
a quote from the docs about this:

  Each row in the table for a given color is a sequence of x, y0,
  y1 tuples. In each sequence, x must increase monotonically from 0
  to 1. For any input value z falling between x[i] and x[i+1], the
  output value of a given color will be linearly interpolated
  between y1[i] and y0[i+1]:
  
    row i:   x  y0  y1
                   /
                  /
    row i+1: x  y0  y1
  
  Hence y0 in the first row and y1 in the last row are never used.

Armed with this knowledge, you can now use the color from
cm.hot_r(norm(14)) to get the entries for the first rows of your
new map (remember that you're doing red, green, and blue
seperately) - and then remap the remaining transition points (the
'x' portion of the tuple) to stretch portion of the colormap's
0.0-1.0 interval that you're interested in (i.e. map 0.345-1.0 to
0.0-1.0).

Now that's only if you want full control of the linear segments -
there's a quick and dirty way to get what you want by specifying
a ListedColormap using values taken from the colormap you're
using. I'll just get a whole bunch of values from the desired
interval of the colormap, map them through the colormap, and get
my new colormap out.

In [209]: vals = norm(np.linspace(14,40,1000))
In [210]: newcm = cm.colors.ListedColormap(cm.hot_r(vals))

Let's plot the original map (as in your email), and the new one
we created.

In [211]: f,(ax2,ax3) = plt.subplots(2,1)
In [212]: cb2 = mpl.colorbar.ColorbarBase(ax2, cmap=cm.hot_r,
   .....:                                  norm=norm,
   .....:                                  orientation='horizontal')
In [213]: cb2.set_label('"percent"')
In [214]: 
In [215]: cb3 = mpl.colorbar.ColorbarBase(ax3, cmap=newcm,
   .....:                                  orientation='horizontal')
In [216]: cb3.set_label("colormap interval 0.0-1.0")
In [217]: plt.draw()


And to further clarify that we did the right thing, let's adjust
the xlim on that original plot.

In [221]: ax2.set_xlim(norm(14),norm(40))
Out[221]: (0.34999999999999998, 1.0)
In [222]: plt.draw()


Hope this clears things up,
-- 
Paul Ivanov
314 address only used for lists,  off-list direct email at:
http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7 

Attachment: signature.asc
Description: Digital signature

------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and, 
should the need arise, upgrade to a full multi-node Oracle RAC database 
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to