16

I am creating a couple of pdf plots with matplotlib which is composed of 400 subplots. Each one has only 5 data points. It takes 420 s on a good computer to save 5 pdf picture. Is there any way to optimize the code or it is just normal for matplotlib?

Portion of code for plotting:

plot_cnt = 1
for k in np.arange(K_min, K_max + 1):
    for l in np.arange(L_min, L_max + 1):
        ax = plt.subplot(grid[0], grid[1], plot_cnt)
        plot_cnt += 1
        plt.setp(ax, 'frame_on', False)
        ax.set_ylim([-0.1, 1.1])
        ax.set_xlabel('K={},L={}'.format(k, l), size=3)
        ax.set_xlim([-0.1, 4.1])
        ax.set_xticks([])
        ax.set_yticks([])
        ax.grid('off')
        ax.plot(np.arange(5), (data['S1']['Azimuth'][:, k - 1, l + offset_l] + \
                data['S1']['Delta Speed'][:, k - 1, l + offset_l] + \
                data['S1']['Speed'][:, k - 1, l + offset_l]) / 3,
                'r-o', ms=1, mew=0, mfc='r')
        ax.plot(np.arange(5), data['S2'][case][:, k - 1, l + offset_l],
                'b-o', ms=1, mew=0, mfc='b')
plt.savefig(os.path.join(os.getcwd(), 'plot-average.pdf'))
plt.clf()
print 'Final plot created.'

Final Picture: enter image description here

rowman
  • 1,516
  • 1
  • 16
  • 26
  • 3
    400 subplots seems a lot for me. Even if you don't have a lot data, matplotlib may no be optimized to display this kind of grids. – Simon Bergot Oct 24 '12 at 09:35
  • 1
    @Simon, is it possible to plot using a single big subplot? Then each five should be connected. Any idea? – rowman Oct 24 '12 at 18:55
  • I don't have the right environment to run the tests, but there are a few things you can do. The first step is to run the profiler on your code (see [here](http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script) for more information). With this, you can locate where the time is spent. The two things you could try is to find some resource to release at each step, or to create the plots in several processes using [multiprocessing](http://docs.python.org/library/multiprocessing.html). If I find the time I will try this, but at this stage I cannot guarantee anything – Simon Bergot Oct 24 '12 at 19:24
  • 1
    @rowman I implemented your idea of using one big `axes`. – tacaswell Oct 25 '12 at 03:15

1 Answers1

24

Building off of what @rowman said, you can do this all in one axes (as you turn off all the ticks etc). Something like:

K_max = 20
K_min = 0
L_max = 20
L_min = 0
ax = plt.subplot(111)
x_offset = 7 # tune these
y_offset = 7 # tune these
plt.setp(ax, 'frame_on', False)
ax.set_ylim([0, (K_max-K_min +1)*y_offset ])
ax.set_xlim([0, (L_max - L_min+1)*x_offset])
ax.set_xticks([])
ax.set_yticks([])
ax.grid('off')



for k in np.arange(K_min, K_max + 1):
    for l in np.arange(L_min, L_max + 1):
        ax.plot(np.arange(5) + l*x_offset, 5+rand(5) + k*y_offset,
                'r-o', ms=1, mew=0, mfc='r')
        ax.plot(np.arange(5) + l*x_offset, 3+rand(5) + k*y_offset,
                'b-o', ms=1, mew=0, mfc='b')
        ax.annotate('K={},L={}'.format(k, l), (2.5+ (k)*x_offset,l*y_offset), size=3,ha='center')
plt.savefig(os.path.join(os.getcwd(), 'plot-average.pdf'))

print 'Final plot created.'

Runs in about a second or two. I think all of the time is spent setting up the axes object which are rather complex internally. output with fake data

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • 1
    Very nice. Just out of curosity, can the technique which is mentioned [here](http://www.scipy.org/Cookbook/Matplotlib/Animations) be used as well? Just using line's `set_ydata`. Should find a method to copy ax objects though. – rowman Oct 26 '12 at 10:02
  • @rowman can you be more specific about which method at that link? If you wanted to make 400 separate figures `set_ydata` would be useful, but I don't immediately see it would be useful in this case. – tacaswell Oct 27 '12 at 01:31
  • For GUI applications I just create a line and update Y only to be fast instead of redrawing the whole figure each time. In this case, I was just thinking instead of creating 400 figures, copy one object 400 times, update Y and the position of the figure axis. It might take the same time though. – rowman Oct 27 '12 at 03:40
  • 1
    @rowman See http://docs.python.org/library/copy.html . I have no guess on speed. however you would still have to deal with setting the grid up by hand because the location the `axes` in the `figure` is a property of the axes. – tacaswell Oct 27 '12 at 13:13