Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Matplotlib加速将绘图保存到磁盘_Python_Matplotlib_Plot_Save - Fatal编程技术网

Python Matplotlib加速将绘图保存到磁盘

Python Matplotlib加速将绘图保存到磁盘,python,matplotlib,plot,save,Python,Matplotlib,Plot,Save,我想从大约250个单独的帧创建一个动画,在一个带有4 x 11子面板的图形中显示作为2D图像绘制的数据。这些数据表示速度功率谱随时间频率和纬度的变化。然而,创建和保存每个帧大约需要4秒,包括数据的运行时计算。在非交互式打印模式中,我使用“agg”作为后端,以避免在交互式打印功能上花费时间 这里的速度瓶颈不是要打印的数据的计算,而是将打印保存到磁盘。随机数据的示例运行时间(见下面的代码)和仅5帧而不保存绘图的情况类似于5秒,保存绘图为17-19秒。对于我使用的实际数据,需要绘制更多的绘图艺术家(面

我想从大约250个单独的帧创建一个动画,在一个带有4 x 11子面板的图形中显示作为2D图像绘制的数据。这些数据表示速度功率谱随时间频率和纬度的变化。然而,创建和保存每个帧大约需要4秒,包括数据的运行时计算。在非交互式打印模式中,我使用“agg”作为后端,以避免在交互式打印功能上花费时间

这里的速度瓶颈不是要打印的数据的计算,而是将打印保存到磁盘。随机数据的示例运行时间(见下面的代码)和仅5帧而不保存绘图的情况类似于5秒,保存绘图为17-19秒。对于我使用的实际数据,需要绘制更多的绘图艺术家(面板上的文本、额外的线图等),但脚本执行时间非常相似对于总共大约250帧,这表示大约900秒,因此需要15分钟来计算数据,然后保存绘图。但是,由于我可能希望多次生成类似的帧或使用稍微不同的数据生成类似的帧,因此最好减少此脚本的执行时间。

下面给出了一个(希望)可复制的代码,使用随机数据,但数据大小等于我使用的实际数据。下面还可以找到一个示例帧(代码生成的第一个帧)。在代码中,函数
create_fig()
生成带有子面板的图形,子面板包含虚拟数据,在不同帧上的
for
-循环中,仅替换子面板中的数据

有没有办法加快将绘图保存到png文件的速度?非常感谢您的帮助

# import packages
import numpy as np
import time

import matplotlib as mpl
import matplotlib.pyplot as plt

path_plots_out = '/home/proxauf'

# set up grids
nt, nlat, nlon = 3328, 24, 48
dlat = 7.5
lats = np.linspace(-90,90-dlat,nlat)

dt = 98191.08

nu = (-1) * np.fft.fftfreq(nt, dt) * 10 ** 9
nnu = len(nu)

nu_fftshift = np.fft.fftshift(nu)
dnu_fftshift = nu_fftshift[1] - nu_fftshift[0]

nu_lims = [-500, 500]
ind_nu_xlims = np.where(np.logical_and(nu_fftshift >= nu_lims[0], nu_fftshift <= nu_lims[1]))[0]
ext_box_nu_lat = [nu_fftshift[ind_nu_xlims][0] - dnu_fftshift / 2, nu_fftshift[ind_nu_xlims][-1] + dnu_fftshift / 2, lats[0] - dlat / 2.0, lats[-1] + dlat / 2.0]
nnu_cut = len(ind_nu_xlims)

plt.ioff()
if plt.rcParams['interactive']:
    mpl.use('Qt5Agg')
else:
    mpl.use('agg')

# plotting function
def create_fig():
    
    data_xlabels = np.zeros((nrows, ncols), dtype='U30')
    data_xlabels[-1, :] = r'Frequency [nHz]'
    data_xticks = np.array([[np.linspace(-300, 300, 3)] * ncols] * nrows)
    data_xticks_minor = np.array([[np.linspace(-500, 500, 21)] * ncols] * nrows)
    data_xlims = np.array([[(-500, 500)] * ncols] * nrows)
    data_ylabels = np.zeros((nrows, ncols), dtype='U30')
    data_ylabels[:, 0] = r'Latitude [deg]'
    data_yticks = np.array([[np.linspace(-90, 90, 7)] * ncols] * nrows)
    data_yticks_minor = np.array([[np.linspace(-90, 90, 25)] * ncols] * nrows)
    data_ylims = np.array([[(-90, 90)] * ncols] * nrows)

    plot_xticks = np.zeros((nrows, ncols), dtype=bool)
    plot_xticks[-1, :] = True
    plot_yticks = np.zeros((nrows, ncols), dtype=bool)
    plot_yticks[:, 0] = True
    
    fig_left, fig_right, fig_bottom, fig_top, fig_hspace, fig_wspace = (0.04, 0.95, 0.06, 0.90, 0.1, 0.1)
    fig, axes = plt.subplots(nrows, ncols, figsize=figsize)
    data_list = []
    
    for i in range(nrows):
        data_list_temp = []
        for j in range(ncols):
            ax = axes[i, j]
            im = ax.imshow(np.zeros((nnu_cut, nlat)).T, interpolation='nearest', origin='lower', aspect='auto', cmap='binary', extent=ext_box_nu_lat)
            im.set_clim(0,1e4)
            ax.set_xlabel(data_xlabels[i, j])
            ax.set_ylabel(data_ylabels[i, j])
            ax.set_xlim(data_xlims[i, j])
            ax.set_ylim(data_ylims[i, j])
            ax.set_xticks(data_xticks[i, j])
            ax.set_xticks(data_xticks_minor[i, j], minor=True)
            ax.set_yticks(data_yticks[i, j])
            ax.set_yticks(data_yticks_minor[i, j], minor=True)
            if not plot_xticks[i, j]:
                ax.tick_params(labelbottom=False)
            if not plot_yticks[i, j]:
                ax.tick_params(labelleft=False)
            data_list_temp.append(im)
        data_list.append(data_list_temp)
    
    fig.subplots_adjust(left=fig_left, right=fig_right, bottom=fig_bottom, top=fig_top, hspace=fig_hspace, wspace=fig_wspace)
    fig.canvas.draw()
    ax1 = axes[0, -1]
    ax2 = axes[-1, -1]
    top = ax1.get_position().y1
    bottom = ax2.get_position().y0
    right = ax2.get_position().x1
    cbar_pad = 0.01
    cbar_width = 0.01
    cbar_height = top - bottom
    cax = fig.add_axes([right + cbar_pad, bottom, cbar_width, cbar_height])
    cbar = plt.colorbar(data_list[-1][-1], ax=axes[-1, -1], cax=cax)
    
    return fig, axes, data_list

nrows = 4
ncols = 11
figsize = (16.5, 8)

# create figure with empty subpanels
fig, axes, data_list = create_fig()

# generate some data
np.random.seed(100)
data1 = np.random.rand(nt,nlat,nlon)
data2 = np.random.rand(nt,nlat,nlon)
data3 = np.random.rand(nt,nlat,nlon)
data4 = np.random.rand(nt,nlat,nlon)

wsize = nt // 4
data1_temp = np.zeros((nt, nlat, nlon))
data2_temp = np.zeros((nt, nlat, nlon))
data3_temp = np.zeros((nt, nlat, nlon))
data4_temp = np.zeros((nt, nlat, nlon))
data1_temp[:wsize,:,:] = data1[:wsize,:,:]
data2_temp[:wsize,:,:] = data2[:wsize,:,:]
data3_temp[:wsize,:,:] = data3[:wsize,:,:]
data4_temp[:wsize,:,:] = data4[:wsize,:,:]

frame_cad = 10
# do not activate, else program will take about 15-20 minutes to finish
# frame_inds = range(0, nt - wsize + 1, frame_cad)
frame_inds = range(0, 50, frame_cad)
t0 = time.time()
for c, i in enumerate(frame_inds):
    print(c)
    if i >= 1:
        # fill in data for the next frame
        data1_temp[i-frame_cad:i] = 0.0
        data1_temp[i+wsize- 1:i+wsize-1+frame_cad] = data1[i+wsize-1:i+wsize-1+frame_cad,:,:]
        data2_temp[i-frame_cad:i] = 0.0
        data2_temp[i+wsize- 1:i+wsize-1+frame_cad] = data2[i+wsize-1:i+wsize-1+frame_cad,:,:]
        data3_temp[i-frame_cad:i] = 0.0
        data3_temp[i+wsize- 1:i+wsize-1+frame_cad] = data3[i+wsize-1:i+wsize-1+frame_cad,:,:]
        data4_temp[i-frame_cad:i] = 0.0
        data4_temp[i+wsize- 1:i+wsize-1+frame_cad] = data4[i+wsize-1:i+wsize-1+frame_cad,:,:]
    # compute power spectrum
    pu1_temp = np.abs(np.fft.fftn(data1_temp, axes=(0, 2))) ** 2
    pu2_temp = np.abs(np.fft.fftn(data2_temp, axes=(0, 2))) ** 2
    pu3_temp = np.abs(np.fft.fftn(data3_temp, axes=(0, 2))) ** 2
    pu4_temp = np.abs(np.fft.fftn(data4_temp, axes=(0, 2))) ** 2
    pu_temp_list = [pu1_temp, pu2_temp, pu3_temp, pu4_temp]
    # update data in subpanels
    for s in range(nrows):
        for j in range(ncols):
            data_list[s][j].set_data(np.fft.fftshift(pu_temp_list[s][:,:,j], axes=(0,))[ind_nu_xlims].T)
    # save figure
    fig.savefig('%s/stackoverflow_test/frame_%04d.png' % (path_plots_out, c))
plt.close()
print(time.time() - t0)

我会给你一些提示,但这不是一个解决方案:

  • 你正在做正确的事情来运行矩阵,但是检查是否可以最大化缓存来转置你的矩阵(当你有一个很高很窄的箱子时)

  • 你听说过稀疏矩阵或矩阵压缩技术吗


  • 做你需要做的事情,当我我会给你一些提示,但这不是一个解决方案:

    • 你正在做正确的事情来运行矩阵,但是检查是否可以最大化缓存来转置你的矩阵(当你有一个很高很窄的箱子时)

    • 你听说过稀疏矩阵或矩阵压缩技术吗


    • 当我时,做你需要做的事情,如果这正是你想要的情节,那么我认为你做得最快。5位数我得15分,不存钱我得5分


      信不信由你,让它更快的简单方法是放下你的小滴答声。如果我把这些行注释掉,我会得到8秒,速度会提高70%。matplotlib中的蜱虫非常昂贵。考虑到你的小刻度很小,我建议作为一个简单的优化。

      因此,如果这正是你想要的图形,那么我认为你正在以最快的速度完成。5位数我得15分,不存钱我得5分


      信不信由你,让它更快的简单方法是放下你的小滴答声。如果我把这些行注释掉,我会得到8秒,速度会提高70%。matplotlib中的蜱虫非常昂贵。考虑到您的小刻度很小,我建议将其作为一个简单的优化。

      我不确定是否遵循了您的所有要点。广告(1):这会影响绘图吗(我不知道)?ad(2):是的,但我还没有使用稀疏矩阵;另外,我不确定稀疏矩阵的情况是否如此,因为所有元素都不同于零。ad(3):i=0的情况可以在for循环之外完成,然后可以删除if语句,但我认为if不会导致运行时间过长;ad(4):我想并行化是可能的,但在大多数情况下,我通常不需要它(因此不使用它);您是否有任何与加速保存绘图直接相关的提示?谢谢是的,尝试保存为原始,您也将节省一些时间
      fig.savefig(,format='raw',)
      。广告(1):这会影响绘图吗(我不知道)?ad(2):是的,但我还没有使用稀疏矩阵;另外,我不确定稀疏矩阵的情况是否如此,因为所有元素都不同于零。ad(3):i=0的情况可以在for循环之外完成,然后可以删除if语句,但我认为if不会导致运行时间过长;ad(4):我想并行化是可能的,但在大多数情况下,我通常不需要它(因此不使用它);您是否有任何与加速保存绘图直接相关的提示?谢谢是的,尝试保存为原始,您也将节省一些时间
      fig.savefig(,format='raw',)
      70%确实是一个巨大的提升。为什么保存绘图上的小刻度需要这么多时间,特别是考虑到matplotlib不需要自己选择刻度位置?这只是一个已知的低效率。70%确实是一个巨大的提升。为什么在绘图上保存小刻度会花费这么多时间,特别是考虑到matplotlib不需要自己选择刻度位置?这只是一个已知的低效率。
      # use np.take_along_axis() with sorting indices instead of np.fft.fftshift() later, gives a slight (not too much!) speed boost
      ind_nu_xlims = np.where(np.logical_and(nu >= nu_lims[0], nu <= nu_lims[1]))[0]
      ind_nu_sort = np.argsort(nu[ind_nu_xlims])
      nu_sort = np.take_along_axis(nu[ind_nu_xlims],ind_nu_sort,axis=0)
      ext_box_nu_lat = [nu_sort[0] + dnu_fftshift / 2, nu_sort[-1] - dnu_fftshift / 2, lats[0] - dlat / 2.0, lats[-1] + dlat / 2.0]
          
      # plotting function
      def create_fig():
          
                  # deactivating ticks massively (!) boosts plotting performance
                  # ax.set_xticks(data_xticks_minor[i, j], minor=True)
                  # ax.set_yticks(data_yticks_minor[i, j], minor=True)
      
      data_list = [data1, data2, data3, data4]
      
      # wisdom makes FFTs much faster using pyfftw than using numpy
      # enable cache and set cache memory-keeping time sufficiently large
      # this depends on the computation time between FFT calls
      pyfftw.interfaces.cache.enable()
      pyfftw.interfaces.cache.set_keepalive_time(5)
      
      for c, i in enumerate(frame_inds):
          print(c)
          data_temp_list = [data1_temp, data2_temp, data3_temp, data4_temp]
          pu_temp_list = []
          for j, data_temp in enumerate(data_temp_list):
              if i >= 1:
                  # fill in data for the next frame
                  data_temp[i-frame_cad:i] = 0.0
                  data_temp[i+wsize-1:i+wsize-1+frame_cad] = data_list[j][i+wsize-1:i+wsize-1+frame_cad,:,:]
              # compute Fourier transform via pyfftw; wisdom makes FFTs much faster using pyfftw than using numpy
              pu_temp = pyfftw.interfaces.numpy_fft.fftn(data_temp, axes=(0, 2), threads=-1)
              # compute absolute-square using np.real(x * np.conj(x));
              # about same speed as np.real(x) * np.imag(x);
              # faster than np.einsum('ijk,ijk->ijk',x,np.conj(x));
              # also faster than np.abs(x)**2 since np.abs(x)**2 first takes square-root, then squares again
              pu_temp = np.real(pu_temp*np.conj(pu_temp))
              pu_temp_list.append(pu_temp)
          # update data in subpanels
          for s in range(nrows):
              for j in range(ncols):
                  # use np.take_along_axis() with sorting indices instead of np.fft.fftshift(), gives a slight (not too much!) speed boost
                  plot_data_list[s][j].set_data(np.take_along_axis(pu_temp_list[s][ind_nu_xlims,:,j], ind_nu_sort[:,None], axis=0).T)
          # save figure
          fig.savefig('%s/stackoverflow_test/frame_%04d.png' % (path_plots_out, c))
      plt.close()
      print(time.time() - t0)