Skip to content

Releases: TJ-Junhao/umber

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 02:56
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

v0.3.2

Choose a tag to compare

@github-actions github-actions released this 18 Oct 06:18
dc06006

Highlights

  • Heatmaps, 2-D histograms and meshes drawn as one image encode faster in SVG and produce smaller files. A 1,000 × 1,000 heatmap's SVG renders in about 0.1 s instead of 0.2 s and drops from 4.5 MB to 2.6 MB. Decoded pixels, vector output and PNG output are unchanged.
  • The performance section of the README now compares end-to-end Python calls with matplotlib 3.11.2 on a standard GitHub Actions runner. umber is faster in every case measured, from 1.1× (hexbin) to 3.7× (a small figure with a legend), and imports 4.7× faster.

Fixes

  • Hexbins whose fit and tick labels alternated without settling, which failed with "the hexagon bounds and tick labels do not settle" (for example 1,000,000 normal points at grid size 50), now render. Layouts that already settled are unchanged.
  • Several hexbins on one axes share one lattice, so their hexagons stay regular when their ranges differ.
  • When an axis uses fewer automatic ticks to make room and the remaining labels need more decimals, the labels are kept apart instead of overlapping. The axis range does not move.

New errors

  • Hexbins on one axes whose ranges are too far apart to share one lattice (about 2⁴⁰ cells) raise DataError: "the hexbin ranges are too far apart for one lattice of regular hexagons on these axes.", with the hint "draw them on separate axes, or set explicit limits."

What's Changed

  • Benchmark Python calls next to matplotlib on GitHub's standard runner by @TJ-Junhao in #138
  • Keep tick labels apart when fewer ticks widen the labels by @TJ-Junhao in #139
  • Settle hexbin layouts that cycled with their tick labels by @TJ-Junhao in #141
  • Measure coverage in CI and report it to Codecov by @TJ-Junhao in #140
  • Encode large embedded images faster in SVG by @TJ-Junhao in #142
  • Version 0.3.2 by @TJ-Junhao in #143

Full Changelog: v0.3.1...v0.3.2

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 17 Oct 17:38
97f7dbf

Highlights

  • Heatmaps, 2-D histograms and meshes take render=ub.Render.VECTOR, ub.Render.RASTER or ub.AUTO (the default). With AUTO, grids of at least 10,000 cells (100 × 100) are drawn as one image with one pixel per cell; smaller grids stay vector shapes.
  • In SVG the image is scaled without smoothing, so cells stay sharp at any zoom in browsers, librsvg, resvg, cairosvg and Inkscape; labels, axes, annotations and colorbars stay vector. In PNG each pixel takes the exact area-weighted average of the cells it covers.
  • A 1,000 × 1,000 heatmap's SVG drops from 94 MB to 4.5 MB and renders in about 0.2 s; its PNG renders in about 0.15 s instead of 0.9 s.

Changes to existing figures

  • Heatmaps, 2-D histograms and evenly spaced meshes with at least 10,000 cells are now drawn as an image by default. Pass render=ub.Render.VECTOR to keep one shape per cell, for example to edit cells in a vector editor. Smaller grids are unchanged.

New errors

  • render=ub.Render.RASTER on a mesh whose edges are not evenly spaced raises UsageError at the mesh() call. It raises StyleError when rendering if the limits would move an edge by more than 0.001 pt or a cut cell would reach more than 10,000 pt past them. ub.AUTO draws such meshes as vector shapes instead.

What's Changed

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 12:08
cf94336

Highlights

  • Color: colormaps (Cmap), ColorBy for scatter and bubble points, clim(), colorbars, and color scales shared across panels with Figure(share_color=...).
  • New charts: heatmaps on two category axes, meshes, 2-D histograms and hexbins.
  • Horizontal bars, boxes and violins, and dot plots, on a category y axis.
  • Time axes with Scale.time(): calendar ticks, concise or ISO 8601 labels.
  • Wheels for free-threaded Python 3.14t and 3.15t.

Changes to existing figures

Code written for 0.2 runs unchanged, apart from the new error below, but some figures look different:

  • Baseline. The dark line at zero (or at the lower edge) is now drawn only for bars, histograms, areas, stacked areas and stems. Lines, scatter plots, boxes, violins, error bars and the other charts show a regular gridline instead. To bring the line back, call ax.baseline(shown=True); shown=False hides it on any chart.
  • Automatic limits and ticks. Limits now follow the data with 5 % padding at each end instead of being rounded out to a tick, and ticks are round multiples of 1, 2, 2.5 or 5 × 10ⁿ inside them. Bars, histograms, areas and stems still start at zero. Set xlim()/ylim() and xticks()/yticks() to fix them explicitly.
  • Crowded category labels. When category labels would overlap, every k-th category is labelled (k = 1, 2, 5, 10, …), starting with the first.

New errors

  • A tick format with fixed decimals that cannot label any value in an automatic axis or colorbar range now raises StyleError with a hint, instead of drawing the axis without ticks. For example, TickFormat.fixed(0) on data between 0.005 and 0.009.

What's Changed

  • End vertical rules and spans at a lower-limit baseline by @TJ-Junhao in #110
  • Add instants, calendar ticks and concise time labels to the core by @TJ-Junhao in #112
  • Fit automatic limits to bubble circles and show translucent fills as drawn in legend swatches by @TJ-Junhao in #111
  • Add colormaps and the theme's sequential and diverging defaults by @TJ-Junhao in #113
  • Make the y axis an axis of any kind in the core by @TJ-Junhao in #115
  • Support free-threaded CPython 3.14t by @TJ-Junhao in #114
  • Color scatter and bubble points by value with ColorBy, and add clim by @TJ-Junhao in #116
  • Draw bars, boxes and violins horizontally on a category y axis, and scatter as a dot plot by @TJ-Junhao in #117
  • Add time axes from Python through the core by @TJ-Junhao in #118
  • Draw a colorbar for color-mapped marks by @TJ-Junhao in #119
  • Support Python 3.15 and 3.15t, build free-threaded stable-ABI wheels and keep frame pointers by @TJ-Junhao in #120
  • Add mesh, hist2d and hexbin by @TJ-Junhao in #122
  • Add heatmaps on two category axes by @TJ-Junhao in #121
  • Benchmark heatmaps, 2-D histograms, hexbins and time-axis lines by @TJ-Junhao in #125
  • Share color scales across panels and draw row, column and figure colorbars by @TJ-Junhao in #123
  • State room errors in whole points that suffice by @TJ-Junhao in #126
  • Draw meshes and bubbles on time axes by @TJ-Junhao in #124
  • Describe colormaps, cell charts, horizontal charts and time axes in the READMEs by @TJ-Junhao in #127
  • Version 0.3.0 by @TJ-Junhao in #128
  • Map each heatmap cell to its color once by @TJ-Junhao in #129
  • Label every k-th category when category labels would overlap by @TJ-Junhao in #130
  • Meet mesh, 2-D histogram and hexbin cells without seams by @TJ-Junhao in #131
  • Draw the baseline only for marks that grow from zero, and add Axes.baseline by @TJ-Junhao in #132
  • Let automatic limits follow the data, with round ticks inside them by @TJ-Junhao in #133
  • Refuse a tick format that cannot show any automatic tick by @TJ-Junhao in #134
  • Render the README images and benchmark table again by @TJ-Junhao in #135

Full Changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 04:44
7dd06ae

What's Changed

Full Changelog: v0.1.0...v0.2.0

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 14:26
7866fb3

What's Changed

New Contributors

Full Changelog: https://github.com/TJ-Junhao/umber/commits/v0.1.0