Confusion about Artist place in matplotlib hierarchy - python

In this period I am working with matplotlib. I studied many examples, and was able to modify it to suit several of my needs. But I would like to better understand the general structure of the library. For this reason, apart reading a lot of tutorials on the web, I also purchased the ebook "Matplotlib for Python Developers", by Tosi. While it is full of good examples, I still don't fully grasp the relationships between all the different levels.
The book clearly explains that matplotlib has 3 main "modes":
1) pylab, to work similarly to Matlab
2) pyplot, to work in a procedural way
3) the full OO system
Concerning the objects of the OO system, the book lists 3 levels:
1) FigureCanvas, the container class for the Figure instance
2) Figure, the container for Axes instances
3) Axes, the areas that hold the basic elements (lines, points, text...)
The problem is that, by reading the official documentation, I also encountered the notions of Backends and Artists. While I understand the basic logic of them, I am quite confused about their role respect to the previous classifications. In particular, are the Artists in an intermediate level between the FigureCanvas and the Figure, or is that hierarchy not suitable in this case?
I would be grateful to receive some clarifications, eventually also referring to other documentation I could have missed.
Thanks.

I do not like those layers
pylab : massive namespace dump that pulls in everything from pyplot and numpy. It is not a 'layer' so much as a very cluttered name space.
pyplot : state-machine based layer (it knows what your 'current axes' and 'current figure' are and applies the functions to that axes/figure. You should use this only when you are playing around in an interactive terminal (other than plt.subplots or plt.figure for setting up the figure/axes objects). Making a distiction between this layer and pylab is dumb. This is the layer that makes it 'like MATLAB'
the OO layer : which is what you should use in all of your scripts
Figures are the top level container objects. They can contain Axes objects and Artist objects (technically Axes are Artists, but it is useful for pedagogical reasons to distinguish between the Axes objects in a figure and the other artists (such as text objects) that are in the Figure, but not associated with an Axes) and know about the Canvas object. Each Axes can contain more Artists objects. The Artists are the useful things you want to put on your graph (lines, text, images, etc). Artists know how to draw themselves on a Canvas. When you call fig.savefig (or render the figure to the screen) the Figure object loops over all of it's children and tell them to draw them selves on to it's Canvas.
The different Backends provide implementations of the Canvas objects, hence the same figure can be rendered to a raster or vector graphic by just changing the Canvas object that is being used.
Unless you want to write a new backend, many of these details are not important and the fact that matplotlib hides them from you is why it is useful.
If the book couldn't get this correct, I would take everything it says with grain of salt.

Related

What are the two styles of matplotlib?

I'm reading the documentation for matplotlib. Under the 'Coding Styles' section, it says:
When viewing this documentation and examples, you will find different coding styles and usage patterns.
Later...
Of the different styles, there are two that are officially supported. Therefore, these are the preferred ways to use matplotlib.
For the pyplot style...
But then in the rest of that section they never explicitly explain or mention the 'second' supported coding style. They say something about a 'MATLAB-style' but it is unclear from the context if that is referring to the pyplot style (as if it is like MATLAB) or if it is a separate style itself.
Question
What is the second supported matplotlib coding style and how does it relate / differ from the pyplot style?
Arguably this part of the usage guide is a bit hard to understand in its current form. There was however an update recently (#14223), which might make it clearer. A preview version of this can be found here:
https://matplotlib.org/devdocs/tutorials/introductory/usage.html#the-object-oriented-interface-and-the-pyplot-interface
As noted above, there are essentially two ways to use Matplotlib:
Explicitly create figures and axes, and call methods on them (the "object-oriented (OO) style").
Rely on pyplot to automatically create and manage the figures and axes, and use pyplot functions for plotting.
The next level down in the hierarchy is the first level of the object-oriented
interface, in which pyplot is used only for a few functions such as figure
creation, and the user explicitly creates and keeps track of the figure and axes
objects. At this level, the user uses pyplot to create figures, and through those
figures, one or more axes objects can be created. These axes objects are then used
for most plotting actions.

Data visualization in python (matplotlib) [duplicate]

I'm not really new to matplotlib and I'm deeply ashamed to admit I have always used it as a tool for getting a solution as quick and easy as possible. So I know how to get basic plots, subplots and stuff and have quite a few code which gets reused from time to time...but I have no "deep(er) knowledge" of matplotlib.
Recently I thought I should change this and work myself through some tutorials. However, I am still confused about matplotlibs plt, fig(ure) and ax(arr). What is really the difference?
In most cases, for some "quick'n'dirty' plotting I see people using just pyplot as plt and directly plot with plt.plot. Since I am having multiple stuff to plot quite often, I frequently use f, axarr = plt.subplots()...but most times you see only code putting data into the axarr and ignoring the figure f.
So, my question is: what is a clean way to work with matplotlib? When to use plt only, what is or what should a figure be used for? Should subplots just containing data? Or is it valid and good practice to everything like styling, clearing a plot, ..., inside of subplots?
I hope this is not to wide-ranging. Basically I am asking for some advice for the true purposes of plt <-> fig <-> ax(arr) (and when/how to use them properly).
Tutorials would also be welcome. The matplotlib documentation is rather confusing to me. When one searches something really specific, like rescaling a legend, different plot markers and colors and so on the official documentation is really precise but rather general information is not that good in my opinion. Too much different examples, no real explanations of the purposes...looks more or less like a big listing of all possible API methods and arguments.
pyplot is the 'scripting' level API in matplotlib (its highest level API to do a lot with matplotlib). It allows you to use matplotlib using a procedural interface in a similar way as you can do it with Matlab. pyplot has a notion of 'current figure' and 'current axes' that all the functions delegate to (#tacaswell dixit). So, when you use the functions available on the module pyplot you are plotting to the 'current figure' and 'current axes'.
If you want 'fine-grain' control of where/what your are plotting then you should use an object oriented API using instances of Figure and Axes.
Functions available in pyplot have an equivalent method in the Axes.
From the repo anatomy of matplotlib:
The Figure is the top-level container in this hierarchy. It is the overall window/page that everything is drawn on. You can have multiple independent figures and Figures can contain multiple Axes.
But...
Most plotting occurs on an Axes. The axes is effectively the area that we plot data on and any ticks/labels/etc associated with it. Usually we'll set up an Axes with a call to subplot (which places Axes on a regular grid), so in most cases, Axes and Subplot are synonymous.
Each Axes has an XAxis and a YAxis. These contain the ticks, tick locations, labels, etc.
If you want to know the anatomy of a plot you can visit this link.
I think that this tutorial explains well the basic notions of the object hierarchy of matplotlib like Figure and Axes, as well as the notion of current figure and current Axes.
If you want a quick answer: There is the Figure object which is the container that wraps multiple Axes(which is different from axis) which also contains smaller objects like legends, line, tick marks ... as shown in this image taken from matplotlib documentation
So when we do
>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots()
>>> type(fig)
<class 'matplotlib.figure.Figure'>
>>> type(ax)
<class 'matplotlib.axes._subplots.AxesSubplot'>
We have created a Figure object and an Axes object that is contained in that figure.
pyplot is matlab like API for those who are familiar with matlab and want to make quick and dirty plots
figure is object-oriented API for those who doesn't care about matlab style plotting
So you can use either one but perhaps not both together.

matplotlib gui respond to axes changes

I have created a little GUI with QT which set's up a single matplotlib figure and axes.
The GUI has controls to change just about everything to do with the appearance of the axes.
Basically, it does this by each widget emitting signals back up to the main frame and it calls the appropriate matplotlib setters on the axes and figure objects.
However, it is possible for the axes (and therefore the image displayed on the FigureCanvas) to change without input from the GUI (e.g. when autoscaling, or adding certain plots which adjust the axes automatically).
In this case, a widget controlling e.g. the limits of the x axis will now be displaying the wrong values.
I would like all the relevant widgets to update when the axes updates....how could I possible achieve this?
I'm thinking that this is a problem that has been solved before - how to enable a two-way communication between distinct objects?
fig.canvas.draw()
time.sleep(1e-2)
whenever anything writes to the plot? however it's hard to help with no code.
Showing an example of how your code is not working would help a lot.
EDIT:
I'll try this again then:
What about getting the state of the plot you are updating? I guess its what #Ajean means by updater method. I know that Artists in matplotlib have an Artist.properties() method that returns all of the properties and values.
I imagine Axes would have a similar method.
A quick look at the matplotlib docs yielded 2 interesting methods of axes:
ax.get_autoscale_on()
and
ax.set_autoscale_on().
ax.set_autoscale_on(False) will prevent plots from updating the state of the axes.

Embed matplotlib figure in larger figure

I am writing a bunch of scripts and functions for processing astronomical data. I have a set of galaxies, for which I want to plot some different properties in a 3-panel plot. I have an example of the layout here:
Now, this is not a problem. But sometimes, I want to create this plot just for a single galaxy. In other cases, I want to make a larger plot consisting of subplots that each are made up of the three+pane structure, like this mockup:
For the sake of modularity and reusability of my code, I would like to do something to the effect of just letting my function return a matplotlib.figure.Figure object and then let the caller - function or interactive session - decide whether to show() or savefig the object or embed it in a larger figure. But I cannot seem to find any hints of this in the documentation or elsewhere, it doesn't seem to be something people do that often.
Any suggestions as to what would be the best road to take? I have speculated whether using axes_grid would be the solution, but it doesn't seem quite clean and caller-agnostic to me. Any suggestions?
The best solution is to separate the figure layout logic from the plotting logic. Write your plotting code something like this:
def three_panel_plot(data, ploting_args, ax1, ax2, ax3):
# what you do to plot
So now the code that turns data -> images takes as arguments the data and where it should plot that data too.
If you want to do just one, it's easy, if you want to do a 3x3 grid, you just need to generate the layout and then loop over the axes sets + data.
The way you are suggesting (returning an object out of your plotting routine) would be very hard in matplotlib, the internals are too connected.

python matplotlib blit to axes or sides of the figure?

I'm trying to refresh some plots that I have within a gui everytime I go once through a fitting procedure. Also, these plots are within a framw which can be resized, so the axes and labels etc need to be redrawn after the resizing. So was wondering if anyone knew how to update the sides of a figure using something like plot.figure.canvas.copy_from_bbox and blit. This appears to only copy and blit the background of the graphing area (where the lines are being drawn) and not to the sides of the graph or figure (where the labels and ticks are). I have been trying to get my graphs to update by trial and error and reading mpl documentation, but so far my code has jst become horrendously complex with things like self.this_plot.canvas_of_plot..etc.etc.. .plot.figure.canvas.copy_from_bbox... which is probably far too convoluted.
I know that my language might be a little off but I've been trying to read through the matplotlb documentation and the differences between Figure, canvas, graph, plot, figure.Figure, etc. are starting to evade me. So my first and foremost question would be:
1 - How do you update the ticks and labels around a matplotlib plot.
and secondly, since I would like to have a better grasp on what the answer to this question,
2 - What is the difference between a plot, figure, canvas, etc. in regards to the area which they cover in the GUI.
Thank you very much for the help.
All this can certainly be rather confusing at first!
To begin with, if you're chaining the ticks, etc, there isn't much point in using blitting. Blitting is just a way to avoid re-drawing everything if only some things are changing. If everything is changing, there's no point in using blitting. Just re-draw the plot.
Basically, you just want fig.canvas.draw() or plt.draw()
At any rate, to answer your first question, in most cases you won't need to update them manually. If you change the axis limits, they'll update themselves. You're running into problems because you're blitting just the inside of the axes instead of redrawing the plot.
As for your second question, a good, detailed overview is the Artist Tutorial of the Matplotlib User's Guide.
In a nutshell, there are two separate layers. One deals with grouping things into the parts that you'll worry about when plotting (e.g. the figure, axes, axis, lines, etc) and another that deals with rendering and drawing in general (the canvas and renderer).
Anything you can see in a matplotlib plot is an Artist. (E.g. text, a line, the axes, and even the figure itself.) An artist a) knows how to draw itself, and b) can contain other artists.
For an artist to draw itself, it uses the renderer (a backend-specific module that you'll almost never touch directly) to draw on a FigureCanvas a.k.a. "canvas" (an abstraction around either a vector-based page or a pixel buffer). To draw everything in a figure, you call canvas.draw().
Because artists can be groups of other artists, there's a hierarchy to things. Basically, something like this (obviously, this varies):
Figure
Axes (0-many) (An axes is basically a plot)
Axis (usually two) (x-axis and y-axis)
ticks
ticklabels
axis label
background patch
title, if present
anything you've plotted, e.g. Line2D's
Hopefully that makes things a touch clearer, anyway.
If you really do want to use blitting to update the tick labels, etc, you'll need to grab and restore the full region including them. This region is a bit tricky to get, because it isn't exactly known until after draw-time (rendering text in matplotlib is more complicated than rendering other things due to latex support, etc). You can do it, and I'll be glad to give an example if it's really what you want, but it's typically not going to yield a speed advantage over just drawing everything. (The exception is if you're only updating one subplot in a figure with lots of subplots.)

Categories

Resources