Make several figures from a dictionary without overwriting the previous figure [duplicate] - python

I have a Python program that generates graphs using matplotlib. I am trying to get the program to generate a bunch of plots in one program run (the user is asked if they want to generate another graph) all in separate windows. Any way I can do this?

To generate a new figure, you can add plt.figure() before any plotting that your program does.
import matplotlib.pyplot as plt
import numpy as np
def make_plot(slope):
x = np.arange(1,10)
y = slope*x+3
plt.figure()
plt.plot(x,y)
make_plot(2)
make_plot(3)

Using the latest matlibplot, I found the following to work for my purposes:
# create figure (will only create new window if needed)
plt.figure()
# Generate plot1
plt.plot(range(10, 20))
# Show the plot in non-blocking mode
plt.show(block=False)
# create figure (will only create new window if needed)
plt.figure()
# Generate plot2
plt.plot(range(10, 20))
# Show the plot in non-blocking mode
plt.show(block=False)
...
# Finally block main thread until all plots are closed
plt.show()

The easiest way to ensure all of your lines go to the correct figure window is something like:
from six.moves import input
import matplotlib.pyplot as plt
another = True
while another:
fig, ax = plt.subplots()
ax.plot(range(5))
fig.canvas.manager.show()
# this makes sure that the gui window gets shown
# if this is needed depends on rcparams, this is just to be safe
fig.canvas.flush_events()
# this make sure that if the event loop integration is not
# set up by the gui framework the plot will update
another = bool(input("would you like another? "))
If you want to run this with a non-gui backend you will need to drop the flush_events call or wrap it in a try: ... except NotImplementedError. Much of this complication is defensive programming because GUIs can be difficult and the behavior of this code may be dependent on many factors which are not obvious from the code shown.
Using the implicit axes of pyplot can cause problems as the 'current axes' is set by the last axes the user clicked on. You should really only use pyplot when interactively typing at the rpel and almost never (other than plt.subplots) in scripts/programs.

Use the .figure() function to create a new window, the following code makes two windows:
import matplotlib.pyplot as plt
plt.plot(range(10)) # Creates the plot. No need to save the current figure.
plt.draw() # Draws, but does not block
plt.figure() # New window, if needed. No need to save it, as pyplot uses the concept of current figure
plt.plot(range(10, 20))
plt.draw()
You can repeat this as many times as you want

Related

Trying to add additional traces to an existing Matplotlib figure

I am using a function which spits out a figure object of validation data. My script calculates a few model parameters that I would like to plot on top of this existing figure object. How can I do this? Whenever I try to plot my modeled data, it does so in a new window. Here's what my code looks like:
datafig = plotting_function(args) #Returning a figure object
datafig.show()
plt.plot([modeled_x],[modeled_y]) #Plotting in a new window
I've tried using plt.hold() / plt.hold(True) but this doesn't do anything. Any ideas?
Edit:
MCVE:
import matplotlib.pyplot as plt
def fig_create():
fig_1, ax_1 = plt.subplots()
ax_1.plot([0,1],[0,1])
fig_2, ax_2 = plt.subplots()
ax_2.plot([0,1],[0,5])
return fig_1, ax_1, fig_2, ax_2
figure_1, axes_1, figure_2, axes_2 = fig_create()
plt.close("all") # Spyder plots even without a plt.show(), so running the function generates figures. I'm closing them here.
figure_2.show()
plt.figure(2)
plt.plot([0,1],[0,10])
Result of the MCVE: https://i.imgur.com/FiCJX33.png
You need to specify which axis to plot on. plt.figure(2) will make a figure with a number of 2, regardless of whether an existing figure has that number or not! axes_2.plot(), however will plot whatever data you input directly onto axes_2 and whatever was there already. If it doesn't immediately show up you should add plt.draw() after the plot function.
Try not to mix plt, notation and ax notation as this will create confusion later on! If you are using fig and ax, stick with those!
You can specify which figure to plot to by calling plt.figure(my_figure_index) before any plt.plot (or any other plt plotting function) call.
For example:
plt.figure(10) # creates new figure if doesn't exist yet
plt.plot(...) # plots in figure 10
plt.figure(2) # creates new figure if doesn't exist yet
plt.plot(...) # plots in this figure 2
plt.figure(10) # figure already exists, just makes it the active one
plt.plot(...) # plots in figure 10 (in addition to already existing stuff)

Matplotlib reuse figure created by another script

I am using Matplotlib on MacOS with Sulime Text.
I use Python 3.5 and Matplotlib 2.0.
When I work on a figure, I usually have a script that plot the data, and save the figure in a .pdf file with plt.savefig(). Then I use Skim (a pdf viewer) in order to refresh the file each time I modify and run the script. This allows me to set my working layout as clean as: there is one window for the script, and one window for the figure which is automatically refreshing.
I would like to do keep the same layout, but using the Matplotlib figures (because they are interactive). I am looking for a way to use plt.show() but always in the same figure that has been created the first time I've run the script.
For instance:
1. First run
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.figure()
noise = np.random.rand(1, 100)
ax(noise)
plt.show()
2. Following runs
import matplotlib.pyplot as plt
import numpy as np
# This is the super command I am looking for
fig = plt.get_previous_run_figure()
ax = fig.axes
noise = np.random.rand(1, 100)
ax.plot(noise)
plt.draw()
In that case of course, I would have to do a first-run script separately from the main script. Does anyone know if it is possible ?
You want to have multiple consecutive python sessions share a common Matplotlib window. I see no way to share this windows from separate processes, especially when the original owner may terminate at any point in time.
However, you could do something similar to your current workflow in which you have an external pdf viewer to view a output file which you update from multiple python instances.
See this question/answer on how to pickle a matplotlib figure:
Store and reload matplotlib.pyplot object
In every script, output your matplotlib figure as a pickled object, rather than calling plt.show():
import matplotlib.pyplot as plt
import numpy as np
import pickle
ax = plt.subplot(111)
x = np.linspace(0, 10)
y = np.exp(x)
plt.plot(x, y)
pickle.dump(ax, file('myplot.pickle', 'w'))
Then, start a dedicated python session which loads this pickled object and calls plt.show(). Have this script run in a loop, checking for updates of the pickled file on disk, and reloading when necessary:
import matplotlib.pyplot as plt
import pickle
while True:
ax = pickle.load(file('myplot.pickle'))
plt.show()
Alternative
Instead of having separate python sessions, I usually have a single Ipython session in which I run different script. By selecting the same figure windows, I end up with a mostly similar setup as you describe, in which the same figure window is reused throughout the day.
import matplotlib.pyplot as plt
fig = plt.figure(0)
fig.clf()
plt.show()
In principle establishing a connection between two different scripts could be done using a system-wide clipboard. (As far as I know the clipboard in windows and macos are system-wide.)
So the idea can be to set up an application using tk or pyqt, and implement a generic FigureCanvas. This application could have an event listener for changes in the clipboard.
The other main workflow script would then call some function that wraps the current figure into a pickle object and sends it to the clipboard, from where it gets caught by the GUI application, is unpickled and shown in the canvas.
This sounds like a little bit of work, but should meet the very restrictive requirements from the question.
The alternative from Daan worked for me. Here's a bit more code. I used this in a Tkinter interactive GUI for reusing/updating a matplotlib figure window:
fig1 = None
if fig1:
#if exists, clear figure 1
plt.figure(1).clf()
plt.suptitle("New Fig Title", fontsize=18, fontweight='bold')
#reuse window of figure 1 for new figure
fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)
else:
#initialize
fig1 = plt.figure(num=1,figsize=(7, int(7*imgRatio)), dpi=80)
plt.tick_params(axis='both', which='major', labelsize=14)
plt.tick_params(axis='both', which='minor', labelsize=14)
plt.suptitle("Title", fontsize=18, fontweight='bold')
fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)
The figure is reusing the (interactive) plt window. For this to work, I had to set interactive : True in the matplotlibrc file (see my comment here)

Showing a few figures without stopping calculations in matplotlib

Hi I would like to show a few figures in matplotlib without stopping calculations. I would like the figure to show up right after the calculations that concern it are finished for example:
import numpy as np
import pylab as py
x=np.linspace(0,50,51)
y=x
fig, axs = plt.subplots(1, 1)
cs = axs.plot(x, y)
now i want to show the plot without blocking the possibility to make some other calculations
plt.show(block=False)
plt.pause(5)
I create the second plot
y1=2*x
fig1, axs1 = plt.subplots(1, 1)
cs1 = axs1.plot(x, y1)
plt.show()
This works however the first freezes (after 5 secound pause which I added) until I call plt.show() at the end. It is crucial that the first figure shows and works, then after calculations another figure is added to it.
The following code should do what you want. I did this in an IPython Notebook.
from IPython import display
import matplotlib.pyplot as plt
def stream_plot(iterable, plotlife=10.):
for I in iterable:
display.clear_output(wait=True)
output = do_calculations_on_i(I)
plt.plot(output)
display.display(plt.gca());
time.sleep(plotlife); #how long to show the plot for
the wait=True will wait to clear the old plot until it has something new to plot, or any other output is printed.
I put the sleep in there so I can observe each plot before it is wiped away. This was useful for having to observe distributions for several entities. You may or may not need it for what you want to do.

Update/Refresh matplotlib plots on second monitor

At the moment I am working with Spyder and doing my plotting with matplotlib. I have two monitors, one for development and another for (data) browsing and other stuff. Since I am doing some calculations and my code often changes, I often (re)execute the code and have a look at the plots to check if the results are valid.
Is there any way to place my matplotlib plots on a second monitor and refresh them from the main monitor?
I have already searched for a solution but could not find anything. It would be really helpful for me!
Here's some additional information:
OS: Ubuntu 14.04 (64 Bit)
Spyder-Version: 2.3.2
Matplotlib-Version: 1.3.1.-1.4.2.
I know it's an old question but I came across a similar problem and found this question. I managed to move my plots to a second display using the QT4Agg backend.
import matplotlib.pyplot as plt
plt.switch_backend('QT4Agg')
# a little hack to get screen size; from here [1]
mgr = plt.get_current_fig_manager()
mgr.full_screen_toggle()
py = mgr.canvas.height()
px = mgr.canvas.width()
mgr.window.close()
# hack end
x = [i for i in range(0,10)]
plt.figure()
plt.plot(x)
figManager = plt.get_current_fig_manager()
# if px=0, plot will display on 1st screen
figManager.window.move(px, 0)
figManager.window.showMaximized()
figManager.window.setFocus()
plt.show()
[1] answer from #divenex: How do you set the absolute position of figure windows with matplotlib?
This has to do with matplotlib, not Spyder. Placing the location of a figure explicitly appears to be one of those things for which there's really just workarounds ... see the answers to the question here. That's an old question, but I'm not sure there's been change since then (any matplotlib devs, feel free to correct me!).
The second monitor shouldn't make any difference, it sounds like the issue is just that the figure is being replaced with a new one.
Fortunately you can update figures you've moved to where you want them pretty easily, by using the object interface specifically, and updating the Axes object without creating a new figure. An example is below:
import matplotlib.pyplot as plt
import numpy as np
# Create the figure and axes, keeping the object references
fig = plt.figure()
ax = fig.add_subplot(111)
p, = ax.plot(np.linspace(0,1))
# First display
plt.show()
# Some time to let you look at the result and move/resize the figure
plt.pause(3)
# Replace the contents of the Axes without making a new window
ax.cla()
p, = ax.plot(2*np.linspace(0,1)**2)
# Since the figure is shown already, use draw() to update the display
plt.draw()
plt.pause(3)
# Or you can get really fancy and simply replace the data in the plot
p.set_data(np.linspace(-1,1), 10*np.linspace(-1,1)**3)
ax.set_xlim(-1,1)
ax.set_ylim(-1,1)
plt.draw()

When to use cla(), clf() or close() for clearing a plot in matplotlib?

Matplotlib offers these functions:
cla() # Clear axis
clf() # Clear figure
close() # Close a figure window
When should I use each function and what exactly does it do?
They all do different things, since matplotlib uses a hierarchical order in which a figure window contains a figure which may consist of many axes. Additionally, there are functions from the pyplot interface and there are methods on the Figure class. I will discuss both cases below.
pyplot interface
pyplot is a module that collects a couple of functions that allow matplotlib to be used in a functional manner. I here assume that pyplot has been imported as import matplotlib.pyplot as plt.
In this case, there are three different commands that remove stuff:
See matplotlib.pyplot Functions:
plt.cla() clears an axis, i.e. the currently active axis in the current figure. It leaves the other axes untouched.
plt.clf() clears the entire current figure with all its axes, but leaves the window opened, such that it may be reused for other plots.
plt.close() closes a window, which will be the current window, if not specified otherwise.
Which functions suits you best depends thus on your use-case.
The close() function furthermore allows one to specify which window should be closed. The argument can either be a number or name given to a window when it was created using figure(number_or_name) or it can be a figure instance fig obtained, i.e., usingfig = figure(). If no argument is given to close(), the currently active window will be closed. Furthermore, there is the syntax close('all'), which closes all figures.
methods of the Figure class
Additionally, the Figure class provides methods for clearing figures.
I'll assume in the following that fig is an instance of a Figure:
fig.clf() clears the entire figure. This call is equivalent to plt.clf() only if fig is the current figure.
fig.clear() is a synonym for fig.clf()
Note that even del fig will not close the associated figure window. As far as I know the only way to close a figure window is using plt.close(fig) as described above.
There is just a caveat that I discovered today.
If you have a function that is calling a plot a lot of times you better use plt.close(fig) instead of fig.clf() somehow the first does not accumulate in memory. In short if memory is a concern use plt.close(fig) (Although it seems that there are better ways, go to the end of this comment for relevant links).
So the the following script will produce an empty list:
for i in range(5):
fig = plot_figure()
plt.close(fig)
# This returns a list with all figure numbers available
print(plt.get_fignums())
Whereas this one will produce a list with five figures on it.
for i in range(5):
fig = plot_figure()
fig.clf()
# This returns a list with all figure numbers available
print(plt.get_fignums())
From the documentation above is not clear to me what is the difference between closing a figure and closing a window. Maybe that will clarify.
If you want to try a complete script there you have:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1000)
y = np.sin(x)
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
plt.close(fig)
print(plt.get_fignums())
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
fig.clf()
print(plt.get_fignums())
If memory is a concern somebody already posted a work-around in SO see:
Create a figure that is reference counted
plt.cla() means clear current axis
plt.clf() means clear current figure
also, there's plt.gca() (get current axis) and plt.gcf() (get current figure)
Read more here: Matplotlib, Pyplot, Pylab etc: What's the difference between these and when to use each?

Categories

Resources