matplotlib savefig performance, saving multiple pngs within loop
我希望找到一种方法来优化以下情况。我有一个大的轮廓图,用imshow的matplotlib创建。然后,我想使用这个轮廓图创建大量PNG图像,其中每个图像都是轮廓图像的一个小部分,通过更改X和Y限制和纵横比。
因此,在循环中没有绘图数据发生变化,只有轴限制和纵横比在每个PNG图像之间发生变化。
下面的mwe在一个"figs"文件夹中创建了70个PNG图像,演示了简化的思想。大约80%的运行时间被
我没有提出任何改进,而是研究了以下内容:
- 作为一种侧重于速度的
matplotlib 的替代方案,我一直在努力寻找具有类似要求的轮廓/表面图的任何示例/文档。 - 多处理——我在这里看到的类似问题似乎要求在循环中调用
fig = plt.figure() 和ax.imshow ,因为fig和ax不能被腌制。在我的例子中,这将比通过实现多处理实现的任何速度增益都要昂贵。
我很感激你的任何见解或建议。
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 | import numpy as np import matplotlib as mpl mpl.use('agg') import matplotlib.pyplot as plt import time, os def make_plot(x, y, fix, ax): aspect = np.random.random(1)+y/2.0-x xrand = np.random.random(2)*x xlim = [min(xrand), max(xrand)] yrand = np.random.random(2)*y ylim = [min(yrand), max(yrand)] filename = '{:d}_{:d}.png'.format(x,y) ax.set_aspect(abs(aspect[0])) ax.set_xlim(xlim) ax.set_ylim(ylim) fig.savefig('figs/'+filename) if not os.path.isdir('figs'): os.makedirs('figs') data = np.random.rand(25, 25) fig = plt.figure() ax = fig.add_axes([0., 0., 1., 1.]) # in the real case, imshow is an expensive calculation which can't be put inside the loop ax.imshow(data, interpolation='nearest') tstart = time.clock() for i in range(1, 8): for j in range(3, 13): make_plot(i, j, fig, ax) print('took {:.2f} seconds'.format(time.clock()-tstart)) |
由于这种情况下的限制是对
在我的机器上运行代码的时间是2.5秒。这似乎还不错。通过使用多处理,可以得到一些改进。
关于多处理的一个注意事项:使用
我为您的案例修改了一个刚才在这里给出的答案,使用多处理和4核上的5个处理,总时间大约减半。我附加了一个显示多处理效果的条形图。
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import numpy as np #import matplotlib as mpl #mpl.use('agg') # use of agg seems to slow things down a bit import matplotlib.pyplot as plt import multiprocessing import time, os def make_plot(d): start = time.clock() x,y=d #using aspect in this way causes a warning for me #aspect = np.random.random(1)+y/2.0-x xrand = np.random.random(2)*x xlim = [min(xrand), max(xrand)] yrand = np.random.random(2)*y ylim = [min(yrand), max(yrand)] filename = '{:d}_{:d}.png'.format(x,y) ax = plt.gca() #ax.set_aspect(abs(aspect[0])) ax.set_xlim(xlim) ax.set_ylim(ylim) plt.savefig('figs/'+filename) stop = time.clock() return np.array([x,y, start, stop]) if not os.path.isdir('figs'): os.makedirs('figs') data = np.random.rand(25, 25) fig = plt.figure() ax = fig.add_axes([0., 0., 1., 1.]) ax.imshow(data, interpolation='nearest') some_list = [] for i in range(1, 8): for j in range(3, 13): some_list.append((i,j)) if __name__ =="__main__": multiprocessing.freeze_support() tstart = time.clock() print tstart num_proc = 5 p = multiprocessing.Pool(num_proc) nu = p.map(make_plot, some_list) tooktime = 'Plotting of {} frames took {:.2f} seconds' tooktime = tooktime.format(len(some_list), time.clock()-tstart) print tooktime nu = np.array(nu) plt.close("all") fig, ax = plt.subplots(figsize=(8,5)) plt.suptitle(tooktime) ax.barh(np.arange(len(some_list)), nu[:,3]-nu[:,2], height=np.ones(len(some_list)), left=nu[:,2], align="center") ax.set_xlabel("time [s]") ax.set_ylabel("image number") ax.set_ylim([-1,70]) plt.tight_layout() plt.savefig(__file__+".png") plt.show() |
。