2

I have defined some plots which I now like to arrange using subplots. So I will pass an axis object to the plot definition and tell it to plot on that instead of making a new plot. However, to make this fool-proof I like to check that the passed object is actually of the right type, i.e. an axis.

When I make a subplot like so: f, ax = pyplot.subfigure(2,2) and inspect type(ax[1,1]) it returns matplotlib.axes._subplots.AxesSubplot, however I cannot use isinstance() to test against that value. What works is isinstace(ax[1,1],matplotlib.axes._subplots.Subplot). But I can also test against matplotlib.axes._subplots.Axes or matplotlib.axes._subplots.SubplotBase, all equate to True. I'm a bit confused by the ambiguity here. What is the correct way to test if something is an object one can plot on?

Matthias Arras
  • 565
  • 7
  • 25
  • 2
    The usual Pythonic approach is, you _don't_. This is generally called the [EAFP principle](https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python), for "It's easier to ask for forgiveness than permission." Just _try_ to plot on the object passed in and handle the error appropriately (or let the caller do it). – bnaecker Dec 01 '20 at 00:29
  • `hasattr(ax, 'plot')` – Paul H Dec 01 '20 at 01:00
  • What's wrong with testing against `matplotlib.axes.SubplotBase` or `matplotlib.axes.Axes` (depending on whether you only want subplots)? If this doesn't do what you want, could you say why. (Also, subplots are axes, so subplots will be instances of both `Axes` and `SubplotBase` and `isinstance` will therefore return True for both for a subplot.) – tom10 Dec 01 '20 at 01:33
  • Nothing wrong with it, I am just trying to understand it better, so that I don't get any unexpected results. Your last parentheses goes into the right direction to help me understand what is going on - would you mind to elaborate as an answer. Besides my curiosity to understand this better, I think for my actual application I will go with the `try` route. – Matthias Arras Dec 01 '20 at 10:39
  • 1
    The `SubplotBase` docs are useful for two reasons: "Base class for subplots, which are Axes instances with additional methods..." 1) when it says "are Axes", in OOP that means they inherit from Axes, so a subplot is a `SubplotBase` and an `Axes`. 2) I disagree with `try` (EAFP) for this case. Eg, say your function needs the "additional methods" of subplots but is passed an `Axes` object that's not a subplot. So you start the plot and things are drawn on the screen, but then throws an exception. If you know you want a subplot, just check at the start. – tom10 Dec 01 '20 at 15:49
  • Then would `matplotlib.axes.Axes` be the widest-spanning (least restrictive) of all things one could plot on? – Matthias Arras Dec 01 '20 at 15:59
  • Yes, I think in matplotlib, `Axes` is a base class for everything with a `plot`. But do you really just want to call `plot`? Usually in plots one also sets colors, legends, labels, sizes, etc. For this reason,I would suggest first writing your function first and then finding a way to pre-check whether you'll get through the function. In the end, checking with `isinstance` is just an easy way to make sure you'll have the functionality and result you need (and often you'll want to return an object where the user can call their own functions which need to be there too). – tom10 Dec 01 '20 at 18:38
  • 1
    But I don't know for sure whether the only `plot` is for axes. I think more the question is, are you writing for things other than Axes -- usually if something runs that you didn't have in mind when you wrote the code it leads to an undesired outcomes. For example, in matplotlib there are many `Artists`: Line2D, Collections, Patches, etc. If one of these had a plot method, would you like your code to run it or not. My guess is not, but if you want it to run with everything, then just try it, and who knows, you might get plots for crimes, theater, and land parcels, too. – tom10 Dec 01 '20 at 18:46

0 Answers0