28 KiB
Datoviz v0.4 GSP Backend Readiness
Status: RC-lane readiness checklist for Datoviz as a GSP/Matplotlib rendering target.
Purpose: make Datoviz v0.4 a stable, ergonomic rendering target for a future Matplotlib backend that lowers Matplotlib draw calls to GSP visuals and then to Datoviz.
0. Executive summary
The proposed Matplotlib backend will not call Datoviz directly from Matplotlib in the long term. It will use this path:
Matplotlib Figure.draw(RendererGSP)
-> RendererGSP emits GSP visuals/display list
-> GSP renderer backend = Datoviz v0.4
-> Datoviz retained scene + offscreen/interactive view
Datoviz v0.4 already has most of the right low-level concepts: retained scene, figures, panels, visual families, dense visual attributes, offscreen views, hosted-loop primitives, and Python ctypes/array-aware bindings. The work before RC should focus on making those APIs stable and ergonomic enough that GSP can depend on them without wrapping unstable internals.
The highest-value pre-RC changes are:
- Stable Python API for retained-scene creation, visual creation, panel attachment, dense data updates, and app/view rendering.
- Offscreen capture to memory (
RGBA/PNG bytes), not only to a filesystem path. - Python-friendly wrappers for
dvz_visual_set_data_many(); keep the existingdvz_visual_set_data_range()array facade in validation. - Clear, documented logical-pixel/device-pixel semantics for screen-space attributes.
- Reliable panel clipping/scissor behavior for all attached visuals.
- A stable line/path/polyline story suitable for Matplotlib
plot()andLineCollection. - Hosted-loop primitives stable enough for later GUI/interactive backends.
0.1 Current v0.4-dev integration update
The current branch is closer to this plan than the original draft assumed:
- The public Python direction is already one generated
ctypesbinding with C-shapeddvz_*names:import datoviz as dvzfor policy-declared NumPy adaptation, anddatoviz.rawfor exact pointers, counts, bytes, and callbacks. Do not add prefixless aliases such ascapture_rgba()orvisual_set_data_many(). dvz_visual_set_data_many()anddvz_visual_set_data_range()already exist in the C API.dvz_visual_set_data_range()is already array-adapted in the top-level Python package. The top-leveldvz_visual_set_data_many()wrapper now accepts mappings or iterables of(attr_name, array)pairs and lowers them toDvzVisualDataUpdate[]for the raw call.- Canvas-level memory capture already exists in C:
dvz_canvas_capture_rgba_into()anddvz_canvas_capture_rgba(). The top-level Python package now exposesdvz_view_capture_rgba(view), which reaches the canvas throughdvz_view_canvas(), usesdvz_canvas_capture_rgba_into(), and returns a copied NumPy RGBA8 array without temporary files or Datoviz-owned memory lifetime hazards. - PNG-to-memory is only partially aligned:
dvz_make_png()writes RGB memory, while screenshot capture is RGBA8. Add an RGBA-capable PNG-bytes path or explicitly document alpha-dropping if RC1 defers alpha-preserving PNG bytes. - Panel scissor/clip infrastructure is active in scene emission and runtime draw emission. Focused proof now covers adjacent panels with reserved plot bands and per-draw plot scissor commands.
- Path, image, and semantic text are already release-facing visual families. Use the current
canonical APIs:
dvz_path(scene, flags),dvz_image(scene, flags)plus sampled fields, and semanticdvz_text(panel, flags)for text. Do not invent a parallel text-as-generic-visual API for RC. - Hosted-loop primitives already include
dvz_view_render_once(),dvz_app_render_once(), external-surface views, request-frame callbacks, and Qt bridge proof. Treat further GUI hosting as validation/documentation unless a specific missing primitive is found.
Revised pre-RC posture: make small Python binding/documentation additions around the existing C surface. Avoid broad C API expansion before RC1 except for an alpha-preserving PNG-memory helper if needed.
0.2 RC-lane completion snapshot
Completed in the current RC lane:
dvz.dvz_visual_set_data_many(visual, updates)accepts mappings and(attr_name, array)iterables in the top-level package, validates item counts before mutation, and preserves raw descriptor-array passthrough whenupdate_countis supplied.dvz.dvz_view_capture_rgba(view)returns Python-owned NumPy RGBA8 memory shaped(framebuffer_height, framebuffer_width, 4)with top-row-first rows.docs/reference/ctypes.mddocuments the Python API, dense data updates, offscreen RGBA capture, and the GSP/VisPy2 boundary.examples/python/direct/offscreen_point.pyandtools/bindings/ctypes_render_smoke.pycover the direct facade offscreen point/capture path where native runtime support is available.- Logical-pixel, framebuffer-pixel, screen-space attribute, and RGBA capture semantics are documented in reference docs.
- Adjacent-panel plot scissor proof is covered by
test_scene_adjacent_panels_plot_scissor_no_bleed. - View2D/domain readback uses ordered endpoints, including reversed finite domains. Axis/grid generation uses explicit internal sorted intervals only where numeric low/high bounds are needed.
DvzAxisTicks,dvz_axis_set_ticks(), anddvz_axis_clear_ticks()provide exact explicit tick positions and optional copied labels. The top-level Python package accepts NumPy-compatible values and Python labels.- Query target scopes now distinguish deferred guide and all-rendered requests:
DVZ_SCENE_TARGET_GUIDEandDVZ_SCENE_TARGET_ALL_RENDEREDreturnDVZ_QUERY_STATUS_UNSUPPORTED_TARGETinstead of degrading to data-only picking.
These slices make the first GSP/Matplotlib backend path viable without private Python modules and without temporary files for ordinary RGBA capture.
0.2.1 GSP backend compatibility matrix
| Capability | Status | Public C API | Top-level Python | Tests/proof | Notes |
|---|---|---|---|---|---|
| View2D/domain readback | supported | dvz_panel_set_domain(), dvz_panel_set_view2d(), dvz_panel_visible_domain() |
exposed through datoviz facade |
test_panel_view2d_reversed_domains |
Public domains are ordered endpoints, not sorted bounds. |
| Reversed finite domains | supported | same as View2D/domain | exposed | axis/panel View2D tests | Data mapping, visible-domain readback, axes, and grid use one oriented snapshot. |
| Explicit axis ticks | supported | DvzAxisTicks, dvz_axis_set_ticks(), dvz_axis_clear_ticks() |
dvz.dvz_axis_set_ticks(axis, values, labels=None) |
test_axis_explicit_ticks_and_labels, testing/test_array_facade.py |
Values are exact data coordinates and keep caller order. |
| Explicit tick labels | supported | DvzAxisTicks.labels |
Python labels supported | axis label copy tests, array facade tests | Labels are copied before the C setter returns. |
| Grid alignment | supported | axis tick state | exposed through axis API | test_axis_explicit_reversed_ticks_grid_alignment |
Grid lines use the same render tick snapshot as tick marks. |
| Axis labels | supported | dvz_axis_set_label() |
exposed | axis tests and text rendering tests | Uses the scene text/glyph pipeline. |
| Guide query | deferred, explicit | DVZ_SCENE_TARGET_GUIDE |
enum exposed in datoviz.raw; top-level query APIs exposed |
test_scene_query_deferred_guide_targets_are_unsupported, ctypes_smoke.py |
Returns DVZ_QUERY_STATUS_UNSUPPORTED_TARGET. |
| All-rendered with guides | deferred, explicit | DVZ_SCENE_TARGET_ALL_RENDERED |
enum exposed in datoviz.raw; top-level query APIs exposed |
same query tests/smoke | No data-only fallback while guide picking is absent. |
| Data query payload completeness | supported/experimental by family | DvzQueryResult fields and visual-family query ops |
DvzQueryResult, dvz_panel_query_px(), dvz_scene_poll_query() |
just test query, ctypes_smoke.py |
Point/marker/image/sample/mesh paths fill promoted fields; unsupported gaps report status. |
| Colorbar render | supported | dvz_colorbar(), title/format/orientation/anchor/layout setters |
symbols probed by array_facade_smoke.py |
test_scene_scale_colormap_colorbar_core, test_scene_colorbar_auto_reserve_and_visuals, test_app_offscreen_colorbar_has_visible_ramp_and_labels |
Range comes from the shared DvzScale; explicit colorbar ticks are not a separate RC API. |
| Colorbar query | deferred | use guide/all-rendered query scopes | unsupported scopes exposed | deferred-target query test | No CPU fallback query for colorbar adornments. |
| Text render | supported | dvz_text(), dvz_text_set_string(), style/placement helpers |
symbols and DvzTextPlacement probed by array_facade_smoke.py |
semantic text and atlas tests under scene/interaction and scene/text_atlas |
Placement may be screen, data, or world; offsets and size are logical pixels. |
| Text query | deferred for semantic text | DVZ_SCENE_TARGET_TEXT currently family/backend dependent |
query APIs exposed | query unsupported/family tests | Use explicit unsupported statuses unless a promoted visual-family path handles the target. |
| Mesh render | supported | dvz_mesh(), dvz_mesh_set_geometry(), dense/index uploads |
symbols probed by array_facade_smoke.py |
mesh geometry/state tests and examples | Indexed triangle topology; supports z=0 2D overlays and 3D depth paths. |
| Mesh query | supported/experimental | query item targets on mesh visuals | query APIs exposed | test_scene_mesh_query_resolves_item, test_scene_mesh_query_resolves_instance_item |
Face-level semantics beyond promoted item/instance payloads remain family-specific. |
0.3 Remaining RC/post-RC follow-up
Remaining work is optional for RC unless a downstream GSP integration finds a concrete blocker:
- Add
dvz_view_capture_png_bytes(view)only if alpha-preserving PNG bytes are required before RC; otherwise defer and keep RGBA memory as the stable backend target. - Keep direct Python binding validation in release evidence:
testing/test_array_facade.py,tools/bindings/ctypes_render_smoke.py, and the adjacent-panel scissor test. - Add deeper family-specific docs only when needed by a real GSP lowering path, especially image upload/update convenience and semantic text update examples.
- Do not add a Matplotlib backend, GSP implementation, or high-level plotting aliases inside Datoviz for v0.4 RC.
1. Scope and non-goals
In scope before RC
Stabilize the Datoviz v0.4 surfaces needed by GSP:
- Python-level retained-scene API.
- Dense visual data update API.
- Offscreen rendering API.
- Basic screen-space visual semantics.
- Panel creation, sizing, clipping, axes/domain plumbing.
- Line/path, point, marker, image, text, mesh, segment primitives.
- Error handling and diagnostics for invalid visual updates.
Not in scope before RC
Do not attempt to implement Matplotlib compatibility inside Datoviz.
Do not add a Matplotlib backend to Datoviz.
Do not promise Datoviz-native PDF/SVG/vector export. Matplotlib vector output should remain an Agg/Matplotlib fallback concern.
Do not block RC on perfect text/mathtext/TeX parity. The future Matplotlib backend can use Agg fallback for complex text.
2. Required API stability surface
The GSP Datoviz v0.4 backend should be able to rely on the following Python calls or close equivalents.
Scene and layout
Required:
import datoviz as dvz
scene = dvz.dvz_scene()
figure = dvz.dvz_figure(scene, width, height, flags)
panel = dvz.dvz_panel(figure, desc) # normalized figure rect
panel = dvz.dvz_panel_full(figure)
Needed behavior:
- Scene owns figure, panels, visuals, and controllers.
- Object lifetimes are clear and documented.
- Destroying the scene releases all retained scene objects.
- Figure size can be updated after creation.
- Panel rect updates are legal and reflected on the next frame.
Visual creation
Required visual families for first Matplotlib/GSP subset:
point = dvz.dvz_point(scene, flags)
pixel = dvz.dvz_pixel(scene, flags)
marker = dvz.dvz_marker(scene, flags)
segment = dvz.dvz_segment(scene, flags)
mesh = dvz.dvz_mesh(scene, flags)
image = ... # whichever retained v0.4 image API is canonical
text = ... # whichever retained v0.4 text API is canonical
path_or_vector = ...
The public Python layer should expose only stable names. Avoid requiring imports from private modules or generated internals except datoviz.raw for low-level consumers.
Visual attachment
Required:
desc = dvz.dvz_visual_attach_desc()
desc.z_layer = z
# desc.controller_mode, coord_space, etc.
dvz.dvz_panel_add_visual(panel, visual, desc)
Needed behavior:
- Multiple visuals can be attached to one panel.
- A visual can be detached or destroyed cleanly.
- Attachment options expose at least
z_layer, controller mode, and coordinate space. - Panel clipping applies to attached visuals by default.
Dense visual data updates
Required:
dvz.dvz_visual_set_data(visual, "position", positions)
dvz.dvz_visual_set_data(visual, "color", colors)
dvz.dvz_visual_set_data(visual, "diameter_px", diameters)
The top-level Python package should accept NumPy arrays directly and infer pointer, dtype, shape, and item count from policy declarations.
Required attributes for the initial Matplotlib subset:
| Visual family | Required attributes |
|---|---|
| point | position, color, diameter_px, optional item_state |
| pixel | position, color, pixel_size_px, optional item_state |
| marker | position, color, diameter_px, angle, shape or symbol, optional item_state |
| segment | position_start, position_end, color, stroke_width_px |
| path/polyline | position, color, stroke_width_px, subpath/group metadata if applicable |
| mesh | position, optional color, optional normal, optional texcoords, optional index buffer |
| image | RGBA texture/data plus position/extent or textured quad attributes |
| text | text, position, optional anchor, size, color, angle |
3. High-priority pre-RC updates
3.1 Add memory-based offscreen capture
Problem
A Matplotlib backend needs to implement APIs such as:
canvas.buffer_rgba()
canvas.print_png(path_or_file)
canvas.tostring_argb()
It should not be forced to write a temporary PNG file and read it back.
Required Datoviz additions
Add Python-level APIs equivalent to:
rgba = dvz.capture_rgba(scene, figure, width, height)
png = dvz.capture_png_bytes(scene, figure, width, height)
or a stateful API:
app = dvz.dvz_app(scene)
view = dvz.dvz_view_offscreen(app, figure, width, height)
dvz.dvz_app_run(app, 1)
rgba = dvz.dvz_view_capture_rgba(view)
png = dvz.dvz_view_capture_png_bytes(view)
Requirements
capture_rgba()returns a contiguousnp.ndarrayormemoryviewwith shape(height, width, 4)and dtypeuint8.- Document channel order:
RGBA, notBGRA, not premultiplied unless explicitly named. - Document origin: first row is top or bottom. Prefer top-left for image buffers if matching common display APIs; if bottom-left, expose an explicit flag.
capture_png_bytes()returnsbytes.- No temporary file required.
- Safe to call repeatedly.
- Safe after
dvz_view_render_once()ordvz_app_run(app, 1). - Fail with a clear Python exception if no GPU/context/offscreen support is available.
Acceptance criteria
- A Python test creates a scene with one point visual, renders offscreen, obtains RGBA bytes/array, and verifies non-background pixels.
- The test does not create any temporary PNG file.
- A second render after a visual data update returns a different image.
3.2 Add Python-friendly visual_set_data_many()
Problem
Matplotlib scatter/path collections update several attributes together:
- positions
- colors
- diameters/sizes
- edge/stroke widths
- marker shapes
Calling dvz_visual_set_data() sequentially can create transient invalid state when item counts change.
Required Datoviz addition
Expose an ergonomic top-level Python wrapper while preserving the C-shaped name:
dvz.dvz_visual_set_data_many(
visual,
{
"position": positions, # float32 (N, 3)
"color": colors, # uint8 (N, 4)
"diameter_px": diameters, # float32 (N,)
},
)
datoviz.raw.dvz_visual_set_data_many() remains the exact ctypes descriptor-array call.
Requirements
- Validate all arrays before mutating retained visual state.
- All per-item attributes must agree on item count.
- Return/raise clear errors for unsupported attribute names, wrong dtype, wrong shape, inconsistent counts.
- Copy semantics must match C API: input arrays may be reused/released after the call.
- Preserve raw
dvz_visual_set_data_many()indatoviz.rawfor low-level users.
Acceptance criteria
- Test one call updates point position/color/diameter for N items.
- Test inconsistent item counts raise a deterministic exception and do not partially update the visual.
- Test wrong dtype gives a useful error message naming the offending attribute.
3.3 Add Python-friendly visual_set_data_range()
Problem
Interactive Matplotlib and future VisPy2/GSP workflows may update slices of large arrays. Full re-upload every frame will waste CPU/GPU bandwidth.
Required Datoviz addition
The current top-level package already exposes this C-shaped convenience:
dvz.dvz_visual_set_data_range(
visual,
"position",
first_item,
positions_chunk,
)
Requirements
- Attribute must already exist and have compatible total item count.
- Chunk shape determines
item_count. - Validate dtype and shape.
- Clear errors if range is out of bounds.
- Support all dense attributes used by point, marker, segment, image, mesh, and text as applicable.
Acceptance criteria
- Test full allocation with
visual_set_data_many()followed by a partial position update. - Render before and after update and verify image changes.
- Test out-of-range update fails cleanly.
3.4 Freeze screen-space attribute semantics
Problem
Matplotlib rendering is dominated by screen/logical-pixel quantities:
- marker size
- linewidth
- image extent
- text size
- dash lengths
- offset transforms
- clipping rectangles
Datoviz already has pixel-space attributes such as diameter_px, pixel_size_px, stroke_width_px, and text size/position. These semantics need to be fully documented and stable.
Required documentation/spec updates
For every screen-space attribute, document:
- Is it in logical pixels or framebuffer pixels?
- Is it affected by device scale?
- Is it affected by
render_scale? - Is it affected by user scale?
- Is it affected by panel controllers?
- Which origin convention applies?
- Is positive Y up or down?
Recommended policy:
Data positions: panel data/visual coordinates unless explicitly fixed/screen.
Screen sizes: logical pixels.
Framebuffer scale: handled by Datoviz view/device scale.
Matplotlib backend: converts Matplotlib display pixels to Datoviz logical pixel semantics.
Acceptance criteria
- Docs include a table for point, marker, pixel, segment, image, text.
- A smoke test renders the same marker diameter under two device-scale settings and confirms expected behavior.
3.5 Stabilize panel clipping/scissor behavior
Problem
Matplotlib clips nearly all axes content to the axes rectangle. If Datoviz visuals bleed outside panels, a GSP/Matplotlib backend cannot be correct.
Required behavior
- Every visual attached to a panel is clipped/scissored to the panel plot rectangle by default.
- Panel background/border/chrome behavior is separate from data visual clipping.
- If panel reserve/padding is used, document whether data visuals clip to full panel rect or plot rect.
- There should be a way to opt out for overlays if already supported, but default should be safe for axes-like content.
Acceptance criteria
- Test point/segment/image/text at positions outside panel bounds: outside portions are not visible.
- Test two adjacent panels: visuals in one panel do not draw into the other.
3.6 Provide a stable path/polyline story
Problem
Matplotlib plot() and LineCollection need an efficient representation for stroked polylines. Rendering every line as many independent segments is acceptable for a prototype but bad for joins/caps and performance.
Required outcome before RC
Use and document the canonical v0.4 API for stroked polylines/paths.
Current branch canonical form:
path = dvz.dvz_path(scene, flags)
dvz.dvz_visual_set_data(path, "position", positions)
dvz.dvz_visual_set_data(path, "color", colors)
dvz.dvz_visual_set_data(path, "stroke_width_px", widths)
dvz.dvz_path_set_subpaths(path, lengths)
dvz.dvz_path_set_caps(path, start_cap, end_cap)
dvz.dvz_path_set_join(path, join, miter_limit)
Minimum required features
- One or more subpaths.
- Open polylines.
- Constant color/width for first milestone; per-item/per-segment color can come later.
- Cap style: butt/round/square if available.
- Join style: miter/round/bevel if available.
- Panel clipping.
- Dense data mutation after creation.
Acceptance criteria
- Python example draws a sine curve as one retained path visual.
- Python example draws a
LineCollection-like set of 1000 short lines. - Data updates mutate the same retained visual.
3.7 Stabilize image visual behavior
Problem
Matplotlib imshow() and fallback layers both require reliable RGBA image upload and placement.
Required features
- Upload
uint8 RGBAarrays. - Draw a 2D image in a panel with explicit extent.
- Support nearest and linear interpolation if available; nearest alone is acceptable for first backend if documented.
- Control origin (
upper/lower) or document conversion required by caller. - Support alpha.
- Support panel clipping.
- Support replacing image data without recreating the visual.
Acceptance criteria
- Test an RGBA checkerboard image in a panel.
- Test updating image data in place.
- Test image extent and clipping.
3.8 Stabilize basic text visual behavior
Problem
The Matplotlib backend can fallback for complex mathtext/TeX, but simple titles, labels, and tick text should eventually be native.
Required features
- Text strings array.
- Pixel or panel-local positions.
- Font size in logical pixels or points with documented conversion.
- RGBA color.
- Anchor/alignment.
- Rotation angle.
- Panel clipping.
- Update text strings without recreating the scene.
Acceptance criteria
- Python example draws three labels with different anchors.
- Python example updates label text and color.
3.9 Stabilize hosted-loop primitives
Problem
The first backend may be offscreen-only, but interactive Matplotlib support will need a hosted event loop.
Required stable C/Python primitives
- Create offscreen and GLFW views.
- Create external-surface hosted view.
- Emit resize, pointer, wheel, and key events.
- Register request-frame callback.
- Render one frame without running Datoviz's own loop.
- Wake/post callbacks from another thread if supported.
Acceptance criteria
- Minimal Python example creates a view, calls render-once, then captures RGBA.
- Hosted-loop API names and signatures are documented as RC-stable or explicitly marked experimental.
4. Error handling and diagnostics
Required improvements
All Python wrappers should raise typed exceptions instead of silently returning -1/false unless the user explicitly calls datoviz.raw.
Suggested exception hierarchy:
class DatovizError(RuntimeError): ...
class DatovizValidationError(DatovizError): ...
class DatovizRuntimeError(DatovizError): ...
class DatovizGpuUnavailableError(DatovizRuntimeError): ...
Every failed data update should include:
- visual family;
- attribute name;
- expected dtype/shape;
- actual dtype/shape;
- item count if relevant.
5. Tests to add in Datoviz
Add tests under the existing Python test suite, or create a focused tests/python/test_retained_scene_python.py module.
Required smoke tests
-
test_scene_point_offscreen_rgba()- Create scene/figure/panel/point.
- Set position/color/diameter.
- Capture RGBA bytes/array.
- Verify shape and non-background pixels.
-
test_visual_set_data_many_atomic_validation()- Attempt inconsistent item counts.
- Verify exception.
- Verify retained visual state not partially changed.
-
test_visual_set_data_range()- Allocate N points.
- Update a slice.
- Capture before/after.
-
test_panel_clipping()- Draw outside panel.
- Verify no bleed into adjacent panel.
-
test_image_rgba_upload_update()- Upload checkerboard.
- Update to inverted checkerboard.
- Verify render changes.
-
test_segment_or_path_smoke()- Draw polyline/segments.
- Capture.
-
test_text_smoke()- Draw simple text.
- Capture.
Tests that require GPU/offscreen support should be skipped with a clear reason if the environment cannot create a Datoviz offscreen view.
6. Documentation updates
Add a short page, e.g. docs/reference/python-retained-scene.md, containing:
- scene/figure/panel lifecycle;
- visual families and supported attributes;
- dense data update API;
- capture-to-memory API;
- coordinate and pixel semantics;
- offscreen rendering example;
- hosted-loop summary;
- known limitations.
Include one compact example equivalent to:
import numpy as np
import datoviz as dvz
scene = dvz.dvz_scene()
figure = dvz.dvz_figure(scene, 800, 600, 0)
panel = dvz.dvz_panel_full(figure)
visual = dvz.dvz_point(scene, 0)
pos = np.random.uniform(-1, 1, (1000, 3)).astype("float32")
color = np.full((1000, 4), [255, 255, 255, 255], dtype="uint8")
diam = np.full(1000, 4, dtype="float32")
dvz.visual_set_data_many(visual, {
"position": pos,
"color": color,
"diameter_px": diam,
})
dvz.dvz_panel_add_visual(panel, visual, None)
rgba = dvz.capture_rgba(scene, figure, 800, 600)
7. Implementation status
Completed RC-lane implementation:
- Keep the existing generated binding model: top-level
datovizfor NumPy-adapteddvz_*calls, anddatoviz.rawfor exactctypescalls. dvz.dvz_visual_set_data_many(visual, {"attr": array, ...})validates arrays, constructsDvzVisualDataUpdate[], keeps temporaries alive through the raw call, and raises deterministic Python exceptions on validation failure.dvz.dvz_view_capture_rgba(view)returns a(height, width, 4)uint8NumPy array using caller-owned Python memory.- Focused tests cover
set_data_many,set_data_range, and capture memory;tools/bindings/ctypes_render_smoke.pyruns raw and direct offscreen smoke examples when runtime support is available. docs/reference/ctypes.mddocuments the Python API, dense data updates, and RGBA capture, with cross-links from status/reference pages.docs/reference/coordinate-systems.mdanddocs/reference/visual-attributes.mddocument logical-pixel, framebuffer-pixel, screen-space attribute, panel clipping, and capture semantics.test_scene_adjacent_panels_plot_scissor_no_bleedcovers adjacent-panel plot scissor emission.
Optional follow-up: add dvz.dvz_view_capture_png_bytes(view) later if an alpha-preserving
PNG-memory path is required.
8. Definition of done
This document is complete when GSP can implement a Datoviz v0.4 renderer without relying on private Datoviz Python modules and without temporary files for ordinary PNG/RGBA capture.
Minimum acceptance:
import datoviz as dvzexposes stable retained-scene functions.- Python can create scene/figure/panel, create point/marker/segment/path/image/text content through
the current canonical APIs, set NumPy data, attach visuals, render offscreen, and get RGBA memory
without temporary files through
dvz_view_capture_rgba(view). - Atomic multi-attribute updates are ergonomic from top-level Python through
dvz.dvz_visual_set_data_many(...). - Partial updates remain available through
dvz.dvz_visual_set_data_range(...). - Screen-space size semantics are documented as logical-pixel semantics unless a family explicitly says otherwise.
- Panel clipping/scissor behavior is documented and covered by focused DRP2 scissor proof for adjacent panels.
- Tests cover the above.