Repository navigation
Releases: physwkim/rsplot
Release list
0.6.1 — storage params blocks, colours in the target's encoding
Fixed
- rsplot: every per-draw params block — the curve pipelines (line,
markers, caps, fill, error bars), the data-area clear, the image tiles, the
3D scene pipelines and the volume ray-caster — is bound as a read-only
storage buffer instead of a uniform. On Windows' DX12 backend with the WARP
software adapter (a GPU-less VM) every curve in a pass read the last
curve's uniform, so all curves took the last curve's colour; storage reads
were per-curve correct. The block layouts are unchanged. - rsplot: curve, per-vertex, dashed-gap and data-background colours are
uploaded in the render target's encoding: sRGB bytes for a non-sRGB target
(egui-wgpu's swapchain), linear for an sRGB one. They were always
linearised, which on the non-sRGB target drew every colour darker than its
Color32and than egui's own legend swatches (#4f9bffshowed as
(20, 84, 255)); PNG export was affected the same way. - rsplot: the 2D image path uploads its colour texels in the render
target's encoding too: the colormap LUT and direct-RGBA tiles are
Rgba8Unormfor a non-sRGB target andRgba8UnormSrgbfor an sRGB one,
and the colormap'snan_colorfollows the same rule. They were always
sRGB-decoded to linear, which on egui-wgpu's non-sRGB swapchain drew every
colormapped image and RGBA image darker than its colormap (viridis' mid
teal(33, 145, 140)showed as(4, 71, 66)). - rsplot: the 3D scene (
paint_scene3d,SceneWidget,ScalarFieldView,
the volume cut plane and iso-surfaces) is rendered into the sRGB variant of
the surface format and the blit encodes the linear result to sRGB when the
surface is non-sRGB, so geometry, mesh shading, fog, image layers and the
background now show at theirColor32values on egui-wgpu's swapchain
instead of darker.snapshot_scene3d/SceneWidget::snapshotread back
the sRGB offscreen target, so their PNGs carry sRGB-encoded bytes whatever
the surface format (they were as dark as the screen). - rsplot:
VolumeRaycasteruploads its voxel colours in the render
target's encoding — the sRGB bytes as is for egui-wgpu's non-sRGB swapchain
(unchanged there), linearised for an sRGB target, where the composite used
to be encoded a second time on store and showed washed out (an opaque
(255, 128, 0)voxel read back as(255, 188, 0)).
0.6.0 — egui 0.36 / wgpu 30, deferred GPU sync, form helpers
Changed
- egui / egui-wgpu 0.36 (wgpu 30), MSRV 1.95.
rsplotre-exports
egui, so downstreams move to 0.36 with it — hence the minor bump. Adapted:
wgpu 30'sOptionvertex buffers and fallibleget_mapped_range, egui's
Panel::show_inside→show,egui_kittest::create_render_statetaking
RendererOptions; the headless widget tests run through
test_util::HeadlessRun, since epaint 0.36 panics when an unapplied
TexturesDeltais dropped. - rsplot:
WgpuBackenddeferssync_gpu_itemsto oneflush_sceneper
frame, so N item mutations (add / remove / update, z, visibility, clear)
rebuild the GPU scene once instead of N times; unchanged z / visibility
writes no longer dirty the scene. - rsplot: the title and the x, y, y2 and extra-axis labels lay out
single-line and elide with…to their gutter run instead of being clipped
mid-glyph on a narrow plot; overlapping tick labels are culled on every
gutter (tick marks never). - rsplot: the compact-toolbar overflow button uses U+2026, which egui's
bundled font covers (U+22EF rendered as the tofu box).
Added
- rsplot:
widget::form— label / fill / group helpers for Qt-style
(QFormLayout) dialog rows in one egui pass; the colormap, print and
limits dialogs use them. - rsplot: a whole-widget plot background:
set_background_colors' first
argument was dropped, so a light canvas over a dark host panel got dark
tick labels on still-dark gutters. When set,PlotViewpaints the widget
rect with it under the data layer. - Documented that hosts must append a broad-coverage fallback font for the
arrow and box-drawing glyphs the ROI descriptions, the style selector and
the image-compare toolbar use.
Fixed
- rsplot: a range ROI's name label stays inside the data area instead of
landing in the title gutter over the plot title.
Full changelog: v0.5.6...v0.6.0
0.5.6 — drop the printers crate (no CUPS build dep)
Changed
- rsplot: the toolbar Print action no longer depends on the
printers
crate, so a default build links no CUPS library (-lcups) and needs no
libcups2-devat build time. Printer enumeration and job submission now shell
out to thelpstat/lpcommand-line tools. Printing works wherever those
are onPATH(CUPS on Linux/macOS); on platforms without them (e.g. Windows)
the printer list is empty and the print action reports no destination
(print_graphreturnsOk(false)). The publicprint_graph/
print_graph_tosignatures are unchanged.
Removed
- rsplot: the
printerscrate dependency (and its transitive CUPS /
libcupsbuild requirement).
0.5.5 — EPICS backends on epics-rs 0.24
Changed
- Bumped the EPICS backends
epics-ca-rs/epics-base-rs/epics-pva-rs
to 0.24.0 (from 0.22.x), affectingrsdm'sca/pva/calcfeatures
only. Three breaking API changes were adapted:ConnectionEvent::Unresponsivewas removed — 0.24 folds the echo-timeout
intoDisconnected(an unresponsive circuit disconnects every consumer; the
distinction now survives only inside the client'sChannelState). rsdm
already handled both identically.- The pvAccess RPC reply became
RpcReply(an enum) instead of a
(descriptor, value)tuple; itsEmptyvariant is pvxs's no-value
ExecOp::reply().rsdmreads the value throughRpcReply::into_value,
treatingEmptyas the existing "connected, no scalar sample" case. EnumInfobecame#[non_exhaustive](it gained astring_form); a test
constructs it viaEnumInfo::newinstead of a struct literal.
0.5.4 — per-crate README
A documentation-only patch release. No code, API, or behaviour changes.
Added
rsdmandadl2rsdmnow carry a README, which crates.io renders on each
crate's page. Both crates previously shipped without areadmefield or a
README file, so their crates.io pages showed nothing whilersplot's
rendered normally. crates.io bakes the README per published version, so this
is why a new release was cut rather than an edit to 0.5.3.
0.5.3 — Round-4 parity fixes
A regression release. A workspace-wide upstream-parity audit (silx / PyDM /
adl2pydm + MEDM C) found that three of the fixes 0.5.2 shipped were wrong, and
turned up ten further divergences from the reference behaviour. All are fixed
here. VolumeRaycaster users should upgrade: the volume it rendered in 0.5.2
carried no thickness cue and lost the hue of faint voxels.
Fixed — rsplot
- Volume opacity depends on the thickness a ray crosses again. 0.5.2's
"Beer-Lambert" correction divided by the step count, an exponent carrying no
world distance, so every ray accumulated the same transmittance whatever chord
it traversed: a uniform volume rendered as a flat silhouette, and at the
default 256 steps the correction was exactly the identity. Each sample is now
corrected from a reference spacing (box_diagonal / 256, a world distance),
which keeps the step-count invariance 0.5.2 was after while restoring the
density cue. A ray crossing the full box diagonal at the default step count
renders exactly as before. - Faint voxels keep their colour. The premultiplied 3-D texture 0.5.2
introduced stored the productrgb · ain 8 bits, and the shader must divide
the coverage back out to recover the straight colour — a product that at
coveragearesolves the quotient only to steps of1/a. An authored
(255, 128, 0)voxel ata = 3/255read back as(255, 170, 0); at
a = 1/255no hue survived at all. The texture is nowRgba16Float, which
carries the straight colour exactly at every coverage while the filter still
interpolates premultiplied colour (no return of the dark fringe). This
doubles the volume texture's VRAM. VolumeRaycaster::removeno longer blanks another view. Two views sharing
aVolumeIdshare one texture, by design;removefreed it outright, so the
survivor silently rendered nothing. The texture is now claim-counted and lives
exactly as long as the views holding its id. Dropping a view releases its
claim too, so aVolumeRaycasterthat is simply dropped no longer pins its
VRAM for the app's lifetime.- Alt+Wheel zooms X only and Shift+Wheel zooms Y/Y2 only, the silx bindings
the axes menu already advertised. Plain wheel and keep-aspect are unchanged. - Middle-button drag pans in every interaction mode, as in silx. The
existing right-button pan is kept. - The Reset-Zoom toolbar button disables when neither axis autoscales, and
its tooltip names the single autoscaling axis when exactly one is on. - Programmatic
set_limitsand toolbar Zoom-In/Out repair their limits.
Inverted, degenerate or float32-overflowing ranges reached the transform
unrepaired; every view-limits commit now runs the same clamp, including the
Y2 and extra-axis paths. - The colormap dialog's histogram drops samples equal to the range maximum,
asHistogramnddoes with its default half-open last bin. ScatterBINNED_STATISTIC drops points on the max edge instead of
clamping them into the last bin, matchingscipy.stats.binned_statistic_2d
as silx calls it. A degenerate extent now admits no point rather than
collapsing every point into bin 0.
Fixed — rsdm
calc://re-evaluates when a child connects or disconnects. PyDM
re-emits on a connection-state change; rsdm only watched values.calc://no longer retriggers on a child's alarm or metadata change, only
on an actual value change, as PyDM'supdatelist specifies.- A
dialect = medmexpression reading operandIorJre-evaluates on an
alarm status / severity change. MEDM'ssetDynamicAttrMonitorFlagsadds
monitorStatusChangedandmonitorSeverityChangedexactly when the
expression uses those operands. rsdm never watched severity, so a transition
left the calc showing a stale value, and it had no alarm status to read at all
— operandIbound a constant0.0. Both are now monitored, and only when
the expression reads them.
Added — rsdm
ChannelState::statuscarries the wire alarm status — the record'sSTAT
forca://, the pvAccessalarm.statusenum forpva://. It backs the MEDM
calc operandI.
Fixed — adl2rsdm
- Embedded-display and composite-file children take the host screen's
colormap. MEDM'sparseCompositeFileparses and discards the child file's
"color map"block and resolves the children'sclr/bclragainst the
parent display's palette; adl2rsdm used the child's own. Screens on the
default palette are unaffected; those with a custom palette rendered every
embedded widget in the wrong colours. - An arc with no
pathspans 90°, not 360° — MEDM'screateDlArcdefault.
Changed — rsplot
- The volume 3-D texture is
Rgba16Floatrather thanRgba8Unorm, doubling its
VRAM. See the faint-voxel fix above for why an 8-bit texture cannot carry the
data. VolumeRaycasternow holds a clone of itsRenderState(a bundle ofArcs)
so it can release its texture claim on drop.
v0.5.2
Patch release over 0.5.1. A correctness and robustness pass over the
VolumeRaycaster, plus two rsdm data-engine race fixes surfaced by the
cross-platform CI. adl2rsdm is re-released in lockstep.
Fixed — rsplot (VolumeRaycaster)
- Dark fringe around opaque regions gone (premultiplied-alpha compositing).
- Opacity no longer depends on the ray step count (Beer–Lambert normalized).
set_stepsclamped to[1, 4096](GPU-timeout watchdog safety).- Invalid volumes rejected up front (extent + RGBA-length validation).
- Ctrl/Cmd-pan tracks the pointer one-to-one (anchored at box-centre depth).
- Same
VolumeIdpainted twice in one frame keeps each camera (per-callback uniforms).
Changed — rsplot
VolumeRaycaster::remove/remove_volume_raycaster(id)free a volume's GPU resources.- Dropped the unused
cam_posuniform.
Fixed — rsdm
ca://no longer leaks a duplicate initial sample when the connect handler re-enters (native-type-change on first connect); the connect-time value is gated on an actual change.calc://always publishes its initial derived value regardless of child connect order (stamp changes folded in only once every child is connected).
Full notes: see CHANGELOG.md.
v0.5.1
[0.5.1] - 2026-07-07
A feature-bearing patch over the 0.5.0 crate rename: a new volume-rendering
widget, a toolbar restructure across the image-widget family, and the profile
overlay drawn on the image. Also the first cross-platform CI (Linux / macOS /
Windows), which surfaced and fixed a Direct3D-12 shader-portability bug. rsdm
and adl2rsdm are re-released in lockstep (no functional change beyond an
internal lint cleanup).
Added — rsplot
VolumeRaycaster— an interactive GPU direct-volume-rendering widget.
Ray-marches a(depth, height, width)RGBA8 volume in a fragment shader
(shaders/volume_raycaster.wgsl): a full-screen triangle un-projects each
pixel through the inverse camera matrix, slab-tests the volume box, and
front-to-back alpha-composites samples of a 3-D texture straight into egui's
render pass (premultiplied-alpha blend, no offscreen target or depth buffer).
Orbit / pan / wheel-zoom reuse the existingCamera+OrbitDrag/PanDrag
interaction state machines. Transfer knobs:set_alpha_scale(global opacity),
set_steps(samples per ray),set_cull_floor(skip near-transparent
samples). UnlikeScalarFieldView(iso-surface geometry), this renders the
volume itself — every voxel's colour and opacity contribute along the ray.
Naga-validated headlessly plus anegui_kittestwgpu render test (opaque
volume ⇒ visible colour, transparent volume ⇒ nothing).- Compact plot control toolbar. The
Plot2Dcontrol toolbar now renders
compact by default — the essential buttons (reset zoom, box-zoom / pan modes,
invert Y, keep-aspect) stay in the row and everything else folds into a single
⋯overflow menu, so the toolbar stays one line and the plot keeps its
height. Toggle withPlot::set_toolbar_compact(toolbar_compactto read). - Shared control toolbar on
ImageView,ImageStack, andCompareImages.
All three now surface the standard silx plot controls above their own rows,
matching the rest of the image-widget family (previously reachable only on the
bare inner plot). ImageViewimage controls as detached settings windows. The image-specific
controls (interp / agg / alpha / profile / mask) are now toolbar buttons that
each open their own detached settings window, matching silx's toolbar-action /
dock-widget layout instead of inline combos and sliders. The colorbar stays a
plain toggle.- Profile overlay drawn on the image. The profile ROI and its width band are
now drawn directly on the image while a profile tool is active.
Fixed — rsplot
- Curve rendering no longer fails on Windows / Direct3D-12. The curve
fragment shader ended in a function-terminaldiscard, which naga's HLSL
backend emits as a path with no return value; the D3D12 FXC compiler rejects
it (X3507, "not all control paths return a value"), socreate_render_pipeline
for the curve pipeline — and every curve / scatter draw — failed on Windows.
Vulkan and Metal tolerate it, so it was invisible until cross-platform CI. A
trailing unreachable return keeps the shader portable. - The plot no longer zooms while a profile drag positions the ROI. A drag
that places or resizes a profile ROI is consumed by the profile tool instead
of also driving a box zoom.
v0.5.0 — crate rename (rsplot / rsdm / adl2rsdm)
Crate rename
The three crates have been renamed and republished on crates.io at 0.5.0:
| old | new |
|---|---|
siplot |
rsplot — silx-style scientific plotting for egui/wgpu |
sidm |
rsdm — PyDM-style EPICS display widgets + data engine on rsplot |
adl2sidm |
adl2rsdm — MEDM .adl → RsDM Rust-source converter |
The old crates (siplot 0.4.3, sidm 0.4.3, adl2sidm 0.4.3) are deprecated:
each publishes a final version that re-exports the renamed crate (pub use rsplot::* /
rsdm::* / adl2rsdm::*) plus a rename notice, so existing use siplot::… code keeps
compiling. Please switch your dependency:
rsplot = "0.5"
rsdm = "0.5"The GitHub repository was renamed physwkim/siplot → physwkim/rsplot (the old URL redirects).
Also since 0.4.2
This release also carries the completed R2 (69/69) and R3 (24/24) reference→port
parity fix rounds against silx / PyDM / MEDM, including the R3 deferred batch: calc://
array binding, external MEDM colormap parsing, loc:// config-bearing gating, and
per-pen strip-chart normalization.
v0.4.2
Follow-up patch to the 0.4.1 trackpad-momentum fix. siplot, sidm, and adl2sidm published to crates.io in lockstep; only siplot has a functional change.
Added — siplot
Plot::scroll_zoom flag (default true) to disable wheel/trackpad zoom per plot. When false the whole wheel handler is skipped — no scroll is read, no momentum guard runs, no zoom happens — while box-drag zoom, the toolbar Home/Zoom buttons, and the context menu are unaffected. Opt out with plot.plot_mut().scroll_zoom = false.
Fixed — siplot
- Wheel-zoom no longer stops working on plots that refit to data on every update. The 0.4.1 momentum guard was armed inside the low-level
reset_zoom_to_data_range, which the widget also funnels its autoscale-refit-on-content-change through (apply_auto_limits→apply_limits_from_data_bounds). A plot rebuilding its curves each update re-armed the guard every frame, so the handler swallowed every scroll and wheel-zoom stopped entirely (box-drag zoom and Zoom Back were unaffected). The arm now lives on the user-facing reset verbs (Plot::reset_zoomarms after the refit;Plot::zoom_backalready armed its own) and the shared low-level path no longer arms. - Context-menu "Reset Zoom" refits to the live data range instead of restoring a stale home snapshot. For a long-lived plot whose content is rebuilt while zoomed in,
home_limitswas re-captured as the zoomed view, so Reset Zoom reverted to the zoom (a no-op). It now callsPlot::reset_zoom— refit the autoscale-on axes to live data, matching the toolbar Home button and silxresetZoom.
Full changelog: v0.4.1...v0.4.2