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

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()

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)

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

How modules know each other

I can plot data from a CSV file with the following code:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('test0.csv',delimiter='; ', engine='python')
df.plot(x='Column1', y='Column3')
plt.show()
But I don't understand one thing. How plt.show() knows about df? I'll make more sense to me seeing, somewhere, an expression like:
plt = something(df)
I have to mention I'm just learning Python.
Matplotlib has two "interfaces": a Matlab-style interface and an object-oriented interface.
Plotting with the Matlab-style interface looks like this:
import matplotlib.pyplot as plt
plt.plot(x, y)
plt.show()
The call to plt.plot implicitly creates a figure and an axes on which to draw.
The call to plt.show displays all figures.
Pandas is supporting the Matlab-style interface by implicitly creating a figure and axes for you when df.plot(x='Column1', y='Column3') is called.
Pandas can also use the more flexible object-oriented interface, in which case
your code would look like this:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('test0.csv',delimiter='; ', engine='python')
fig, ax = plt.subplots()
df.plot(ax=ax, x='Column1', y='Column3')
plt.show()
Here the axes, ax, is explicitly created and passed to df.plot, which then
calls ax.plot under the hood.
One case where the object-oriented interface is useful is when you wish to use
df.plot more than once while still drawing on the same axes:
fig, ax = plt.subplots()
df.plot(ax=ax, x='Column1', y='Column3')
df2.plot(ax=ax, x='Column2', y='Column4')
plt.show()
From the pandas docs on plotting:
The plot method on Series and DataFrame is just a simple wrapper
around :meth:plt.plot() <matplotlib.axes.Axes.plot>
So as is, the df.plot method is an highlevel call to plt.plot (using a wrapper), and thereafter, calling plt.show will simply:
display all figures and block until the figures have been closed
as it would with for all figures plotted with plt.plot.
Therefore, you don't see plt = something(df) as you would expect, because matpotlib.pyplot.plot is being called behind the scene by df.plot.
According to http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.show , the plt.show() itself doesn't know about the data, you need to pass the data as parameters.
What you are seeing should be the plot of pandas library, according to the usage http://pandas.pydata.org/pandas-docs/stable/visualization.html#basic-plotting-plot.
Hope this solves your question.

Turn axes off for all subplots of a figure

I am creating a large array of subplots and I want to turn off axes for all the subplots.
Currently I am achieving this by
fig, ax = plt.subplots(7, len(clusters))
fig.subplots_adjust(wspace=0, top=1.0, bottom=0.5, left=0, right=1.0)
for x in ax.ravel():
x.axis("off")
but looping over the subplots to turn of the axes individually is ugly.
Is there a way to tell subplots to turn od axes at creation time
or some setting on Figure or pyplot that turns axes off globally.
pyplot.axis('off') turns off axes just on the last subplot.
I agree with #tcaswell that you should probably just use what you're already using. Another option to use it as a function is to use numpy.vectorize():
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(7, len(clusters))
np.vectorize(lambda ax:ax.axis('off'))(ax)
or, if you need to invoke it multiple times, by assigning the vectorized function to a variable:
axoff_fun = np.vectorize(lambda ax:ax.axis('off'))
# ... stuff here ...
fig, ax = plt.subplots(7, len(clusters))
axoff_fun(ax)
Again, note that this is the same thing that #tcaswell suggested, in a fancier setting (only slower, probably). And it's essentially the same thing you're using now.
However, if you insist on doing it some other way (i.e. you are a special kind of lazy), you can set matplotlib.rcParams once, and then every subsequent axes will automatically be off. There's probably an easier way to emulate axis('off'), but here's how I've succeeded:
import matplotlib as mpl
# before
mpl.pyplot.figure()
mpl.pyplot.plot([1,3,5],[4,6,5])
# kill axis in rcParams
mpl.rc('axes.spines',top=False,bottom=False,left=False,right=False);
mpl.rc('axes',facecolor=(1,1,1,0),edgecolor=(1,1,1,0));
mpl.rc(('xtick','ytick'),color=(1,1,1,0));
# after
mpl.pyplot.figure()
mpl.pyplot.plot([1,3,5],[4,6,5])
Result before/after:
Hopefully there aren't any surprises which I forgot to override, but that would become clear quite quickly in an actual application anyway.

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