为使用plt.fill制作的绘图创建颜色条

时间:2012-01-18 19:12:34

标签: python matplotlib colorbar

我是Python的新手(之前是IDL用户),所以我希望我能以一种可以理解的方式问这个问题。我一直在尝试创建一个带有x个bin的极坐标图,其中bin中的数据被平均并给出与该值相关联的颜色。这似乎在使用plt.fill命令时工作正常,我可以在其中定义bin然后填充填充颜色。当我尝试制作一个颜色条时,问题就来了。我不断收到状态AttributeError的错误:'Figure'对象没有属性'autoscale_None'

任何建议都会有所帮助,谢谢。

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()

* 这里是我的真实数据的一个稍微好一点的例子,到处都有漏洞,所以在这个例子中,我刚刚在四分之一的圈子里做了一个大的。当我尝试网格化时,代码似乎试图在这些区域上进行插值。

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()

然后进行网格划分......

来自matplotlib.mlab导入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()

2 个答案:

答案 0 :(得分:7)

colorbar需要事物成为ScalarMappable的实例才能从中制作颜色条。

因为您手动设置每个图块,所以基本上没有颜色条。

有很多方法可以从你的色彩图中伪造它,但在这种情况下,有一个更简单的解决方案。

pcolormesh完全符合您的要求,而且会更快。

举个例子:

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

或者,如果你更喜欢非极轴,就像在你的示例代码中那样:

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

注意:如果您希望边界线稍微暗一点,只需指定linewidth=0.5或与pcolormesh类似的东西。

最后,如果您确实希望直接从原始代码中的colormap生成颜色条,则可以从中创建ScalarMappable的实例并将其传递给colorbar。它比听起来容易,但它有点冗长。

例如,在原始代码中,如果您执行以下操作:

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

它应该做你想要的。

答案 1 :(得分:1)

所以我找到了一个解决方法。因为我知道一个我绝对不会有数据的区域,所以我在那里画了一些。我已经确保数据涵盖了我正在灌输的整个范围。然后我把它覆盖起来(无论如何这个区域都会被覆盖,它显示了“地球”所在的位置)。现在我可以像往常一样使用plt.fill并使用随机封装数据中的颜色条。我知道这可能不是正确的方法,但它有效并且不会尝试插入我的数据。

非常感谢帮助对此进行排序。如果你知道更好的方法,我会很高兴听到它!

hid = plt.pcolormesh(X,Y, data, antialiased=True)

#here we cover up the region that we just plotted in
r3 = [1 for i in range(360)]
theta3 = np.arange(360)*np.pi/180.
plt.fill(theta3, r3, 'w')

#now we can go through and fill in all the regions
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)
        colorv = np.sin(r[j]/10.*np.pi)
        plt.fill(thetabox,rbox, facecolor = my_cmap(colorv))
#And now we can plot the color bar that fits the data Tada :)
plt.colorbar()
plt.show()

Output of above code