Repository navigation
Releases: TJ-Junhao/umber
Releases · TJ-Junhao/umber
Release list
v0.4.0
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
v0.3.2
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
Highlights
- Heatmaps, 2-D histograms and meshes take
render=ub.Render.VECTOR,ub.Render.RASTERorub.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.VECTORto keep one shape per cell, for example to edit cells in a vector editor. Smaller grids are unchanged.
New errors
render=ub.Render.RASTERon a mesh whose edges are not evenly spaced raisesUsageErrorat themesh()call. It raisesStyleErrorwhen 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.AUTOdraws such meshes as vector shapes instead.
What's Changed
- Draw large cell grids as one image by @TJ-Junhao in #136
- Version 0.3.1 by @TJ-Junhao in #137
Full Changelog: v0.3.0...v0.3.1
v0.3.0
Highlights
- Color: colormaps (
Cmap),ColorByfor scatter and bubble points,clim(), colorbars, and color scales shared across panels withFigure(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=Falsehides 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()andxticks()/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
StyleErrorwith 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
What's Changed
- Package links and legend layout cleanup by @TJ-Junhao in #78
- Split panel layout into measurement and placement by @TJ-Junhao in #79
- Rename BarSeries to Series by @TJ-Junhao in #80
- Lay out several axes on a grid by @TJ-Junhao in #81
- Add step lines by @TJ-Junhao in #82
- Align plot areas across the grid by @TJ-Junhao in #83
- Add reference lines and spans by @TJ-Junhao in #84
- Add bands by @TJ-Junhao in #85
- Keep limits exact when downsampling, and other drawing fixes by @TJ-Junhao in #89
- Validate color and scale arguments like the rest, and fix cmap format 2 by @TJ-Junhao in #88
- Keep automatic tick labels apart by @TJ-Junhao in #86
- Add error bars by @TJ-Junhao in #87
- Share axes across the grid by @TJ-Junhao in #90
- Format explicit ticks and log scales exactly by @TJ-Junhao in #92
- Add stems by @TJ-Junhao in #91
- Make a Linux x86_64 host the reference machine for output hashes by @TJ-Junhao in #93
- Add figure titles, title alignment and a merged legend by @TJ-Junhao in #95
- Refine the label-fit prices so nearly parallel bounds stay feasible by @TJ-Junhao in #94
- Add stacked areas by @TJ-Junhao in #96
- Add the Python grid API by @TJ-Junhao in #97
- Hide shared tick labels only behind panels with the same span by @TJ-Junhao in #98
- Add legend positions by @TJ-Junhao in #100
- Add box plots and grouped box plots by @TJ-Junhao in #99
- Add figure titles, title alignment and legend positions to Python by @TJ-Junhao in #101
- Benchmark a 20-panel grid, shared axes and the best legend position by @TJ-Junhao in #102
- Add violins and grouped violins by @TJ-Junhao in #103
- Add bubbles and the size legend by @TJ-Junhao in #104
- Version 0.2.0 by @TJ-Junhao in #105
- Document the 0.2 types and charts in the core overview, README and Distribution docs by @TJ-Junhao in #106
- Reject binary buffers as containers and check labeled ticks in the core's order by @TJ-Junhao in #107
- Fix violin quantiles on log axes, bound bubble sizes and scale KDE without the span by @TJ-Junhao in #108
- Blame the right cause for a narrow right legend, keep bottom legends clear of tick labels and keep extrema under the stroke halo by @TJ-Junhao in #109
Full Changelog: v0.1.0...v0.2.0
v0.1.0
What's Changed
- Spec: neutral positioning wording, define ScaleKind by @TJ-Junhao in #1
- Stop tracking design documents by @TJ-Junhao in #2
- M1: foundation and CI by @TJ-Junhao in #3
- M2: M4 downsampling by @TJ-Junhao in #5
- M2: color primitives by @TJ-Junhao in #4
- M2: scales and ticks by @TJ-Junhao in #6
- M3: bundled fonts by @TJ-Junhao in #7
- M3: text shaping and outlines by @TJ-Junhao in #8
- M4: scene model by @TJ-Junhao in #9
- M4: SVG backend by @TJ-Junhao in #10
- M4: PNG backend by @TJ-Junhao in #11
- M5: theme by @TJ-Junhao in #12
- M5: figure model by @TJ-Junhao in #13
- M5: layout and axes by @TJ-Junhao in #14
- M5: line and scatter by @TJ-Junhao in #15
- Professional public text by @TJ-Junhao in #18
- Release prep: 0.0.1 pre-alpha by @TJ-Junhao in #16
- Refactor R1: comparison gate and test support by @TJ-Junhao in #17
- Refactor: separate the figure model from the render pipeline by @TJ-Junhao in #19
- Refactor: split text into leaf modules by @TJ-Junhao in #21
- Refactor: share stroke and clip rules across backends by @TJ-Junhao in #20
- Refactor: validated stored series, limits and resolved mark colors by @TJ-Junhao in #22
- Refactor: split system font index, lookup and shaping by @TJ-Junhao in #23
- Refactor: split draw into chrome and mark modules by @TJ-Junhao in #24
- Refactor: one module for exact arithmetic by @TJ-Junhao in #25
- Refactor: typed coordinate spaces and policy enums by @TJ-Junhao in #26
- Refactor: settle the public API surface and shared primitives by @TJ-Junhao in #27
- Refactor: one TextItem adapter; Scene text shaping in its own module by @TJ-Junhao in #28
- Refactor: typed resolved marks and module skeletons by @TJ-Junhao in #31
- Output gate: extension check for new features by @TJ-Junhao in #30
- Binning, stacking and bar outlines by @TJ-Junhao in #32
- Layout: y tick labels outside the plot; padded auto limits; whole line ends by @TJ-Junhao in #33
- Golden gallery and larger theme titles by @TJ-Junhao in #29
- Bar marks by @TJ-Junhao in #34
- Grouped and stacked bars by @TJ-Junhao in #36
- Header legend and legend switch by @TJ-Junhao in #35
- Chips legend by @TJ-Junhao in #37
- Histograms by @TJ-Junhao in #38
- Direct labels by @TJ-Junhao in #39
- Structured errors: parameter and hint by @TJ-Junhao in #40
- Baseline at the lower limit; direct labels where a cut line leaves the plot by @TJ-Junhao in #42
- Core: integer inputs, error context and palette index by @TJ-Junhao in #44
- Python: documentation and typing checks by @TJ-Junhao in #43
- Bindings: values, enums and errors by @TJ-Junhao in #47
- Area mark; lines never fill by @TJ-Junhao in #46
- Python: error notes by @TJ-Junhao in #45
- Bindings: theme and figure by @TJ-Junhao in #48
- Readable numbers in error messages by @TJ-Junhao in #51
- Python: enums, Color and Scale by @TJ-Junhao in #50
- Python: argument and data conversion by @TJ-Junhao in #49
- Python: Theme by @TJ-Junhao in #53
- Per-series width and marker size by @TJ-Junhao in #52
- Core: continuous y axis by @TJ-Junhao in #55
- Python: Figure and Axes by @TJ-Junhao in #54
- Refactor: a continuous-only resolved y axis by @TJ-Junhao in #56
- Python: bars, histograms and quick functions by @TJ-Junhao in #57
- Python: typing tests and verification by @TJ-Junhao in #58
- Python: Size by @TJ-Junhao in #60
- Tick control by @TJ-Junhao in #59
- Python: area and FillStyle by @TJ-Junhao in #61
- Python: tick control by @TJ-Junhao in #62
- Python: one check order for every method by @TJ-Junhao in #63
- Examples by @TJ-Junhao in #64
- Store series values with a single copy by @TJ-Junhao in #65
- Keep the last x tick label inside the figure by @TJ-Junhao in #66
- Gallery: bars, histograms and legends by @TJ-Junhao in #41
- Wheel builds and PyPI publishing by @TJ-Junhao in #68
- Python: type parameter defaults by @TJ-Junhao in #70
- Fail fast when x tick labels cannot fit by @TJ-Junhao in #69
- Benchmarks by @TJ-Junhao in #67
- Faster marker blitting and data extents by @TJ-Junhao in #71
- Keep the plot wide enough for its x labels by @TJ-Junhao in #72
- PNG encoding at a faster compression level by @TJ-Junhao in #73
- README for the first release by @TJ-Junhao in #75
- Cleanups by @TJ-Junhao in #74
- Fail fast when the plot has no vertical room by @TJ-Junhao in #76
- Version 0.1.0 by @TJ-Junhao in #77
New Contributors
- @TJ-Junhao made their first contribution in #1
Full Changelog: https://github.com/TJ-Junhao/umber/commits/v0.1.0