Repository navigation
Idea: Reducing verbosity through more compact API patterns #30941
Description
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. Theset_*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)
Activity
anntzer commentedon Jan 7, 2026
In the single axes case, this already exists as
which is actually the pattern I use most of the time (In fact, this is the underlying motivation for #30585). Having a separate figure() call is useful because you can put the relevant kwargs there (figsize, layout, ...).
jklymak commentedon Jan 7, 2026
I use the figure handle all the time to save the figure:
fig.savefig(). (EDIT: as pointed out below, alsofig.colorbaris used a lot)ax.set(foo="")is fine, but doesn't allow any customization. eg I often pass extra args toax.set_title('my title', loc='left', fontsize='medium').I personally find it cumbersome to read large argument lists inside of brackets, but wouldn't object to some keywords being added there. However, note that 95% of the time I am actually doing
fig, axs = plt.subplots(2, 2, ...); ax[0, 0].set_xlabel()so passing labels in doesn't usually make any sense in this case.story645 commentedon Jan 7, 2026
I mostly like the tradeoff we currently have of more verbosity but tighter scoping. It's super easy to teach (roughly: subplots for creating things, axes methods for plotting, sets for labeling) and document, vs everything all at once methods. Which what we've been doing is recommending the third party APIs that provide the all at once methods.
story645 commentedon Jan 7, 2026
Same. Also, there's no colorbar method on Axes (#25880) so
fig.colorbaris as far as I know still the simplest way to add one.timhoffm commentedon Jan 8, 2026
To clarify:
axes(),subplots(),add_subplot()etc. all accept Axes properties (i.e. the names fromset_*as kwargs. This is more a question of what we want to advertise/teach.As said,
works as well with advantages:
plt.subplots()And you could do
axs = plt.figure().subplots(2, 2), which does not help with kwargs (unless they are the same for all subplots), but still saves you some typing if you don't need the figure.Semi-OT, but it may be worth considering to add one. After all, it's the typical case that a colorbar is "semantically associated" with an Axes; and even technically, it's associated to a ScalarMappable that lives in one Axes.
jklymak commentedon Jan 8, 2026
I'd argue teaching one main way to do things is best, and leave shortcuts for more advanced treatment.
rcomer commentedon Jan 11, 2026
A tutorial or User Guide page specifically about shortcuts would be useful. It was embarrassingly recent that I learned about the
setmethod.