Changelog
Version 0.5.0
New:
mp.tstack(*plots): animations as values. The third stacking operation, arranging plots in time rather than across the screen. Supportslen, indexing and slicing (a[0],a[10:20],a[::-1]),mapfor applying a combinator to every frame,playfor showing it in the terminal, andsavegif. Frames are padded to a common size, so an animation cannot change shape while it plays.mp.animation(array): atstackstraight from an array with a time axis, taking whatmp.imagetakes with a leading frame index.mp.animate(): a context manager that runs an animation loop.anim.update(plot)writes one frame and returns the string it wrote. Optionally caps the frame rate (fps=), keeps the frames (record=True, readable asanim.frames), and ends quietly on Ctrl-C (stop_on_interrupt=True). Reports the rate actually achieved asanim.achieved_fps.anim.print(...): print a line above a running animation instead of through it. Also available as a stream,anim.out, forprint(file=...),logging.StreamHandler, or redirectingsys.stdoutfor the block.mp.tstack(...).savegif(f, fps="achieved")encodes a recorded animation at the frame rate it really ran at, rather than the one that was requested.life.pyexample: Conway’s Game of Life, demonstrating differential redraw.quickstart3.pyexample:quickstart2.pywith the animation loop handed tomp.animate.boing.pyexample: the Amiga Boing Ball, built withmp.animationfrom a computed array of frames, spinning by palette cycling as the original did, with the cycling palette shown underneath it.- A compatibility page (
pages/compatibility.md): every escape sequence the library emits, the terminal behaviours it relies on, the glyph blocks it draws with, and which terminals are actually tested. terminal_test.pyexample: does your terminal render matthewplotlib correctly? Four stages exercising every escape sequence the library can emit, each saying what it should look like. Measures the terminal’s width and draws to it, so that the last stage puts a plot against the right margin.
Change:
mp.save_animation(plots, filename, ...)is retired in favour ofmp.tstack(*plots).savegif(filename, ...).teacher_student.pytakes a--log-everyargument, and logs its loss withanim.print.- Animated redraws now speak only VT100, apart from the SGR colours.
CHA(absolute column) became a carriage return plus a cursor forward,CNL(next line) a carriage return plus a cursor down, andECH(erase character) written spaces. The screens are identical – across every example snapshot only the byte counts moved – and the point isCHA, whose old use depended on it cancelling a deferred wrap, which is the thing terminals disagree about most. A full repaint now costs less rather than more; a sparse diff costs one byte more. Seenotes/closed/escape-vocabulary.md.
Fix:
dashboard.pyno longer raisesNameErrorwhen asked to save an unbounded run.axesno longer paints theylabeldown the plot’s right-hand border when the y tick labels are narrower thanypad + 1. The tick gutter now widens to make room. An absentylabelno longer erases that border either.- Correct the Python version classifiers, which still advertised 3.10 and 3.11 after 0.4.0 raised the requirement to 3.12.
Dev:
tests/test_exports.pychecks that everythingplots,colormapsandanimationsdefine is reachable asmp.something, deriving the expectation from the modules rather than from a list, so adding a feature does not mean editing a third file.- Add module docstrings for
core,colorsanddata, so every module now introduces itself in the API reference. - Escape sequences are now tested against a real terminal (a tmux pane, see
tests/test_terminal.pyandtests/tmux.py) rather than a hand-written emulator, which retires the emulator and makes tmux a development dependency. Seenotes/terminal-test-backend.md. - The example smoke tests are replaced by snapshot tests. Every example is replayed into a real terminal print by print and compared against a golden in
tests/goldens/, cell by cell in both glyph and colour, along with the byte cost of each print and a digest of the image it saved. Regenerate withmake goldens. Seenotes/closed/example-snapshot-tests.md. life.pyseedsnp.random.seedrather thannp.random.default_rng, whose stream NumPy does not guarantee across releases. Its initial board, andimages/life.gif, change accordingly.TestEmittedVocabularypins the set of escape sequences the renderer is allowed to emit, over every path that emits any. It is the executable form of the compatibility page, so the page cannot go quietly out of date.
Version 0.4.0
New:
- Add differential redraw for animated plots:
print(plot - prev)repaints only the cells that changed. SubtractNonefor the first frame.
Change:
- Every string the library returns is now shaped for a plain
print. In particularclearstr(-plot) must no longer be printed withend="".
Fix:
clearstr(-plot) erases only the plot’s own rows, rather than everything below it on screen, and handles a plot with no rows.- Stop passing the deprecated
modeargument to Pillow, which will be an error in Pillow 13. - Declare the Python version actually required (3.12, for
typealiases); the package never supported the 3.10 it claimed.
Version 0.3.8
Fix:
- Make automatic
wraplayout work without an attached terminal.
Version 0.3.7
Fix:
- Fix BIDS colormaps (magma, inferno, plasma, viridis) returning wrong dtype.
Dev:
- Add unit test suite and
make testtarget. - Add integration tests for all examples.
- Add
pytestto dev dependencies. - Add
tyroCLI argument parsing to long-running examples.
Version 0.3.6
Fix:
- Fix operator precedence bug in
isblank/isnonblank(affecteddstackoverlays). - Fix
axes.__repr__returning"border(...)"instead of"axes(...)". - Accept
listas a valid color input inparse_color. - Fix
save_animationplaying GIFs twice instead of once whenrepeat=False. - Fix mypy errors.
Version 0.3.5
New:
- Diverging colormaps divreds, divgreens, divblues.
Fix:
- Fix bug in bar chart layout.
Version 0.3.4
New:
- Per-column and per-bar colours in column and bar plots.
Fix:
- Fix bug in column/bar spacing implementation.
Version 0.3.3
New:
dstack2for stacking data, extend axes to more datatypes.teacher_student.pyexample
Fix:
- Missing title parameter from border.
Notes:
- Plausibly
dstack2should be the default anddstackshould be removed.
Version 0.3.2
New:
- Transpose parameter for wrap.
Version 0.3.1
New:
- Axes subplot type. Takes a scatter plot or function2 plot as input, and adds axes with labels and ticks. Basic API.
- Animated version of quickstart example.
Version 0.3.0
Breaking changes:
- scatter and scatter3 take xs, ys, (zs), and color as series tuples in positional arguments.
- removed function plot type (since scatter is now much easier to use).
New:
- scatter and scatter3 accept cs, an array of colors (one for each point), and plot using them, using weighted averaging to combine plots.
- scatter and scatter3 now accept multiple series at once.
- special series for X/Y/Z axes.
- some new examples (deigned by Gemini 2.5 pro): voronoi, dashboard, mandelbrot.
Version 0.2.1
Fix:
- Regenerate documentation.
- Update version number properly.
Version 0.2.0
Breaking changes:
- Various argument name changes, especially for colors.
- Inverted
cybercolormap. - Move
plots.border.Styletocore.BoxStyle.
New:
- Configurable background colour for image rendering.
- 3d scatterplot.
- Discrete colourmaps are now cyclic.
- New discrete colourmaps
tableau,nouveau. - New border styles.
- Export animations as GIFs.
- New configuration options for bar/column sizes.
Internal:
- Refactor backend to use numpy arrays rather than nested lists.
Version 0.1.2
Breaking changes:
- Change operators used for shortcuts.
- Rename
fimagetofunction2.
New:
- New plot types:
bars,columns,histogram,vistogram,histogram2,function. - More documentation.
- Generated markdown documentation.
- Additional examples.
Dependencies:
- Make example dependency on
scikit-learnexplicit.
Version 0.1.1
New:
- Add type annotations.
Dependencies:
- Add
mypyas a dev dependency. - Remove dependency on
unscii(bundle the specific version of the font we want).
Internal:
- Refactor from long single-file script to multi-file library.
Version 0.1.0
Much unstructured development.