|
From: T J <tj...@gm...> - 2010-05-27 19:32:57
|
Hi,
I am plotting with imshow() and interpolation is turned on
('gaussian'). Part of my issue is that the distribution of values is
such that I need to set the over/under colors to grab the most
relevant values. If I set the over color to be the "maximum" color,
then the result is too dark. Conversely for the under color. I can
set the over/under colors to not draw, but then I have "holes" in my
image. Is it possible to incorporate interpolation? That is, I would
like to set my over color to be interpolated among its neighboring
cells. This seems like it would require an (more) "intelligent"
colormap, so my guess is that this isn't currently supported. I'm
growing more comfortable with the mpl internals and might give a stab
at implementing this, but I'm not quite sure where to start.
Thanks in advance.
|
|
From: Eric F. <ef...@ha...> - 2010-05-27 22:24:00
|
On 05/27/2010 09:32 AM, T J wrote:
> Hi,
>
> I am plotting with imshow() and interpolation is turned on
> ('gaussian'). Part of my issue is that the distribution of values is
> such that I need to set the over/under colors to grab the most
> relevant values. If I set the over color to be the "maximum" color,
> then the result is too dark. Conversely for the under color. I can
> set the over/under colors to not draw, but then I have "holes" in my
> image. Is it possible to incorporate interpolation? That is, I would
> like to set my over color to be interpolated among its neighboring
> cells. This seems like it would require an (more) "intelligent"
> colormap, so my guess is that this isn't currently supported. I'm
> growing more comfortable with the mpl internals and might give a stab
> at implementing this, but I'm not quite sure where to start.
>
> Thanks in advance.
I'm not sure I understand the problem; could you provide a tiny example
to illustrate?
Eric
|
|
From: T J <tj...@gm...> - 2010-05-27 23:58:40
|
On Thu, May 27, 2010 at 3:23 PM, Eric Firing <ef...@ha...> wrote: > > I'm not sure I understand the problem; could you provide a tiny example > to illustrate? > Sure, let me focus just on the interpolation and I'll leave the filtering issue out. In the script below, I plot a 3x3 array with the center element having an "over" value. In the default case, because its value is over, the colormap will assign it the maximum color. I also plot the case when the "over" color is explicitly set to the minimum color and also to white. What I want is this: The center element should be an equal mixture of the 4 elements around it. This is partially achieved with "white" (and I suppose I could pick "grey" or "black"), but I think it might be nicer if it were a pure mixture, rather than a mixture of the surrounding colors and the "over" color. The script is attached below. Sorry it is a bit long, but I needed a discrete colormap. Can we get cmap_discrete() into matplotlib? ------------------ import matplotlib.pyplot as plt import matplotlib.colors import numpy as np from scipy import interpolate #### http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations #### Can this be added to matplotlib? def cmap_discretize(cmap, N): """Return a discrete colormap from the continuous colormap cmap. cmap: colormap instance, eg. cm.jet. N: Number of colors. Example x = resize(arange(100), (5,100)) djet = cmap_discretize(cm.jet, 5) imshow(x, cmap=djet) """ cdict = cmap._segmentdata.copy() # N colors colors_i = np.linspace(0,1.,N) # N+1 indices indices = np.linspace(0,1.,N+1) for key in ('red','green','blue'): # Find the N colors D = np.array(cdict[key]) I = interpolate.interp1d(D[:,0], D[:,1]) colors = I(colors_i) # Place these colors at the correct indices. A = np.zeros((N+1,3), float) A[:,0] = indices A[1:,1] = colors A[:-1,2] = colors # Create a tuple for the dictionary. L = [] for l in A: L.append(tuple(l)) cdict[key] = tuple(L) # Return colormap object. return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024) def draw(m, cm, norm, ncolors): ax = plt.gca() ai = ax.imshow(m, cmap=cm, norm=norm, interpolation='gaussian') cb = ax.figure.colorbar(ai) cb.set_ticks(np.linspace(.5, ncolors-.5, ncolors)) cb.set_ticklabels(['$%s$' % (i,) for i in np.arange(ncolors)]) return ai, cb if __name__ == '__main__': ncolors = 4 norm = plt.Normalize(vmax=ncolors) m = np.array([[0, 0, 1], [3, 10, 1], [3, 2, 2]]) for over in [None, 'min', (1,1,1,1)]: f = plt.figure() cm = cmap_discretize(plt.cm.jet, ncolors) if over == 'min': cm.set_over(cm(0.0)) elif over is not None: cm.set_over(over) ai, cb = draw(m, cm, norm, ncolors) plt.show() |
|
From: Eric F. <ef...@ha...> - 2010-05-28 00:44:22
|
On 05/27/2010 01:58 PM, T J wrote:
> On Thu, May 27, 2010 at 3:23 PM, Eric Firing<ef...@ha...> wrote:
>>
>> I'm not sure I understand the problem; could you provide a tiny example
>> to illustrate?
>>
>
> Sure, let me focus just on the interpolation and I'll leave the
> filtering issue out.
>
> In the script below, I plot a 3x3 array with the center element having
> an "over" value. In the default case, because its value is over, the
> colormap will assign it the maximum color. I also plot the case when
> the "over" color is explicitly set to the minimum color and also to
> white. What I want is this:
>
> The center element should be an equal mixture of the 4 elements around it.
You can't do this via any manipulation of the colormap, or any fancier
colormap specification--instead, you have to manipulate the data value.
For example, you could identify the "over" values in your data, and
then use 2-D interpolation to replace them with the values you want.
Basemap includes a 2-D interpolation routine:
from mpl_toolkits.basemap import interp
>
> This is partially achieved with "white" (and I suppose I could pick
> "grey" or "black"), but I think it might be nicer if it were a pure
> mixture, rather than a mixture of the surrounding colors and the
> "over" color.
>
> The script is attached below. Sorry it is a bit long, but I needed a
> discrete colormap. Can we get cmap_discrete() into matplotlib?
No, because it doesn't make much sense, given the mpl paradigm in which
a colormap and a norm work together. If you want 4 colors, make a
colormap with 4 colors, and use a norm that maps your data to those 4
colors.
For example:
cm4 = get_cmap('jet', 4)
cm4a = mpl.colors.ListedColormap(get_cmap('jet', 256)([20, 70, 150, 200]))
You can select any discrete set of colors you want using ListedColormap.
Then you can use the default Normalize, or a custom BoundaryNorm, to map
data ranges to the colors. You just don't need a lookup table with 1024
entries to specify 4 colors--it doesn't gain you anything.
Eric
>
> ------------------
>
> import matplotlib.pyplot as plt
> import matplotlib.colors
>
> import numpy as np
> from scipy import interpolate
>
> #### http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations
> #### Can this be added to matplotlib?
> def cmap_discretize(cmap, N):
> """Return a discrete colormap from the continuous colormap cmap.
>
> cmap: colormap instance, eg. cm.jet.
> N: Number of colors.
>
> Example
> x = resize(arange(100), (5,100))
> djet = cmap_discretize(cm.jet, 5)
> imshow(x, cmap=djet)
> """
>
> cdict = cmap._segmentdata.copy()
> # N colors
> colors_i = np.linspace(0,1.,N)
> # N+1 indices
> indices = np.linspace(0,1.,N+1)
> for key in ('red','green','blue'):
> # Find the N colors
> D = np.array(cdict[key])
> I = interpolate.interp1d(D[:,0], D[:,1])
> colors = I(colors_i)
> # Place these colors at the correct indices.
> A = np.zeros((N+1,3), float)
> A[:,0] = indices
> A[1:,1] = colors
> A[:-1,2] = colors
> # Create a tuple for the dictionary.
> L = []
> for l in A:
> L.append(tuple(l))
> cdict[key] = tuple(L)
> # Return colormap object.
> return matplotlib.colors.LinearSegmentedColormap('colormap',cdict,1024)
>
> def draw(m, cm, norm, ncolors):
> ax = plt.gca()
> ai = ax.imshow(m, cmap=cm, norm=norm, interpolation='gaussian')
> cb = ax.figure.colorbar(ai)
> cb.set_ticks(np.linspace(.5, ncolors-.5, ncolors))
> cb.set_ticklabels(['$%s$' % (i,) for i in np.arange(ncolors)])
> return ai, cb
>
> if __name__ == '__main__':
> ncolors = 4
> norm = plt.Normalize(vmax=ncolors)
> m = np.array([[0, 0, 1],
> [3, 10, 1],
> [3, 2, 2]])
>
> for over in [None, 'min', (1,1,1,1)]:
> f = plt.figure()
> cm = cmap_discretize(plt.cm.jet, ncolors)
> if over == 'min':
> cm.set_over(cm(0.0))
> elif over is not None:
> cm.set_over(over)
> ai, cb = draw(m, cm, norm, ncolors)
>
> plt.show()
|
|
From: T J <tj...@gm...> - 2010-05-28 08:16:11
|
On Thu, May 27, 2010 at 5:44 PM, Eric Firing <ef...@ha...> wrote:
> You can't do this via any manipulation of the colormap, or any fancier
> colormap specification--instead, you have to manipulate the data value. For
> example, you could identify the "over" values in your data, and then use 2-D
> interpolation to replace them with the values you want.
>
> Basemap includes a 2-D interpolation routine:
>
> from mpl_toolkits.basemap import interp
>
Thanks!
>>
>> This is partially achieved with "white" (and I suppose I could pick
>> "grey" or "black"), but I think it might be nicer if it were a pure
>> mixture, rather than a mixture of the surrounding colors and the
>> "over" color.
>>
>> The script is attached below. Sorry it is a bit long, but I needed a
>> discrete colormap. Can we get cmap_discrete() into matplotlib?
>
> No, because it doesn't make much sense, given the mpl paradigm in which a
> colormap and a norm work together. If you want 4 colors, make a colormap
> with 4 colors, and use a norm that maps your data to those 4 colors.
>
> For example:
>
> cm4 = get_cmap('jet', 4)
> cm4a = mpl.colors.ListedColormap(get_cmap('jet', 256)([20, 70, 150, 200]))
>
> You can select any discrete set of colors you want using ListedColormap.
>
> Then you can use the default Normalize, or a custom BoundaryNorm, to map
> data ranges to the colors. You just don't need a lookup table with 1024
> entries to specify 4 colors--it doesn't gain you anything.
>
Wonderful. Definitely makes the cookbook entry seem unnecessary
|