207

I want to plot data, then create a new figure and plot data2, and finally come back to the original plot and plot data3, kinda like this:

import numpy as np
import matplotlib as plt

x = arange(5)
y = np.exp(5)
plt.figure()
plt.plot(x, y)

z = np.sin(x)
plt.figure()
plt.plot(x, z)

w = np.cos(x)
plt.figure("""first figure""") # Here's the part I need
plt.plot(x, w)

FYI How do I tell matplotlib that I am done with a plot? does something similar, but not quite! It doesn't let me get access to that original plot.

Community
  • 1
  • 1
Peter D
  • 3,283
  • 4
  • 24
  • 23

6 Answers6

191

If you find yourself doing things like this regularly it may be worth investigating the object-oriented interface to matplotlib. In your case:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(5)
y = np.exp(x)
fig1, ax1 = plt.subplots()
ax1.plot(x, y)
ax1.set_title("Axis 1 title")
ax1.set_xlabel("X-label for axis 1")

z = np.sin(x)
fig2, (ax2, ax3) = plt.subplots(nrows=2, ncols=1) # two axes on figure
ax2.plot(x, z)
ax3.plot(x, -z)

w = np.cos(x)
ax1.plot(x, w) # can continue plotting on the first axis

It is a little more verbose but it's much clearer and easier to keep track of, especially with several figures each with multiple subplots.

simonb
  • 2,777
  • 2
  • 18
  • 16
  • 4
    I prefer the object oriented approach as when I anticipate having many figures, it will be easier to keep track of them by using names rather than numbers. Thanks! – Peter D Aug 04 '11 at 04:37
  • 1
    But how can one change the label and axis limits with this approach. If I use `ax1.ylabel` it says that it is not found. Same with `fig1.ylabel` ... – George Datseris Aug 28 '16 at 07:45
  • 4
    @GeorgeDatseris The syntax is a little different. It's `ax1.set_xlabel("your x label")`, `ax1.set_ylabel("your y label")`, and `ax1.set_title("your title")`. – simonb Sep 12 '16 at 14:43
  • 1
    why did you use 111 ? – Yash Sodha May 16 '18 at 12:53
  • 3
    @yashSodha - that's a matlab-style specification of number of subplots (rows, col, index). But it's much easier now to use `plt.subplots(nrows, ncols)`. Have updated the example. – simonb Jun 10 '18 at 18:55
  • I upvoted you, cauz you're answer worked for me, thanks! But could you please add images to your answer, maybe more examples with different parameters? I mean, I had to look up the documentation to find best fit for my solution. Would have been really helpful to add images with different effects. – KareemJ Mar 29 '19 at 11:59
181

When you call figure, simply number the plot.

x = arange(5)
y = np.exp(5)
plt.figure(0)
plt.plot(x, y)

z = np.sin(x)
plt.figure(1)
plt.plot(x, z)

w = np.cos(x)
plt.figure(0) # Here's the part I need
plt.plot(x, w)

Edit: Note that you can number the plots however you want (here, starting from 0) but if you don't provide figure with a number at all when you create a new one, the automatic numbering will start at 1 ("Matlab Style" according to the docs).

agf
  • 171,228
  • 44
  • 289
  • 238
  • 4
    This appears to work in matplotlib's interactive mode, while the figure() ... add_subplot() method does not. Thanks! – chbrown Apr 02 '14 at 22:02
  • 2
    @SebMa Please don't change the code without understanding it. This answer was specifically about passing a number to `figure`, which you removed. The other things you changed were copied from the original post and not mistakes in my answer. – agf Jun 16 '18 at 15:02
  • @agf Hi, I removed the `1` inside `plt.figure(1)` because I thought the number was auto incremented and therefore not necessary. Sorry. – SebMa Jun 16 '18 at 16:35
  • But then only figure(0) gets the title and legend – Nathan B May 13 '23 at 15:11
25

However, numbering starts at 1, so:

x = arange(5)
y = np.exp(5)
plt.figure(1)
plt.plot(x, y)

z = np.sin(x)
plt.figure(2)
plt.plot(x, z)

w = np.cos(x)
plt.figure(1) # Here's the part I need, but numbering starts at 1!
plt.plot(x, w)

Also, if you have multiple axes on a figure, such as subplots, use the axes(h) command where h is the handle of the desired axes object to focus on that axes.

(don't have comment privileges yet, sorry for new answer!)

strpeter
  • 2,562
  • 3
  • 27
  • 48
Ross B.
  • 986
  • 9
  • 14
  • 12
    `0` works, _automatic_ numbering just start at `1`, if you don't give it a number at all. – agf Aug 02 '11 at 19:26
4

The accepted answer here says to use the object oriented interface (matplotlib) but the answer itself incoporates some of the MATLAB-style interface (matplotib.pyplot).

It is possible to use solely the OOP method, if you like that sort of thing:

import numpy as np
import matplotlib

x = np.arange(5)
y = np.exp(x)
first_figure      = matplotlib.figure.Figure()
first_figure_axis = first_figure.add_subplot()
first_figure_axis.plot(x, y)

z = np.sin(x)
second_figure      = matplotlib.figure.Figure()
second_figure_axis = second_figure.add_subplot()
second_figure_axis.plot(x, z)

w = np.cos(x)
first_figure_axis.plot(x, w)

display(first_figure) # Jupyter
display(second_figure)

This gives the user manual control over the figures, and avoids problems associated with pyplot's internal state supporting only a single figure.

c z
  • 7,726
  • 3
  • 46
  • 59
3

An easy way to plot separate frame for each iteration could be:

import matplotlib.pyplot as plt  
for grp in list_groups:
        plt.figure()
        plt.plot(grp)
        plt.show()

Then python will plot different frames.

Amirkhm
  • 948
  • 11
  • 13
  • Seems to be exactly what the OP asked for, and what is required when using the original interface. – mins Jul 21 '23 at 17:56
1

One way I found after some struggling is creating a function which gets data_plot matrix, file name and order as parameter to create boxplots from the given data in the ordered figure (different orders = different figures) and save it under the given file_name.

def plotFigure(data_plot,file_name,order):
    fig = plt.figure(order, figsize=(9, 6))
    ax = fig.add_subplot(111)
    bp = ax.boxplot(data_plot)
    fig.savefig(file_name, bbox_inches='tight')
    plt.close()
emir
  • 321
  • 3
  • 6