15

I have a plotting function similar to this one

def fct():
    f=figure()
    ax=f.add_subplot(111)
    x,y=mgrid[0:5,0:5]
    z=sin(x**2+y**2)
    ax.pcolormesh(x,y,z)

When I define the function above in ipython (using the --pylab option), and then call

fct()
colorbar()

I get an error

"RuntimeError: No mappable was found to use for colorbar creation.".

def fct():
    f=figure()
    x,y=mgrid[0:5,0:5]
    z=sin(x**2+y**2)
    pcolormesh(x,y,z)

Then it works. I guess this has to do with garbage collection - how can I prevent this problem in the first example?

John Smith
  • 1,059
  • 1
  • 13
  • 35
  • The second answer may be relevant: http://stackoverflow.com/questions/2643953/attributeerror-while-adding-colorbar-in-matplotlib – Reed Richards Apr 14 '16 at 11:32

4 Answers4

20

It is because you first example, you are using ax.polormesh, not pyplot.polotmesh (namespace imported by pylab), when you call colorbar() (actually plt.colorbar()), it lost track of which mappable and which ax it should make colorbar to.

Therefore adding these lines will make it work:

import matplotlib.pyplot as plt
fct()
ax=plt.gca() #get the current axes
PCM=ax.get_children()[2] #get the mappable, the 1st and the 2nd are the x and y axes
plt.colorbar(PCM, ax=ax) 

enter image description here

Now you mentioned that your actual plot is a much more complex one. You want to make sure it is the ax.get_children()[2] or you can pick the it by look for a matplotlib.collections.QuadMesh instance.

CT Zhu
  • 52,648
  • 17
  • 120
  • 133
  • 4
    In my case the plot was more complex, to find the correct child I had to do: `for PCM in ax.get_children(): if type(PCM) == matplotlib.image.AxesImage: break` – lib Jun 20 '16 at 08:29
  • I can remove the color bar in this way, but the numbers next to the color bar are still there. Is there any way to remove them too? – HelloGoodbye Jul 19 '22 at 15:14
9

I think it has more to do with the pylab state machine and scoping.

A better practice would be to do the following (explicit is better than implicit):

import numpy as np
import matplotlib.pyplot as plt

def fct():
    f = plt.figure()
    ax = f.add_subplot(111)
    x, y = np.mgrid[0:5,0:5]
    z = np.sin(x**2+y**2)
    mesh = ax.pcolormesh(x, y ,z)

    return ax, mesh

ax, mesh = fct()
plt.colorbar(mesh, ax=ax)
Paul H
  • 65,268
  • 20
  • 159
  • 136
5

You function is quite small and takes no arguments, so do you really need to wrap the plotting in a function? What about:

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1)
x, y = np.mgrid[0:5,0:5]
z = np.sin(x**2+y**2)
mesh = ax.pcolormesh(x, y ,z)
fig.colorbar(mesh)
plt.show()

enter image description here

wflynny
  • 18,065
  • 5
  • 46
  • 67
  • 3
    my function was just a minimum working example. The actual plotting function is much more complicated and gets called repeatedly, so I only want to write it once. – John Smith Apr 15 '14 at 18:06
1

For me the following code did not work

PCM=ax.get_children()[2] 
plt.colorbar(PCM, ax=ax)

since my plot was a little bit more complicated I had to go with the following code based on the comment by @lib.

ax=plt.gca() #get the current axes
for PCM in ax.get_children():
    if isinstance(PCM, mpl.cm.ScalarMappable):
        break
        
plt.colorbar(PCM, ax=ax)
willcrack
  • 1,794
  • 11
  • 20