0

I have a 2D matrix I want to plot. The plotting itself works, but I need a colorbar with it. The figure only makes sense when the data is log-tranformed. And I want the colorbar show the original values. How do I do this?

A search provided A logarithmic colorbar in matplotlib scatter plot but I cannot make this work.

The code below gives an idea of what I attempt to do. Only the revevant lines are included (as far as I could see).

import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np

my_speed=np.ones(shape=(no,no))

fig=plt.figure(2)
ax=fig.add_subplot(1,1,1)

my_speed=np.log10(my_speed)
ax.imshow(my_speed, interpolation='bilinear', cmap=cm.jet)
plt.colorbar() #this does not work

plt.savefig('myspeedplot.png')
plt.close(2)

Thank you for any help

Community
  • 1
  • 1
frits
  • 327
  • 2
  • 15
  • A new problem popped up: Because I start with np.ones, the lowest value in the colorbar is 10E0. I add values to this base-value. But in the results this should be interpreted as 0. Is there an elegant way to fix this? The value 1 makes a nice black, but how do make this represented on the scale nicely? – frits Jul 17 '14 at 17:15
  • Sorry, I'm not sure if I understand your problem. Why do you want to do the log transformation in the first place? Log transformation has the problem that you should not have zeros in counting matrices. If you have, you can go with pseudo counts (starting with ones as you apparently did). If you want to plot values between [0, oo[, you could try out the `matplotlib.colors.PowerNorm` normalization which is shipped with `matplotlib-1.4.x`. That way you can emphasize low values, if that's your goal. I don't know your use case so it's hard to give good advice. – cel Jul 19 '14 at 09:19
  • Thank you for your reply. My numbers range from 0-10E4. The low numbers are important, so lognormal does give a nice representation. The only problem is that the colorbar starts at 1, not 0, and 0 is an important value in my case. So when people study is they will be surprised by the fact that there are no 0-value areas – frits Jul 21 '14 at 06:34
  • 1
    If the concrete size of the large numbers does not matter and it suffices to know that they're large you probably have a perfect use case for the `PowerNorm` normalization. Unfortunately it's not in a release yet, but you can try if you install matplotlib-1.4.0-r1 from https://github.com/matplotlib/matplotlib/releases. I don't know how to hack the colorbar scaling, you probably have to google that or ask another question. Yet, I would try to avoid that if you can. – cel Jul 21 '14 at 06:53
  • 1
    Sorry, I just tested again and you should be able to use LogNorm even if you have zeros in your matrix. Just plotting a matrix with only zeros does not seem to work with imshow. – cel Jul 21 '14 at 07:07
  • Yes, you are correct, but the result was very different from what I expected: In the old situation, '0' (converted to '1') shows black, if I take the log of the matrix with '0's, this becomes white... – frits Jul 24 '14 at 08:21

2 Answers2

1

The idea is not to transform your data, but let the visualization do the trick for you.

pylot.imshow[1] has an optional parameter norm that can do the log transformation for you.

my_speed=np.ones(shape=(no,no))

fig = plt.figure(2)
ax = fig.add_subplot(1,1,1)

# my_speed=np.log10(my_speed)
img = ax.imshow(my_speed, interpolation='bilinear', cmap=cm.jet,
                norm=mpl.colors.LogNorm())
fig.colorbar(img)
cel
  • 30,017
  • 18
  • 97
  • 117
  • Thank you for your reply. I already tried this and should have mentioned this. It raised an error: ` raise RuntimeError('No mappable was found to use for colorbar ' RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).` I am missing something. (sorry for the poor layout, I do not really understand this tool) – frits Jul 17 '14 at 16:34
  • Sorry I should have mentioned that you should probably try your example with `np.ones` instead of `np.zeros`, since taking the log of 0 is not a good thing to do :) – cel Jul 17 '14 at 16:35
  • I already fixed this in another way in the code. I will update the example. – frits Jul 17 '14 at 16:37
  • 1
    Yes! The img-part was what was needed. Thank you! – frits Jul 17 '14 at 16:44
1

As far as I see, there are two problems with your code.

First, you are trying to have the ticks on colorbar show original values. For this you should not transform the data, but just normalize the plot.

And second, you are using the ax.imshow and this is why the colorbar does not see it. You should use plt.imshow or use im=ax.imshow and then colorbar(im)

Here is a working solution:

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

my_speed = np.random.rand(20, 20)

fig = plt.figure(2)
ax = fig.add_subplot(1, 1, 1)

im = ax.imshow(my_speed, interpolation='bilinear',
               norm=mpl.colors.LogNorm(),
               cmap=plt.cm.jet)
cb = plt.colorbar(im, orientation='vertical')

plt.show()
jure
  • 402
  • 5
  • 9