Skip to content

Add materials for Python Plotting With Matplotlib (Guide) - #845

Open
realpython-bot wants to merge 1 commit into
masterfrom
materials/python-matplotlib-guide-20260916
Open

realpython-bot wants to merge 1 commit into
masterfrom
materials/python-matplotlib-guide-20260916

Conversation

@realpython-bot

@realpython-bot realpython-bot commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

What this is

A brand-new folder for a tutorial that has never had companion code. python-matplotlib-guide/ did not exist before this branch, so this needs an editorial eye as well as a code review — nothing here is a diff against a previously reviewed baseline.

Source of truth: the updated draft, not the live article — https://realpython.com/pbjt/blog/post/2331/change/
Maintenance card: https://trello.com/c/5rsIxkMx

How it maps to the article

The tutorial is 100% REPL (pycon) blocks — it names no scripts at all. Following the house pattern already used in python-statistics/, each section's REPL sequence became one runnable script, in the article's order and with the article's variable names, with print() added where seeing the output is the point.

File Tutorial section
object_hierarchy.py The Matplotlib Object Hierarchy
subplots_notation.py Understanding plt.subplots() Notation
gridspec_housing.py Understanding plt.subplots() Notation — the subplot2grid() / California housing examples (split out because it downloads data)
figures_behind_the_scenes.py The "Figures" Behind The Scenes
imshow_and_matshow.py A Burst of Color: imshow() and matshow()
plotting_in_pandas.py Plotting in Pandas
appendix_a_configuration.py Appendix A: Configuration and Styling
appendix_b_interactive_mode.py Appendix B: Interactive Mode

Plus README.md in the repo's house form and requirements.txt.

Two of the tutorial's blocks are deliberately not shipped, because there is nothing for a reader to run: the one-line canonical imports in "Pylab: What Is It, and Should I Use It?", and the abridged excerpt of matplotlib's own pyplot.py source in "Stateful Versus Stateless Approaches". The README says so explicitly.

No examples were invented and no code was "improved". The only deviations from the article's literal text are house style (double quotes, 79 columns, ruff format) and one lint-forced change: the article writes fig = plt.figure(figsize=(12, 8)) in the gridspec example but never uses fig, which trips F841, so the binding is dropped with a comment pointing that out.

⚠️ The article's dependencies field is stale — please look at this

The draft's dependencies field still reads:

matplotlib==2.1.2
numpy==1.14.1
pandas==0.22.0
python==3.6

Those pins are not what the draft's own output was produced with, and they cannot be installed at all today (uv has no Python 3.6 interpreter available, and pandas==0.22.0 fails to even resolve: its pytz (>=2011k) requirement is not a parseable version). I tried them first and recorded the failure rather than skipping the step.

The draft's shown output pins the real versions unambiguously:

  • array([[<Axes: >, ...]], dtype=object) — the <Axes: > repr is matplotlib ≥ 3.6
  • <class 'matplotlib.axes._axes.Axes'> — the private-module path is matplotlib ≥ 3.7
  • plt.style.available including petroff6, petroff8, and petroff10 — matplotlib ≥ 3.11
  • .squeeze("columns") on read_csv — modern pandas

So requirements.txt here pins matplotlib==3.11.2, numpy==2.5.3, pandas==3.0.5 — the current releases, which are also exactly what the sibling python-statistics/ folder pins. Every piece of output in the article reproduces byte for byte on these. CMS is read-only for this run, so the dependencies field on post 2331 still needs a human to correct it — that is the one follow-up this PR can't do itself.

How it was verified

  1. Built a venv on the pins above (Python 3.14.6) and ran all eight scripts with MPLBACKEND=Agg. All exit 0, with zero warnings on stderr.
  2. Compared every printed line against the draft. Exact matches for: <class 'matplotlib.figure.Figure'>, <class 'matplotlib.axis.YTick'>, <class 'matplotlib.axes._axes.Axes'>, (True, True), <class 'numpy.ndarray'>, the array([[<Axes: >, ...]], dtype=object) repr, (2, 2), the full nolabels dict, [1, 2], [<Figure size 640x480 with 1 Axes>, <Figure size 640x480 with 1 Axes>], [], True for id(plt.gca()) == id(ax), the seven rc* attributes, and the complete 28-entry plt.style.available list.
  3. Re-rendered each figure to PNG to confirm the plots are real and non-empty (e.g. the matshow() heatmap renders the expected X-pattern with the white in-cell numbers and the make_axes_locatable colorbar).
  4. Repo gates at the version the root requirements.txt pins: uvx ruff@0.14.1 format --check python-matplotlib-guide8 files already formatted; uvx ruff@0.14.1 check python-matplotlib-guideAll checks passed!

Two outputs that legitimately cannot match, both documented in the README

  • figures_behind_the_scenes.py prints id() values — memory addresses, so the numbers differ from the article's 4525567840. Only the comparisons between them are meaningful, and those match.
  • appendix_b_interactive_mode.py first prints False where the article shows True. The article is in an interactive session; matplotlib starts a script with interactive mode off. The plt.ioff() toggle the section is actually about behaves identically.

Nothing was skipped

Both network-dependent scripts really ran in CI-like conditions here: gridspec_housing.py downloaded the California housing archive from figshare, and plotting_in_pandas.py downloaded the VIX series from FRED. No GUI, server, or paid API key is needed by anything in this folder. Note for reviewers that these two are live-network scripts and will fail offline — the README calls that out.

🤖 Generated with Claude Code

New companion-code folder for a tutorial that never had one. The
tutorial's REPL examples are grouped into one runnable script per
section, with print() where seeing the output is the point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant