Matplotlib animation with blit -- how to update plot title? - python

I use matplotlib to animate a plot, by copying the background and blitting:
f = Figure(tight_layout=True)
canvas = FigureCanvasTkAgg(f, master=pframe)
canvas.get_tk_widget().pack()
ax = f.add_subplot(111)
# Set inial plot title
title = ax.set_title("First title")
canvas.show()
# Capture the background of the figure
background = canvas.copy_from_bbox(ax.bbox)
line, = ax.plot(x, y)
canvas._tkcanvas.pack()
Periodically I update the plot:
# How to update the title here?
line.set_ydata(new_data)
ax.draw_artist(line)
canvas.blit(ax.bbox)
How could I update -- as efficiently as possible, the plot title every time I update the plot?
Edit:
title.set_text("New title")
ax.draw_artist(title)
either before or after
canvas.blit(ax.bbox)
does not update the title. I think somehow I should redraw the title artist, or I should only capture the graph, as blit(ax.bbox) overwrites the entire title plot area including the title.

Swooping in years later to say that I too was stuck on this problem for the last few days, and disabling blit wasn't an option for me (as the fps would become way too slow). For matplotlib 3.1.3 at least, if you send a resize event to the canvas, it properly flushes the background and regenerates it with any updates. So you can work around this by detecting when you need to update the title, and then calling fig.canvas.resize_event() to force a flush. Hope this helps future people!

The following draws the plot and allows you to make changes,
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(1,1)
ax.plot(np.linspace(0.,10.,100))
title = ax.set_title("First title")
plt.show(block=False)
The title can then be updated using,
title.set_text("Second title")
plt.draw()

Related

plt.show() does nothing when used for the second time

I am just starting to learn data science using python on Data Camp and I noticed something while using the functions in matplotlib.pyplot
import matplotlib.pyplot as plt
year = [1500, 1600, 1700, 1800, 1900, 2000]
pop = [458, 580, 682, 1000, 1650, 6,127]
plt.plot(year, pop)
plt.show() # Here a window opens up and shows the figure for the first time
but when I try to show it again it doesn't..
plt.show() # for the second time.. nothing happens
And I have to retype the line above the show() to be able to show a figure again
Is this the normal thing or a problem?
Note: I am using the REPL
Answer
Yes, this is normal expected behavior for matplotlib figures.
Explanation
When you run plt.plot(...) you create on the one hand the lines instance of the actual plot:
>>> print( plt.plot(year, pop) )
[<matplotlib.lines.Line2D object at 0x000000000D8FDB00>]
...and on the other hand a Figure instance, which is set as the 'current figure' and accessible through plt.gcf() (short for "get current figure"):
>>> print( plt.gcf() )
Figure(432x288)
The lines (as well as other plot elements you might add) are all placed in the current figure. When plt.show() is called, the current figure is displayed and then emptied (!), which is why a second call of plt.show() doesn't plot anything.
Standard Workaround
One way of solving this is to explicitly keep hold of the current Figure instance and then show it directly with fig.show(), like this:
plt.plot(year, pop)
fig = plt.gcf() # Grabs the current figure
plt.show() # Shows plot
plt.show() # Does nothing
fig.show() # Shows plot again
fig.show() # Shows plot again...
A more commonly used alternative is to initialize the current figure explicitly in the beginning, prior to any plotting commands.
fig = plt.figure() # Initializes current figure
plt.plot(year, pop) # Adds to current figure
plt.show() # Shows plot
fig.show() # Shows plot again
This is often combined with the specification of some additional parameters for the figure, for example:
fig = plt.figure(figsize=(8,8))
For Jupyter Notebook Users
The fig.show() approach may not work in the context of Jupyter Notebooks and may instead produce the following warning and not show the plot:
C:\redacted\path\lib\site-packages\matplotlib\figure.py:459:
UserWarning: matplotlib is currently using a non-GUI backend, so
cannot show the figure
Fortunately, simply writing fig at the end of a code cell (instead of fig.show()) will push the figure to the cell's output and display it anyway. If you need to display it multiple times from within the same code cell, you can achieve the same effect using the display function:
fig = plt.figure() # Initializes current figure
plt.plot(year, pop) # Adds to current figure
plt.show() # Shows plot
plt.show() # Does nothing
from IPython.display import display
display(fig) # Shows plot again
display(fig) # Shows plot again...
Making Use of Functions
One reason for wanting to show a figure multiple times is to make a variety of different modifications each time. This can be done using the fig approach discussed above but for more extensive plot definitions it is often easier to simply wrap the base figure in a function and call it repeatedly.
Example:
def my_plot(year, pop):
plt.plot(year, pop)
plt.xlabel("year")
plt.ylabel("population")
my_plot(year, pop)
plt.show() # Shows plot
my_plot(year, pop)
plt.show() # Shows plot again
my_plot(year, pop)
plt.title("demographics plot")
plt.show() # Shows plot again, this time with title
Using command:
%matplotlib
in ipython3 help me to use separate window with plot
Start ipython3 and issue the commands:
import matplotlib.pyplot as plt
%matplotlib #plot in separate window
fig, ax = plt.subplots() #Appear empty Tcl window for image
ax.plot([1, 2, 3, 4], [5, 6, 7, 8]) #Appear graph in window
In some version of matplotlib, fig.show() does not block the window for showing plot multiple times. so, Quick fixes using self.fig.waitforbuttonpress() it waits user to press the button for next plot visualisation.
self.fig.show()
plt.pause(0.1)
self.fig.waitforbuttonpress()

assigning name to matplotlib subplot figure that can be used to make figure current

My question is very similar to the one asked here, but I'd like to be able to make the named figure current again, which the solution to the other question didn't address. Here's an attempt:
import matplotlib.pyplot as plt
plt.ion()
f, ax = plt.subplots()
f.canvas.set_window_title('My Window Title')
# make another figure, which will become current
plt.figure()
# attempts to make previous figure current, but instead creates third figure
plt.figure('My Window Title')
Is there a way to assign a name to a figure that's created using subplots() that can be referred to later?
If you want to keep using plt.subplots(), you can give the figure its name using keyword arguments. Any kwargs not used by subplots are passed on to plt.figure, so in this case we want to set the num option (that's what you are setting to 'My Window Title' in your example:
f, ax = plt.subplots(num='My Window Title')
I've figured it out. The answer is to separate out the f,ax=plt.subplots() line and use the add_subplot command:
import matplotlib.pyplot as plt
plt.ion()
f = plt.figure('My Window Title')
ax = f.add_subplot(1,2,1)
# ...
# make another figure, which will become current
plt.figure()
# make previous figure current
plt.figure('My Window Title')

Extend python plots to full screen

I want to extent the python plots I am plotting using mpld3 to full screen. I wish to use mpld3 due to the following reasons
I wish to have around 4 plots and have the zoom option for each plot.
All plots must be displayed in the same window.
Here, I tried using tight_layout option to extend the plots to occupy full screen but it does not work as shown in the link at the end.I guess tight_layout does not work with mpld3. Is there any other way to make it stretch to full screen?
Also,how do I add text to the screen where am plotting? Like the 4 plots occupying 90% of the screen from top to bottom and the text occupying remaining 10% at the bottom?
import matplotlib.pyplot as plt
import mpld3
x = [1,2,3]
y = [1,4,9]
fig = plt.figure()
ax = fig.add_subplot(411)
ax.plot(x,y)
ax = fig.add_subplot(412)
ax.plot(x,y)
ax = fig.add_subplot(413)
ax.plot(x,y)
ax = fig.add_subplot(414)
ax.plot(x,y)
fig.tight_layout()
mpld3.show()
Check this link for output of the code http://i.stack.imgur.com/4mBRI.png
I think the size is defined by matplotlib, this means that adjusting this would result in a fullscreen plot.
From this topic: How to maximize a plt.show() window using Python
mng = plt.get_current_fig_manager()
mng.frame.Maximize(True)
Something like this might work.
fig.set_size_inches(x_val,y_val)
helped me resize the plot to fit the screen
Use window.state option to get a zoomed version:
plt.get_current_fig_manager().window.state('zoomed')

Change resolution of Matplotlib Figure window when saving plot?

I'm using Windows XP v3/Python 2.7 with Canopy and Anaconda package managers/editors.
I am using Python/Matplotlib to produce some Bland-Altman plots (statistical scatter plots) for publication.
After processing the data, the plt.show() command opens a new "Figure" window containing the plot, which looks fine.
I want to be able to use the dynamic pan and zoom commands in this window to interactively optimise the appearance of my plot, then save it as it appears in the window as a high resolution press-quality png image (400-600 dpi, 7 x 5 inches).
The default setting for saving images from the "Figure" window appears to be set to screen resolution (800 x 600 pixels), and I cannot find any options in this window which allow me to change these settings.
I've read other posts on this forum which explain how to directly save a plot from Python in higher resolution by using the following commands to manipulate dpi and image size, e.g.:
plt.figure(figsize=(18, 12), dpi=400)
plt.savefig("myplot.png", dpi = 400)
However, this is not the solution that I'm looking for; as I want to be able to modify the plot using the dynamic pan and zoom features of the "Figure" window before saving in a higher resolution than the default screen resolution.
I'd be grateful for your help.
Many thanks in anticipation & Happy New Year.
Dave
(UK)
Try this:
Determine how to set width and height using a pixels-to-inches converter, like in the following matplotlib documentation. Then try:
import matplotlib.pyplot as plt
fig = plt.figure(frameon=False)
fig.set_size_inches(width,height)
I had this issue in spyder and found changing the value in Preferences > iPython Console > Inline Backend > Resolution changes the resolution when I save figures from the built in window viewing application.
One may register an event upon a key press that would save the figure with some previously given size and dpi. The following uses a class that stores some figsize and dpi and upon pressing t wll change the figure size and dpi of the figure. It will then save this figure and restore the old size and dpi such that the figure on screen remains unchanged.
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
fig,ax=plt.subplots()
ax.plot([1,3,1])
class AnySizeSaver():
def __init__(self, fig=None, figsize=None, dpi=None, filename=None):
if not fig: fig=plt.gcf()
self.fig = fig
if not figsize: figsize=self.fig.get_size_inches()
self.figsize=figsize
if not dpi: dpi=self.fig.dpi
self.dpi=dpi
if not filename: filename="myplot.png"
self.filename=filename
self.cid = self.fig.canvas.mpl_connect("key_press_event", self.key_press)
def key_press(self, event):
if event.key == "t":
self.save()
def save(self):
oldfigsize = self.fig.get_size_inches()
olddpi=self.fig.dpi
self.fig.set_size_inches(self.figsize)
self.fig.set_dpi(self.dpi)
self.fig.savefig(self.filename, dpi=self.dpi)
self.fig.set_size_inches(oldfigsize, forward=True)
self.fig.set_dpi(olddpi)
self.fig.canvas.draw_idle()
print(fig.get_size_inches())
ass = AnySizeSaver(fig=fig, figsize=(3,3), dpi=600)
plt.show()

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