Skip to content

Idea: Reducing verbosity through more compact API patterns #30941

@timhoffm

Description

@timhoffm

Summary

Matplotlib is often considered verbose. I've been pondering whether/how one could write the code more compact without completely reinventing our API. The two main points for simplification I've come up with are:

  • Don't use set_* for configuration, but instead do the configuration via kwargs. The set_* methods can be a fallback for mor complex configuration.
  • Don't hold a figure reference as it's rarely needed.

What I explicitly do not want to change:

  • No breakage of existing API
  • No completely new interface namespace
  • No method chaining

This is just an early and wild idea, not a proposal. Thoughts and feedback are welcome.

Proposed fix

The ideas are illustrated on a slightly modified variant of https://matplotlib.org/devdocs/gallery/lines_bars_and_markers/simple_plot.html

The formal Axes interface approach is:

fig, ax = plt.subplots()
ax.plot(t, s)
ax.set_xlabel('time (s)')
ax.set_ylabel('voltage (mV)')
ax.set_title('A simple plot')
plt.show()

In some parts, we already have replaced the individual setters by ax.set(...) with kwargs.

fig, ax = plt.subplots()
ax.plot(t, s)
ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot')
plt.show()

Possible improvement 1: Replace ax.set(...) by kwargs during Axes creation:

fig, ax = plt.subplots(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot')
ax.plot(t, s)
plt.show()

Possible improvement 2: Don't store a reference to the figure - rationale: The fig, ax = plt.subplots() pattern is quite boilerplate and you rarely need the figure. One can always get the figure via ax.get_figure() if needed, which is only mildy more work than holding a fig variable.

ax = plt.figure().subplots(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot')
ax.plot(t, s)
plt.show()

What is still not so nice is that you still need the plt.figure().subplots( chaining for the simple single-Axes case. While

ax = plt.axes(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot')

works with the same result, there's a caveat in that plt.axes() reuses an existing Figure if possible whereas plt.figure().subplot() always creates a new figure. That's a potential footgun and we may want to think whether there's a way around this. Otherwise

ax = plt.axes(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot')
ax.plot(t, s)
plt.show()

would look quite clean to me:

  • create an Axes with some properties set
  • add data
  • show

In jupyter notebooks you'd even not need the show and could (as an abbreviation, not as a universally recommended pattern) create the plot in one line:

plt.axes(xlabel='time (s)', ylabel='voltage (mV)', title='A simple plot').plot(t, s)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions