Repository navigation
Highlights
- PDF output.
fig.save_pdf(path)andfig.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 andFont.system(family)finds an installed family. A font without a bold face raisesStyleErrorwhen bold text is drawn, unless it was created withbold_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 gainstyle=Hist.STEP/STACKED,stat=Stat.FRACTION/DENSITY,cumulative=Trueand bin edges. - Long-form data with
by=online,step,scatter,area,ecdf,kde,histandbar: one series per group, from pandas, polars, NumPy or lists. - Text on the chart:
ax.text(),ax.annotate()with an arrow, andannotate=Trueon 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()andax.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=...)andax.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, andfig.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(alsocodex,cursor,pi;--userfor 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.Fontis a class, no longer anEnum. The bundled fonts are stillFont.SOURCE_SERIF_4,Font.IBM_PLEX_SANS,Font.GEIST,Font.INTERandFont.JETBRAINS_MONO, and work as before inTheme.with_title_font()andTheme.with_body_font(). Enum behaviour is gone:.name,.value, iterating overFont,Font["INTER"]andFont(3).repr(Font.INTER)is nowFont.INTER. Fonts pickled by 0.3 cannot be loaded.ub.Timeis atypestatement. Use it in annotations as before;isinstance(x, ub.Time)no longer works. Check fordatetime.date,datetime.datetimeornumpy.datetime64instead.- The hint of the error raised when pickling a
Figurenow mentionssave_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)
Fontis now an enum ofBundled(BundledFont),File(..)andSystem(..), and isClonebut notCopy. The bundled fonts are the constantsFont::SOURCE_SERIF_4,Font::IBM_PLEX_SANS,Font::GEIST,Font::INTERandFont::JETBRAINS_MONO; the former variants areBundledFont, whichfont_bytesandlicense_textnow take.Theme::title_font()andTheme::body_font()return&Font.- Text:
TextStyle::fontis replaced byface: FaceId,Scenehas a publicfontsfield,Scene::push_texttakes&SceneFontsand returnsResult, andFontLibrary::layoutreturnsResult<TextLayout>. AxesMut::legend(style, size)andlegend_at(style, position, size)take a text size and returnResult.grouped_barandstacked_bartake aValueLabelsargument.BarOptionshas a newannotationfield,ColorbarOptionsa newsizefield, andHistOptionsnewstyle,cumulativeandstatfields, withbinsnow aBins; code that builds these structs with literals needs the new fields.Figure::panels()yieldsPanelvalues (CartesianorPie) instead of&Axes, andaxes_aton a pie cell returns an error.Itemhas a newRotatedTextvariant;Markhas new variants for the new charts.- Error message fields are
ErrorMessageinstead ofString; it dereferences to the same text. SceneFonts::layoutandScene::push_textreturnError::Stylefor 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
StyleErrorwhen 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 withTheme.with_font_scale(); for a title with a fixedsize=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 inby=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
StyleErrorfor a custom font without a bold face (seebold_fallbackabove).
What's Changed
- Ship an Agent Skill with the package by @TJ-Junhao in #144
- Add histogram variants, ECDF and KDE by @TJ-Junhao in #145
- Pass the PNG canvas and each item as values instead of long parameter lists by @TJ-Junhao in #146
- Make fonts values instead of a closed list by @TJ-Junhao in #147
- Add event, strip and swarm plots by @TJ-Junhao in #148
- Set text sizes per call by @TJ-Junhao in #149
- Fix what the linters flagged instead of silencing them by @TJ-Junhao in #150
- Add contour lines and filled contours by @TJ-Junhao in #152
- Group long-form data with by= by @TJ-Junhao in #151
- Load fonts from files and from installed families by @TJ-Junhao in #153
- Write figures as PDF by @TJ-Junhao in #156
- Build release wheels with LTO and stripped symbols by @TJ-Junhao in #157
- Add text, annotations and bar value labels by @TJ-Junhao in #154
- Add pie and donut charts by @TJ-Junhao in #155
- Save figures as PDF from Python and check every corpus PDF by @TJ-Junhao in #158
- Benchmark PDF output next to PNG and SVG by @TJ-Junhao in #159
- Compress PDF cell images faster by @TJ-Junhao in #160
- Add a twin y axis by @TJ-Junhao in #161
- Write the Agent Skill's guide by @TJ-Junhao in #162
- Version 0.4.0 by @TJ-Junhao in #163
- Refuse titles and axis titles that do not fit by @TJ-Junhao in #164
- Line breaks in titles, subtitles, text and annotations by @TJ-Junhao in #165
- Describe line breaks and title room errors in the READMEs and the skill by @TJ-Junhao in #166
- Open the READMEs with a gallery of twelve charts by @TJ-Junhao in #167
- Separate Pigment histogram bars and refresh the gallery by @TJ-Junhao in #171
- Show figures in Jupyter and with show() by @TJ-Junhao in #168
- Lay out pie panels in their whole grid cell by @TJ-Junhao in #169
- Outline color-mapped points that are close to the background by @TJ-Junhao in #170
Full Changelog: v0.3.2...v0.4.0