Files
astrolabe/docs/spec/04-live-preview.md
T

14 KiB

04 · Live Preview

The right pane renders the active snippet's current specification as a live Vega-Lite visualization. It mirrors whatever the editor currently shows and updates on its own as the user types, giving immediate visual feedback without any explicit "run" action.

Purpose & Live Updating

  • Renders the active snippet's current spec as a Vega-Lite visualization.
  • Always reflects the version currently shown in the editor: while the user edits the draft, the preview renders the draft; once published/viewing the published version, it renders that (see Spec Editor & Draft/Published Workflow).
  • Updates automatically as the user edits, after a brief render debounce so rapid keystrokes do not trigger constant re-rendering. The debounce delay is user-configurable (see Settings).
  • A subtle busy indication may appear over the preview while a render is in progress; it clears when rendering completes.
  • When no snippet is active, or the editor content is empty/blank, the preview renders nothing (a clean, empty pane) rather than showing an error.

Dataset Reference Resolution

When a spec uses inline data, the preview renders it directly. When a spec instead references a named dataset from the library, the preview resolves that reference and renders using the stored dataset's contents (see Datasets).

  • A spec may point at a dataset from the library by name instead of embedding the data inline.
  • Before rendering, the preview substitutes the referenced dataset's stored contents into the spec.
  • URL-sourced datasets render from their local snapshot (fetched when the dataset was created or last refreshed; see Datasets), so the preview does not fetch at render time and works offline. A URL dataset that has never been fetched has no snapshot and instead renders against its live URL as a fallback, until it is refreshed.
  • If a referenced dataset cannot be found, the preview shows a readable error (see Error Display) rather than a broken chart.

Fit / Sizing Modes

The preview pane header has a "Fit" control offering exactly four modes that determine how the chart is sized within the pane. The chosen mode applies immediately and re-renders the current chart.

  • Original — renders the chart at its natural size as defined by the spec. If the chart is larger than the pane, it overflows and the pane provides scrolling to reach the rest.
  • Width — fits the chart's width to the pane (the width becomes responsive to the pane); the height is left to the chart's own natural sizing.
  • Height — fits the chart's height to the pane; the width is left to the chart's own natural sizing.
  • Full — fits the chart to the pane in both dimensions, so it occupies the full available width and height.

The exact spec transform each mode performs is defined in Rendering Contract below.

Behavior of the selected mode:

  • The control shows the four modes with the active one visibly indicated.
  • The selected mode persists across sessions, stored in Settings as previewFitMode.
  • The default is the natural Original mode.

Chart theme

The preview pane header carries a Chart theme picker — a value-select disclosure choosing which Vega-Lite config is injected when charts render:

  • Astrolabe (default) — the house style; follows the app's light/dark theme.
  • Stock Vega-Lite — injects nothing; charts render exactly as plain Vega-Lite defaults would anywhere else (white background, default palette and fonts).
  • Custom themes — the user's saved themes (see Theme Builder below), listed by name between the built-ins and the presets.
  • Edit themes… — closes the custom-themes block (before the long preset roster, so it's visible without scrolling); opens the Theme Builder instead of changing the selection.
  • Presets — the vega-themes preset configs (Excel, ggplot2, FiveThirtyEight, LA Times, Power BI, the Carbon family, …), rendered verbatim and independent of the app's light/dark theme. A divider separates the preset roster from everything above it — the built-ins, the user's themes, and the manage entry read as "ours"; the presets as the imported catalogue.

Behavior:

  • The choice is a global preference, not per-snippet; it persists across sessions, stored in Settings as ui.chartTheme (custom:<id> for a custom theme).
  • The injected config applies at render time only — it is never written into the snippet's stored spec. A spec's own config block overrides the injected config property by property, so a snippet can opt out of any part of it locally (see also Spec Editor → Spec ↔ config actions).
  • Image export reflects the selected theme: exports render from the same themed view.
  • The Chart Builder preview and onboarding thumbnails are app surfaces and stay house-styled regardless of this choice.
  • A selected custom theme whose record is missing (still loading, or deleted in another tab) renders as the house style; deleting the actively-selected theme resets the selection to Astrolabe.

Theme Builder

The Theme Builder is a full-size modal for creating and editing custom chart themes — named, persistent Vega-Lite configs (see Data Model → CustomTheme). It opens from the Chart theme picker's "Edit themes…" entry.

Layout: a saved-theme list on the left; the open theme's editor on the right.

  • New theme creates a theme seeded as a copy of the chart theme currently selected in the preview (house style, stock, a preset, or another custom theme), named after its source (e.g. "FiveThirtyEight copy") and auto-suffixed if taken. Duplicating a preset is the expected starting point. The other creation path is the editor's Extract Config to New Theme action (see Spec Editor → Spec ↔ Config Actions), which turns a pasted spec's config block into a theme directly.
  • Structured controls organize the config into panels by domain — Color, Marks, Type, Title, Layout, Axes & grid, Legend, Headers, Formats — navigated by a vertical tab list, each panel's properties grouped into collapsible sections. A control writes one config property, and clearing it removes the key, so a theme stays a minimal diff against stock. The controls cover the common brand-tuning surface, not every Vega-Lite property.
  • The theme's name and its full config as editable JSON text sit below the controls as the escape hatch for anything they don't expose. Invalid JSON is reported inline and blocks saving (and is the only editing surface while invalid); the text must parse to a JSON object.
  • A font control applies a chosen font family across the whole config in one step: it sets the top-level font (Vega-Lite's default for every text mark, label, and title) and rewrites every explicit font/labelFont/titleFont/subtitleFont slot anywhere in the config — the slots that would otherwise keep overriding the new default. Offered fonts are the self-hosted roster plus any the user uploads (see Data Model → FontAsset), the user's own faces listed first.
  • A gallery of small fixed sample charts re-renders live from the draft config — the same config-injection path the preview uses — spanning the mark types, the color families, faceting, and titled charts so one edit is previewed across every surface a config styles. Every structured control has a visible mirror in at least one card; the default chart size and tooltips are the exceptions (the cards are fixed-size; tooltips are hover-only). While the JSON is invalid, the gallery keeps the last valid state.
  • Save commits the draft (disabled while unchanged or unparseable). Names are unique case-insensitively, like dataset names. Delete removes the theme after confirmation.
  • Closing with unsaved edits prompts for discard, like other form modals. A backdrop click does not dismiss the builder (Escape and the close button do).

Export control

The preview pane header also carries a per-chart Export control — a disclosure for copying or downloading the current chart's spec, or downloading its rendered image (PNG/SVG). It exports what the preview shows. The behavior is specified in Import & Export → Per-chart export; it lives in this header because the image formats are produced from the live rendered view.

Data Inspector

Below the chart, a collapsible Data panel shows the rows behind the chart — the answer to "why is my chart empty or wrong" is to look at the data the spec produced. It reads the live rendered view, so it reflects exactly what was drawn.

  • A disclosure at the bottom of the pane, collapsed by default (a debugging aid, not the default view); the open state persists across sessions, stored in Settings as ui.dataInspectorOpen.
  • An Input | Resolved switch chooses which rows to show:
    • Resolved (default) — the rows the chart draws, after the spec's transforms (filters, calculated fields, aggregation).
    • Input — the parsed source rows, before those transforms. A spec with no transforms shows the same rows for both.
  • The table is read-only and capped (the first rows, with a "first N of M" note), like the dataset and builder previews, and updates whenever the chart re-renders.
  • States: when nothing has rendered, the panel guides the user to render a chart; when the chosen view's table is empty, it names which side is empty and why (the resolved side's transforms produced nothing to draw; the input side's source has no rows).
  • A draggable divider between the chart and the panel sizes the panel's height (the chart above absorbs the change) — the same window-splitter interaction as the layout panes (see Application Shell & Navigation). The height persists, stored in Settings as ui.dataInspectorHeight.

Rendering Contract

Before the chart is drawn, the spec shown in the editor is transformed into the spec actually rendered. Two deterministic transforms are applied in order. They are specified here because reproducing them faithfully is what makes references and fit modes behave correctly; the result is observable as the rendered chart.

1. Dataset reference resolution. Any named-data reference (data with a name) is replaced in-place with the referenced dataset's actual contents, shaped by the dataset's source and format (see Datasets):

Dataset source / format The reference's data becomes
URL, fetched (any format) its snapshot, inlined and tagged exactly like the inline rows below
URL, not yet fetched a live URL reference to the dataset's address, tagged with its format (fallback)
Inline JSON the parsed values, inlined
Inline CSV / TSV the raw text, inlined, tagged with its format (CSV or TSV)
Inline TopoJSON the value, inlined, tagged as TopoJSON
  • Resolution recurses into nested sub-specs (layered and concatenated specs, and a parent spec's child spec), so references anywhere in the spec are resolved.
  • If a referenced dataset does not exist, rendering fails with a "dataset not found" error (see Error Display).

2. Fit-mode sizing. The selected fit mode rewrites the spec's sizing using Vega-Lite's responsive "container" sizing keyword, recursing into the same nested sub-specs:

Mode Transform
Original spec sizing left untouched (the spec's own width/height, or Vega-Lite defaults, apply)
Width set width to "container"; remove any explicit height
Height set height to "container"; remove any explicit width
Full set both width and height to "container"
  • For the responsive (non-Original) modes the chart's container-relative dimension follows the pane size, while the unconstrained dimension is recomputed naturally — this is why Width/Height do not preserve the original aspect ratio.
  • The transform operates on a copy; the user's stored spec is never modified by rendering.

The preview renders the resulting spec without the charting library's built-in action/export menu, so the output is a clean chart with no overlaid controls.

Error Display

When a spec cannot be rendered, the preview replaces the chart area with a clear, readable error message rather than a broken or partial visualization, and recovers on its own once the spec becomes valid again.

  • Invalid JSON, incomplete specs, Vega-Lite errors, and data problems (e.g. a missing or unfetchable dataset) all surface as a legible error message.
  • The message identifies it as a rendering error and includes the underlying reason, with a hint to check the JSON syntax and the Vega-Lite specification.
  • As soon as the spec becomes valid again, the error clears automatically and the chart renders without any manual retry.
  • Empty/blank specs are not treated as errors — they simply render nothing.

Responsiveness

  • The preview re-fits when the pane is resized, re-applying the current fit mode so the chart continues to honor the chosen sizing (see panes in Application Shell & Navigation).
  • Resizing does not require a manual refresh; the displayed chart adapts to the new pane dimensions.