1

Due to the 2nd answer of this question I supposed the following code

import matplotlib.pyplot as plt

for i1 in range(2):

    plt.figure(1)
    f, ax = plt.subplots()
    plt.plot((0,3), (2, 2), 'b')


    for i2 in range(2):
        plt.figure(2)
        f, ax = plt.subplots()
        plt.plot([1,2,3], [1,2,3], 'r')
        plt.savefig('foo_{}_bar_{}.jpg'.format(i2, i1))
        plt.close()

    plt.figure(1)
    plt.plot( [1,2,3],[1,2,3], 'r')

    plt.savefig('bar_{}.jpg'.format(i1))
    plt.close()

to create plots bar_0.jpg and bar_1.jpg showing a blue and a red line each.

However, figures look like

enter image description here

instead of

enter image description here

How can I achieve the desired behaviour? Note that plots foo_*.jpg have to be closed and saved during handling of the bar plots.

Community
  • 1
  • 1
corinna
  • 629
  • 7
  • 18
  • I can't quite see why you would want to write foo_1 and foo_2 to file twice, also, could you clearly state your desired behaviour? – M.T Feb 22 '16 at 15:04
  • This is just a minimal example, I want to plot SOMETHING in foo_1.jpg and foo_2.jpg. The desired behaviour is the following: Do several times: (1) create a plot and plot something to it, (2) create a new plot, draw something in it, and save and close it (3) go back to the previous plot, and plot something additional into it, and save it. – corinna Feb 22 '16 at 15:18

2 Answers2

2

You're already saving the Axes objects, so instead of calling the PyPlot plot function (which draws on the last created or activated Axes), use the objects' plot function:

ax.plot(...)

If you then give both a different name, say ax1 and ax2, you can draw on the one you like without interfering with the other. All plt. commands also exist as an Axes member function, but sometimes the name changes (plt.xticks becomes ax.set_xticks for example). See the documentation of Axes for details.

To save to figures, use the Figure objects in the same way:

f.savefig(...)

This API type is only just coming to Matlab, FYI, and will probably replace the old-fashioned "draw on the last active plot" behaviour in the future. The object-oriented approach here is more flexible with minimal overhead, so I strongly recommend you use it everywhere.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • why are we talking about matlab? – tmdavison Feb 22 '16 at 15:42
  • Works, thanks a lot! But the answer mentioned in my question is wrong then, isn't it? – corinna Feb 22 '16 at 15:59
  • @tom No one is talking about Matlab except me. And you, now. I brought it up because the Pyplot API is modelled after the Matlab API, and the "object oriented API" is not. – rubenvb Feb 22 '16 at 15:59
  • @corinna It's not wrong, it's a different way of approaching the problem. Calling `plt.figure(1)` sets the current figure to the first one created, just like in Matlab, a call to `figure(1)` will activate the first figure. This way of doing things introduces hidden state (i.e. which figure is current?), while using the objects directly makes it explicit from the code where things are being done. – rubenvb Feb 22 '16 at 16:02
  • right, but the object oriented approach has existed in matplotlib for a long time, and just felt weird adding it to an answer which has nothing to do with matlab. But, you know, each to his/her own – tmdavison Feb 22 '16 at 16:03
2

If unsure, better to make it explicit:

import matplotlib.pyplot as plt

for i1 in range(2):
    fig1,ax1 = plt.subplots()
    fig2,ax2 = plt.subplots()
    ax1.plot([0,4],[2,2],'b')

for i2 in range(2):
    ax2.plot([1,2,3],[1,2,3],'r')
    fig2.savefig('abc{}.png'.format(2*i1+i2))
    plt.figure(1)
    ax1.plot([1,2,3],[1,2,3],'r')

fig1.savefig('cba{}.png'.format(i1))
M.T
  • 4,917
  • 4
  • 33
  • 52