Bug in colorbar()

I am trying to make a plot with a colorbar that has a reduced axis over which the colorbar is executed.

This is set via passing in a norm to contourf:

logNorm = colors.Normalize(vmax=0,vmin=-100)

surf = ax.contourf(X,Y,logZ, map_scale, cmap=cm.jet, norm=logNorm)

The output of this will have the colorbar extend to the full range of the data and not limited by the norm set:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03)

so I assumed modifying by setting the norm like this would do the trick:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03, norm=logNorm)

This isn’t what happens. norm has no effect. The norm is recognized but not passed to ColorbarBase is my guess from doing this instead to get the desired effect:

axcb, _ = mpl.colorbar.make_axes_gridspec(ax, shrink=0.7)

cbar = mpl.colorbar.ColorbarBase(axcb, cmap=cm.jet, norm=logNorm)

Is this a bug or any reason why the norm is not passed through if specified in colorbar??

Yes, there is a reason why it is not passed through; both the cmap and the norm are taken from the mappable, so that the colorbar will actually match the mappable. There may be a bug, but it is not immediately obvious to me. Please provide a complete, minimal, self-contained example that illustrates the problem, and specify what version of mpl you are using.

Eric

···

On 2012/07/26 7:52 PM, Jeffrey Spencer wrote:

I am trying to make a plot with a colorbar that has a reduced axis over
which the colorbar is executed.

This is set via passing in a norm to contourf:
         logNorm = colors.Normalize(vmax=0,vmin=-100)
         surf = ax.contourf(X,Y,logZ, map_scale, cmap=cm.jet, norm=logNorm)

The output of this will have the colorbar extend to the full range of
the data and not limited by the norm set:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03)

so I assumed modifying by setting the norm like this would do the trick:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03,
norm=logNorm)

This isn't what happens. norm has no effect. The norm is recognized but
not passed to ColorbarBase is my guess from doing this instead to get
the desired effect:

         axcb, _ = mpl.colorbar.make_axes_gridspec(ax, shrink=0.7)
         cbar = mpl.colorbar.ColorbarBase(axcb, cmap=cm.jet, norm=logNorm)

Is this a bug or any reason why the norm is not passed through if
specified in colorbar??

Further after doing a little digging the code in matplotlib.colorbar.Colorbar looks correct to me but doesn’t work correctly.

It essentially ignores the norm value because always sets the norm to the norm for the contour plot (eg. mappable.norm) which this is the same norm with vmin and vmax values I want to use anyway. It seems as though somehow instead it uses the vmin and vmax not from the norm but from the actual data.

So from the code below it would use vmin and vmax from the mappable object (eg. surf) which are (-152,0). It won’t use surf.norm vmin and vmax values which are desired (-100,0). I couldn’t find where this mistake occurs because looked right to me from prodding around but let me know.

···

Jeff Spencer

Department of Electrical and Electronic Engineering

The University of Melbourne

jeffspencerd@…287…

On Fri, Jul 27, 2012 at 3:52 PM, Jeffrey Spencer <jeffspencerd@…287…> wrote:

I am trying to make a plot with a colorbar that has a reduced axis over which the colorbar is executed.

This is set via passing in a norm to contourf:

logNorm = colors.Normalize(vmax=0,vmin=-100)

surf = ax.contourf(X,Y,logZ, map_scale, cmap=cm.jet, norm=logNorm)

The output of this will have the colorbar extend to the full range of the data and not limited by the norm set:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03)

so I assumed modifying by setting the norm like this would do the trick:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03, norm=logNorm)

This isn’t what happens. norm has no effect. The norm is recognized but not passed to ColorbarBase is my guess from doing this instead to get the desired effect:

axcb, _ = mpl.colorbar.make_axes_gridspec(ax, shrink=0.7)

cbar = mpl.colorbar.ColorbarBase(axcb, cmap=cm.jet, norm=logNorm)

Is this a bug or any reason why the norm is not passed through if specified in colorbar??

I am using 1.2.X and here is a minimalist example to see what happens:

Link to figure of output:

https://dl.dropbox.com/u/13534143/example.png

Example:

import numpy as np

import matplotlib as mpl

X, Y = np.meshgrid(arange(20),arange(20))

Z = np.arange(20*20)

Z = Z.reshape(20,20)

logNorm = mpl.colors.Normalize(vmin=0,vmax=200)

fig = mpl.pyplot.figure(10)

ax = fig.add_subplot(111)

surf = ax.contourf(X,Y,Z, 100, cmap=matplotlib.cm.jet, norm = logNorm)

cbar = fig.colorbar(surf, shrink=0.70, norm=logNorm)

show()

draw()

···

On Fri, Jul 27, 2012 at 5:00 PM, Eric Firing <efiring@…202…> wrote:

On 2012/07/26 7:52 PM, Jeffrey Spencer wrote:

I am trying to make a plot with a colorbar that has a reduced axis over

which the colorbar is executed.

This is set via passing in a norm to contourf:

     logNorm = colors.Normalize(vmax=0,vmin=-100)
     surf = ax.contourf(X,Y,logZ, map_scale, cmap=cm.jet, norm=logNorm)

The output of this will have the colorbar extend to the full range of

the data and not limited by the norm set:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03)

so I assumed modifying by setting the norm like this would do the trick:

cbar = fig.colorbar(surf, shrink=0.70, aspect=36, fraction=.15,pad=.03,

norm=logNorm)

This isn’t what happens. norm has no effect. The norm is recognized but

not passed to ColorbarBase is my guess from doing this instead to get

the desired effect:

     axcb, _ = mpl.colorbar.make_axes_gridspec(ax, shrink=0.7)
     cbar = mpl.colorbar.ColorbarBase(axcb, cmap=cm.jet, norm=logNorm)

Is this a bug or any reason why the norm is not passed through if

specified in colorbar??

Yes, there is a reason why it is not passed through; both the cmap and

the norm are taken from the mappable, so that the colorbar will actually

match the mappable. There may be a bug, but it is not immediately

obvious to me. Please provide a complete, minimal, self-contained

example that illustrates the problem, and specify what version of mpl

you are using.

Eric


Live Security Virtual Conference

Exclusive live event will cover all the ways today’s security and

threat landscape has changed and how IT managers can respond. Discussions

will include endpoint security, mobile security and the latest in malware

threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

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

OK, the basic problem here is that you are specifying 100 levels, which are being auto-selected to cover the actual data range; and the colorbar is doing what it is supposed to do, which is show the levels you actually have. Try leaving out the norm, and just specify the levels to cover what you want, more like this:

surf = ax.contourf(X, Y, Z, np.arange(0, 200.1, 2), cmap=mpl.cm.jet, extend='both')
cbar = fig.colorbar(surf, shrink=0.7)

If you actually do want a log norm, you can pass that in to contourf and it will be passed on to colorbar; but most likely you should still specify the levels you want as an array, and not specify vmin and vmax in the norm. If you want log scaling, it may work better to simply plot the log of Z, and use the colorbar label to indicate that this is what you are doing.

Note that with a recent change, you can use the set_under and set_over methods of the cmap to specify arbitrary colors, or no color, for the extended regions; or you can leave out the "extend" kwarg and not color the regions outside the range of your contour levels.

In general, contourf is most appropriate when there is a moderate number of levels, well under 100; if you want that many gradations, then you might do better with pcolormesh or ax.pcolorfast or imshow. For those image-like methods, it is appropriate to use vmin and vmax, either directly, or in a norm.

Eric

···

On 2012/07/26 9:20 PM, Jeffrey Spencer wrote:

import numpy as np
import matplotlib as mpl
X, Y = np.meshgrid(arange(20),arange(20))
Z = np.arange(20*20)
Z = Z.reshape(20,20)
logNorm = mpl.colors.Normalize(vmin=0,vmax=200)
fig = mpl.pyplot.figure(10)
ax = fig.add_subplot(111)
surf = ax.contourf(X,Y,Z, 100, cmap=matplotlib.cm.jet, norm = logNorm)
cbar = fig.colorbar(surf, shrink=0.70, norm=logNorm)
show()