Skip to content

v0.4.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Oct 02:56
· 2 commits to main since this release
a8d57d4

Highlights

  • PDF output. fig.save_pdf(path) and fig.to_pdf() write a single-page vector PDF with the fonts embedded as subsets, so text can be selected and searched. A 1,000,000-point line saves as PDF 4.5× faster than with matplotlib.
  • Your own fonts. Font.from_file(regular, bold=...) reads TrueType or OpenType files and Font.system(family) finds an installed family. A font without a bold face raises StyleError when bold text is drawn, unless it was created with bold_fallback=True.
  • New charts: contours (ax.contour(..., style=Contour.LINES | FILLED | BOTH)), pies and donuts (ub.pie, fig.add_pie_axes()), ECDFs, KDEs, strip and swarm plots, and event rows. Histograms gain style=Hist.STEP/STACKED, stat=Stat.FRACTION/DENSITY, cumulative=True and bin edges.
  • Long-form data with by= on line, step, scatter, area, ecdf, kde, hist and bar: one series per group, from pandas, polars, NumPy or lists.
  • Text on the chart: ax.text(), ax.annotate() with an arrow, and annotate=True on bars to write their values; automatic limits grow to fit them.
  • A second y axis with ax.twin_y(), sharing x, one legend and one palette.
  • Line breaks: "\n" starts a new line in titles, subtitles, pie titles, ax.text() and ax.annotate(). Other text refuses line breaks, and all text refuses other control characters, with an error that names the character and where line breaks are supported.
  • Text sizes per call: size= on titles, labels, legends, colorbars, text, annotations, bar values and pie labels; ax.xtick_labels(size=...) and ax.ytick_labels(size=...) for tick labels.
  • Jupyter and show(): a figure or an axes at the end of a notebook cell displays itself as one sharp PNG, and fig.show() (also on axes) displays it in a notebook or opens it in the system's image viewer elsewhere.
  • An Agent Skill for coding agents ships in the wheel: python -m umber skill install --agent claude-code (also codex, cursor, pi; --user for the home directory). Its API reference is generated from the installed version.
  • Smaller wheels: the largest wheel is about 2.9 MB, down from about 4 MB.

Changes to existing figures

Figures drawn by 0.3 code look the same in 0.4, except:

  • Points colored with ColorBy (scatter and bubbles) are outlined 0.5 pt in a shade of their own color that contrasts with the background (darker on light themes, lighter on Midnight), with a strength that grows the closer their color is to the background. Points near the middle of a diverging colormap stay visible; points that already stand out keep the background-colored outline. Fills and colorbars are unchanged.
  • Histograms in the Pigment theme separate their bars by 1 pt, as the Graphite and Midnight themes already did. Theme.PIGMENT.with_hist_gap(0) restores touching bars.

Changes to existing code

Python code written for 0.3 runs unchanged, except:

  • ub.Font is a class, no longer an Enum. The bundled fonts are still Font.SOURCE_SERIF_4, Font.IBM_PLEX_SANS, Font.GEIST, Font.INTER and Font.JETBRAINS_MONO, and work as before in Theme.with_title_font() and Theme.with_body_font(). Enum behaviour is gone: .name, .value, iterating over Font, Font["INTER"] and Font(3). repr(Font.INTER) is now Font.INTER. Fonts pickled by 0.3 cannot be loaded.
  • ub.Time is a type statement. Use it in annotations as before; isinstance(x, ub.Time) no longer works. Check for datetime.date, datetime.datetime or numpy.datetime64 instead.
  • The hint of the error raised when pickling a Figure now mentions save_pdf(), and two grid room errors word their hints differently.

All other changes to existing methods are new keyword arguments with defaults.

Rust (umber-core)

  • Font is now an enum of Bundled(BundledFont), File(..) and System(..), and is Clone but not Copy. The bundled fonts are the constants Font::SOURCE_SERIF_4, Font::IBM_PLEX_SANS, Font::GEIST, Font::INTER and Font::JETBRAINS_MONO; the former variants are BundledFont, which font_bytes and license_text now take. Theme::title_font() and Theme::body_font() return &Font.
  • Text: TextStyle::font is replaced by face: FaceId, Scene has a public fonts field, Scene::push_text takes &SceneFonts and returns Result, and FontLibrary::layout returns Result<TextLayout>.
  • AxesMut::legend(style, size) and legend_at(style, position, size) take a text size and return Result.
  • grouped_bar and stacked_bar take a ValueLabels argument. BarOptions has a new annotation field, ColorbarOptions a new size field, and HistOptions new style, cumulative and stat fields, with bins now a Bins; code that builds these structs with literals needs the new fields.
  • Figure::panels() yields Panel values (Cartesian or Pie) instead of &Axes, and axes_at on a pie cell returns an error.
  • Item has a new RotatedText variant; Mark has new variants for the new charts.
  • Error message fields are ErrorMessage instead of String; it dereferences to the same text.
  • SceneFonts::layout and Scene::push_text return Error::Style for text holding control characters, and setters that take a mark label check it when the mark is added.

New errors

  • A title, subtitle or x/y axis label wider than its room now raises StyleError when the figure is rendered, naming the text and the room in whole points that suffice, instead of being cut off at the edge of the figure or running into the next panel. Make the figure wider or lower the font scale with Theme.with_font_scale(); for a title with a fixed size=Size.pt(...), pass a smaller size.
  • Text holding a control character (\t, \r, U+0000 and the like), or a line break where text is one line (axis labels, legend labels, tick labels, category names, colorbar labels), now raises at the call instead of being drawn as a missing-glyph box. Group names in by= that hold a NUL character are refused instead of being cut at it.
  • Otherwise the new checks apply to the new arguments and methods; the one most likely to be met is StyleError for a custom font without a bold face (see bold_fallback above).

What's Changed

Full Changelog: v0.3.2...v0.4.0