modifying colorbar ticklabels

Hi,

it's probably a rather simple problem. Unfortunately I'm unable to solve it.

The following code example describes my problem:
import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

pyplot.contourf(x,y,z)

cb = pyplot.colorbar(format=r"%2.1f")
for j in cb.ax.get_yticklabels():
   j.set_text('bla')
pyplot.show()

Now I'd like to change the smallest label of the colorbar to 0.0 (without the minus sign). But any attemps to change the ticklabels of the colorbar fail:

cb = pyplot.colorbar(format=r"%2.1f")
for j in cb.ax.get_yticklabels():
   j.set_text('bla')
pyplot.show()

Doesn't do anything. Evenmore I don't understand why
for j in cb.ax.get_yticklabels():
   print str(j)

results in

Text(0,0,'')

Thanks in advance

Mario Mech

2010/1/20 Mario Mech <mech@...2927...>:
cb = pyplot.colorbar(format=r"%2.1f")
for j in cb.ax.get_yticklabels():
j.set_text('bla')
pyplot.show()

Doesn't do anything.

It looks like cb.ax.get_yticklabels() returns a list of copies of the
Text objects. Since you are only changing the copies it has no effect
on your figure.

You'll need to use cb.ax.set_yticklabels() and pass a list of strings
to use as tick labels. See
http://matplotlib.sourceforge.net/examples/pylab_examples/colorbar_tick_labelling_demo.html
for an example.

Cheers,
Scott

Ok, something like

cl = cb.ax.get_yticklabels()
cl[0].set_text('bla')
cb.ax.set_yticklabels([elem.get_text() for elem in cl])

would work for the horizontal colorbars and y replaced by x. But

cl = cb.ax.get_yticklabels()

results in a list of Text objects like Text(0,0,''). So my problem is more to get the TickLabels for vertical colorbars.

Cheers

Mario

···

On 20.01.2010 14:55, Scott Sinclair wrote:

2010/1/20 Mario Mech<mech@...2927...>:
cb = pyplot.colorbar(format=r"%2.1f")
for j in cb.ax.get_yticklabels():
   j.set_text('bla')
pyplot.show()

Doesn't do anything.

It looks like cb.ax.get_yticklabels() returns a list of copies of the
Text objects. Since you are only changing the copies it has no effect
on your figure.
You'll need to use cb.ax.set_yticklabels() and pass a list of strings
to use as tick labels. See
http://matplotlib.sourceforge.net/examples/pylab_examples/colorbar_tick_labelling_demo.html
for an example.

Cheers,
Scott

--
Dr. Mario Mech

Institute for Geophysics and Meteorology
University of Cologne
Zuelpicher Str. 49a
50674 Cologne
Germany

t: +49 (0)221 - 470 - 1776
f: +49 (0)221 - 470 - 5198
e: mech@...2927...
w: http://www.meteo.uni-koeln.de/~mmech/

2010/1/20 Mario Mech <mech@...2927...>:
Ok, something like

cl = cb.ax.get_yticklabels()
cl[0].set_text('bla')
cb.ax.set_yticklabels([elem.get_text() for elem in cl])

This works for me.

But

cl = cb.ax.get_yticklabels()

results in a list of Text objects like Text(0,0,'').

I have no idea what's happening then. I see:

for l in cl:
     print(l)

Text(0,0,'bla')
Text(0.166667,0.166667,'1.5')
Text(0.333333,0.333333,'3.0')
Text(0.5,0.5,'4.5')
Text(0.666667,0.666667,'6.0')
Text(0.833333,0.833333,'7.5')
Text(1,1,'9.0')

Cheers,
Scott

This works for me.

But

cl = cb.ax.get_yticklabels()

results in a list of Text objects like Text(0,0,'').

I have no idea what's happening then. I see:

for l in cl:
      print(l)

Text(0,0,'bla')
Text(0.166667,0.166667,'1.5')
Text(0.333333,0.333333,'3.0')
Text(0.5,0.5,'4.5')
Text(0.666667,0.666667,'6.0')
Text(0.833333,0.833333,'7.5')
Text(1,1,'9.0')

Cheers,
Scott

Has it anything to do with my matplotlib version (0.99.0) and python (2.6.4) on ubuntu karmic?

following code:

···

#------
import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

pyplot.contourf(x,y,z)

cb = pyplot.colorbar()

for j in cb.ax.get_yticklabels():
   print(j)
#----

results in:

Text(0,0,'')

That's not what i expected and makes it hard to change single ticklabels.

Cheers,

Mario
--
Dr. Mario Mech

Institute for Geophysics and Meteorology
University of Cologne
Zuelpicher Str. 49a
50674 Cologne
Germany

t: +49 (0)221 - 470 - 1776
f: +49 (0)221 - 470 - 5198
e: mech@...2927...
w: http://www.meteo.uni-koeln.de/~mmech/

Mario Mech wrote:

...
#------
import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

pyplot.contourf(x,y,z)

cb = pyplot.colorbar()

for j in cb.ax.get_yticklabels():
   print(j)
#----

results in:

Text(0,0,'')
...

I think you have to pyplot.show() or pyplot.savefig("deleteme.ps") in
order to have the ticklabels populated.

best,
sebastian.

Can you elaborate why you need to do this?
This is a general behavior of Axes in matplotlib (i.e., not colorbar
specific). There are things that are evaluated later when the figure
gets drawn.
You may use iter_ticks method if it fits your need.

for j, p, l in cb.ax.yaxis.iter_ticks():
    print l

To change the ticklabels of colorbar, they need to be set when the
colorbar is created, as Scott suggested. This is a limitation of the
current colobar implementation. Changing ticklabels (or locations)
after colorbar is created is quite tricky.

Regards,

-JJ

···

On Wed, Jan 20, 2010 at 9:17 AM, Mario Mech <mech@...2927...> wrote:

cl = cb.ax.get_yticklabels()

results in a list of Text objects like Text(0,0,''). So my problem is more to get the TickLabels for vertical colorbars.

Can you elaborate why you need to do this?

As you can see in my example:

···

#------
import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

pyplot.contourf(x,y,z)

cb = pyplot.colorbar()

pyplot.show()
#------

the smallest value (0.0) is labeled with "-0.0". I just want to get rid of the minus sign.

Cheers

Mario

This is a general behavior of Axes in matplotlib (i.e., not colorbar
specific). There are things that are evaluated later when the figure
gets drawn.
You may use iter_ticks method if it fits your need.

for j, p, l in cb.ax.yaxis.iter_ticks():
     print l

To change the ticklabels of colorbar, they need to be set when the
colorbar is created, as Scott suggested. This is a limitation of the
current colobar implementation. Changing ticklabels (or locations)
after colorbar is created is quite tricky.

Regards,

-JJ

--
Dr. Mario Mech

Institute for Geophysics and Meteorology
University of Cologne
Zuelpicher Str. 49a
50674 Cologne
Germany

t: +49 (0)221 - 470 - 1776
f: +49 (0)221 - 470 - 5198
e: mech@...2927...
w: http://www.meteo.uni-koeln.de/~mmech/

This is because the actual value is "-9.00000000e-06" (this inherits
from the levels of contour).
While I think we're fixing a wrong problem (the contour routine need
to be fixed in my view), here is a workaround you may use.

-JJ

import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

cntr = pyplot.contourf(x,y,z)

cb = pyplot.colorbar(format=r"%2.1f")

ticklabel_seq = cb.ax.yaxis.major.formatter.seq
try:
    indx = ticklabel_seq.index("-0.0")
    ticklabel_seq[indx]="0.0"
except ValueError:
    pass

pyplot.show()

···

On Wed, Jan 20, 2010 at 12:12 PM, Mario Mech <mech@...2927...> wrote:

the smallest value (0.0) is labeled with "-0.0". I just want to get rid of the minus sign.

Jae-Joon Lee wrote:

the smallest value (0.0) is labeled with "-0.0". I just want to get rid of the minus sign.

This is because the actual value is "-9.00000000e-06" (this inherits
from the levels of contour).
While I think we're fixing a wrong problem (the contour routine need
to be fixed in my view), here is a workaround you may use.

Careful, that slight adjustment of the lower limit, when automatically generated, is there for a reason (though I don't recall offhand where it is arising and why). There may be a better way to do it--and we can try to figure it out and implement it--but my advice in general is: don't use automatically generated contour or contourf levels except for exploratory, interactive work, when slight imperfections are acceptable. Instead, figure out what levels you really want, and supply them explicitly as one of the arguments.

Second and related advice: don't fiddle directly with tick labels except as a *last* resort. Instead, take care in selecting tick values, and if necessary, customize the Formatter.

The fact that a default Formatter is writing -0.0 strikes me as a bug that should be fixed in the Formatter; but it would be good to have more opinions about this.

Eric

···

On Wed, Jan 20, 2010 at 12:12 PM, Mario Mech <mech@...2927...> wrote:

-JJ

import numpy as np
from matplotlib import pyplot,mpl

x = np.arange(10)
y = np.arange(25)
z = np.floor(10*np.random.random((25,10)))

cntr = pyplot.contourf(x,y,z)

cb = pyplot.colorbar(format=r"%2.1f")

ticklabel_seq = cb.ax.yaxis.major.formatter.seq
try:
    indx = ticklabel_seq.index("-0.0")
    ticklabel_seq[indx]="0.0"
except ValueError:
    pass

pyplot.show()

------------------------------------------------------------------------------
Throughout its 18-year history, RSA Conference consistently attracts the
world's best and brightest in the field, creating opportunities for Conference
attendees to learn about information security's most important issues through
interactions with peers, luminaries and emerging and established companies.
http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Jae-Joon Lee wrote:

the smallest value (0.0) is labeled with "-0.0". I just want to get rid of the minus sign.

This is because the actual value is "-9.00000000e-06" (this inherits
from the levels of contour).

The reason for this fudge in contour is that contourf fills
lower < z <= upper
for each consecutive pair of contour levels.
When the minimum value of z coincides with the lowest level, then regions with that minimum are left blank; so the lowest level is adjusted downward slightly, making the lowest contour interval include the minimum value.

The fudge could be made optional via a kwarg, e.g.,
include_minimum=True (default) or False (to defeat the fudge).

This would not help Mario, though, assuming he is happy with the present contouring, and simply wants sane labeling of the 0-tick. For that, a Formatter adjustment is the simplest solution.

Eric

···

On Wed, Jan 20, 2010 at 12:12 PM, Mario Mech <mech@...2927...> wrote:

Second and related advice: don't fiddle directly with tick labels except as
a *last* resort. Instead, take care in selecting tick values, and if
necessary, customize the Formatter.

Agreed. It was a quick hack.

The fact that a default Formatter is writing -0.0 strikes me as a bug that
should be fixed in the Formatter; but it would be good to have more opinions
about this.

This is a behavior of python and I think it makes sense.

In [92]: print "%2.1f" % (-9e-6,)
-0.0

Regards,

-JJ

···

On Wed, Jan 20, 2010 at 1:36 PM, Eric Firing <efiring@...202...> wrote:

I understand levels can be adjusted for a better contouring, but I'm
not sure whether this change needs to be visible to users.

The autoleveler, initially creates following levels

[0, 1.5, 3, 4.5, 6, 7.5, 9.]

But due to the reason you described above, they become

array([ -9.00000000e-06, 1.50000000e+00, 3.00000000e+00,
         4.50000000e+00, 6.00000000e+00, 7.50000000e+00,
         9.00000900e+00])

And the colorbar uses the adjusted levels for labeling. But I think it
may make more sense to use the initial levels (at least for the
colorbar ticks).

Regards,

-JJ

···

On Wed, Jan 20, 2010 at 2:04 PM, Eric Firing <efiring@...202...> wrote:

The reason for this fudge in contour is that contourf fills
lower < z <= upper
for each consecutive pair of contour levels.
When the minimum value of z coincides with the lowest level, then regions
with that minimum are left blank; so the lowest level is adjusted downward
slightly, making the lowest contour interval include the minimum value.

Jae-Joon Lee wrote:

The reason for this fudge in contour is that contourf fills
lower < z <= upper
for each consecutive pair of contour levels.
When the minimum value of z coincides with the lowest level, then regions
with that minimum are left blank; so the lowest level is adjusted downward
slightly, making the lowest contour interval include the minimum value.

I understand levels can be adjusted for a better contouring, but I'm
not sure whether this change needs to be visible to users.

The autoleveler, initially creates following levels

[0, 1.5, 3, 4.5, 6, 7.5, 9.]

But due to the reason you described above, they become

array([ -9.00000000e-06, 1.50000000e+00, 3.00000000e+00,
         4.50000000e+00, 6.00000000e+00, 7.50000000e+00,
         9.00000900e+00])

And the colorbar uses the adjusted levels for labeling. But I think it
may make more sense to use the initial levels (at least for the
colorbar ticks).

JJ,

I changed my mind and decided you are correct in thinking the change should be made in contour.py. I now make the bottom boundary adjustment at the last possible time, and in such a way that it does not change the levels array at all. Therefore the colorbar never sees it, and the result of explicitly supplying a set of levels is identical to the case where those levels result from autoscaling.

Eric

···

On Wed, Jan 20, 2010 at 2:04 PM, Eric Firing <efiring@...202...> wrote:

Regards,

-JJ

Great! Thanks~

-JJ

···

On Thu, Jan 21, 2010 at 9:24 PM, Eric Firing <efiring@...202...> wrote:

I changed my mind and decided you are correct in thinking the change should
be made in contour.py. I now make the bottom boundary adjustment at the
last possible time, and in such a way that it does not change the levels
array at all. Therefore the colorbar never sees it, and the result of
explicitly supplying a set of levels is identical to the case where those
levels result from autoscaling.