plotting an array of enumerated values

Hi all

I have some data with enumerated values in an array. Values are like
1,2,7,9 spread around in the array. I want to plot those values so that
I can see the 'regions' in my data, then I want to overlay this with
some contour lines drawn from other data.

I want to be able to specify the colors for each of the enumerated
values, as they need to be consistent throughout my work. My array of
enumerated values is *masked* so that there are areas where I don't want
to show anything (this would plot as transparent pixels).

Has anyone got suggestions on the best way of doing this? It seems that
the technique in
http://www.scipy.org/Cookbook/Matplotlib/Plotting_Images_with_Special_Values
might be overkill, right? It also seemed that it had some problems with
masked arrays.

Cheers

JP

···

--
John Pye
School of Mechanical and Manufacturing Engineering
The University of New South Wales
Sydney NSW 2052 Australia
t +61 2 9385 5127
f +61 2 9663 1222
mailto:john.pye_AT_student_DOT_unsw.edu.au
http://pye.dyndns.org/

By the way, I had some success with this, but my approach is really
inefficient. Perhaps someone could suggest how I can improve the following:

import matplotlib.numerix as nx
from numarray import ma

def enumimage(A,colors):
    """
        Create an image from a matrix of enumerated values
        A is a matrix
        colors is a dictionary mapping enumerated values to (r,g,b,a) tuples
        If a value in A is masked, the resulting image will be transparent
        If a value in A is not present in the color map, it will plot black.
    """

    B = nx.zeros((nx.size(A,0),nx.size(A,1),4))
    mask = A.mask()

    for r in range(nx.size(A,0)):
        for c in range(nx.size(A,1)):
            v = A[r,c]
            if mask[r,c]:
                B[r,c,:]=[1,1,1,0]
            else:
                try:
                    B[r,c,:]=colors[v]
                except KeyError,e:
                    B[r,c,:]=[0,0,0,1]

    return B
       
if __name__=='__main__':
    import pylab
    A = nx.array([[1,2,7],[1,2,2],[1,1,9]])
    print "A =",A
    A1 = ma.array(A,mask=ma.where(A==1,1,0))
    print "A1 =",A1
    colors={
        2:(1,0,0,1)
        ,7:(0,1,0,1)
    }
    B = enumimage(A1,colors)
    print "B =",B
    pylab.figure()
    pylab.hold()
   
pylab.imshow(B,interpolation='nearest',extent=0.5+nx.array([0,nx.size(A,0),nx.size(A,1),0]))
    pylab.axes
    pylab.show()

John Pye wrote:

···

Hi all

I have some data with enumerated values in an array. Values are like
1,2,7,9 spread around in the array. I want to plot those values so that
I can see the 'regions' in my data, then I want to overlay this with
some contour lines drawn from other data.

I want to be able to specify the colors for each of the enumerated
values, as they need to be consistent throughout my work. My array of
enumerated values is *masked* so that there are areas where I don't want
to show anything (this would plot as transparent pixels).

Has anyone got suggestions on the best way of doing this? It seems that
the technique in
http://www.scipy.org/Cookbook/Matplotlib/Plotting_Images_with_Special_Values
might be overkill, right? It also seemed that it had some problems with
masked arrays.

Cheers

JP

--
John Pye
School of Mechanical and Manufacturing Engineering
The University of New South Wales
Sydney NSW 2052 Australia
t +61 2 9385 5127
f +61 2 9663 1222
mailto:john.pye_AT_student_DOT_unsw.edu.au
http://pye.dyndns.org/

John,

Something like this might be what you want:

from pylab import *
import matplotlib.numerix.ma as ma
import matplotlib.colors as colors
xx = rand(10,15)
xxx = (xx*15 - 5).astype(Int)
xxx = ma.masked_where(xxx < 0, xxx)
xxx.set_fill_value(-1) #(not necessary)
cmap = colors.ListedColormap(('r', 'g', 'b',
                                 'c', 'y', 'm',
                                 'k', '0.3', '0.5',
                                 '0.7'))
#cmap.set_bad((1,1,1,0)) # setting alpha to zero does not work, at least
                         # for imshow
im = imshow(xxx, interpolation='nearest',
                  cmap=cmap, norm=colors.no_norm())
cb = colorbar(shrink=0.6)

What we are doing here is making a custom colormap from a list of colors (using any valid mpl color specification), and then indexing directly into it with values from a (masked) integer array. Note the use of "norm=colors.no_norm()" so that the array values are passed directly to the colormap as integers.

Caution: the colorbar command works correctly in this example only with the modifications that I committed to svn a few minutes ago.

As noted, the masked regions will have a specified color; they will not be transparent. If you need transparent masked regions, then try pcolor instead of imshow. Pcolor plots nothing at all in masked cells. Pcolormesh, on the other hand, is like imshow in plotting the assigned bad color and in using a single alpha for everything.

Eric

John Pye wrote:

···

Hi all

I have some data with enumerated values in an array. Values are like
1,2,7,9 spread around in the array. I want to plot those values so that
I can see the 'regions' in my data, then I want to overlay this with
some contour lines drawn from other data.

I want to be able to specify the colors for each of the enumerated
values, as they need to be consistent throughout my work. My array of
enumerated values is *masked* so that there are areas where I don't want
to show anything (this would plot as transparent pixels).

Has anyone got suggestions on the best way of doing this? It seems that
the technique in
http://www.scipy.org/Cookbook/Matplotlib/Plotting_Images_with_Special_Values
might be overkill, right? It also seemed that it had some problems with
masked arrays.

Cheers

JP

Hi Eric,

Thanks for your suggestion. The colorbar(shrink) command throws me an
error, as you said it would. But I get another error with the '0.3',
'0.5', etc. I had to replace those with (0.3,0.3,0.3) etc -- RGB tuples.

Finally, my plot only shows white, grey red. I don't get any other
colors -- do you? Is that because of the colorbar(shrink) thing, or is
something else not working? Do I *need* your SVN changes?

Also, when should I be using pcolor versus imshow? If my image is
constructed of colors at specified sample points, is it better that I
use pcolor? The pcolor command isn't mentioned at all in the matplotlib
user's guide...

Cheers
JP

Eric Firing wrote:

···

John,

Something like this might be what you want:

from pylab import *
import matplotlib.numerix.ma as ma
import matplotlib.colors as colors
xx = rand(10,15)
xxx = (xx*15 - 5).astype(Int)
xxx = ma.masked_where(xxx < 0, xxx)
xxx.set_fill_value(-1) #(not necessary)
cmap = colors.ListedColormap(('r', 'g', 'b',
                                'c', 'y', 'm',
                                'k', '0.3', '0.5',
                                '0.7'))
#cmap.set_bad((1,1,1,0)) # setting alpha to zero does not work, at least
                        # for imshow
im = imshow(xxx, interpolation='nearest',
                 cmap=cmap, norm=colors.no_norm())
cb = colorbar(shrink=0.6)

What we are doing here is making a custom colormap from a list of
colors (using any valid mpl color specification), and then indexing
directly into it with values from a (masked) integer array. Note the
use of "norm=colors.no_norm()" so that the array values are passed
directly to the colormap as integers.

Caution: the colorbar command works correctly in this example only
with the modifications that I committed to svn a few minutes ago.

As noted, the masked regions will have a specified color; they will
not be transparent. If you need transparent masked regions, then try
pcolor instead of imshow. Pcolor plots nothing at all in masked
cells. Pcolormesh, on the other hand, is like imshow in plotting the
assigned bad color and in using a single alpha for everything.

Eric

John Pye wrote:

Hi all

I have some data with enumerated values in an array. Values are like
1,2,7,9 spread around in the array. I want to plot those values so that
I can see the 'regions' in my data, then I want to overlay this with
some contour lines drawn from other data.

I want to be able to specify the colors for each of the enumerated
values, as they need to be consistent throughout my work. My array of
enumerated values is *masked* so that there are areas where I don't want
to show anything (this would plot as transparent pixels).

Has anyone got suggestions on the best way of doing this? It seems that
the technique in
http://www.scipy.org/Cookbook/Matplotlib/Plotting_Images_with_Special_Values

might be overkill, right? It also seemed that it had some problems with
masked arrays.

Cheers

JP

John,

It sounds like you are not using the latest *released* version of mpl, which is 0.87.3; the only thing in my example that requires svn is the colorbar command. If you did install 0.87.3, then you must have an earlier installation still in place and being found.

imshow requires a uniform rectangular grid. pcolor is much more general and colors rectangles specified by their boundaries, not their centers. pcolormesh is similar (though not identical) but faster.

As you described it, your application seems most natural for imshow, except for the problem with masked areas not being transparent. I suggested pcolor only as a workaround for that, if you really need that transparency.

Eric

John Pye wrote:

···

Hi Eric,

Thanks for your suggestion. The colorbar(shrink) command throws me an
error, as you said it would. But I get another error with the '0.3',
'0.5', etc. I had to replace those with (0.3,0.3,0.3) etc -- RGB tuples.

Finally, my plot only shows white, grey red. I don't get any other
colors -- do you? Is that because of the colorbar(shrink) thing, or is
something else not working? Do I *need* your SVN changes?

Also, when should I be using pcolor versus imshow? If my image is
constructed of colors at specified sample points, is it better that I
use pcolor? The pcolor command isn't mentioned at all in the matplotlib
user's guide...

Cheers
JP

Eric Firing wrote:

John,

Something like this might be what you want:

from pylab import *
import matplotlib.numerix.ma as ma
import matplotlib.colors as colors
xx = rand(10,15)
xxx = (xx*15 - 5).astype(Int)
xxx = ma.masked_where(xxx < 0, xxx)
xxx.set_fill_value(-1) #(not necessary)
cmap = colors.ListedColormap(('r', 'g', 'b',
                               'c', 'y', 'm',
                               'k', '0.3', '0.5',
                               '0.7'))
#cmap.set_bad((1,1,1,0)) # setting alpha to zero does not work, at least
                       # for imshow
im = imshow(xxx, interpolation='nearest',
                cmap=cmap, norm=colors.no_norm())
cb = colorbar(shrink=0.6)

What we are doing here is making a custom colormap from a list of
colors (using any valid mpl color specification), and then indexing
directly into it with values from a (masked) integer array. Note the
use of "norm=colors.no_norm()" so that the array values are passed
directly to the colormap as integers.

Caution: the colorbar command works correctly in this example only
with the modifications that I committed to svn a few minutes ago.

As noted, the masked regions will have a specified color; they will
not be transparent. If you need transparent masked regions, then try
pcolor instead of imshow. Pcolor plots nothing at all in masked
cells. Pcolormesh, on the other hand, is like imshow in plotting the
assigned bad color and in using a single alpha for everything.

Eric

John Pye wrote:

Hi all

I have some data with enumerated values in an array. Values are like
1,2,7,9 spread around in the array. I want to plot those values so that
I can see the 'regions' in my data, then I want to overlay this with
some contour lines drawn from other data.

I want to be able to specify the colors for each of the enumerated
values, as they need to be consistent throughout my work. My array of
enumerated values is *masked* so that there are areas where I don't want
to show anything (this would plot as transparent pixels).

Has anyone got suggestions on the best way of doing this? It seems that
the technique in
http://www.scipy.org/Cookbook/Matplotlib/Plotting_Images_with_Special_Values

might be overkill, right? It also seemed that it had some problems with
masked arrays.

Cheers

JP