从 matplotlib 中的图形中删除颜色条
Posted
技术标签:
【中文标题】从 matplotlib 中的图形中删除颜色条【英文标题】:remove colorbar from figure in matplotlib 【发布时间】:2011-07-12 21:24:41 【问题描述】:这应该很容易,但我很难做到。基本上,我在 matplotlib 中有一个子图,每次调用函数时我都会绘制一个 hexbin 图,但是每次调用该函数时,我都会得到一个新的颜色条,所以我真正想做的是更新颜色条.不幸的是,这似乎不起作用,因为颜色条所附加的对象正在由 subplot.hexbin 重新创建。
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.cb.update_bruteforce() # Doesn't work (hb is new)
else:
self.cb = self.figure.colorbar(hb)
我现在在这个烦人的地方,我试图完全删除颜色条轴并简单地重新创建它。不幸的是,当我删除颜色条轴时,子图轴不会回收空间,并且调用 self.subplot.reset_position() 并没有像我想象的那样做。
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.figure.delaxes(self.figure.axes[1])
del self.cb
# TODO: resize self.subplot so it fills the
# whole figure before adding the new colorbar
self.cb = self.figure.colorbar(hb)
有人有什么建议吗?
非常感谢! 亚当
【问题讨论】:
我认为您不应该在每次调用该函数时都创建一个新的 hexbin 图。我认为您想要的是以某种方式更新现有绘图的数据(我对 hexbin 不太熟悉,无法说明如何)。我有一些疑问。这个剧情有动画吗?您是否并排获得多个颜色条?你能发布一个包含一些假数据的运行示例吗? 我考虑过这一点,但我觉得这是一条更难走的路,因为这完全是一个交互式绘图工具。用户可以更改 bin 的数量、网格大小、轴比例、数据源等。我现在会一直用头撞这个颜色条的东西,如果我撞到墙上,我会考虑把它归结为一个工作示例我可以分享。谢谢保罗。 您可以为颜色条创建一个特定的斧头并清除此斧头。fig.colorbar(cax=cax)
和 cax.cla()
【参考方案1】:
我认为问题在于del
您取消了变量,但没有取消引用的对象颜色条。
如果您希望颜色条从绘图中移除并消失,您必须使用颜色条实例的 remove
方法,为此您需要将颜色条放在变量中,您有两种选择:
-
在创建时将颜色条保持在一个值中,如其他答案所示,例如
cb=plt.colorbar()
检索现有的颜色条,您可以按照我在此处写的内容进行操作(并点赞 :)):How to retrieve colorbar instance from figure in matplotlib
那么:
cb.remove() plt.draw() #update plot
完整代码和结果:
from matplotlib import pyplot as plt
import numpy as np
plt.ion()
plt.imshow(np.random.random(15).reshape((5,3)))
cb = plt.colorbar()
plt.savefig('test01.png')
cb.remove()
plt.savefig('test02.png')
【讨论】:
我不明白这个答案如何帮助回收颜色条保留的空间,因为它是在问题中特别提出的。调用cb.remove()
只会删除颜色条,将空间留空。如果您添加另一个颜色条,它将出现在这个空白区域的上方,依此类推。
我不明白,这不是发生在我身上的事。当我调用 cb.remove() 时,颜色条被移除,图像被调整大小以占据整个图形。如果有帮助,我可以附上一个例子。
没关系,谢谢您的意见,这一定是我的问题。我想出了一种方法,使用手动创建的 ax 作为颜色条容器,它可以满足我的需要。抱歉挖了这么老的帖子。
没问题,反正我觉得加个例子还是有用的。【参考方案2】:
好的,这是我的解决方案。不是很优雅,但也不是很糟糕。
def foo(self):
self.subplot.clear()
hb = self.subplot.hexbin(...)
if self.cb:
self.figure.delaxes(self.figure.axes[1])
self.figure.subplots_adjust(right=0.90) #default right padding
self.cb = self.figure.colorbar(hb)
这可以满足我的需要,因为我只有一个子图。在使用多个子图或在不同位置绘制颜色条时遇到相同问题的人需要进行调整。
【讨论】:
这里有同样的问题:与散点图关联的颜色条,每次绘制新的散点图时都会重现。发布的解决方案有效。我想知道是否有人到了“更清洁”的地方。【参考方案3】:我设法使用 fig.clear() 和 display.clear_output() 解决了同样的问题
import matplotlib.pyplot as plt
import IPython.display as display
import matplotlib.tri as tri
from pylab import *
%matplotlib inline
def plot_res(fig):
ax=fig.add_axes([0,0,1,1])
ax.set_xlabel("x")
ax.set_ylabel('y')
plotted=ax.imshow(rand(250, 250))
ax.set_title("title")
cbar=fig.colorbar(mappable=plotted)
display.clear_output(wait=True)
display.display(plt.gcf())
fig.clear()
fig=plt.figure()
N=20
for j in range(N):
plot_res(fig)
【讨论】:
【参考方案4】:我遇到了类似的问题并玩了一点。我想出了两个可能更优雅的解决方案:
清除整个图并再次添加子图(+colorbar,如果需要)。
如果总是有颜色条,您可以简单地使用自动缩放更新坐标区,这也会更新颜色条。
我已经用 imshow 试过了,但我猜它对其他绘图方法也有类似的效果。
from pylab import *
close('all') #close all figures in memory
#1. Figures for fig.clf method
fig1 = figure()
fig2 = figure()
cbar1=None
cbar2=None
data = rand(250, 250)
def makefig(fig,cbar):
fig.clf()
ax = fig.add_subplot(111)
im = ax.imshow(data)
if cbar:
cbar=None
else:
cbar = fig.colorbar(im)
return cbar
#2. Update method
fig_update = figure()
cbar3=None
data_update = rand(250, 250)
img=None
def makefig_update(fig,im,cbar,data):
if im:
data*=2 #change data, so there is change in output (look at colorbar)
#im.set_data(data) #use this if you use new array
im.autoscale()
#cbar.update_normal(im) #cbar is updated automatically
else:
ax = fig.add_subplot(111)
im = ax.imshow(data)
cbar=fig.colorbar(im)
return im,cbar,data
#Execute functions a few times
for i in range(3):
print i
cbar1=makefig(fig1,cbar1)
cbar2=makefig(fig2,cbar2)
img,cbar3,data_update=makefig_update(fig_update,img,cbar3,data_update)
cbar2=makefig(fig2,cbar2)
fig1.show()
fig2.show()
fig_update.show()
【讨论】:
解决方案 1 的问题在于,如果您在图中有超过 1 个图,它肯定会清除整个问题 - 对吧? 是的,它会清除整个事情。我不知道如何只清除一个子图。【参考方案5】:我需要删除颜色条,因为我正在绘制 pcolormesh 并将颜色条添加到循环中的图形中。每个循环都会创建一个新的颜色条,十次循环后我会有十个颜色条。那很糟糕。
要删除颜色条,我将 pcolormesh 和 colorbar 命名为变量,然后在循环结束时删除每个变量。在删除 pcolormesh 之前删除颜色条很重要。
伪代码:
for i in range(0,10):
p = plt.pcolormesh(datastuff[i])
cb = plt.colorbar(p)
plt.savefig('name_'+i)
cb.remove()
p.remove()
同样,有必要在 pcolormesh 之前删除颜色条
【讨论】:
我在子图上遇到了这个问题。这个解决方案真的很有帮助。我将颜色条添加到列表中,然后使用列表删除每个颜色条。 对,就是这个! 这太直观了……当你看到它的时候。 @Blaylockbk 我欠你一个!【参考方案6】:如果你有一个 matplotlib 图形对象,你只需要fig.delaxes(fig.axes[1])
例如:
用彩条绘图
import matplotlib.pyplot as plt
# setup some generic data
N = 37
x, y = np.mgrid[:N, :N]
Z = (np.cos(x*0.2) + np.sin(y*0.3))
# mask out the negative and positive values, respectively
Zpos = np.ma.masked_less(Z, 0)
Zneg = np.ma.masked_greater(Z, 0)
fig, ax1 = plt.subplots(figsize=(13, 3), ncols=1)
# plot just the positive data and save the
# color "mappable" object returned by ax1.imshow
pos = ax1.imshow(Zpos, cmap='Blues', interpolation='none')
# add the colorbar using the figure's method,
# telling which mappable we're talking about and
# which axes object it should be near
fig.colorbar(pos, ax=ax1)
移除彩条
import matplotlib.pyplot as plt
# setup some generic data
N = 37
x, y = np.mgrid[:N, :N]
Z = (np.cos(x*0.2) + np.sin(y*0.3))
# mask out the negative and positive values, respectively
Zpos = np.ma.masked_less(Z, 0)
Zneg = np.ma.masked_greater(Z, 0)
fig, ax1 = plt.subplots(figsize=(13, 3), ncols=1)
# plot just the positive data and save the
# color "mappable" object returned by ax1.imshow
pos = ax1.imshow(Zpos, cmap='Blues', interpolation='none')
# add the colorbar using the figure's method,
# telling which mappable we're talking about and
# which axes object it should be near
fig.colorbar(pos, ax=ax1)
fig.delaxes(fig.axes[1])
【讨论】:
【参考方案7】:我正在使用 matplotlib 1.4.0。这就是我解决这个问题的方法:
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
# A contour plot example:
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)
#
# first drawing
fig = plt.figure()
ax = fig.add_subplot(111) # drawing axes
c = ax.contourf(Z) # contour fill c
cb = fig.colorbar(c) # colorbar for contour c
# clear first drawimg
ax.clear() # clear drawing axes
cb.ax.clear() # clear colorbar axes
# replace with new drawing
# 1. drawing new contour at drawing axes
c_new = ax.contour(Z)
# 2. create new colorbar for new contour at colorbar axes
cb_new = ax.get_figure().colorbar(c_new, cax=cb.ax)
plt.show()
上面的代码用颜色条绘制了一个等高线填充图,清除它并在同一个图中用新的颜色条绘制一个新的等高线图。
通过使用
cb.ax
我能够识别彩条轴并清除旧彩条。
并且指定 cax=cb.ax
只是在旧颜色条轴上绘制新颜色条。
【讨论】:
【参考方案8】:不想从这个blog post (Joseph Long) 的作者那里拿走任何东西,但这显然是我迄今为止找到的最佳解决方案。它包括代码片段、很好的解释和许多示例。
总而言之,从命令的 ax 轴的任何输出:plot、image、scatter 、收藏等如:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5,5), dpi=300)
ax = fig.add_subplot(1, 1, 1)
data = ax.plot(x,y)
# or
data = ax.scatter(x, y, z)
# or
data = ax.imshow(z)
# or
data = matplotlib.collection(patches)
ax.add_collection(data)
您使用 make_axes_locatable 和绘图的原始轴创建一个颜色条轴。
from mpl_toolkits.axes_grid1 import make_axes_locatable
# the magical part
divider = make_axes_locatable(ax)
caxis = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(data, cax=caxis)
plt.show()
创建的颜色条将具有与图形或子图相同的大小,您可以在使用时修改它的 width、location、padding divider.append_axes 命令。
【讨论】:
【参考方案9】:我的解决方案是拥有一个 Axes,其唯一目的是保持颜色条,并在需要时完全清除它。
例如,定义一次:
figure, ax = plt.subplots() # All the plotting is done on `ax`.
cax = ax.inset_axes([1.03, 0, 0.1, 1], transform=ax.transAxes) # Colorbar is held by `cax`.
然后根据需要多次执行此操作:
cax.clear()
colorbar = figure.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax,
cax=cax,
**kwargs)
【讨论】:
你的方法对我有帮助,谢谢【参考方案10】:"on_mappable_changed" 在我的情况下有效。但是,根据文档,“通常......不应手动调用”方法。
if self.cb:
self.cb.on_mappable_changed(hb)
else:
self.cb = self.fig.colorbar(hb)
【讨论】:
以上是关于从 matplotlib 中的图形中删除颜色条的主要内容,如果未能解决你的问题,请参考以下文章