我希望找到一种方法来优化以下情况。我有一个用 matplotlib 的 imshow 创建的大等高线图。然后,我想使用此等高线图创建大量 png 图像,其中通过更改 x 和 y 限制以及纵横比,每个图像都是等高线图像的一小部分。
因此循环中没有绘图数据发生变化,只有轴限制和纵横比在每个 png 图像之间发生变化。
以下 MWE 在“无花果”文件夹中创建了 70 张 png 图像,展示了简化的想法。 fig.savefig('figs/'+filename)
占用了大约 80% 的运行时间。
我已经研究了以下内容,但没有提出改进意见:
matplotlib
的替代方案,着重于速度——我一直在努力寻找任何具有类似要求的等高线/曲面图的示例/文档- 多处理——我在这里看到的类似问题似乎需要在循环中调用
fig = plt.figure()
和ax.imshow
,因为 fig斧头不能腌制。就我而言,这将比通过实现多处理实现的任何速度提升都更加昂贵。
如果您有任何见解或建议,我将不胜感激。
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))
最佳答案
由于在这种情况下的限制是对 plt.savefig()
的调用,因此无法进行太多优化。在内部,图形是从头开始渲染的,这需要一段时间。可能减少要绘制的顶点数量可能会减少一点时间。
在我的机器(Win 8,i5,4 核 3.5GHz)上运行你的代码的时间是 2.5 秒。这似乎还不错。通过使用Multiprocessing 可以获得一点改进。
关于 Multiprocessing 的注意事项:在 multiprocessing
中使用 pyplot 的状态机应该可以工作,这似乎令人惊讶。但确实如此。
在这种情况下,由于每个图像都基于相同的图形和坐标轴对象,因此甚至不必创建新的图形和坐标轴。
我修改了一个 answer I gave here不久前,您的案例使用多处理和 4 核上的 5 个进程,总时间大约减半。我附加了一个显示多处理效果的条形图。
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()
关于python - matplotlib savefig 性能,在循环中保存多个 png,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41037840/