如何检查图形上是否存在颜色条
How to check if colorbar exists on figure
问题:有没有办法检查颜色条是否已经存在?
我正在用循环制作很多情节。问题是每次迭代都会绘制颜色条!
如果我可以确定颜色条是否存在,那么我可以将颜色条函数放在 if 语句中。
if cb_exists:
# do nothing
else:
plt.colorbar() #draw the colorbar
如果我用multiprocessing来制作图形,是否可以防止添加多个颜色条?
import numpy as np
import matplotlib.pyplot as plt
import multiprocessing
def plot(number):
a = np.random.random([5,5])*number
plt.pcolormesh(a)
plt.colorbar()
plt.savefig('this_'+str(number))
# I want to make a 50 plots
some_list = range(0,50)
num_proc = 5
p = multiprocessing.Pool(num_proc)
temps = p.map(plot, some_list)
我意识到我可以在绘制下一次迭代之前用 plt.clf() 和 plt.cla() 清除图形。但是,我的底图图层上有我不想重新绘制的数据(这会增加创建绘图所需的时间)。所以,如果我可以删除颜色条并添加一个新的颜色条,我会节省一些时间。
一种方法是:
最初(在绘制任何颜色条之前),设置一个变量
colorBarPresent = False
在绘制彩条的方法中,查看是否已经绘制完成。如果没有,绘制它并设置 colorBarPresent 变量 True:
def drawColorBar():
if colorBarPresent:
# leave the function and don't draw the bar again
else:
# draw the color bar
colorBarPresent = True
从绘图中删除颜色条然后再为其绘制一个新颜色条实际上并不容易。
我目前能想到的最佳解决方案如下,它假设图中只有一个轴。现在,如果有第二个轴,它一定是存在的颜色条。所以通过检查我们在图上找到了多少个轴,我们可以判断是否有颜色条。
这里我们也考虑到用户不希望从外部引用任何命名对象的愿望。 (这没有多大意义,因为无论如何我们都需要使用 plt
,但是嘿..问题是这样的)
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="k", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
for i in range(10):
# inside this loop we should not access any variables defined outside
# why? no real reason, but questioner asked for it.
#draw new colormesh
im = plt.gcf().gca().pcolormesh(np.random.rand(2,2))
#check if there is more than one axes
if len(plt.gcf().axes) > 1:
# if so, then the last axes must be the colorbar.
# we get its extent
pts = plt.gcf().axes[-1].get_position().get_points()
# and its label
label = plt.gcf().axes[-1].get_ylabel()
# and then remove the axes
plt.gcf().axes[-1].remove()
# then we draw a new axes a the extents of the old one
cax= plt.gcf().add_axes([pts[0][0],pts[0][1],pts[1][0]-pts[0][0],pts[1][1]-pts[0][1] ])
# and add a colorbar to it
cbar = plt.colorbar(im, cax=cax)
cbar.ax.set_ylabel(label)
# unfortunately the aspect is different between the initial call to colorbar
# without cax argument. Try to reset it (but still it's somehow different)
cbar.ax.set_aspect(20)
else:
plt.colorbar(im)
plt.show()
一般来说,更好的解决方案是对图中已经存在的对象进行操作,并且只用新数据更新它们。因此,我们不需要删除和添加轴并找到更清洁和更快的解决方案。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="k", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
for i in range(10):
data = np.array(np.random.rand(2,2) )
im.set_array(data.flatten())
cbar.set_clim(vmin=data.min(),vmax=data.max())
cbar.draw_all()
plt.draw()
plt.show()
更新:
实际上,后一种从外部引用对象的方法甚至可以与提问者所需的 multiprocess
方法一起使用。
所以,这是更新图形的代码,无需删除颜色条。
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
import time
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="w", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
tx = ax.text(0.2,0.8, "", fontsize=30, color="w")
tx2 = ax.text(0.2,0.2, "", fontsize=30, color="w")
def do(number):
start = time.time()
tx.set_text(str(number))
data = np.array(np.random.rand(2,2)*(number+1) )
im.set_array(data.flatten())
cbar.set_clim(vmin=data.min(),vmax=data.max())
tx2.set_text("{m:.2f} < {ma:.2f}".format(m=data.min(), ma= data.max() ))
cbar.draw_all()
plt.draw()
plt.savefig("multiproc/{n}.png".format(n=number))
stop = time.time()
return np.array([number, start, stop])
if __name__ == "__main__":
multiprocessing.freeze_support()
some_list = range(0,50)
num_proc = 5
p = multiprocessing.Pool(num_proc)
nu = p.map(do, some_list)
nu = np.array(nu)
plt.close("all")
fig, ax = plt.subplots(figsize=(16,9))
ax.barh(nu[:,0], nu[:,2]-nu[:,1], height=np.ones(len(some_list)), left=nu[:,1], align="center")
plt.show()
(最后的代码显示了一个时间表,可以看到确实发生了多处理)
如果您可以访问轴和图像信息,则可以检索颜色条
作为图像的 属性(或关联颜色条的可映射对象)。
根据之前的回答 (How to retrieve colorbar instance from figure in matplotlib),示例可能是:
ax=plt.gca() #plt.gca() for current axis, otherwise set appropriately.
im=ax.images #this is a list of all images that have been plotted
if im[-1].colorbar is None: #in this case I assume to be interested to the last one plotted, otherwise use the appropriate index or loop over
plt.colorbar() #plot a new colorbar
请注意,没有颜色条的图像 returns None 到 im[-1].colorbar
有一种间接的猜测方法(我认为对于大多数应用程序来说具有合理的准确性)Axes
实例是否是彩条的所在地。根据它是水平还是垂直颜色条,X 轴或 Y 轴(但不是两者)将满足所有这些条件:
- 没有刻度
- 没有刻度标签
- 没有轴标签
- 坐标轴范围为(0, 1)
所以这里有一个功能适合你:
def is_colorbar(ax):
"""
Guesses whether a set of Axes is home to a colorbar
:param ax: Axes instance
:return: bool
True if the x xor y axis satisfies all of the following and thus looks like it's probably a colorbar:
No ticks, no tick labels, no axis label, and range is (0, 1)
"""
xcb = (len(ax.get_xticks()) == 0) and (len(ax.get_xticklabels()) == 0) and (len(ax.get_xlabel()) == 0) and \
(ax.get_xlim() == (0, 1))
ycb = (len(ax.get_yticks()) == 0) and (len(ax.get_yticklabels()) == 0) and (len(ax.get_ylabel()) == 0) and \
(ax.get_ylim() == (0, 1))
return xcb != ycb # != is effectively xor in this case, since xcb and ycb are both bool
感谢这个很酷的 !=
异或技巧的答案:
使用此功能,您可以通过以下方式查看颜色条是否存在:
colorbar_exists = any([is_colorbar(ax) for ax in np.atleast_1d(gcf().axes).flatten()])
或者,如果您确定颜色栏将始终放在最后,您可以轻松下手:
colorbar_exists = is_colorbar(gcf().axes[-1])
问题:有没有办法检查颜色条是否已经存在?
我正在用循环制作很多情节。问题是每次迭代都会绘制颜色条!
如果我可以确定颜色条是否存在,那么我可以将颜色条函数放在 if 语句中。
if cb_exists:
# do nothing
else:
plt.colorbar() #draw the colorbar
如果我用multiprocessing来制作图形,是否可以防止添加多个颜色条?
import numpy as np
import matplotlib.pyplot as plt
import multiprocessing
def plot(number):
a = np.random.random([5,5])*number
plt.pcolormesh(a)
plt.colorbar()
plt.savefig('this_'+str(number))
# I want to make a 50 plots
some_list = range(0,50)
num_proc = 5
p = multiprocessing.Pool(num_proc)
temps = p.map(plot, some_list)
我意识到我可以在绘制下一次迭代之前用 plt.clf() 和 plt.cla() 清除图形。但是,我的底图图层上有我不想重新绘制的数据(这会增加创建绘图所需的时间)。所以,如果我可以删除颜色条并添加一个新的颜色条,我会节省一些时间。
一种方法是:
最初(在绘制任何颜色条之前),设置一个变量
colorBarPresent = False
在绘制彩条的方法中,查看是否已经绘制完成。如果没有,绘制它并设置 colorBarPresent 变量 True:
def drawColorBar(): if colorBarPresent: # leave the function and don't draw the bar again else: # draw the color bar colorBarPresent = True
从绘图中删除颜色条然后再为其绘制一个新颜色条实际上并不容易。 我目前能想到的最佳解决方案如下,它假设图中只有一个轴。现在,如果有第二个轴,它一定是存在的颜色条。所以通过检查我们在图上找到了多少个轴,我们可以判断是否有颜色条。
这里我们也考虑到用户不希望从外部引用任何命名对象的愿望。 (这没有多大意义,因为无论如何我们都需要使用 plt
,但是嘿..问题是这样的)
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="k", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
for i in range(10):
# inside this loop we should not access any variables defined outside
# why? no real reason, but questioner asked for it.
#draw new colormesh
im = plt.gcf().gca().pcolormesh(np.random.rand(2,2))
#check if there is more than one axes
if len(plt.gcf().axes) > 1:
# if so, then the last axes must be the colorbar.
# we get its extent
pts = plt.gcf().axes[-1].get_position().get_points()
# and its label
label = plt.gcf().axes[-1].get_ylabel()
# and then remove the axes
plt.gcf().axes[-1].remove()
# then we draw a new axes a the extents of the old one
cax= plt.gcf().add_axes([pts[0][0],pts[0][1],pts[1][0]-pts[0][0],pts[1][1]-pts[0][1] ])
# and add a colorbar to it
cbar = plt.colorbar(im, cax=cax)
cbar.ax.set_ylabel(label)
# unfortunately the aspect is different between the initial call to colorbar
# without cax argument. Try to reset it (but still it's somehow different)
cbar.ax.set_aspect(20)
else:
plt.colorbar(im)
plt.show()
一般来说,更好的解决方案是对图中已经存在的对象进行操作,并且只用新数据更新它们。因此,我们不需要删除和添加轴并找到更清洁和更快的解决方案。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="k", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
for i in range(10):
data = np.array(np.random.rand(2,2) )
im.set_array(data.flatten())
cbar.set_clim(vmin=data.min(),vmax=data.max())
cbar.draw_all()
plt.draw()
plt.show()
更新:
实际上,后一种从外部引用对象的方法甚至可以与提问者所需的 multiprocess
方法一起使用。
所以,这是更新图形的代码,无需删除颜色条。
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
import time
fig, ax = plt.subplots()
im = ax.pcolormesh(np.array(np.random.rand(2,2) ))
ax.plot(np.cos(np.linspace(0.2,1.8))+0.9, np.sin(np.linspace(0.2,1.8))+0.9, c="w", lw=6)
ax.set_title("Title")
cbar = plt.colorbar(im)
cbar.ax.set_ylabel("Label")
tx = ax.text(0.2,0.8, "", fontsize=30, color="w")
tx2 = ax.text(0.2,0.2, "", fontsize=30, color="w")
def do(number):
start = time.time()
tx.set_text(str(number))
data = np.array(np.random.rand(2,2)*(number+1) )
im.set_array(data.flatten())
cbar.set_clim(vmin=data.min(),vmax=data.max())
tx2.set_text("{m:.2f} < {ma:.2f}".format(m=data.min(), ma= data.max() ))
cbar.draw_all()
plt.draw()
plt.savefig("multiproc/{n}.png".format(n=number))
stop = time.time()
return np.array([number, start, stop])
if __name__ == "__main__":
multiprocessing.freeze_support()
some_list = range(0,50)
num_proc = 5
p = multiprocessing.Pool(num_proc)
nu = p.map(do, some_list)
nu = np.array(nu)
plt.close("all")
fig, ax = plt.subplots(figsize=(16,9))
ax.barh(nu[:,0], nu[:,2]-nu[:,1], height=np.ones(len(some_list)), left=nu[:,1], align="center")
plt.show()
(最后的代码显示了一个时间表,可以看到确实发生了多处理)
如果您可以访问轴和图像信息,则可以检索颜色条 作为图像的 属性(或关联颜色条的可映射对象)。
根据之前的回答 (How to retrieve colorbar instance from figure in matplotlib),示例可能是:
ax=plt.gca() #plt.gca() for current axis, otherwise set appropriately.
im=ax.images #this is a list of all images that have been plotted
if im[-1].colorbar is None: #in this case I assume to be interested to the last one plotted, otherwise use the appropriate index or loop over
plt.colorbar() #plot a new colorbar
请注意,没有颜色条的图像 returns None 到 im[-1].colorbar
有一种间接的猜测方法(我认为对于大多数应用程序来说具有合理的准确性)Axes
实例是否是彩条的所在地。根据它是水平还是垂直颜色条,X 轴或 Y 轴(但不是两者)将满足所有这些条件:
- 没有刻度
- 没有刻度标签
- 没有轴标签
- 坐标轴范围为(0, 1)
所以这里有一个功能适合你:
def is_colorbar(ax):
"""
Guesses whether a set of Axes is home to a colorbar
:param ax: Axes instance
:return: bool
True if the x xor y axis satisfies all of the following and thus looks like it's probably a colorbar:
No ticks, no tick labels, no axis label, and range is (0, 1)
"""
xcb = (len(ax.get_xticks()) == 0) and (len(ax.get_xticklabels()) == 0) and (len(ax.get_xlabel()) == 0) and \
(ax.get_xlim() == (0, 1))
ycb = (len(ax.get_yticks()) == 0) and (len(ax.get_yticklabels()) == 0) and (len(ax.get_ylabel()) == 0) and \
(ax.get_ylim() == (0, 1))
return xcb != ycb # != is effectively xor in this case, since xcb and ycb are both bool
感谢这个很酷的 !=
异或技巧的答案:
使用此功能,您可以通过以下方式查看颜色条是否存在:
colorbar_exists = any([is_colorbar(ax) for ax in np.atleast_1d(gcf().axes).flatten()])
或者,如果您确定颜色栏将始终放在最后,您可以轻松下手:
colorbar_exists = is_colorbar(gcf().axes[-1])