Python figure and axes object - python

I have a big unresolved question about the matplotlib Python module.
If I create a figure called [Figure1], with 2 axes [Ax1, Ax2], and another figure [Figure2], is there a function or method that will allow me to export the Ax1 object from Figure1 and redraw it to the Figure2 object?

In general axes are bound to a figure. The reason is, that matplotlib usually performs some operations in the background to make them look nice in the figure.
There are some hacky ways around this, also this one, but the general consensus seems to be that one should avoid trying to copy axes.
On the other hand this need not be a problem or a restriction at all.
You can always define a function which does the plotting and use this on several figures like so:
import matplotlib.pyplot as plt
def plot1(ax, **kwargs):
x = range(5)
y = [5,4,5,1,2]
ax.plot(x,y, c=kwargs.get("c", "r"))
ax.set_xlim((0,5))
ax.set_title(kwargs.get("title", "Some title"))
# do some more specific stuff with your axes
#create a figure
fig, (ax1, ax2) = plt.subplots(1,2)
# add the same plot to it twice
plot1(ax1)
plot1(ax2, c="b", title="Some other title")
plt.savefig(__file__+".png")
plt.close("all")
# add the same plot to a different figure
fig, ax1 = plt.subplots(1,1)
plot1(ax1)
plt.show()

Related

set xlim across multiple figures in python? [duplicate]

I'm trying to share two subplots axes, but I need to share the x axis after the figure was created. E.g. I create this figure:
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig = plt.figure()
ax1 = plt.subplot(211)
plt.plot(t,x)
ax2 = plt.subplot(212)
plt.plot(t,y)
# some code to share both x axes
plt.show()
Instead of the comment I want to insert some code to share both x axes.
How do I do this? There are some relevant sounding attributes
_shared_x_axes and _shared_x_axes when I check to figure axis (fig.get_axes()) but I don't know how to link them.
The usual way to share axes is to create the shared properties at creation. Either
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1)
or
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
Sharing the axes after they have been created should therefore not be necessary.
However if for any reason, you need to share axes after they have been created (actually, using a different library which creates some subplots, like here might be a reason), there would still be a solution:
Using
ax1.get_shared_x_axes().join(ax1, ax2)
creates a link between the two axes, ax1 and ax2. In contrast to the sharing at creation time, you will have to set the xticklabels off manually for one of the axes (in case that is wanted).
A complete example:
import numpy as np
import matplotlib.pyplot as plt
t= np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212)
ax1.plot(t,x)
ax2.plot(t,y)
ax1.get_shared_x_axes().join(ax1, ax2)
ax1.set_xticklabels([])
# ax2.autoscale() ## call autoscale if needed
plt.show()
The other answer has code for dealing with a list of axes:
axes[0].get_shared_x_axes().join(axes[0], *axes[1:])
As of Matplotlib v3.3 there now exist Axes.sharex, Axes.sharey methods:
ax1.sharex(ax2)
ax1.sharey(ax3)
Just to add to ImportanceOfBeingErnest's answer above:
If you have an entire list of axes objects, you can pass them all at once and have their axes shared by unpacking the list like so:
ax_list = [ax1, ax2, ... axn] #< your axes objects
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list)
The above will link all of them together. Of course, you can get creative and sub-set your list to link only some of them.
Note:
In order to have all axes linked together, you do have to include the first element of the axes_list in the call, despite the fact that you are invoking .get_shared_x_axes() on the first element to start with!
So doing this, which would certainly appear logical:
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list[1:])
... will result in linking all axes objects together except the first one, which will remain entirely independent from the others.

Matplotlibs' affine transform rotation returns a blank cell in a grid figure unless it is the last cell [duplicate]

I have searched on google but didn't get an answer. I created a subplot consisting of 2 axes and called plt.gca() but every time it only referred to the last axis in the axes of my subplots. I then started to wonder if it is possible to get a particular axis by passing in some kwargs but didn't find such parameter. I would really like to know how plt.gca() works and why you can't specify which axis to get.
gca means "get current axes".
"Current" here means that it provides a handle to the last active axes. If there is no axes yet, an axes will be created. If you create two subplots, the subplot that is created last is the current one.
There is no such thing as gca(something), because that would translate into "get current axes which is not the current one" - sound unlogical already, doesn't it?
The easiest way to make sure you have a handle to any axes in the plot is to create that handle yourself. E.g.
ax = plt.subplot(121)
ax2 = plt.subplot(122)
You may then use ax or ax2 at any point after that to manipulate the axes of choice.
Also consider using the subplots (note the s) command,
fig, (ax, ax2) = plt.subplots(ncols=2)
If you don't have a handle or forgot to create one, you may get one e.g. via
all_axes = plt.gcf().get_axes()
ax = all_axes[0]
to get the first axes. Since there is no natural order of axes in a plot, this should only be used if no other option is available.
As a supplement to Importance's very fine answer, I thought I would point out the pyplot command sca, which stands for "set current axes".
It takes an axes as an argument and sets it as the current axes, so you still need references to your axes. But the thing about sca that some may find useul is that you can have multiple axes and work on all of them while still using the pyplot interface rather than the object-oriented approach.
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.subplot(121)
ax2 = plt.subplot(122)
# Check if ax2 is current axes
print(ax2 is plt.gca())
# >>> True
# Plot on ax2
plt.plot([0,1],[0,1])
plt.xlabel('X')
plt.ylabel('Y')
# Now set ax as current axes
plt.sca(ax)
print(ax2 is plt.gca())
# >>> False
print(ax is plt.gca())
# >>> True
# We can call the exact same commands as we did for ax2, but draw on ax
plt.plot([0,1],[0,1])
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
So you'll notice that we were able to reuse the same code to plot and add labels to both axes.

Adjusting the x-axis label for multiple subplots [duplicate]

I'm trying to share two subplots axes, but I need to share the x axis after the figure was created. E.g. I create this figure:
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig = plt.figure()
ax1 = plt.subplot(211)
plt.plot(t,x)
ax2 = plt.subplot(212)
plt.plot(t,y)
# some code to share both x axes
plt.show()
Instead of the comment I want to insert some code to share both x axes.
How do I do this? There are some relevant sounding attributes
_shared_x_axes and _shared_x_axes when I check to figure axis (fig.get_axes()) but I don't know how to link them.
The usual way to share axes is to create the shared properties at creation. Either
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1)
or
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
Sharing the axes after they have been created should therefore not be necessary.
However if for any reason, you need to share axes after they have been created (actually, using a different library which creates some subplots, like here might be a reason), there would still be a solution:
Using
ax1.get_shared_x_axes().join(ax1, ax2)
creates a link between the two axes, ax1 and ax2. In contrast to the sharing at creation time, you will have to set the xticklabels off manually for one of the axes (in case that is wanted).
A complete example:
import numpy as np
import matplotlib.pyplot as plt
t= np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212)
ax1.plot(t,x)
ax2.plot(t,y)
ax1.get_shared_x_axes().join(ax1, ax2)
ax1.set_xticklabels([])
# ax2.autoscale() ## call autoscale if needed
plt.show()
The other answer has code for dealing with a list of axes:
axes[0].get_shared_x_axes().join(axes[0], *axes[1:])
As of Matplotlib v3.3 there now exist Axes.sharex, Axes.sharey methods:
ax1.sharex(ax2)
ax1.sharey(ax3)
Just to add to ImportanceOfBeingErnest's answer above:
If you have an entire list of axes objects, you can pass them all at once and have their axes shared by unpacking the list like so:
ax_list = [ax1, ax2, ... axn] #< your axes objects
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list)
The above will link all of them together. Of course, you can get creative and sub-set your list to link only some of them.
Note:
In order to have all axes linked together, you do have to include the first element of the axes_list in the call, despite the fact that you are invoking .get_shared_x_axes() on the first element to start with!
So doing this, which would certainly appear logical:
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list[1:])
... will result in linking all axes objects together except the first one, which will remain entirely independent from the others.

about .show() of matplotlib

I am working with matplotlib to generate some graphs but I do not know the difference between these two ways of showing an image. I already read some documentation about it but I do not understand yet.
First way:
import matplotlib.pyplot as plt
plt.figure()
plt.plot(x, y)
plt.show()
Second way:
import matplotlib.pyplot as plt
graph = plt.figure()
plt.plot(x, y)
graph.show()
I think this two ways do not do the same thing but it is not clear to me.
Could someone explain it step by step for the two ways?
Simplified, plt.show() will start an event loop and create a graphical representation for each figure that is active inside the pyplot state.
In contrast, fig.show(), where fig is a figure instance, would show only this figure. Since it would also not block, it is (only) useful in interactive sessions; else the figure would be closed directly after showing it due to the script exiting.
In the usual case you would hence prefer plt.show(). This does not prevent you from using the object-oriented interface. A recommended way of creating and showing a figure is hence,
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
For two windows you can just repeat the plotting,
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots()
ax1.plot(x1, y1)
fig2, ax2 = plt.subplots()
ax2.plot(x2, y2)
plt.show()
Matplotlib has two styles of API implemented. One is object based (graph.show()) and the other is procedural (plt.show()) and looks a lot like the Matlab plotting API.
The procedural API works on the current figure and/or set of axes. You can always getting the current figure with plt.gcf() and the current axes with plt.gca().
There are occasionally some slight differences in syntax here and there. For example, if you want to set the x axis limits:
plt.xlim([0, 10])
or
ax = plt.gca()
ax.set_xlim([0, 10])
plt.figure returns an object that is assigned with graph = plt.figure() to graph . this is used when specific characteristics of this object ( the plot ) are intended to be changed, now the object can be refered to by its instance graph ( object-based plotting )
you use this i.e. if you want to access the axes of the graph or labels, subplots, ...
see https://python4mpia.github.io/plotting/advanced.html for object-based plotting
to manipulate the plot object you have to get a reference to it ( handle ) and this is done by graph = plt.figure() ( cf Object-Oriented Programming )

Why do many examples use `fig, ax = plt.subplots()` in Matplotlib/pyplot/python

I'm learning to use matplotlib by studying examples, and a lot of examples seem to include a line like the following before creating a single plot...
fig, ax = plt.subplots()
Here are some examples...
Modify tick label text
http://matplotlib.org/examples/pylab_examples/boxplot_demo2.html
I see this function used a lot, even though the example is only attempting to create a single chart. Is there some other advantage? The official demo for subplots() also uses f, ax = subplots when creating a single chart, and it only ever references ax after that. This is the code they use.
# Just a figure and one subplot
f, ax = plt.subplots()
ax.plot(x, y)
ax.set_title('Simple plot')
plt.subplots() is a function that returns a tuple containing a figure and axes object(s). Thus when using fig, ax = plt.subplots() you unpack this tuple into the variables fig and ax. Having fig is useful if you want to change figure-level attributes or save the figure as an image file later (e.g. with fig.savefig('yourfilename.png')). You certainly don't have to use the returned figure object but many people do use it later so it's common to see. Also, all axes objects (the objects that have plotting methods), have a parent figure object anyway, thus:
fig, ax = plt.subplots()
is more concise than this:
fig = plt.figure()
ax = fig.add_subplot(111)
Just a supplement here.
The following question is that what if I want more subplots in the figure?
As mentioned in the Doc, we can use fig = plt.subplots(nrows=2, ncols=2) to set a group of subplots with grid(2,2) in one figure object.
Then as we know, the fig, ax = plt.subplots() returns a tuple, let's try fig, ax1, ax2, ax3, ax4 = plt.subplots(nrows=2, ncols=2) firstly.
ValueError: not enough values to unpack (expected 4, got 2)
It raises a error, but no worry, because we now see that plt.subplots() actually returns a tuple with two elements. The 1st one must be a figure object, and the other one should be a group of subplots objects.
So let's try this again:
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(nrows=2, ncols=2)
and check the type:
type(fig) #<class 'matplotlib.figure.Figure'>
type(ax1) #<class 'matplotlib.axes._subplots.AxesSubplot'>
Of course, if you use parameters as (nrows=1, ncols=4), then the format should be:
fig, [ax1, ax2, ax3, ax4] = plt.subplots(nrows=1, ncols=4)
So just remember to keep the construction of the list as the same as the subplots grid we set in the figure.
Hope this would be helpful for you.
As a supplement to the question and above answers there is also an important difference between plt.subplots() and plt.subplot(), notice the missing 's' at the end.
One can use plt.subplots() to make all their subplots at once and it returns the figure and axes (plural of axis) of the subplots as a tuple. A figure can be understood as a canvas where you paint your sketch.
# create a subplot with 2 rows and 1 columns
fig, ax = plt.subplots(2,1)
Whereas, you can use plt.subplot() if you want to add the subplots separately. It returns only the axis of one subplot.
fig = plt.figure() # create the canvas for plotting
ax1 = plt.subplot(2,1,1)
# (2,1,1) indicates total number of rows, columns, and figure number respectively
ax2 = plt.subplot(2,1,2)
However, plt.subplots() is preferred because it gives you easier options to directly customize your whole figure
# for example, sharing x-axis, y-axis for all subplots can be specified at once
fig, ax = plt.subplots(2,2, sharex=True, sharey=True)
whereas, with plt.subplot(), one will have to specify individually for each axis which can become cumbersome.
In addition to the answers above, you can check the type of object using type(plt.subplots()) which returns a tuple, on the other hand, type(plt.subplot()) returns matplotlib.axes._subplots.AxesSubplot which you can't unpack.
Using plt.subplots() is popular because it gives you an Axes object and allows you to use the Axes interface to define plots.
The alternative would be to use the global state interface, the plt.plot etc functionality:
import matplotlib.pyplot as plt
# global state version - modifies "current" figure
plt.plot(...)
plt.xlabel(...)
# axes version - modifies explicit axes
ax.plot(...)
ax.set_xlabel(...)
So why do we prefer Axes?
It is refactorable - you can put away some of the code into a function that takes an Axes object, and does not rely on global state
It is easier to transition to a situation with multiple subplots
One consistent/familiar interface instead of switching between two
The only way to access the depth of all features of matplotlib
The global state version was created that way to be easy to use interactively, and to be a familiar interface for Matlab users, but in larger programs and scripts the points outlined here favour using the Axes interface.
There is a matplotlib blog post exploring this topic in more depth: Pyplot vs Object Oriented Interface
It is relatively easy to deal with both worlds. We can for example always ask for the current axes: ax = plt.gca() ("get current axes").
fig.tight_layout()
such a feature is very convenient, if xticks_labels goes out of plot-window, such a line helps to fit xticks_labels & the whole chart to the window, if automatic positioning of chart in plt-window works not correctly. And this code-line works only if you use fig-object in the plt-window
fig, ax = plt.subplots(figsize=(10,8))
myData.plot(ax=ax)
plt.xticks(fontsize=10, rotation=45)
fig.tight_layout()
plt.show()

Categories