Turn axes off for all subplots of a figure - python

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.

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

How to apply an option to several figures at the same time

If I do this
import numpy as np
import matplotlib.pyplot as plt
a=[1,2,3]
b=[3,4,5]
plt.figure(1)
plt.xlim(0,3)
plt.plot(b)
plt.figure(2)
plt.plot(a)
plt.show()
the choice of the x axes will be applied only to figure 1. What can I use to discriminate between the options that I want to be valid for only figure 1 or 2 and the ones that I want to be applied to both figures?
Clarification: I know that it is possible to call plt.xlim several times. I was rather looking for some command of a form like
plt.apply_options_to(1,2)
and from that moment on every time I call plt.xlim the option is applied to both figures and not only one of the two.
With pyplot, each command applies to the currently active figure or axes. This means you can easily loop over the figures and apply each command like
for i in (1,2):
plt.figure(i)
plt.xlim(0,3)
Now those are three lines of code. If the requirement is to use a single line of code, the following would be a solution
[plt.setp(plt.figure(i).axes[0], xlim=(0,3)) for i in plt.get_fignums() if i in (1,2)]
This is neither elegant nor easy to type, so when using pyplot I would recommend the first solution.
In general however I would recommend using the object oriented approach, where creating two figures would look like:
import matplotlib.pyplot as plt
a=[1,2,3]
b=[3,4,5]
fig, ax = plt.subplots()
ax.plot(b)
fig2, ax2 = plt.subplots()
ax2.plot(a)
plt.show()
Then the single line solution is also a bit more compact
plt.setp([ax,ax2], xlim=(0,3))

how to make easy and efficient plots on Python

I use matplotlib for my plots, I find it great, but sometimes too much complicated. Here an example:
import matplotlib.pyplot as plt
import numpy as np
idx1 = -3
idx2 = 3
x = np.arange(-3, 3, 0.01)
y = np.sin(np.pi*x*7)/(np.pi*x*7)
major_ticks = np.arange(idx1, idx2, 1)
minor_ticks = np.arange(idx1, idx2, 0.1)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_ylim(-0.3, 1.2)
ax.set_xlim(idx1, idx2)
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor = True)
ax.grid(True, which = 'both')
ax.tick_params(axis = 'x', labelsize = 18)
ax.tick_params(axis = 'y', labelsize = 18)
ax.plot(x, y)
plt.show()
Is there anything implemented on matplotlib and/or seaborn in which I can provide all these plot settings just as argument of a function only? It may considerably reduce the number of code lines and make the script easier both to write and understand.
Matplotlib provides an object oriented API. This means that all the elements of the figure are acutally objects for which one can get and set properties and which can be easily manipulated. This makes matplotlib really flexible such that it can produce almost any plot you'd imagine.
Since a plot may consist of a hundred or more elements, a function that would allow the same flexibility would need that amount of possible arguments. It is not necessarily easier to remember all possible arguments of a function than all possible attributes of a class.
Having a single function call that does all of this, does not necessarily mean that you have to type in less characters. The commands would just be ordered differently.
Furthermore the object oriented approach allows to keep things seperate. Some properties of the axes, like the grid or the axis labels are completely independend on what you plot to the axes. So you wouldn't want to set the xticks in the call to plot, because they are simply not related and it may be very confusing to set twice the same ticklabels when plotting two lines in the same axes.
On the other hand, matplotlib is really easy. In order to produce a plot you need two lines
import matplotlib.pyplot as plt
plt.plot([1,2,3],[2,1,3])
which sets most of the parameters exactly as they are needed. The more you want to customize this plot, the more settings you have to apply. Which is fine as it allows the user himself to determine how much in depth he wants to control the appearance of the plot.
Most matplotlib codes can be separated into three parts.
Setting the style
Creating the plot
Customizing the plot
Setting the style in the case of the code from the question involves e.g. the ticklabel size and the use of a grid. Those properties can set as it's done in the code but it may indeed be that one always wants to use the same properities here and finds it annoying to type the same parameters in every time one creates a plot. Therefore matplotlib provides general style settings, called rcParams. They can be set at the beginning of a script, e.g.
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['axes.grid '] = True
plt.rcParams['axes.labelsize'] = 18
and will be applied to all plots within the script. It is also possible to define a complete stylesheet using those parameters. For more information see the Customizing matplotlib article.
It is equally possible to use predefined stylesheets for certain applications.
Simply importing import seaborn is also a possible way to change the style.
Creating the plot can not be simplified much more. It's clear that one needs as many plotting commands as items to plot. Creating the figure and axes like
fig, ax = plt.subplots()
saves one line though.
Equally no simplification is possible if customizing ticks or tickmarks are required. One may however consider to use Tickers and Formatters for this purpose.
At the end one may of course consider to write a custom function which performs much of those tasks, but everyone can decide if that is useful for himself.
Browsing around I saw this wabe page.
This line of code can summarise many settings
import matplotlib as mpl
mpl.rc('lines', linewidth=2, color='r')
ax.set is very useful for this:
ax.set(xlim=(idx1, idx2), ylim=(-0.3, 1.2),
xticks=major_ticks, ...)
You can only set simple single-argument properties (e.g. those which don't need further keywords), but it's a nice timesaver.

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