 # Making a data-driven colormap

Hi everyone,

I am trying to make a color-map which will respond to the range of values in the data itself. That is - I want to take one of the mpl colormaps and use parts of it, depending on the range of the data.

In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the data has both negative and positive values, I want 0 to map to the central value of this colormap (a pale whitish yellow) and I want negative values to be in blue and positive numbers to be in red. Also - I would want to use the parts of the colormap that represent how far away the smallest and largest values in the data are from 0. So - if my data is in the range [x1,x2] I would want to use the part of the colormap in indices 127-127abs(x1)/(x2-x1) through 127+127x2/(x2-x1). If the data only includes positive numbers, I would want to only use the blue part of the colormap and if there are negative numbers, I would want to only use the red part of the colormap (in these cases, I would also want to take only a portion of the colormap which represents the size of the interval [x1,x2] relative to the interval [0,x1] or [x2,0], as the case may be).

I think that this might be useful when comparing matrices generated from different data, but with the same computation, such as correlation or coherence (see http://nipy.sourceforge.net/nitime/examples/fmri.html to get an idea of what I mean).

First of all - is this a good idea? Or in other words - is there any reason I am not thinking of why this idea is a really bad idea?

Second - the technical questions. I think that I can make this happen by using matplotlib.colors.LinearSegmentedColormap, after fiddling with the values of the color-map a bit (as described above), but in order to do that, I need to know what segmentdata was used in order to generate the original colormap (for example, how many lines did each of the entries in the cdict have? Looking at a plot of the cmap it looks like there must have been 8 or 9 for RdYlBu_r, but I can’t be sure). I could analyze it in more detail to get that out empirically, but I am guessing that someone around here might be able to spare me that lunacy (if not others…).

Ariel

···

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

not sure if this is what you want (I’d never heard of RdYlBu_r…I need to go read up!), but I’ve used a similar colormap with the code posted below. You might be able to modify it for your case.

``````	hope this helps!

bb
``````

from pylab import *

def bluewhitered(a,N=256):

bottom = [0, 0, 0.5]

botmiddle = [0, 0.5, 1]

middle = [1, 1, 1]

topmiddle = [1, 0, 0]

top = [0.5, 0, 0]

lims=[a.min(),a.max()]

if lims<0 and lims>0:

ratio=abs(lims)/(abs(lims)+lims)

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

# negative part

red=[(0.0, 0.0, 0.0),

(ratio/2, 0.0, 0.0),

(ratio, 1.0, 1.0)]

green=[(0.0, 0.0, 0.0),

(ratio/2, 0.5, 0.5),

(ratio, 1.0, 1.0)]

blue=[(0.0, 0.5, 0.5),

(ratio/2, 1, 1),

(ratio, 1.0, 1.0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

nratio=1-(1-ratio)/2.0

# positive part

red=[(ratio, 1.0, 1.0),

(nratio, 1.0, 1.0),

(1, 0.5, 0.5)]

green=[(ratio, 1.0, 1.0),

(nratio, 0., 0.),

(1, 0.0, 0.0)]

blue=[(ratio, 1., 1.),

(nratio, 0, 0),

(1, 0, 0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

elif lims>=0: # all positive

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

ratio=0.0

nratio=0.5

# positive part

red=[(ratio, 1.0, 1.0),

(nratio, 1.0, 1.0),

(1, 0.5, 0.5)]

green=[(ratio, 1.0, 1.0),

(nratio, 0., 0.),

(1, 0.0, 0.0)]

blue=[(ratio, 1., 1.),

(nratio, 0, 0),

(1, 0, 0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

else: # all negative

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

ratio=1.0

# negative part

red=[(0.0, 0.0, 0.0),

(ratio/2, 0.0, 0.0),

(ratio, 1.0, 1.0)]

green=[(0.0, 0.0, 0.0),

(ratio/2, 0.5, 0.5),

(ratio, 1.0, 1.0)]

blue=[(0.0, 0.5, 0.5),

(ratio/2, 1, 1),

(ratio, 1.0, 1.0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

my_cmap = matplotlib.colors.LinearSegmentedColormap(‘my_colormap’,cdict,N)

return my_cmap

if name==“main”:

a=randn(20,20)

my_cmap=bluewhitered(a,256)

clf()

pcolor(a,cmap=my_cmap)

colorbar()

···

On Mar 27, 2010, at 1:13 , Ariel Rokem wrote:

In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the data has both negative and positive values, I want 0 to map to the central value of this colormap (a pale whitish yellow) and I want negative values to be in blue and positive numbers to be in red.

Brian Blais

bblais@…1129…

http://web.bryant.edu/~bblais

Hi Brian,

Thanks for the code - this is definitely in the direction of what I want to make!

The RdYlBu_r colormap is one of the built-in colormaps available in matplotlib.pyplot.cm (you can see all of them here:http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps). I think that using the built-in colormaps might give nicer transitions between the colors, so instead of transitioning linearily between red and white and white and blue, it transitions in a slightly non-linear way, along several segments.

Compare:

plot(plt.cm.RdYlBu_r(arange(256)))

with

plot(my_cmap(arange(256)))

I think that the more nonlinear one might look a little bit nicer (and might be less perceptually misleading in interpreting color differences in the result). But I need to figure out how many segments there are in there.

Thanks - Ariel

···

On Sat, Mar 27, 2010 at 4:14 AM, Brian Blais <bblais@…1129…> wrote:

On Mar 27, 2010, at 1:13 , Ariel Rokem wrote:

In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the data has both negative and positive values, I want 0 to map to the central value of this colormap (a pale whitish yellow) and I want negative values to be in blue and positive numbers to be in red.

not sure if this is what you want (I’d never heard of RdYlBu_r…I need to go read up!), but I’ve used a similar colormap with the code posted below. You might be able to modify it for your case.

``````  hope this helps!
``````
``````  	bb
``````

from pylab import *

def bluewhitered(a,N=256):

bottom = [0, 0, 0.5]

botmiddle = [0, 0.5, 1]

middle = [1, 1, 1]

topmiddle = [1, 0, 0]

top = [0.5, 0, 0]

lims=[a.min(),a.max()]

if lims<0 and lims>0:

ratio=abs(lims)/(abs(lims)+lims)

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

# negative part

red=[(0.0, 0.0, 0.0),

(ratio/2, 0.0, 0.0),

(ratio, 1.0, 1.0)]

green=[(0.0, 0.0, 0.0),

(ratio/2, 0.5, 0.5),

(ratio, 1.0, 1.0)]

blue=[(0.0, 0.5, 0.5),

(ratio/2, 1, 1),

(ratio, 1.0, 1.0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

nratio=1-(1-ratio)/2.0

# positive part

red=[(ratio, 1.0, 1.0),

(nratio, 1.0, 1.0),

(1, 0.5, 0.5)]

green=[(ratio, 1.0, 1.0),

(nratio, 0., 0.),

(1, 0.0, 0.0)]

blue=[(ratio, 1., 1.),

(nratio, 0, 0),

(1, 0, 0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

elif lims>=0: # all positive

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

ratio=0.0

nratio=0.5

# positive part

red=[(ratio, 1.0, 1.0),

(nratio, 1.0, 1.0),

(1, 0.5, 0.5)]

green=[(ratio, 1.0, 1.0),

(nratio, 0., 0.),

(1, 0.0, 0.0)]

blue=[(ratio, 1., 1.),

(nratio, 0, 0),

(1, 0, 0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

else: # all negative

cdict={}

cdict[‘red’]=[]

cdict[‘green’]=[]

cdict[‘blue’]=[]

ratio=1.0

# negative part

red=[(0.0, 0.0, 0.0),

(ratio/2, 0.0, 0.0),

(ratio, 1.0, 1.0)]

green=[(0.0, 0.0, 0.0),

(ratio/2, 0.5, 0.5),

(ratio, 1.0, 1.0)]

blue=[(0.0, 0.5, 0.5),

(ratio/2, 1, 1),

(ratio, 1.0, 1.0)]

cdict[‘red’].extend(red)

cdict[‘green’].extend(green)

cdict[‘blue’].extend(blue)

my_cmap = matplotlib.colors.LinearSegmentedColormap(‘my_colormap’,cdict,N)

return my_cmap

if name==“main”:

a=randn(20,20)

my_cmap=bluewhitered(a,256)

clf()

pcolor(a,cmap=my_cmap)

colorbar()

Brian Blais

bblais@…1129…

http://web.bryant.edu/~bblais

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

2010/3/27 Ariel Rokem <arokem@...1016...>:

I am trying to make a color-map which will respond to the range of values in
the data itself. That is - I want to take one of the mpl colormaps and use
parts of it, depending on the range of the data.

In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the
data has both negative and positive values, I want 0 to map to the central
value of this colormap (a pale whitish yellow) and I want negative values to
be in blue and positive numbers to be in red. Also - I would want to use the
parts of the colormap that represent how far away the smallest and largest
values in the data are from 0. So - if my data is in the range [x1,x2] I
would want to use the part of the colormap in indices
127-127*abs(x1)/(x2-x1) through 127+127*x2/(x2-x1). If the data only
includes positive numbers, I would want to only use the blue part of the
colormap and if there are negative numbers, I would want to only use the red
part of the colormap (in these cases, I would also want to take only a
portion of the colormap which represents the size of the interval [x1,x2]
relative to the interval [0,x1] or [x2,0], as the case may be).

I think that this might be useful when comparing matrices generated from
different data, but with the same computation, such as correlation or
coherence (see http://nipy.sourceforge.net/nitime/examples/fmri.html to get
an idea of what I mean).

I might miss something important, but why not use pcolor() with kwargs
vmin and vmax,
http://matplotlib.sourceforge.net/api/axes_api.html#matplotlib.axes.Axes.pcolor,
e.g.:

maxval = numpy.abs(C).max()
pcolor(C, vmin = -maxval, vmax = maxval)

As far as I can judge, this should have the desired effect.

Friedrich

Hi Friedrich,

Thanks a lot for your response. I think that you are right - using the vmin/vmax args into imshow (as well as into pcolor) does seem to do what I want. Great!

The only thing that remains now is to simultaneously stretch the colormap in the image itself to this range, while also restricting the range of the colorbar which is displayed, to only the part of the colormap which actually has values (in the attached .png, I only want values between 0 and ~0.33 to appear in the colorbar, not from negative -0.33 to +0.33).

Does anyone know how to do that?

Thanks again -

Ariel ···

On Sat, Mar 27, 2010 at 3:29 PM, Friedrich Romstedt <friedrichromstedt@…287…> wrote:

2010/3/27 Ariel Rokem <arokem@…1836…016…>:

I am trying to make a color-map which will respond to the range of values in

the data itself. That is - I want to take one of the mpl colormaps and use

parts of it, depending on the range of the data.

In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the

data has both negative and positive values, I want 0 to map to the central

value of this colormap (a pale whitish yellow) and I want negative values to

be in blue and positive numbers to be in red. Also - I would want to use the

parts of the colormap that represent how far away the smallest and largest

values in the data are from 0. So - if my data is in the range [x1,x2] I

would want to use the part of the colormap in indices

127-127abs(x1)/(x2-x1) through 127+127x2/(x2-x1). If the data only

includes positive numbers, I would want to only use the blue part of the

colormap and if there are negative numbers, I would want to only use the red

part of the colormap (in these cases, I would also want to take only a

portion of the colormap which represents the size of the interval [x1,x2]

relative to the interval [0,x1] or [x2,0], as the case may be).

I think that this might be useful when comparing matrices generated from

different data, but with the same computation, such as correlation or

coherence (see http://nipy.sourceforge.net/nitime/examples/fmri.html to get

an idea of what I mean).

I might miss something important, but why not use pcolor() with kwargs

vmin and vmax,

e.g.:

pcolor(C, vmin = -maxval, vmax = maxval)

As far as I can judge, this should have the desired effect.

Friedrich

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

To zoom in on the relevant section of a colorbar -- I convinced myself once that I'd need an auxiliary function to define a new cdict that covers only the current section of the original cdict. (and then define a new colorbar from the cdict, and maybe do a little norming of the data).

_segmentdata will give you the original cdict for whichever colorbar you're using.

Not that I got around to actually doing it! But it would be great for paper readability and passing-around of plots.

&C

···

On Mar 27, 2010, at 9:24 PM, Ariel Rokem wrote:

Hi Friedrich,

Thanks a lot for your response. I think that you are right - using the vmin/vmax args into imshow (as well as into pcolor) does seem to do what I want. Great!

The only thing that remains now is to simultaneously stretch the colormap in the image itself to this range, while also restricting the range of the colorbar which is displayed, to only the part of the colormap which actually has values (in the attached .png, I only want values between 0 and ~0.33 to appear in the colorbar, not from negative -0.33 to +0.33).

Does anyone know how to do that?

Thanks again -

Ariel

On Sat, Mar 27, 2010 at 3:29 PM, Friedrich Romstedt <friedrichromstedt@...287... > > wrote:
2010/3/27 Ariel Rokem <arokem@...1016...>:
> I am trying to make a color-map which will respond to the range of values in
> the data itself. That is - I want to take one of the mpl colormaps and use
> parts of it, depending on the range of the data.
>
> In particular, I am interested in using the plt.cm.RdYlBu_r colormap. If the
> data has both negative and positive values, I want 0 to map to the central
> value of this colormap (a pale whitish yellow) and I want negative values to
> be in blue and positive numbers to be in red. Also - I would want to use the
> parts of the colormap that represent how far away the smallest and largest
> values in the data are from 0. So - if my data is in the range [x1,x2] I
> would want to use the part of the colormap in indices
> 127-127*abs(x1)/(x2-x1) through 127+127*x2/(x2-x1). If the data only
> includes positive numbers, I would want to only use the blue part of the
> colormap and if there are negative numbers, I would want to only use the red
> part of the colormap (in these cases, I would also want to take only a
> portion of the colormap which represents the size of the interval [x1,x2]
> relative to the interval [0,x1] or [x2,0], as the case may be).
>
> I think that this might be useful when comparing matrices generated from
> different data, but with the same computation, such as correlation or
> coherence (see http://nipy.sourceforge.net/nitime/examples/fmri.html to get
> an idea of what I mean).

I might miss something important, but why not use pcolor() with kwargs
vmin and vmax,
http://matplotlib.sourceforge.net/api/axes_api.html#matplotlib.axes.Axes.pcolor,
e.g.:

maxval = numpy.abs(C).max()
pcolor(C, vmin = -maxval, vmax = maxval)

As far as I can judge, this should have the desired effect.

Friedrich

--
Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel
<colorbar.png>------------------------------------------------------------------------------
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Like so, not that it couldn't be improved:

import matplotlib.cm as cm
import matplotlib.colors as colors
import pylab as p

def rgb_to_dict(value, cbar):
return dict(zip(('red','green','blue','alpha'), cbar(value)))

def subcolorbar(xmin, xmax, cbar):
'''Returns the part of cbar between xmin, xmax, scaled to 0,1.'''
assert xmin < xmax
assert xmax <=1
cd = cbar._segmentdata.copy()
colornames = ('red','green','blue')
rgbmin, rgbmax = rgb_to_dict(xmin, cbar), rgb_to_dict(xmax, cbar)
for k in cd:
tmp = [x for x in cd[k] if x >= xmin and x <= xmax]
if tmp == [] or tmp > xmin:
tmp = [(xmin, rgbmin[k], rgbmin[k])] + tmp
if tmp == [] or tmp[-1] < xmax:
tmp = tmp + [ (xmax,rgbmax[k], rgbmax[k])]
#now scale all this to (0,1)
square = zip(*tmp)
xbreaks = [(x - xmin)/(xmax-xmin) for x in square]
square = xbreaks
tmp = zip(*square)
cd[k] = tmp
return colors.LinearSegmentedColormap('local', cd, N=256)

if __name__=="__main__":
subset = [.1, .3, .6]
scb = subcolorbar(min(subset), max(subset), cm.jet)
print 'main segments', cm.jet._segmentdata
print 'smaller', scb._segmentdata
p.subplot(121)
p.scatter([1,2,3],[1,2,3],s=49, c = subset, cmap=scb)
p.colorbar()
p.subplot(122)
p.scatter([2,3,4],[2,3,4],s=49, c =[.001, .5, .99], cmap=cm.jet)
p.colorbar()
p.show()

···

On Mar 27, 2010, at 11:52 PM, Chloe Lewis wrote:

To zoom in on the relevant section of a colorbar -- I convinced myself
once that I'd need an auxiliary function to define a new cdict that
covers only the current section of the original cdict. (and then
define a new colorbar from the cdict, and maybe do a little norming of
the data).

_segmentdata will give you the original cdict for whichever colorbar
you're using.

Not that I got around to actually doing it! But it would be great for
paper readability and passing-around of plots.

&C

On Mar 27, 2010, at 9:24 PM, Ariel Rokem wrote:

Hi Friedrich,

Thanks a lot for your response. I think that you are right - using
the vmin/vmax args into imshow (as well as into pcolor) does seem to
do what I want. Great!

The only thing that remains now is to simultaneously stretch the
colormap in the image itself to this range, while also restricting
the range of the colorbar which is displayed, to only the part of
the colormap which actually has values (in the attached .png, I only
want values between 0 and ~0.33 to appear in the colorbar, not from
negative -0.33 to +0.33).

Does anyone know how to do that?

Thanks again -

Ariel

On Sat, Mar 27, 2010 at 3:29 PM, Friedrich Romstedt <friedrichromstedt@...287... >>> wrote:
2010/3/27 Ariel Rokem <arokem@...1016...>:

I am trying to make a color-map which will respond to the range of

values in

the data itself. That is - I want to take one of the mpl colormaps

and use

parts of it, depending on the range of the data.

In particular, I am interested in using the plt.cm.RdYlBu_r

colormap. If the

data has both negative and positive values, I want 0 to map to the

central

value of this colormap (a pale whitish yellow) and I want negative

values to

be in blue and positive numbers to be in red. Also - I would want

to use the

parts of the colormap that represent how far away the smallest and

largest

values in the data are from 0. So - if my data is in the range

[x1,x2] I

would want to use the part of the colormap in indices
127-127*abs(x1)/(x2-x1) through 127+127*x2/(x2-x1). If the data only
includes positive numbers, I would want to only use the blue part

of the

colormap and if there are negative numbers, I would want to only

use the red

part of the colormap (in these cases, I would also want to take

only a

portion of the colormap which represents the size of the interval

[x1,x2]

relative to the interval [0,x1] or [x2,0], as the case may be).

I think that this might be useful when comparing matrices

generated from

different data, but with the same computation, such as correlation

or

coherence (see http://nipy.sourceforge.net/nitime/examples/

fmri.html to get

an idea of what I mean).

I might miss something important, but why not use pcolor() with kwargs
vmin and vmax,
http://matplotlib.sourceforge.net/api/axes_api.html#matplotlib.axes.Axes.pcolor
,
e.g.:

maxval = numpy.abs(C).max()
pcolor(C, vmin = -maxval, vmax = maxval)

As far as I can judge, this should have the desired effect.

Friedrich

--
Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel
<
colorbar
.png

------------------------------------------------------------------------------
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Hi Chloe,

_segmentdata - that’s what I was looking for!

Thanks a lot also for that bit of code!

Cheers - Ariel

···

On Sun, Mar 28, 2010 at 1:53 AM, Chloe Lewis <chlewis@…1016…> wrote:

Like so, not that it couldn’t be improved:

import matplotlib.cm as cm

import matplotlib.colors as colors

import pylab as p

def rgb_to_dict(value, cbar):

``````return dict(zip(('red','green','blue','alpha'), cbar(value)))
``````

def subcolorbar(xmin, xmax, cbar):

``````'''Returns the part of cbar between xmin, xmax, scaled to 0,1.'''

assert xmin < xmax

assert xmax <=1

cd =  cbar._segmentdata.copy()

colornames = ('red','green','blue')

rgbmin, rgbmax = rgb_to_dict(xmin, cbar), rgb_to_dict(xmax, cbar)

for k in cd:

tmp = [x for x in cd[k] if x >= xmin and x <= xmax]

if tmp == [] or tmp > xmin:

tmp = [(xmin, rgbmin[k], rgbmin[k])] + tmp

if tmp == [] or tmp[-1] < xmax:

tmp = tmp + [ (xmax,rgbmax[k], rgbmax[k])]

#now scale all this to (0,1)

square = zip(*tmp)

xbreaks = [(x - xmin)/(xmax-xmin) for x in square]

square = xbreaks

tmp = zip(*square)

cd[k] = tmp

return colors.LinearSegmentedColormap('local', cd, N=256)
``````

if name==“main”:

``````subset = [.1, .3, .6]

scb = subcolorbar(min(subset), max(subset), cm.jet)

print 'main segments', cm.jet._segmentdata

print 'smaller', scb._segmentdata

p.subplot(121)

p.scatter([1,2,3],[1,2,3],s=49, c = subset, cmap=scb)

p.colorbar()

p.subplot(122)

p.scatter([2,3,4],[2,3,4],s=49, c =[.001, .5, .99], cmap=cm.jet)

p.colorbar()

p.show()
``````

On Mar 27, 2010, at 11:52 PM, Chloe Lewis wrote:

To zoom in on the relevant section of a colorbar – I convinced myself

once that I’d need an auxiliary function to define a new cdict that

covers only the current section of the original cdict. (and then

define a new colorbar from the cdict, and maybe do a little norming of

the data).

_segmentdata will give you the original cdict for whichever colorbar

you’re using.

Not that I got around to actually doing it! But it would be great for

paper readability and passing-around of plots.

&C

On Mar 27, 2010, at 9:24 PM, Ariel Rokem wrote:

Hi Friedrich,

Thanks a lot for your response. I think that you are right - using

the vmin/vmax args into imshow (as well as into pcolor) does seem to

do what I want. Great!

The only thing that remains now is to simultaneously stretch the

colormap in the image itself to this range, while also restricting

the range of the colorbar which is displayed, to only the part of

the colormap which actually has values (in the attached .png, I only

want values between 0 and ~0.33 to appear in the colorbar, not from

negative -0.33 to +0.33).

Does anyone know how to do that?

Thanks again -

Ariel

On Sat, Mar 27, 2010 at 3:29 PM, Friedrich Romstedt <friedrichromstedt@…287… > > > > wrote:
2010/3/27 Ariel Rokem <arokem@…1016…>:

I am trying to make a color-map which will respond to the range of
values in
the data itself. That is - I want to take one of the mpl colormaps
and use
parts of it, depending on the range of the data.

In particular, I am interested in using the plt.cm.RdYlBu_r
colormap. If the
data has both negative and positive values, I want 0 to map to the
central
value of this colormap (a pale whitish yellow) and I want negative
values to
be in blue and positive numbers to be in red. Also - I would want
to use the
parts of the colormap that represent how far away the smallest and
largest
values in the data are from 0. So - if my data is in the range
[x1,x2] I
would want to use the part of the colormap in indices

127-127abs(x1)/(x2-x1) through 127+127x2/(x2-x1). If the data only

includes positive numbers, I would want to only use the blue part
of the
colormap and if there are negative numbers, I would want to only
use the red
part of the colormap (in these cases, I would also want to take
only a
portion of the colormap which represents the size of the interval
[x1,x2]
relative to the interval [0,x1] or [x2,0], as the case may be).

I think that this might be useful when comparing matrices
generated from
different data, but with the same computation, such as correlation
or
coherence (see http://nipy.sourceforge.net/nitime/examples/
fmri.html to get
an idea of what I mean).

I might miss something important, but why not use pcolor() with kwargs

vmin and vmax,

http://matplotlib.sourceforge.net/api/axes_api.html#matplotlib.axes.Axes.pcolor

,

e.g.:

pcolor(C, vmin = -maxval, vmax = maxval)

As far as I can judge, this should have the desired effect.

Friedrich

Ariel Rokem

Helen Wills Neuroscience Institute

University of California, Berkeley

http://argentum.ucbso.berkeley.edu/ariel

<

colorbar

.png

Try the new software tools for yourself. Speed compiling, find bugs

proactively, and fine-tune applications for parallel performance.

See why Intel Parallel Studio got high marks during beta.

http://p.sf.net/sfu/intel-sw-dev_______________________________________________

Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Try the new software tools for yourself. Speed compiling, find bugs

proactively, and fine-tune applications for parallel performance.

See why Intel Parallel Studio got high marks during beta.

http://p.sf.net/sfu/intel-sw-dev

Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

2010/3/28 Ariel Rokem <arokem@...1016...>:

Hi Chloe,

_segmentdata - that's what I was looking for!

Hmm, much easier would maybe be:

colorbar = figure.colorbar(...)

colorbar.ax.set_xlim((C.min(), C.max()) # Or .set_ylim() for vertical cbars.

I just did a dive into the matplotlib code and docu:
http://matplotlib.sourceforge.net/api/colorbar_api.html#matplotlib.colorbar.ColorbarBase

It has also the advantage that the xticks represent the correct values.

For small C ranges one should consider using a cmap subdivided finer?

Friedrich

That would be a lot nicer, Friedrich; could you share demo code? I can't make the set_ylim work, but I think I'm being clumsy with the object model.

E.g., from this:

utilities.py (1.64 KB) 2010/3/28 Chloe Lewis <chlewis@...1016...>:

That would be a lot nicer, Friedrich; could you share demo code? I can't
make the set_ylim work, but I think I'm being clumsy with the object model.

It seems that I cannot read the sections following after the "From
this:" and "I get this:"?

But anyway, I solved it for you See attached script. colorbar()
takes the argument *boundaries*, defining the region to draw. It's
code from Alan G Isaac slightly modified and also posted there back,
too. You will want to run the code via python -i norm.py.

For the vmin and vmax, if you like it more you can also pass in norm =

Note that the ticking is a bit weird, there is also a bug in
matplotlib I will report on right after this e-mail, whose bugfix you
will maybe want to apply to get ticking properly working. When you
have insane values for C.min() and C.max() anyway, I'm afraid you have
to retick manually with *ticks* to colorbar(). The ticker.MaxNLocator
is only used when not using the *boundaries* arg to colorbar(),
unfortunately. Otherwise it tries to create maximal many and less
than 11 ticks by using the lowest value and an appropriate step in
*boundaries*. I think the implementation of ticking is cumbersome and
never optimal.

Friedrich

norm.py (510 Bytes)

I once had a similar issue. I solved it like this. It takes the minimum and
maximum of the data and returns a colormap: Zero: White, Positive values:
blue, Negative values: red.

def mxcmap(_min,_max):
if _min >= 0 and _max >= 0:
cdict = {'red': ((0.0, 1.0, 1.0),
(1.0, 0.0, 0.0)),
'green': ((0.0, 1.0, 1.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 1.0, 1.0),
(1.0, 1.0, 1.0))}
elif _min <= 0 and _max <= 0:
cdict = {'red': ((0.0, 1.0, 1.0),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),
(1.0, 1.0, 1.0))}
else:
full_red = 1
full_blue = 1
if -_min > _max:
full_blue = -float(_max)/_min
else:
full_red = -float(_min)/_max
zero = 0.5-((_max+_min)/2.)/(_max-_min)

cdict = {'red': ((0.0, 1.0, 1.0),
(zero, 1.0, 1.0),
(1.0, 1-full_blue, 1-full_blue)),
'green': ((0.0, 1-full_red, 1-full_red),
(zero, 1.0, 1.0),
(1.0, 1-full_blue, 1-full_blue)),
'blue': ((0.0, 1-full_red, 1-full_red),
(zero,1.0, 1.0),
(1.0, 1.0, 1.0))}
return
pylab.matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict,256)

···

--
View this message in context: http://old.nabble.com/Making-a-data-driven-colormap-tp28050311p28067995.html
Sent from the matplotlib - users mailing list archive at Nabble.com.

2010/3/29 Friedrich Romstedt <friedrichromstedt@...287...>:

Note that the ticking is a bit weird, there is also a bug in
matplotlib I will report on right after this e-mail, whose bugfix you
will maybe want to apply to get ticking properly working. When you
have insane values for C.min() and C.max() anyway, I'm afraid you have
to retick manually with *ticks* to colorbar(). The ticker.MaxNLocator
is only used when not using the *boundaries* arg to colorbar(),
unfortunately. Otherwise it tries to create maximal many and less
than 11 ticks by using the lowest value and an appropriate step in
*boundaries*. I think the implementation of ticking is cumbersome and
never optimal.

You can get rid of this night mare by giving the kwarg "ticks =
matplotlib.ticker.MaxNLocator()" to fig.colorbar(). Then the
*boundaries* aren't used for ticking (but still for plotting).

Friedrich

Hi -

I ended up with the code below, using Chloe’s previously posted ‘subcolormap’ and, in order to make the colorbar nicely attached to the main imshow plot, I use make_axes_locatable in order to generate the colorbar axes. I tried it out with a couple of use-cases and it seems to do what it is supposed to, (with ticks only for the edges of the range of the data and 0, if that is within that range), but I am not entirely sure. Do you think it works?

Cheers,

Ariel

``````from mpl_toolkits.axes_grid import make_axes_locatable

fig=plt.figure()
divider = make_axes_locatable(ax_im)

#Extract the minimum and maximum values for scaling of the colormap/colorbar:
max_val = np.max(m[np.where(m<1)])
min_val = np.min(m)

#This makes sure that 0 is always the center of the colormap:
if min_val<-max_val:
ax_max = -min_val
ax_min = min_val

else:
ax_max = max_val
ax_min = -max_val

#Keyword args to imshow:
kw = {'origin': 'upper',
'interpolation': 'nearest',
'cmap':cmap,
'vmin':ax_min,
'vmax':ax_max}

im=ax_im.imshow(m,**kw)

#The following produces the colorbar and sets the ticks
if colorbar:
delta = ax_max-ax_min #The size of the entire interval of data
min_p = (min_val-ax_min)/delta
max_p = (max_val-ax_min)/delta
print min_p
print max_p

cnorm = mpl.colors.Normalize(vmin=min_val,vmax=max_val)
subcmap = subcolormap(min_p,max_p,cmap)
cb = mpl.colorbar.ColorbarBase(ax_cb, cmap=subcmap,
orientation='horizontal',norm=cnorm)

#Set the ticks - if 0 is in the interval of values, set that, as well
#as the maximal and minimal values:
if min_val<0:
cb.set_ticks([min_val,0,max_val])
cb.set_ticklabels(['%.2f'%min_val,'0','%.2f'%max_val])

#Otherwise - only set the minimal and maximal value:
else:
cb.set_ticks([min_val,max_val])
cb.set_ticklabels(['%.2f'%min_val,'%.2f'%max_val])
``````
···

On Mon, Mar 29, 2010 at 6:41 AM, Friedrich Romstedt <friedrichromstedt@…287…> wrote:

2010/3/29 Friedrich Romstedt <friedrichromstedt@…287…>:

Note that the ticking is a bit weird, there is also a bug in

matplotlib I will report on right after this e-mail, whose bugfix you

will maybe want to apply to get ticking properly working. When you

have insane values for C.min() and C.max() anyway, I’m afraid you have

to retick manually with ticks to colorbar(). The ticker.MaxNLocator

is only used when not using the boundaries arg to colorbar(),

unfortunately. Otherwise it tries to create maximal many and less

than 11 ticks by using the lowest value and an appropriate step in

boundaries. I think the implementation of ticking is cumbersome and

never optimal.

You can get rid of this night mare by giving the kwarg "ticks =

matplotlib.ticker.MaxNLocator()" to fig.colorbar(). Then the

boundaries aren’t used for ticking (but still for plotting).

Friedrich

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

2010/3/30 Ariel Rokem <arokem@...1016...>:

I ended up with the code below, using Chloe's previously posted
'subcolormap' and, in order to make the colorbar nicely attached to the main
imshow plot, I use make_axes_locatable in order to generate the colorbar
axes. I tried it out with a couple of use-cases and it seems to do what it
is supposed to, (with ticks only for the edges of the range of the data and
0, if that is within that range), but I am not entirely sure. Do you think
it works?

I think even Chloe would agree that you should avoid the subcolormap()
if you can. I tried to create an as minimalistic as possible but
working self-contained example, please find the code also attached as
.py file:

from matplotlib import pyplot as plt
import matplotlib as mpl
from mpl_toolkits.axes_grid import make_axes_locatable
import numpy as np

fig = plt.figure()
divider = make_axes_locatable(ax_im)
ax_cb = divider.new_vertical(size = '20%', pad = 0.2, pack_start = True)

x = np.linspace(-5, 5, 101)
y = x
Z = np.sin(x*y[:,None]).clip(-1,1-0.1)

# Leave out if you want:
Z += 2

min_val = Z.min()
max_val = Z.max()
bound = max(np.abs(Z.max()), np.abs(Z.min()))

patch = ax_im.imshow(Z, origin = 'upper', interpolation = 'nearest',
vmin = -bound, vmax = bound)

cb = fig.colorbar(patch, cax = ax_cb, orientation = 'horizontal',
norm = patch.norm,
boundaries = np.linspace(-bound, bound, 256),
ticks = [min_val, 0, max_val],
format = '%.2f')

plt.show()

Friedrich

cbar.py (845 Bytes) Hi Friedrich,

Thanks a lot - very nice!

Cheers - Ariel

···

On Tue, Mar 30, 2010 at 6:52 AM, Friedrich Romstedt <friedrichromstedt@…287…> wrote:

2010/3/30 Ariel Rokem <arokem@…1836…016…>:

I ended up with the code below, using Chloe’s previously posted

‘subcolormap’ and, in order to make the colorbar nicely attached to the main

imshow plot, I use make_axes_locatable in order to generate the colorbar

axes. I tried it out with a couple of use-cases and it seems to do what it

is supposed to, (with ticks only for the edges of the range of the data and

0, if that is within that range), but I am not entirely sure. Do you think

it works?

I think even Chloe would agree that you should avoid the subcolormap()

if you can. I tried to create an as minimalistic as possible but

working self-contained example, please find the code also attached as

.py file:

from matplotlib import pyplot as plt

import matplotlib as mpl
from mpl_toolkits.axes_grid import make_axes_locatable

import numpy as np

fig = plt.figure()

divider = make_axes_locatable(ax_im)

ax_cb = divider.new_vertical(size = ‘20%’, pad = 0.2, pack_start = True)

x = np.linspace(-5, 5, 101)

y = x

Z = np.sin(x*y[:,None]).clip(-1,1-0.1)

# Leave out if you want:

Z += 2

min_val = Z.min()

max_val = Z.max()

bound = max(np.abs(Z.max()), np.abs(Z.min()))

patch = ax_im.imshow(Z, origin = ‘upper’, interpolation = ‘nearest’,

``````    vmin = -bound, vmax = bound)
``````

cb = fig.colorbar(patch, cax = ax_cb, orientation = ‘horizontal’,

``````    norm = patch.norm,

boundaries = np.linspace(-bound, bound, 256),

ticks = [min_val, 0, max_val],

format = '%.2f')
``````

plt.show()

Friedrich

Ariel Rokem
Helen Wills Neuroscience Institute
University of California, Berkeley
http://argentum.ucbso.berkeley.edu/ariel

But this example doesn't solve the problem I was thinking of: it shows lots of colors in the colorbar that aren't used in the plot.

&C

···

On Mar 30, 2010, at 6:52 AM, Friedrich Romstedt wrote:

2010/3/30 Ariel Rokem <arokem@...1016...>:

I ended up with the code below, using Chloe's previously posted
'subcolormap' and, in order to make the colorbar nicely attached to the main
imshow plot, I use make_axes_locatable in order to generate the colorbar
axes. I tried it out with a couple of use-cases and it seems to do what it
is supposed to, (with ticks only for the edges of the range of the data and
0, if that is within that range), but I am not entirely sure. Do you think
it works?

I think even Chloe would agree that you should avoid the subcolormap()
if you can. I tried to create an as minimalistic as possible but
working self-contained example, please find the code also attached as
.py file:

from matplotlib import pyplot as plt
import matplotlib as mpl
from mpl_toolkits.axes_grid import make_axes_locatable
import numpy as np

fig = plt.figure()
divider = make_axes_locatable(ax_im)
ax_cb = divider.new_vertical(size = '20%', pad = 0.2, pack_start = True)

x = np.linspace(-5, 5, 101)
y = x
Z = np.sin(x*y[:,None]).clip(-1,1-0.1)

# Leave out if you want:
Z += 2

min_val = Z.min()
max_val = Z.max()
bound = max(np.abs(Z.max()), np.abs(Z.min()))

patch = ax_im.imshow(Z, origin = 'upper', interpolation = 'nearest',
vmin = -bound, vmax = bound)

cb = fig.colorbar(patch, cax = ax_cb, orientation = 'horizontal',
norm = patch.norm,
boundaries = np.linspace(-bound, bound, 256),
ticks = [min_val, 0, max_val],
format = '%.2f')

plt.show()

Friedrich
<cbar.py><cbar.png>

Here's a patch (and example) that I've cooked up that adds a
colorbar.set_limits() method. It works pretty well, but there's still
one issue to be sorted out: Setting the data limits distorts the
aspect ratio. I haven't quite figured out how best to make it so that
the aspect ratio is handled based on the size in axes coordinates and
not based on the data range (or rather, data aspect ratio).
(I'd love to hear any ideas the other devs have.)

Ryan

test_cbar.py (317 Bytes)

···

On Tue, Mar 30, 2010 at 11:15 AM, Chloe Lewis <chlewis@...1016...> wrote:

But this example doesn't solve the problem I was thinking of: it shows
lots of colors in the colorbar that aren't used in the plot.

--
Ryan May
School of Meteorology
University of Oklahoma

2010/3/30 Chloe Lewis <chlewis@...1016...>:

But this example doesn't solve the problem I was thinking of: it shows lots
of colors in the colorbar that aren't used in the plot.

I'm so stupid! Here is the correct code. I just interchanged
"-bounds, bound" with "min_val, max_val" on line 28. The only thing I
didn't fix was to exclude the 0.00 from the ticks, but this Ariel
already did, so I leave it now like it is.

Friedrich

cbar.py (848 Bytes) 