1

I usually see Matplotlib being used like this:

import matplotlib.pyplot as plt

years = [1980, 1990, 2000, 2010]
gdp = [300, 400, 520, 700]
plt.plot(years, gdp, marker='o')
plt.show()

does that actually create or use a bunch of variables scoped to plt? (such as plt.someKindOfPlotDataArray)

I sometimes see Matplotlib used as:

from matplotlib.pyplot import plot, show

years = [1980, 1990, 2000, 2010]
gdp = [300, 400, 520, 700] 
plot(years, gdp, marker='o')
show()

which is to directly import plot and show into our namespace. If used this way, doesn't it potentially add variables or instance variables to our code? (or else, how can plot add data and then show will be able to use it? Does the import add these 2 methods plot and show to the current object? But when Python runs, is it as if it is running inside a method of a global object? If so, if we just import plot and show, what if plot actually needs another method from the module, such as plotHelper?)

nonopolarity
  • 146,324
  • 131
  • 460
  • 740

1 Answers1

2

I think your question is essentially: "How does matplotlib's state machine interface work?". I'll answer that in a second.

However, let's back up and answer the import question first.

Namespaces and import from

Say we have a file name foo.py with the following contents:

DUMMY = 1

def talk():
    print DUMMY

And then we do:

from foo import talk
talk()

The function will still work as expected, even though DUMMY is nowhere in the namespace that we're working in.

If we do:

print DUMMY

We'll get a NameError.

Instead on injecting things into the current namespace, each function keeps track of the namespace in which it was created. In this case:

assert 'DUMMY' in talk.__globals__

With that out of the way, let's get back to matplotlib


The matplotlib State Machine

Matplotlib's pyplot interface uses a state machine to keep track of the currently active figure, axes, image, etc. It's meant to directly mirror Matlab's approach for an easier transition from Matlab to Python.

However, you'll typically use an object-oriented approach when using matplotlib, and limit the usage of pyplot to a couple of convenience functions: plt.subplots() or plt.figure() and plt.show().

Let's break down a simple example using only the pyplot interface and explain the steps that matplotlib takes.

For example, if we do something like:

import matplotlib.pyplot as plt

plt.plot(range(10))
plt.show()

What happens? plt.plot is basically a one-liner. It's return plt.gca().plot(*args, **kwargs). Essentially, it boils down to this:

  1. plt.plot tries to get the current Axes instance.
  2. Because there hasn't been one created yet, it creates a Figure and adds an Axes to it.
  3. The Axes instance's plot method is called and a line is added to the axes (the line object is also returned).
  4. The gui mainloop for the Figure is entered when we call show

If all this seems a bit indirect, it is. That's why shouldn't be using that style. Instead, use the standard object-oriented interface. That way it's much clearer what Axes you're plotting on, which Figure you're saving, etc.

With that in mind, let's back up and use the more common style instead of the matlab-esque plt.plot:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot(range(10))
plt.show()

Here, we've used a few pyplot functions to create a new figure/axes and display the figure. You can skip them entirely, but it gets a touch verbose.

Basically:

  1. subplots creates a new Figure instance (fig) and adds one or more Axes (subplots) to the figure. By default, a single Axes (ax) will be added to the figure.
  2. We add a line to the Axes instance by calling its plot method (ax.plot(data)).
  3. We enter the gui mainloop with plt.show().

Hopefully that clarifies things a touch. If you're still struggling, you might have a look through the documentation or a few other SO questions. For example:

Community
  • 1
  • 1
Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • so `talk()` is like a closure that captures the scope at the place it was defined? – nonopolarity Dec 30 '15 at 08:45
  • @太極者無極而生 - Yep! Though technically, a closure only happens when you're dealing with nested functions. In that case, the variables in the "outer" function's scope would be stored in `talk.__closure__`. At any rate, you can think of all functions in Python as being closures in the sense that they preserve the scope that they're defined in. (There are caveats there that I'll skip for brevity, though.) – Joe Kington Dec 30 '15 at 14:23