When is matplotlib's pyplot.figure redundant? - python

From my understanding of matplotlib, the figure method creates a new, blank figure, basically a "white canvas," and via, for example, plot I can add the actual plot. The show method then clears the figure:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0, 1], [0, 1])
plt.show()
1) Now, I am wondering why the same can be achieved when no figure was created. More specifically, I am wondering how matplotlib handles this internally.
2) Is there any advantage in using plt.figure if I don't intend to manipulate figure objects?
import matplotlib.pyplot as plt
plt.plot([0, 1], [0, 1])
plt.show()

plt.plot internally calls gca (get current axes) which then calls gcf (get current figure), which returns the current (last used) figure. If there is no current figure it calls plt.figure and returns the newly created figure. So yes, weather or not you call plt.figure yourself doesn't really matter. I wouldn't say it is redundant (since it has to be done), but you can safely let matplotlib take care of it.
Directly calling plt.figure if you don't intend to manipulate the figure or pass arguments to the constructor is only useful to create multiple figures to show them simultaneously when calling plt.show.
plt.figure()
plt.plot(1,1,'x')
plt.figure()
plt.plot(2,2,'o')
plt.show()

Related

Understanding of fig, ax, and plt when combining Matplotlib and Pandas

I'm trying to get a better understanding of how figure, axes, and plt all fit together when combining Matplotlib and Pandas for plotting. The accepted answer here helped me connect Matplotlib and Pandas in an object oriented way I understand through this line:
fig, ax = plt.suplots()
df.plot(ax=ax)
But as I'm diving deeper the answer here threw me off. Specifically, I still have methods I need to call directly off plt, that don't apply to either a figure or an axis. Example:
fig, ax = plt.subplots()
df[['realgdp','trend']]["2000-03-31":].plot(figsize=(8,8), ax=ax)
ax.set_title('Real GDP & Trend')
ax.set_ylabel('Readl GDP')
plt.xticks(rotation=45)
If I try to call xticks(rotation=45) off ax or fig I get an error that neither ax nor fig have an xticks method. The solution I have above works, but I don't understand why.
When I type plt.xticks(rotations=45), where does that information get sent? Why does the comment in the answer here that "when you use the functions available on the module pyplot you are plotting to the 'current figure' and 'current axes'" not apply in this case? Why do I need to call off plt directly?
plt.xticks() only works on the "current" ax. You should use ax.set_xticks(), ax.set_xticklabels() and ax.tick_params() instead.
plt.xticks() is a rather old function that is still supported, mimicking similar matlab code, born in a time when people were only plotting onto a single plot. The newer functions are more general with more options.
In short: you don't need to call plt directly, you are invited to use the ax functions instead. When calling plt.xticks(), it gets rerouted to the currently active ax (often the last one created).

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)

How to suppress seaborn output when recalling figure object with regplot

I am trying to plot data to a figure and respective axis in matplotlib and as new work comes up, recall the figure with the additional plot on the axis:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
x=np.arange(0,20)
y=2*x
fig,ax=plt.subplots()
ax.scatter(x,x)
ax.scatter(x,y)
fig
Which works fine with matplotlib, if I however use seaborn's regplot:
fig2,ax2=plt.subplots()
sns.regplot(x,x,ax=ax2,fit_reg=False)
sns.regplot(x,y,ax=ax2,fit_reg=False)
fig2
fig2 generates the figure that I want but the regplot command generates an empty figure. Is there a way to suppress the regplot's empty output or have it display the updated ax2 without recalling fig2?
It seems you are using the jupyter notebook with the inline backend. In some circumstances regplot triggers the creation of a new figure even if the artists are being added to the previous one and this messes up the output. I don't know why this happens but I found a workaround that might help you, using plt.ioff to temporarily disable automatic display of figures.
plt.ioff()
fig, ax = plt.subplots()
sns.regplot(x, x, ax=ax)
fig
sns.regplot(x, 2 * x, ax=ax)
fig
You have to call plt.ioff before creating the figure for this to work. After that you have to explicitly display the figure. Then you can call plt.ion to restore the default behaviour.
regplot does not generate an empty figure. According to the documentation:
Understanding the difference between regplot() and lmplot() can be a
bit tricky. In fact, they are closely related, as lmplot() uses
regplot() internally and takes most of its parameters. However,
regplot() is an axes-level function, so it draws directly onto an axes
(either the currently active axes or the one provided by the ax
parameter), while lmplot() is a figure-level function and creates its
own figure, which is managed through a FacetGrid.
When I do the following:
fig2,ax2 = plt.subplots()
same_fig2 = sns.regplot(x,x,ax=ax2,fit_reg=False)
same_fig2.figure is fig2
>>> True

Why do pyplot methods apply instantly and subplot axes methods do not?

I'm editing my graphs step by step. Doing so, plt functions from matplotlib.pyplot apply instantly to my graphical output of pylab. That's great.
If I address axes of a subplot, it does not happen anymore.
Please find both alternatives in my minimal working example.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
f = plt.figure()
sp1 = f.add_subplot(1,1,1)
f.show()
# This works well
sp1.set_xlim([1,5])
# Now I plot the graph
df = pd.Series([0,5,9,10,15])
df.hist(bins=50, color="red", alpha=0.5, normed=True, ax=sp1)
# ... and try to change the ticks of the x-axis
sp1.set_xticks(np.arange(1, 15, 1))
# Unfortunately, it does not result in an instant change
# because my plot has already been drawn.
# If I wanted to use the code above,
# I would have to execute him before drawing the graph.
# Therefore, I have to use this function:
plt.xticks(np.arange(1, 15, 1))
I understand that there is a difference between matplotlib.pyplot and an axis instance. Did I miss anything or does it just work this way?
Most of pyplot functions (if not all) have a call to plt.draw_if_interactive() before returning. So if you do
plt.ion()
plt.plot([1,2,3])
plt.xlim([-1,4])
you obtain that the plot is updated as you go. If you have interactive off, it won't create or update the plot until you don't call plt.show().
But all pyplot functions are wrappers around corresponding (usually) Axes methods.
If you want to use the OO interface, and still draw stuff as you type, you can do something like this
plt.ion() # if you don't have this, you probably don't get anything until you don't call a blocking `plt.show`
fig, ax = plt.subplots() # create an empty plot
ax.plot([1,2,3]) # create the line
plt.draw() # draw it (you can also use `draw_if_interactive`)
ax.set_xlim([-1,4]) #set the limits
plt.draw() # updata the plot
You don't have to use the pyplot you don't want, just remember to draw
The plt.xticks() method calls a function draw_if_interactive() that comes from pylab_setup(), who is updating the graph. In order to do it using sp1.set_xticks(), just call the corresponding show() method:
sp1.figure.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