You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Grouped style.py, colors.py, ticker.py, and dates.py into plotpress/style/ -- the "how a value becomes appearance" cluster
(Style, colormaps, tick locating/formatting, its datetime extension). style.py becomes style/__init__.py (it names the package); colors.py, ticker.py, dates.py become plain siblings with no re-export. The
genuinely public API this exposes (plotpress.Normalize, plotpress. register_cmap, etc.) is unaffected -- it's re-exported through plotpress/__init__.py's existing lazy-attribute layer, which only needed
its internal path strings updated. Code importing plotpress.colors/ .ticker/.dates directly needs the style.-prefixed path.
Moved qt.py into plotpress/gui/ and png.py into plotpress/backends/ -- png.py is only ever used by the render
backends (SVG/Vega/Vega-Lite embedding PNG data URIs), never by axes.py
or anything outside backends/.
Grouped the remaining top-level modules into backends/ and core/. svg/, raster.py, vega.py, vega_lite.py, and _interactive.py
(+ _js/) moved into plotpress/backends/ -- every format a Figure
renders itself to, matching AGENTS.md's own render-pipeline diagram. artists.py, primitives.py, and transform.py moved into plotpress/core/ -- the shared scene/geometry layer every backend reads
from. Neither new package re-exports (unlike figure//svg/'s own __init__.pys, which preserve their pre-split single-file import path on
purpose): these were already independent top-level modules, so there is no
single prior path to preserve, and the new one is plotpress.backends.svg/ plotpress.core.artists/etc. This does change any code importing plotpress.svg/plotpress.raster/plotpress.vega/plotpress.vega_lite/ plotpress._interactive/plotpress.artists/plotpress.primitives/ plotpress.transform directly (all internal-facing, underscore-prefixed
members throughout) -- update those imports to the backends./core.
prefixed path.
Moved the package to a src/ layout.plotpress/ now lives at src/plotpress/ rather than the repo root, so an accidental import plotpress while developing can't silently resolve to the working tree
instead of the actually-installed package. No public API or import path
changed (import plotpress is identical); this only moves where the
source lives on disk. If you have a local editable install, re-run pip install -e . after pulling this.
figure.py split into plotpress/figure/. The root object had grown to
5000+ lines; it's now six submodules -- _core (Figure itself, plus the
grid/group machinery it's genuinely mutually coupled to), the two leaf
modules it depends on (_layout, _html_options), and three things built from a Figure rather than needed by it (_template, _report, _io) -- all re-exported from plotpress/figure/__init__.py. No public
API changed.
svg.py split into plotpress/svg/. The SVG backend had grown to
3300+ lines across 90 top-level functions with no classes to group
them; it's now eight submodules by concern (formatting, ticks/frame,
text/annotations, legend, per-artist rendering, Figure.group() boxes,
the entry point, and the interactive-HTML metadata payloads), all
re-exported from plotpress/svg/__init__.py so every existing from plotpress.svg import X keeps resolving unchanged. No public API
changed.
The interactive toolbar's JS moved out of _interactive.py into plotpress/_js/*.js. The Python file had grown to ~5650 lines, nearly
all of it one JS string literal that had roughly doubled this session
from the Slice tool alone. The JS is now split into ten real .js files
by tool/feature (toolbar/pan-zoom, mode buttons, Slice, ticks/pins,
Extract, Save, sliders, ...), assembled into the same script at import
time -- verified byte-for-byte identical to the pre-split output. No
public API changed.
Fixed
set_aspect/set_box_aspect reject a non-positive value.aspect=0
used to crash the whole render with a ZeroDivisionError; a negative
aspect silently corrupted that axes' geometry instead. Both now raise ValueError at the call site.
An explicit, non-positive limit on a log axis now raises, instead of
crashing or silently blanking the axis.set_ylim(-5, -1) on a
log-scaled axis used to crash tick generation with ValueError: math domain error; set_xlim(-1, 100) used to silently NaN-blank the whole
axis with no error. Both close at the same shared validation point,
regardless of the order set_xscale/set_xlim/set_ylim were called in.
A one-sided limit (the open end left to autoscale, e.g. set_ylim(bottom= -5)) used to slip past this same check and still silently blank the
axis -- it is now validated per end, not only when both ends are set.
violinplot()/kdeplot() no longer crash on a constant-valued sample
once it's large enough (>= 4000 points) to use the binned KDE estimator --
the degenerate grid produced NaN positions that crashed np.bincount.
get_cmap()/register_cmap() no longer hand out the shared colormap
array by reference. Mutating a value returned from either function, or
a LUT already passed to register_cmap(), used to silently corrupt that
colormap for every other figure/artist in the process; both now always
return/store a copy, on every path (registering a colormap and then
mutating what it handed back used to still corrupt the registry).
Huge-line decimation no longer lets a NaN mask a real peak. A pixel
column containing both a genuine extreme value and a NaN (a common
shape for a real time series with missing samples) used to pick the NaN
as that column's rendered maximum, silently dropping the true peak.
Figure.to_vega()/to_vega_lite() now honor errorbar(..., errorevery=)
and export a mapped marker shape (square/diamond/the four triangle_*) instead of always rendering a circle. A marker shape with no
native Vega/Vega-Lite equivalent (+/x/|/_) still falls back to a
circle, now with a caveat naming the axes instead of silently.
hist() now ignores non-finite values, matching every sibling
distribution method (kdeplot/ecdfplot/rugplot/boxplot/ violinplot) -- it used to raise a bare, context-free NumPy error on a
NaN in the data. It also now warns when a dataset had no finite values at
all and was dropped entirely, matching boxplot()/violinplot() below.
boxplot()/violinplot() warn when a dataset is dropped entirely
(all its values were non-finite) instead of silently rendering one fewer
box/violin with no indication anything was missing.
Figure.print_layout_summary()/Axes.print_summary() no longer report
a false "OK" when to_vega()/to_vega_lite() actually raised -- the
crash now shows up as a gap in the summary instead of being swallowed. Axes.print_summary() now also flags when there is a figure-level export
gap it can't attribute to that specific axes, rather than only checking
its own axes and missing one it can't name.
Documentation
Several docs gallery scripts and cross-references still pointed at
pre-reorganization module paths (plotpress.raster, plotpress. artists, and stale :mod:/:class:/:func: roles across several
docstrings) after the moves above. None were caught by this session's own
earlier docs-build checks, because sphinx-gallery caches each script's
execution by a hash of its own source text -- a script whose only problem
was its import target moving elsewhere never re-executed, and kept
reusing its stale pre-move result build after build. Fixed, and confirmed
this time with every gallery cache wiped first so every script actually
re-ran.