if I create a figure then do plt.close() :
from matplotlib import pyplot as plt
fig1 = plt.figure()
fig2 = plt.figure()
fig1.show()
plt.close()
fig1.show()
fig2.show()
the fig1 will only show once, because the plt.close() will destroy the figure object referred by fig1. How can I only close the window without destroy the figure?
So far nothing really works.
after each plt.figure(), a new figure_manager is going to be generated. And will be put into a list in plt instance.
>>> print plt.get_fignums()
[1, 2]
however, after plt.close(), the figure_manager of the specific figure will be pop out.
>>> print plt.get_fignums()
[2]
As #John Sharp mentioned plt._backend_mod.new_figure_manager_given_figure(plt.get_fignums()[-1]+1,fig1) will create a new figure_manager for the fig1. However, it has not been added to the plt. So it is impossible to control those figure_manager while plt:
>>> plt._backend_mod.new_figure_manager_given_figure(plt.get_fignums()[-1]+1,fig1)
<matplotlib.backends.backend_tkagg.FigureManagerTkAgg instance at 0x2b0f680>
>>> print plt.get_fignums()
[2]
>>> plt.new_figure_manager(1)
<matplotlib.backends.backend_tkagg.FigureManagerTkAgg instance at 0x2b1e3f8>
>>> plt.get_fignums()
[2]
So it cannot be closed by plt.close(), except directly call figure_manager.destroy()
The suggestion to set current fm directly will be worse:
fm = plt.get_current_fig_manager()
fm.canvas.figure = fig1
fig1.canvas = fm.canvas
at the first glance, this seems work. However, it will directly change the fig2's fm to point to fig1, which will cause lots of trouble.
If there is any way, we can make the pyplot to register manually generated fm, that may work. So far have no luck there.
Since the Figure is still referenced by the name fig1 it is not destroyed. You just need to create a new figure manager for the figure. One way to do this is to get a new figure manager by generating a new blank figure and manually set the canvas figure to be fig1:
plt.figure()
fm = plt.get_current_fig_manager()
fm.canvas.figure = fig1
fig1.canvas = fm.canvas
Once you've done this you can show and then close the figure with:
fig1.show()
plt.close()
Alternatively, if you were showing two figures at once and only wanted to close a particular one, instead of using plt.close() you can call the fm.destroy() method to close the window showing only the particular figure referenced by that frame manager.
Related
I need to create a figure in a file without displaying it within IPython notebook. I am not clear on the interaction between IPython and matplotlib.pylab in this regard. But, when I call pylab.savefig("test.png") the current figure get's displayed in addition to being saved in test.png. When automating the creation of a large set of plot files, this is often undesirable. Or in the situation that an intermediate file for external processing by another app is desired.
Not sure if this is a matplotlib or IPython notebook question.
This is a matplotlib question, and you can get around this by using a backend that doesn't display to the user, e.g. 'Agg':
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('/tmp/test.png')
EDIT: If you don't want to lose the ability to display plots, turn off Interactive Mode, and only call plt.show() when you are ready to display the plots:
import matplotlib.pyplot as plt
# Turn interactive plotting off
plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('/tmp/test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
plt.figure()
plt.plot([1,3,2])
plt.savefig('/tmp/test1.png')
# Display all "open" (non-closed) figures
plt.show()
We don't need to plt.ioff() or plt.show() (if we use %matplotlib inline). You can test above code without plt.ioff(). plt.close() has the essential role. Try this one:
%matplotlib inline
import pylab as plt
# It doesn't matter you add line below. You can even replace it by 'plt.ion()', but you will see no changes.
## plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
fig2 = plt.figure()
plt.plot([1,3,2])
plt.savefig('test1.png')
If you run this code in iPython, it will display a second plot, and if you add plt.close(fig2) to the end of it, you will see nothing.
In conclusion, if you close figure by plt.close(fig), it won't be displayed.
In Matplotlib, I can update the visual effect of the plot in a figure by calling the Figure object, say fig and calling the method show (fig.show()). But I also can do that by calling the canvas object in the figure and then calling method draw (fig.canvas.draw()).
Example:
import matplotlib.pyplot as plt
fig, axes = plt.subplots()
axes.plot([1,2,3],[2,3,4])
fig.show()
axes.plot([1,2,3],[-2,23,14])
fig.show()
and
import matplotlib.pyplot as plt
fig, axes = plt.subplots()
axes.plot([1,2,3],[2,3,4])
fig.show()
axes.plot([1,2,3],[-2,23,14])
fig.canvas.draw()
I suspected the fig.show also performs self.canvas.draw() and some other things. But when I checked the code, I see only that it may call self.canvas.draw_idle().
What is the difference between fig.show, fig.canvas.draw, fig.canvas.draw_idle??
When I call fig.show() in a python script that is run from the command line (in Anaconda on Windows), it briefly appears and disappears from my screen. This is different from plt.show() which shows all open figures and the Python script hangs until I close them to continue running. (I know you are not discussing plt.show() above but wanted to mention it for clairty and completeness.)
fig.show() calls plt.canvas.draw_idle(), which "schedules a rendering the next time the GUI window is going to re-paint the screen" and thus calls fig.canvas.draw() under certain conditions. In fact, that same link continues to note that "Even if multiple calls to draw_idle occur before control returns to the GUI event loop, the figure will only be rendered once". To be sure that the screen is updated as soon as possible, the documentation suggests that fig.canvas.draw_idle should be followed by fig.canvas.flush_events().
By contrast, fig.canvas.draw() renders the figure even if no output is produced. Looking at the documentation, this function renders the figure and "walk[s] the artist tree even if not output is produced because this will trigger deferred work (like computing limits auto-limits and tick values)". So you can generate the figure in memory and not actually show or print it. The only instance I have seen where it is useful is when you need details about the formatting of the figure before the final rendering and printing/saving.
Based on that info, I did a timing experiment:
import matplotlib.pyplot as plt
import datetime
N = 10**4
fig, axes = plt.subplots()
axes.plot([1,2,3],[2,3,4])
a = datetime.datetime.now()
for i in range(N):
fig.show()
b = datetime.datetime.now()
print("fig.show: ", b-a)
a = datetime.datetime.now()
for i in range(N):
fig.canvas.draw_idle()
b = datetime.datetime.now()
print("fig.canvas.draw_idle: ", b-a)
a = datetime.datetime.now()
for i in range(N):
fig.canvas.draw()
b = datetime.datetime.now()
print("fig.canvas.draw: ", b-a)
for i in range(N):
fig.canvas.draw_idle()
fig.canvas.flush_events()
b = datetime.datetime.now()
print("draw_idle, flush_events:", b-a)
# fig.show: 0:00:00.280800
# fig.canvas.draw_idle: 0:00:00.015600
# fig.canvas.draw: 0:03:43.450512
# draw_idle, flush_events: 0:08:29.103440
Based on these timings, you can see why the documentation recommends using fig.canvas.draw_idle() over fig.canvas.draw() in most cases.
I have plotted a histogram and would like to modify it, then re-plot it. It won't plot again without redefining the Figure and Axes object definitions. I'm using Jupyter Notebook, and I'm new to matplotlib, so I don't know if this is something that I'm not understanding about matplotlib, if it's an issue with the Jupyter Notebook or something else.
Here's my 1st block of code:
"""Here's some data."""
some_data = np.random.randn(150)
"""Here I define my `Figure` and `Axes` objects."""
fig, ax = plt.subplots()
"""Then I make a histogram from them, and it shows up just fine."""
ax.hist(some_data, range=(0, 5))
plt.show()
Here's the output from my 1st block of code:
Here's my 2nd block of code:
"""Here I modify the parameter `bins`."""
ax.hist(some_data, bins=20, range=(0, 5))
"""When I try to make a new histogram, it doesn't work."""
plt.show()
My 2nd block of code generates no visible output, which is the problem.
Here's my 3rd and final block of code:
"""But it does work if I define new `Figure` and `Axes` objects.
Why is this?
How can I display new, modified plots without defining new `Figure` and/or `Axes` objects? """
new_fig, new_ax = plt.subplots()
new_ax.hist(some_data, bins=20, range=(0, 5))
plt.show()
Here's the output from my 3rd and final block of code:
Thanks in advance.
When you generate a figure or an axis, it remains accessible for rendering or display until it's used for rendering or display. Once you execute plt.show() in your first block, the ax becomes unavailable. Your 3rd block of code is showing a plot because you're regenerating the figure and axes.
I'm looking for a way to add an "on click" event to an annotation in matplotlib.pyplot to destroy it. The relevant code:
import matplotlib.pyplot as plt
plt.ion()
plt.plot()
plt.annotate("Kill me",xy=(0,0))
Now we need to find the annotation, one way is to iterate over:
plt.gca().texts
Though there may be a better way. So far I have not found how to obtain the widget/add an event with this. This may be possible using mpl_connect of the plt figure canvas but I'm not sure, and that would require going by the bounding box, which I would like to avoid, but if no other is solution is available is fine.
You can indeed use mpl_connect to connect a picker event to an object in the canvas. In this case the call to annotate can be given a picker argument, which specifies the radius around the object that should trigger the event.
You can then directly operate on the object that triggered the event, which is available in the event slot as event.artist.
import matplotlib.pyplot as plt
fig = plt.figure()
ax=fig.add_subplot(111)
plt.plot([0,5],[0,6], alpha=0)
plt.xlim([-1,6])
plt.ylim([-1,6])
for i in range(6):
for j in range(6):
an = plt.annotate("Kill me",xy=(j,i), picker=5)
def onclick(event):
event.artist.set_text("I'm killed")
event.artist.set_color("g")
event.artist.set_rotation(20)
# really kill the text (but too boring for this example;-) )
#event.artist.set_visible(False)
# or really REALLY kill it with:
#event.artist.remove()
fig.canvas.draw()
cid = fig.canvas.mpl_connect('pick_event', onclick)
plt.show()
I need to create a figure in a file without displaying it within IPython notebook. I am not clear on the interaction between IPython and matplotlib.pylab in this regard. But, when I call pylab.savefig("test.png") the current figure get's displayed in addition to being saved in test.png. When automating the creation of a large set of plot files, this is often undesirable. Or in the situation that an intermediate file for external processing by another app is desired.
Not sure if this is a matplotlib or IPython notebook question.
This is a matplotlib question, and you can get around this by using a backend that doesn't display to the user, e.g. 'Agg':
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('/tmp/test.png')
EDIT: If you don't want to lose the ability to display plots, turn off Interactive Mode, and only call plt.show() when you are ready to display the plots:
import matplotlib.pyplot as plt
# Turn interactive plotting off
plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('/tmp/test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
plt.figure()
plt.plot([1,3,2])
plt.savefig('/tmp/test1.png')
# Display all "open" (non-closed) figures
plt.show()
We don't need to plt.ioff() or plt.show() (if we use %matplotlib inline). You can test above code without plt.ioff(). plt.close() has the essential role. Try this one:
%matplotlib inline
import pylab as plt
# It doesn't matter you add line below. You can even replace it by 'plt.ion()', but you will see no changes.
## plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
fig2 = plt.figure()
plt.plot([1,3,2])
plt.savefig('test1.png')
If you run this code in iPython, it will display a second plot, and if you add plt.close(fig2) to the end of it, you will see nothing.
In conclusion, if you close figure by plt.close(fig), it won't be displayed.