Drawings and plot parity

Plan to make user drawing tools and Pine plot/drawing outputs match PYNE and render with correct pane, color, geometry, and settings.

This page

Drawings and plot parity

AXIS has two independent render paths:

PathSourcePaint
User drawingsToolbar toolsDrawingLayer user SVG group, editable
Pine outputPYNE RunResultplots → LWC series; shapes/barcolor → candle markers; bgcolor → histogram; fill → SVG; line/label/box/polyline/linefill → script SVG; tables → HUD

This plan is the work list from a four-agent audit of AXIS (src/chart, src/results, src/indicators/runner.ts) against PYNE (pynescript drawing.py, evaluator.py, host.py).

Phases

P0 — AXIS correctness (this pass)

User tools and apply-pipeline bugs that do not wait on a PYNE export change.

  1. 1-point body-moveshiftDrawing only special-cased text / priceLabel. Shift any drawing with p1 (and points[] when present): note, flag, crossline, anchoredText, arrowMarkUp/Down.
  2. p3 / extra vertex handleshitTestHandle / resizeDrawing only p1/p2. Add p3 (and remaining points[i] as p3 for the third anchor). Paint extra handles after registry paint.
  3. Linefill GCgarbageCollectScriptDrawings early-return ignored skip.linefill.
  4. Polyline / linefill overlay — copy force_overlay and polyline fill_colorbgcolor.
  5. Stale SVG — silent live re-run with drawings: [] must clear script drawings.
  6. Pane routingbgcolor and fill() use the script pane when overlay=false (syncBgcolorBands(paneId), ensureScriptPaneLayer for fills). plotshape / plotchar / plotarrow attach to a series on that pane when possible; otherwise stay on price (LWC markers need a host series).

P1 — User-tool settings (AXIS)

Done:

  • Shared style bar: color (presets + custom), width, dash, fill for shapes / ranges / fib / highlighter / positions.
  • Per-tool extras via src/chart/drawings/tool-settings.ts + settings popover (axis-drawing-settings).
  • Last-used style per kind (drawingPrefs.byKind).
  • extendLeft / extendRight UI + paint (trend, ray, extend, info line, channel, fib).
  • Fib level editor, reverse, show % / price, fill between levels.
  • Text re-edit (popover + double-click), font size.
  • Per-drawing lock in the style bar (unlock bypasses updateSelected lock gate).
  • Long/short risk-reward (meta.rr).
  • Highlighter width honors style.width (create default 8).
  • hray: 1-click (price only).
  • xabcd / headShoulders: commit on 5th point.

P2 — PYNE export (pynescript repo)

AXIS cannot paint fields the engine never serializes.

GapWhereNeeded on the wire
Table cell keys (row,col) vs (col,row)drawing.py table.cell vs cell_set_*One index order
Table styleexport_for_apihalign, valign, width, tooltip, text_size, borders
table.cell kwargsctorwidth, halign, valign, size
plotshape Y / location.absolute_coerce_plot_shapekeep numeric series (or {y, on} cells)
plotbar / plotcandleevaluatoropen/high/low/close (or sibling titles in plot_meta)
fill() compile / untitled plotshost + evaluatorplot1/plot2 series keys + per-bar fill color column
Positional plot(..., linewidth)evaluator.py ~425Pine order: series, title, color, linewidth, style
plotarrowevaluatorcolorup / colordown / minheight / maxheight
offset, force_overlay, histbase_pack_interpret_plot_columnsremaining plot_meta fields (display is packed)
Polylineexportfill_color, curved, force_overlay
Box / label extrasexportclosed, extend, text_*, tooltip, border

P3 — Remaining Pine paint

Done this pass:

  • Hide-drawings toggle includes script SVG + fill bands (all pane layers).
  • Label yloc pad (8px off wick); label.style_text_outline as outlined text.
  • First addIndicator re-owns plot fills / script drawings / plotshape (EDITOR_RUN_KEY → script id).
  • Histogram histbase from plot_meta (default 0). PYNE still needs to serialize it for live values.
  • Pine display.* (none / pane / data_window / price_scale / status_line / all) on plot, hline, shapes, fill, bgcolor, barcolor.

Still open:

  • location.top / bottom = pane edges, not bar (LWC markers only have above/below/in bar).
  • Per-bar plot(..., color=expr), plotarrow length (colorup/colordown/minheight/maxheight wait on PYNE).

Invariants

  • User drawings ≠ Pine drawings. Do not share hit-testing or magnet with script SVG (pointer-events: none).
  • overlay=false plots, fills, bgcolor, and shapes belong on ind_* unless force_overlay.
  • barcolor() stays on price candles.
  • Color sanitize: #rgb(a), #rrggbb(aa), rgb/rgba. Unknown → VOID indigo for user tools; Pine should keep engine hex (including #RRGGBBAA).
  • GC caps match Pine: 50 default, 500 lines/labels/boxes, 100 polylines. Linefill cap is AXIS-only until PYNE emits max_lines_fills_count.

Tests

  • shiftDrawing / resizeDrawing for 1-pt and 3-pt kinds.
  • Linefill GC overflow.
  • Polyline force_overlay + fill_color.
  • Runner: bgcolor/fill target pane when overlay=false (unit with a fake manager if needed).
  • PYNE: table cell key, fill meta, plotshape Y (in the pynescript repo).