What exactly is a matplotlib axes object? - python

When we create a new figure:
import matplotlib.pyplot as plt
fig = plt.figure()
we can see in the console an output like:
<Figure size 432x288 with 0 Axes>
so when we use add_axes:
add_axes(rect, projection=None, polar=False, **kwargs)
are we actually defining the x,y axes that encompass the "box" that will bound the figure (the axes in a more mathematical sense) and nothing more? or in fact this line of code is creating an empty figure with the desired dimensions in which any data we add later will be fitted in? (or None of the above maybe?)
That questioning left me wondering how can I physically understand what the axes are for matplotlib.
Thanks for helping.

From the point of view of the viewer, the axes is the box which will contain the data and which (usually) has an x-axis and y-axis.
From the programmatical point of view, the axes is an object, which stores several other objects like XAxis, YAxis and provides methods to create plots. Importantly, it has a transformation stored, which allows to draw the data points in pixel space.

Related

Python3 - Plotting the same matplotlib axes object on multiple figures?

I have a script which I'm adapting to include a GUI. In it, I create a plot with subplots (the arrangement of which depends on the number of plots - e.g. 4 plots go into a square rather than 4-across). That plot (with a subplot for each of the "targets" analyzed) gets saved to a .png.
In building the GUI, I'm writing up the 'results' frame and would like to show these individual subplots on their own tabs. I've written the code to lay out the frame how I want it, but in order to separate the subplots into their own plots, I need to draw the completed Axes object (e.g. the entire subplot for that target) onto a new figure in the frame.
Since the number of subplots isn't known before runtime, I already have my Axes objects/subplots in an array (/list?) axs, whose members are the individual Axes objects (each containing data points created with ax.scatter() and several lines and annotations created with ax.plot() and ax.annotate).
When I initially create the axes, I do so with
fig, axs = plt.subplots(num='Title', nrows=numrow, ncols=numcol,
figsize=[numcol*5, numrow*5],
subplot_kw={'adjustable':'box', 'aspect':1})
Is there a way to now take these axes and draw them onto a new figure (the one that will be contained in the 'results' frame of the GUI)? In my searches, I only came up with ways to plot multiple axes onto a single figure (i.e. how to use subplots()) but nothing came up on how I'd throw a pre-existing Axes object into a new figure that it wasn't originally associated with. I'd rather not re-draw the axes from scratch -- there's quite a bit of decoration and multiple datasets / lines plotted onto them already.
Any ideas? Happy to post code as requested, but since this more of a "How do I do this" than a "why doesn't my code work", I didn't post much of it.
Thank you!
I believe that's not possible and you will have to recreate the Axes objects inside the other figure. Which is just a matter of code reorganization. Note that your approach would not noticeably improve rendering performance. Matplotlib would have to re-render the Axes objects anyway, and that's the computationally expensive part. Creating the objects is relatively cheap.
What you're trying to do is pretty much this:
from matplotlib import pyplot
pyplot.ion()
figure1 = pyplot.figure()
axes = figure1.add_subplot()
axes.plot([0, 1], [0, 1])
figure2 = pyplot.figure()
figure2.add_axes(axes)
Which raises:
ValueError: The Axes must have been created in the present figure
And the documentation of add_axes() notes:
In rare circumstances, add_axes may be called with a single argument, an Axes instance already created in the present figure but not in the figure's list of Axes.
So that's a pretty clear indication that this is not a supported use case.

matplotlib figure vs subplot vs axes?

Though I've been able to create basic plots with matplotlib.pyplot before, I cannot fully understand what the difference between these are:
figure
subplot
axes
(axis?)
As I understand, all three of these are objects for the area in which a graph is drawn, so what distinguishes them in terms of what can be drawn inside them?
Matplotlib's user guide gives a great description about the parts of a figure.
The components are hierarchical:
Figure object: the whole figure
Axes object: belongs to a Figure object and is the space where we add the data to visualize
Axis object: belongs to an Axes object. Axis object can be categorized as XAxis or YAxis.
For further info, visit this link:
Getting Started with Matplotlib

seaborn change clustermap visualization options without redoing the clustering

Is it possible to run seaborn.clustermap on a previously obtained ClusterGrid object?
For example I user clustermap to obtain g in the following example:
import seaborn as ns
data = sns.load_dataset("iris")
species = iris.pop("species")
g = sns.clustermap(
data,
cmap="mako",
col_cluster=False,
yticklabels=False, figsize=(5, 10),
method='ward',
metric="euclidean"
)
I would like to try different visualization options like different colormaps, figure sizes, how it looks with and without labels etc.
With the iris dataset everything is really fast, but I have a way larger dataset and the clustering part takes a lot of time.
Can I use g to show the heatmap and dendrogram using different options?
the object returned by clustermap is of type ClusterGrid. That object is not really documented in seaborn, however, it is essentially just a container for a few Axes objects. Depending on the kind of manipulations you want to make, you may simply need to access the relevant Axes object or the figure itself:
# change the figure size after the fact
g.fig.set_size_inches((4,4))
# remove the labels of the heatmap
g.ax_heatmap.set_xticklabels([])
The colormap thing is a little more difficult to access. clustermap uses matplotlib pcolormesh under the hood. This function returns a collection object (QuadMesh), which is store in the list of collections of the main axes (g.ax_heatmap.collections). Since, AFAIK, seaborn doesn't plot anything else on that axes, We can get the QuadMesh object by its index [0], and then we can use any function applicable to that object.
# change the colormap used
g.ax_heatmap.collections[0].set_cmap('seismic')

Re-initialize the plot in pylab

I am new to using PyLab. I want to plot some points. But I don't want to show the previous points i.e. as a new point comes the previous plotted point will vanish and the new point will be plotted. I have searched a lot but I could not find how to re-initialize the plot in between. The problem I am facing is I can set the current figure by using
plt.figure(f1.number) but after plotting the point in that figure it gets permanently changed.
plt.hold(False) before you start plotting will do what you want.
hold determines of old artists are held-on to when new ones are plotted. The default is for hold to be on.
ex
# two lines
plt.figure()
plt.hold(True)
plt.plot(range(5))
plt.plot(range(5)[::-1])
#one line
plt.figure()
plt.hold(False)
plt.plot(range(5))
plt.plot(range(5)[::-1])
Changing it via plt.hold changes it for all (new) axes. You can change the hold state for an individual axes by
ax = gca()
ax.hold(True)
With pylab, pylab.clf() should clear the figure, after which you can redraw the plot.
Alternatively, you can update your data with set_xdata and set_ydata that are methods on the axes object that gets returned when you create a new plot (either with pylab.plot or pylab.subplot).
The latter is probably preferred, but requires a litte more work. One example I can quickly find is another SO question.

How do I convert (or scale) axis values and redefine the tick frequency in matplotlib?

I am displaying a jpg image (I rotate this by 90 degrees, if this is relevant) and of course
the axes display the pixel coordinates. I would like to convert the axis so that instead of displaying the pixel number, it will display my unit of choice - be it radians, degrees, or in my case an astronomical coordinate. I know the conversion from pixel to (eg) degree. Here is a snippet of what my code looks like currently:
import matplotlib.pyplot as plt
import Image
import matplotlib
thumb = Image.open(self.image)
thumb = thumb.rotate(90)
dpi = plt.rcParams['figure.dpi']
figsize = thumb.size[0]/dpi, thumb.size[1]/dpi
fig = plt.figure(figsize=figsize)
plt.imshow(thumb, origin='lower',aspect='equal')
plt.show()
...so following on from this, can I take each value that matplotlib would print on the axis, and change/replace it with a string to output instead? I would want to do this for a specific coordinate format - eg, rather than an angle of 10.44 (degrees), I would like it to read 10 26' 24'' (ie, degrees, arcmins, arcsecs)
Finally on this theme, I'd want control over the tick frequency, on the plot. Matplotlib might print the axis value every 50 pixels, but I'd really want it every (for example) degree.
It sounds like I would like to define some kind of array with the pixel values and their converted values (degrees etc) that I want to be displayed, having control over the sampling frequency over the range xmin/xmax range.
Are there any matplotlib experts on Stack Overflow? If so, thanks very much in advance for your help! To make this a more learning experience, I'd really appreciate being prodded in the direction of tutorials etc on this kind of matplotlib problem. I've found myself getting very confused with axes, axis, figures, artists etc!
Cheers,
Dave
It looks like you're dealing with the matplotlib.pyplot interface, which means that you'll be able to bypass most of the dealing with artists, axes, and the like. You can control the values and labels of the tick marks by using the matplotlib.pyplot.xticks command, as follows:
tick_locs = [list of locations where you want your tick marks placed]
tick_lbls = [list of corresponding labels for each of the tick marks]
plt.xticks(tick_locs, tick_lbls)
For your particular example, you'll have to compute what the tick marks are relative to the units (i.e. pixels) of your original plot (since you're using imshow) - you said you know how to do this, though.
I haven't dealt with images much, but you may be able to use a different plotting method (e.g. pcolor) that allows you to supply x and y information. That may give you a few more options for specifying the units of your image.
For tutorials, you would do well to look through the matplotlib gallery - find something you like, and read the code that produced it. One of the guys in our office recently bought a book on Python visualization - that may be worthwhile looking at.
The way that I generally think of all the various pieces is as follows:
A Figure is a container for all the Axes
An Axes is the space where what you draw (i.e. your plot) actually shows up
An Axis is the actual x and y axes
Artists? That's too deep in the interface for me: I've never had to worry about those yet, even though I rarely use the pyplot module in production plots.

Categories

Resources