How to check if colorbar exists on figure
问题:有没有办法检查颜色条是否已经存在?
我正在用一个圈做许多情节。问题是每次迭代都会绘制颜色条!
如果我可以确定颜色条是否存在,那么我可以将颜色条函数放入if语句中。
1 2 3 4 | if cb_exists: # do nothing else: plt.colorbar() #draw the colorbar |
如果我使用多处理来制作图形,是否可以阻止添加多个颜色条?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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()清除这个图。但是,我的basemap层上有数据,我不想重新绘制(这增加了创建绘图所需的时间)。所以,如果我能移除颜色条并添加一个新的,我会节省一些时间。
实际上,从绘图中删除颜色条并随后绘制新的颜色条并不容易。目前我能想到的最好的解决方案是下面的,假设图中只有一个轴。现在,如果有第二个轴,它一定是彩色条。因此,通过检查我们在图上找到多少轴,我们可以判断是否有一个颜色条。
在这里,我们也注意到用户不希望从外部引用任何命名对象。(这没有多大意义,因为我们无论如何都需要使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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() |
一般来说,更好的解决方案是对已经存在于绘图中的对象进行操作,并且只使用新数据更新它们。因此,我们抑制了移除和添加轴的需要,并找到一个更干净和更快的解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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() |
更新:
实际上,后一种从外部引用对象的方法甚至与提问者所希望的
所以,这里有一个代码可以更新这个数字,而不需要删除颜色条。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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() |
(结尾的代码显示了一个时间表,允许查看是否确实进行了多处理)
如果可以访问轴和图像信息,则可以检索颜色条作为图像的属性(或与颜色条关联的可映射)。
在前面的回答(如何从Matplotlib中的图中检索颜色条实例)之后,一个示例可以是:
1 2 3 4 | 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 |
请注意,没有颜色条的图像不会返回到
一种方法是:
最初(在绘制任何颜色条之前),设置一个变量
1 | colorBarPresent = False |
在绘制颜色条的方法中,检查是否已绘制颜色条。如果没有,则绘制它并将colorbarpresent变量设置为真:
1 2 3 4 5 6 | def drawColorBar(): if colorBarPresent: # leave the function and don't draw the bar again else: # draw the color bar colorBarPresent = True |
有一种间接的猜测方法(我认为,对于大多数应用程序来说,具有合理的准确性)
- 无蜱
- 无蜱标签
- 无轴标签
- 轴范围是(0,1)
下面是一个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
多亏了这个关于酷酷的
使用此功能,您可以通过以下方式查看颜色栏是否存在:
1 | colorbar_exists = any([is_colorbar(ax) for ax in np.atleast_1d(gcf().axes).flatten()]) |
或者,如果您确定颜色条始终是最后一个,您可以轻松摆脱:
1 | colorbar_exists = is_colorbar(gcf().axes[-1]) |