Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a colour bar for a plot made with plt.fill

I'm new to Python (was an IDL user before hand) so I hope that I'm asking this in an understandable way. I've been trying to create a polar plot with x number of bins where the data in the bin is averaged and given a colour associated with that value. This seems to work fine while using the plt.fill command where I can define the bin and then the fill colour. The problem comes when I then try to make a colour bar to go with it. I keep getting errors that state AttributeError: 'Figure' object has no attribute 'autoscale_None'

Any advice would be helpful thanks.

import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.pyplot import figure, show, rc, grid
import pylab

r = np.arange(50)/5.
rstep = r[1] - r[0]
theta = np.arange(50)/50.*2.*np.pi
tstep = theta[1] - theta[0]
colorv = np.arange(50)/50.

# force square figure and square axes looks better for polar, IMO
width, height = mpl.rcParams['figure.figsize']
size = min(width, height)
# make a square figure
fig = figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, .8, .8])#, polar=True)

my_cmap = cm.jet
for j in range(len(r)):
    rbox = np.array([r[j], r[j], r[j]+ rstep, r[j] + rstep])
    for i in range(len(theta)):
        thetabox = np.array([theta[i], theta[i] + tstep, theta[i] + tstep, theta[i]])
        x = rbox*np.cos(thetabox)
        y = rbox*np.sin(thetabox)
        plt.fill(x,y, facecolor = my_cmap(colorv[j]))



# Add colorbar, make sure to specify tick locations to match desired ticklabels
cbar = fig.colorbar(fig, ticks=[np.min(colorv), np.max(colorv)])
cb = plt.colorbar()
plt.show()

* here is a slightly better example of my real data, there are holes missing everywhere, so in this example I've just made a big one in a quarter of the circle. When I've tried meshing, the code seems to try to interpolate over these regions.

r = np.arange(50)/50.*7. + 3.
rstep = r[1] - r[0]
theta = np.arange(50)/50.*1.5*np.pi - np.pi
tstep = theta[1] - theta[0]
colorv = np.sin(r/10.*np.pi)

# force square figure and square axes looks better for polar, IMO
width, height = mpl.rcParams['figure.figsize']
size = min(width, height)
# make a square figure
fig = figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, .8, .8])#, polar=True)

my_cmap = cm.jet

for j in range(len(r)):
    rbox = np.array([r[j], r[j], r[j]+ rstep, r[j] + rstep])
    for i in range(len(theta)):
        thetabox = np.array([theta[i], theta[i] + tstep, theta[i] + tstep, theta[i]])
        x = rbox*np.cos(thetabox)
        y = rbox*np.sin(thetabox)
        plt.fill(x,y, facecolor = my_cmap(colorv[j]))


# Add colorbar, make sure to specify tick locations to match desired ticklabels
#cbar = fig.colorbar(fig, ticks=[np.min(colorv), np.max(colorv)])
#cb = plt.colorbar()
plt.show()

And then with a meshing involved...

from matplotlib.mlab import griddata

r = np.arange(50)/5.
rstep = r[1] - r[0]
theta = np.arange(50)/50.*1.5*np.pi - np.pi
tstep = theta[1] - theta[0]
colorv = np.sin(r/10.*np.pi)

# force square figure and square axes looks better for polar, IMO
width, height = mpl.rcParams['figure.figsize']
size = min(width, height)
# make a square figure
fig = figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, .8, .8])#, polar=True)

my_cmap = cm.jet

x = r*np.cos(theta)
y = r*np.sin(theta)
X,Y = np.meshgrid(x,y)

data = griddata(x,y,colorv,X,Y)
cax = plt.contourf(X,Y, data)
plt.colorbar()

# Add colorbar, make sure to specify tick locations to match desired ticklabels
#cbar = fig.colorbar(fig, ticks=[np.min(colorv), np.max(colorv)])
#cb = plt.colorbar()
plt.show()
like image 974
Alexa Halford Avatar asked Jan 18 '12 19:01

Alexa Halford


1 Answers

colorbar needs things to be an instance of ScalarMappable in order to make a colorbar from them.

Because you're manually setting each tile, there's nothing that essentially has a colorbar.

There are a number of ways to fake it from your colormap, but in this case there's a much simpler solution.

pcolormesh does exactly what you want, and will be much faster.

As an example:

import numpy as np
import matplotlib.pyplot as plt

# Linspace makes what you're doing _much_ easier (and includes endpoints)
r = np.linspace(0, 10, 50)
theta = np.linspace(0, 2*np.pi, 50)

fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')

# "Grid" r and theta into 2D arrays (see the docs for meshgrid)
r, theta = np.meshgrid(r, theta)
cax = ax.pcolormesh(theta, r, r, edgecolors='black', antialiased=True)

# We could just call `plt.colorbar`, but I prefer to be more explicit
# and pass in the artist that I want it to extract colors from.
fig.colorbar(cax)

plt.show()

enter image description here

Or, if you'd prefer non-polar axes, as in your example code:

import numpy as np
import matplotlib.pyplot as plt

r = np.linspace(0, 10, 50)
theta = np.linspace(0, 2*np.pi, 50)

# "Grid" r and theta and convert them to cartesian coords...
r, theta = np.meshgrid(r, theta)
x, y = r * np.cos(theta), r * np.sin(theta)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axis('equal')

cax = ax.pcolormesh(x, y, r, edgecolors='black', antialiased=True)

fig.colorbar(cax)

plt.show()

enter image description here

Note: If you'd prefer the boundary lines a bit less dark, just specify linewidth=0.5 or something similar to pcolormesh.

Finally, if you did want to directly make the colorbar from the colormap in your original code, you'd create an instance of ScalarMappable from it and pass this to colorbar. It's easier than it sounds, but it's a bit verbose.

As an example, in your original code, if you do something like the following:

cax = cm.ScalarMappable(cmap=my_cmap)
cax.set_array(colorv)
fig.colorbar(cax)

It should do what you want.

like image 86
Joe Kington Avatar answered Nov 16 '22 01:11

Joe Kington