Standard use of matplotlib color printing

I am using matplotlib 1.3.0 and I have the following:

import matplotlib.pyplot as plt cmap = plt.cm.jet plt.contourf([[.12, .2], [.8, 2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap, vmin=0, vmax=3) plt.colorbar() 

which produces:

enter image description here

A bit that I don’t understand, where do all the other colors go? As I understand it, specifying vmin=0 , vmax=3 , then the color bar should use the entire cmap range, as in this image:

enter image description here

which is created without providing the arguments vmin , vmax and levels . So ... what am I missing here?

EDIT 1

In response to tom10 and tcaswell. I would expect it to be the way you say it, but ... unfortunately, it is not. Take a look at this:

 plt.contourf([[.12, .2], [.8, 3.2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap, vmin=0, vmax=3) plt.colorbar() 

from:

enter image description here

Perhaps this is a little clarify: let's say I have data, and important features - about 0.1, but there are about 3, say. Therefore, I give it levels=[0, 0.005, 0.075, 0.1, 0.125, 0.15, 0.2, 1, 2.5, 2.75, 3, 3.25] and vmin=0, vmax=3.25 . Now I expect to see the whole range of colors, but instead, all the important data points from 0.005 to 0.125 will be in the blue area (using the standard plt.cm.jet color map). I think I think ... if I give levels=[0, 1, 2, 3], vmin=0, vmax=3 for some data that go from 0 to 3, I expect to see all the colors in this color to the map, but if I give levels=[0, 0.9, 0.1, 0.11, 1, 3], vmi=0, vmax=3 , I would expect the same thing to see all the colors in this color map, except for the display at the right intervals, instead I see a bunch of blues staining the 0-0.11 area, and some green / yellow colors in another part of the region. Hope this is ... a little clear.

EDIT 2

The same thing happens even if I don't give any norm or vmin, vmax .

EDIT 3

Referring to the tcaswell comment, we act as if ... for me, at least, it contradicts intuition. I expected the color to be incompatible with data points. I would expect that the entire range of colors from the color palette will be used all the time (except when vmin, vmax greater / less than the levels min, max values). In other words, looking at this code, I did some time ago (Python 3):

 import matplotlib.colors as mc def addNorm(cmapData): cmapData['norm'] = mc.BoundaryNorm(cmapData['bounds'], cmapData['cmap'].N) return True def discretize(cmap, bounds): resCmap = {} resCmap['cmap'] = mc.ListedColormap( \ [cmap(i/len(bounds[1:])) for i in range(len(bounds[1:]))] ) resCmap['bounds'] = bounds addNorm(resCmap) return resCmap 

then use it like:

 levels = [0, .1, .3, .5, 1, 3] cmapData = discretize(plt.cm.jet, bounds=levels) plt.contourf([[.12, .2], [.8, 3.2]], levels=levels, cmap=cmapData['cmap'], norm=cmapData['norm']) plt.colorbar() 

which gives a graph in which you can really distinguish the signs (0.1-0.5), i.e. they are no longer in the blue area using the above method with plt.cm.jet :

enter image description here

I mean, I know that I solved this, and some time ago too ... but my question is, I think ... how it turned out that the default in matplotlib is not so? I would expect it to be that way ... or maybe it's just a configuration / argument / something to enable this by default, what am I missing?

+8
matplotlib colorbar color-mapping
source share
4 answers

After playing a little, it seems that the answer to this question is much simpler than I ever thought. First, I’ll explain some explanation. Reading the documentation for normalizing classes from matplotlib.colors , I realized ... well, matplotlib.colors.BoundaryNorm should be used here! but something is wrong, as you can see in the following example:

 import matplotlib.pyplot as plt import matplotlib.colors as mc levels = [0, .1, .3, .5, 1, 3] norm = mc.BoundaryNorm(levels, len(levels)-1) plt.contourf([[.12, .2], [.8, 2]], levels=levels, norm=norm) plt.colorbar() plt.show() 

which gives the following: enter image description here and this is clearly what we do not want! And I thought ... why should you give the BoundaryNorm constructor the number of colors to use? ... Shouldn't BoundaryNorm use the full color map? And then it hit me only by slightly changing the code above:

 # use here 256 instead of len(levels)-1 becuase # as it mentioned in the documentation for the # colormaps, the default colormaps use 256 colors in their # definition: print(plt.cm.jet.N) for example norm = mc.BoundaryNorm(levels, 256) 

and get: enter image description here this is exactly what we want!

Or you can do:

 cmap = # user define cmap norm = mc.BoundaryNorm(levels, cmap.N) # which is I guess a little bit more programatically (is this a word?!) correct 
+3
source share

The color of the filled area is selected by the midpoint of the two lines that it fills between (iirc). The yellow you see is display 2 according to the color map and the restrictions you set.

If you want to match the color by register index, do a little correction of the monkeys:

 def _process_colors_by_index(self): """ Color argument processing for contouring. The color is based in the index in the level set, not the actual value of the level. """ self.monochrome = self.cmap.monochrome if self.colors is not None: # Generate integers for direct indexing. i0, i1 = 0, len(self.levels) if self.filled: i1 -= 1 # Out of range indices for over and under: if self.extend in ('both', 'min'): i0 = -1 if self.extend in ('both', 'max'): i1 += 1 self.cvalues = list(range(i0, i1)) self.set_norm(colors.NoNorm()) else: self.cvalues = range(len(self.levels)) self.set_array(range(len(self.levels))) self.autoscale_None() if self.extend in ('both', 'max', 'min'): self.norm.clip = False # self.tcolors are set by the "changed" method orig = matplotlib.contour.ContourSet._process_colors matplotlib.contour.ContourSet._process_colors = _process_colors_by_index cmap = plt.cm.jet figure() out = plt.contourf([[.12, .2], [.8, 2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap) plt.colorbar() # fix what we have done matplotlib.contour.ContourSet._process_colors = orig 

output

You can probably do better and remove the 1/2 shift as well.

You can also achieve and simply change the color of existing contours. It looks like you need to change the values ​​of out.cvalues and then call out.changed() on the object.

A less destructive version would be to write a custom norm by subclassing matplotlib.colors.Normalize , see colors.py for a template.

+2
source share

The maximum value of your data is 2 . In the plot in question, you set vmax=3 .

In more detail, vmax sets the range of colors used in matching. Since this is much larger than your data range, when you create the data, you do not see the full range of colors. This is even more confusing for the small number of levels that you have chosen, which does not show you all the available colors, since the color bar displays only one color for the entire range from 1 to 3, again, the shading of the available colors is above 2.

0
source share

In fact, I think the best solution so far is in this place:

http://protracted-matter.blogspot.ie/2012/08/nonlinear-colormap-in-matplotlib.html

He defines this little class that solves all the problems:

 class nlcmap(mc.LinearSegmentedColormap): """A nonlinear colormap""" name = 'nlcmap' def __init__(self, cmap, levels): self.cmap = cmap # @MRR: Need to add N for backend self.N = cmap.N self.monochrome = self.cmap.monochrome self.levels = np.asarray(levels, dtype='float64') self._x = self.levels / self.levels.max() self._y = np.linspace(0.0, 1.0, len(self.levels)) #@MRR Need to add **kw for 'bytes' def __call__(self, xi, alpha=1.0, **kw): yi = np.interp(xi, self._x, self._y) return self.cmap(yi, alpha) 

The script was originally developed by a guy named Robert Hetland. All details are indicated in the link above.

0
source share

All Articles