problem with design of matplotlib.pyplot.scatter?

I'd like to generate a scatter plot in which symbols are colored using a
specified colormap, with a specified mapping from the range of the data to
the [0,1] colormap interval. I thought at first that one could use the norm
argument to specify a function that would perform this mapping, but from
closer reading of the documentation (and experimentation) it seems as though
one cannot do this. Is there another mechanism for doing this? (I could
remap the data itself before plotting it, but this is unacceptable because
the colorbar tic lables would then take values in [0,1] rather than values
from the range of the data).

···


View this message in context: http://www.nabble.com/problem-with-design-of-matplotlib.pyplot.scatter--tp25687299p25687299.html
Sent from the matplotlib - users mailing list archive at Nabble.com.

Dr. Phillip M. Feldman wrote:

I'd like to generate a scatter plot in which symbols are colored using a
specified colormap, with a specified mapping from the range of the data to
the [0,1] colormap interval. I thought at first that one could use the norm
argument to specify a function that would perform this mapping, but from
closer reading of the documentation (and experimentation) it seems as though
one cannot do this. Is there another mechanism for doing this? (I could
remap the data itself before plotting it, but this is unacceptable because
the colorbar tic lables would then take values in [0,1] rather than values
from the range of the data).

I don't understand--what you say you want to do is exactly what the norm is designed for. Maybe the problem is that you can't pass in a simple function--you need to subclass colors.Normalize. An example is colors.LogNorm.

It looks like what we need is a FuncNorm, which would be initialized with two functions, the forward and inverse transformation functions, each taking vmin, vmax, and a val.

Eric

Hello Eric-

I've looked at the code in colors.py. I think that I'm starting to understand what's going on, but I'm unclear about a few things. In particular:

- Why do we need to define both forward and reverse transformations? Shouldn't the forward transformation be sufficient?

- I don't follow what the snippet of code below is doing:

        if cbook.iterable(value):
            vtype = 'array'
            val = ma.asarray(value).astype(np.float)
        else:
            vtype = 'scalar'
            val = ma.array([value]).astype(np.float)

- In some cases I'd like to map the data values to discrete output values, e.g., values below x_0 map to 0 (which the colormap in turn maps to red), values between x_0 and x_1 map to 0.5 (which maps to yellow), and values greater than x_1 map to 1 (which maps to green). Such a function does not have a mathematical inverse because it is a many to one mapping. How does one handle this situation?

The ability to pass in an ordinary function (or a pair of functions if the inverse is really necessary) would be a great benefit.

Thanks!

Phillip

Eric Firing wrote:

···

Dr. Phillip M. Feldman wrote:

I'd like to generate a scatter plot in which symbols are colored using a
specified colormap, with a specified mapping from the range of the data to
the [0,1] colormap interval. I thought at first that one could use the norm
argument to specify a function that would perform this mapping, but from
closer reading of the documentation (and experimentation) it seems as though
one cannot do this. Is there another mechanism for doing this? (I could
remap the data itself before plotting it, but this is unacceptable because
the colorbar tic lables would then take values in [0,1] rather than values
from the range of the data).

I don't understand--what you say you want to do is exactly what the norm is designed for. Maybe the problem is that you can't pass in a simple function--you need to subclass colors.Normalize. An example is colors.LogNorm.

It looks like what we need is a FuncNorm, which would be initialized with two functions, the forward and inverse transformation functions, each taking vmin, vmax, and a val.

Eric

Phillip M. Feldman wrote:

Hello Eric-

I've looked at the code in colors.py. I think that I'm starting to understand what's going on, but I'm unclear about a few things. In particular:

- Why do we need to define both forward and reverse transformations? Shouldn't the forward transformation be sufficient?

The inverse is used by colorbar to auto-generate the boundaries and values arrays when they are not specified. The norms that do not have inverses have special-case code in colorbar to handle this.

- I don't follow what the snippet of code below is doing:

       if cbook.iterable(value):
           vtype = 'array'
           val = ma.asarray(value).astype(np.float)
       else:
           vtype = 'scalar'
           val = ma.array([value]).astype(np.float)

- In some cases I'd like to map the data values to discrete output values, e.g., values below x_0 map to 0 (which the colormap in turn maps to red), values between x_0 and x_1 map to 0.5 (which maps to yellow), and values greater than x_1 map to 1 (which maps to green). Such a function does not have a mathematical inverse because it is a many to one mapping. How does one handle this situation?

BoundaryNorm does exactly this--when working with a suitable colormap---and its lack of an inverse is handled inside colorbar.

from matplotlib import colors
x_0 = 0
x_1 = 0.5
cmap = colors.ListedColormap(['y'])
cmap.set_under('r')
cmap.set_over('g')
norm = colors.BoundaryNorm([x_0, x_1], cmap.N)
z = (np.arange(100) / 50.0) - 1.0
z.shape = (10,10)
imshow(z, cmap=cmap, norm=norm, interpolation='nearest')

The ability to pass in an ordinary function (or a pair of functions if the inverse is really necessary) would be a great benefit.

I will try to get to this ASAP.

Eric

···

Thanks!

Phillip

Eric Firing wrote:

Dr. Phillip M. Feldman wrote:

I'd like to generate a scatter plot in which symbols are colored using a
specified colormap, with a specified mapping from the range of the data to
the [0,1] colormap interval. I thought at first that one could use the norm
argument to specify a function that would perform this mapping, but from
closer reading of the documentation (and experimentation) it seems as though
one cannot do this. Is there another mechanism for doing this? (I could
remap the data itself before plotting it, but this is unacceptable because
the colorbar tic lables would then take values in [0,1] rather than values
from the range of the data).

I don't understand--what you say you want to do is exactly what the norm is designed for. Maybe the problem is that you can't pass in a simple function--you need to subclass colors.Normalize. An example is colors.LogNorm.

It looks like what we need is a FuncNorm, which would be initialized with two functions, the forward and inverse transformation functions, each taking vmin, vmax, and a val.

Eric

- I don't follow what the snippet of code below is doing:

       if cbook.iterable(value):
           vtype = 'array'
           val = ma.asarray(value).astype(np.float)
       else:
           vtype = 'scalar'
           val = ma.array([value]).astype(np.float)

The idea is that the norm __call__ method should return a scalar when given a scalar input, or an array when given a sequence input. It is easiest to do the calculation with masked arrays or ndarrays, however, so inputs are converted, keeping track of whether it is a scalar or not, so that if it is a scalar, the output can be converted from 1-element array back to a scalar.

Eric