# Changelog

## [0.15.13] - 2026-08-12

### Changed
- **Reverted 0.15.11's two-column field layout in the Charts tab.** X/Category + Y and Group/Color + Value/Size are back to one field per row each, as they were before.

## [0.15.12] - 2026-08-12

### Changed
- **Reverted 0.15.11's shorter tabs** back to the original height, and widened them by the requested 1.2× instead.
- **Brought back a clear "this tab is open" indicator** — a small teal dot icon on the active tab, instead of 0.15.9's border accent stripe. Tab icons are a native `QTabBar` feature Qt paints in its own dedicated slot, so it can't collide with this tab bar's native-theme box-model quirks the way a border property did.

## [0.15.11] - 2026-08-12

### Changed
- **Shorter, wider tabs.** The tab strip's vertical padding is cut roughly in half (33px → 19px tall) and the horizontal padding is increased — direct feedback on the tab row's proportions.
- **Paired field pickers in the Charts tab.** X/Category + Y, and Group/Color + Value/Size, now sit two-up in one row each instead of four separate full-width rows, saving vertical space in an already long Chart card.

## [0.15.10] - 2026-08-12

### Fixed
- **Reverted 0.15.9's accent-stripe border on the active tab.** A real screenshot showed it covering part of the tab's text with a white strip, not highlighting it — this native Windows tab style had already shown once (0.15.6) that it doesn't reliably honour a custom QSS border addition, and the accent stripe turned out to be another instance of the same problem. The active tab is shown with a background/text-colour difference again, exactly as it was in every release before 0.15.9, with no border property on this tab bar at all. Tab widths remain proportionate to each label (unchanged from 0.15.9 — that part wasn't the problem).

## [0.15.9] - 2026-08-12

### Changed
- **Redesigned the tab strip.** Each tab is now sized to its own label instead of every tab being forced to match the widest one ("Diagrams") — the shared minimum-width fix from 0.15.8 fixed the fit, but made the two shorter tabs ("Charts", "Labels") look oversized and out of proportion. The active tab is now shown with a clean teal accent stripe along its top edge — a clearer, more conventional way to signal "this one is open" than relying on a size or colour difference alone, and it holds the same reserved thickness whether selected or not, so choosing a tab never resizes it.

## [0.15.8] - 2026-08-12

### Fixed
- **Tab labels are correctly sized on every machine, not guessed.** A second real screenshot showed "Diagrams" and "Labels" still losing their last letter to the ellipsis fallback, meaning every fixed padding value tried across 0.15.2–0.15.7 still came up short against real desktop font rendering — this project's offscreen test harness simply can't reproduce the exact metrics of a real Windows session closely enough to pin down the right constant by trial and error. Instead of another guessed number, the tab bar's minimum width is now measured at runtime from `QFontMetrics` on the actual font Qt is using on your machine, with a generous safety margin added on top — it is derived from the same measurement Qt itself uses to paint the text, so it cannot be wrong about its own labels' width regardless of font, size, or DPI. Verified against four very different test fonts/sizes to confirm the value tracks whatever is actually active rather than assuming one specific font.

## [0.15.7] - 2026-08-12

### Changed
- **Tabs are noticeably bigger than their own text**, not just barely fitting it.
- **Removed the toolbar's separate "About" icon.** Its content already lives in the dock's own Guide — a second icon was pure redundancy.
- **The Guide now links to the online documentation site** (a small "🌐 Online docs & manual" link in its sidebar, always visible while scrolling).
- **Histogram axis labels are rounded** to at most 3 decimal places instead of Python's default 6-significant-figure formatting, which could produce long, unreadable numbers for small-magnitude fields (a 0–1 ratio field, for instance) and made the chart hard to read.

### Fixed
- **Suggest on a wide/tall layer no longer pulls every field into memory before even deciding whether to sample.** The 0.15.4 fix bounded the O(fields²·rows) correlation *scan*, but a report of the crash recurring twice more showed that wasn't the whole story: pulling every column of a genuinely wide grid/zonal-statistics layer into Python for up to 100,000 rows was itself heavy enough to strain memory, before any analysis began. The field count is now checked from cheap layer metadata and bounded up front — 60 numeric fields by default, 300 if you explicitly choose "Scan the full dataset" — independent of, and in addition to, the existing scan cap.

## [0.15.6] - 2026-08-12

### Fixed
- **Found the actual cause of the tab-label clipping**, from a user screenshot rather than another guess: every tab was missing its *first letter* — "Charts" read "harts", "Diagrams" read "iagram", "Labels" read "abels". That is a known Qt/Windows quirk: the native Windows tab style paints tabs through the real Windows theme engine, which reserves its own internal left inset that a custom stylesheet doesn't fully override, so the leading glyph gets painted under the tab's rounded left edge. This project's offscreen test harness has no native Windows theme engine to reproduce it against, which is why the previous few rounds (width, padding, label length) all missed the real mechanism. Fixed with extra left padding on each tab plus a small leading space in the label text — whatever gets eaten from the left edge is now blank space, never a real letter, regardless of the exact pixel amount. (An attempt to force the tab bar onto Qt's own Fusion style — which draws purely from the stylesheet and would have sidestepped the native theme rendering entirely — was tried and reverted: it segfaulted on dock teardown and didn't reliably apply anyway, likely from mixing an explicit style override with the panel's own stylesheet-driven style proxy. Not worth the crash risk for an unproven fix.)

## [0.15.5] - 2026-08-12

### Changed
- **More breathing room in the tab strip.** Each tab's padding is more generous again (without reintroducing 0.15.2's fixed minimum width, so tabs still shrink to fit any dock size instead of running off the edge).
- **Suggest asks first on a wide or tall layer.** If the layer has enough numeric fields or rows that the correlation search would otherwise be limited to a sample, Suggest now shows a short dialog: use a fast representative sample (recommended — the previous, silent default) or scan the entire dataset, with a plain-language note about what that trade-off means. Either way, the result now says which one was used, and a sampled result invites you to Suggest again and choose the full scan.

## [0.15.4] - 2026-08-12

### Fixed
- **A real regression from 0.15.2/0.15.3.** Forcing the tab strip to expand and hold a fixed minimum width meant Qt kept it at that size even when the dock was too narrow to show it — and with the panel's horizontal scrollbar disabled (from the earlier scrollable-panel fix), the overflow simply ran off the right edge with no way to reach it. That is worse than the original "tab looks tight" complaint: a real user report confirmed part of the "Diagrams" label was being clipped mid-letter. Tabs are back to their natural, always-fit width (verified: every tab's text fits its own box at every dock width from 140px to 600px) with an ellipsis fallback for a genuine edge case, and the panel's horizontal scrollbar is now shown whenever something actually needs it, so nothing can become silently unreachable again.
- **The real cause of an oversized panel.** Two tab intro sentences ("Draw a diagram on every feature…" and "Turn fields into well-placed labels…") were missing word-wrap, so Qt sized them to fit their *entire sentence on one line* — over 1000px each — which alone was forcing the whole studio panel more than 1500px wide. Both now wrap normally.
- **A crash/hang risk in 💡 Suggest on wide layers.** Scanning every pair of numeric fields for the strongest correlation is quadratic in field count. A typical layer has a handful of numeric fields and this is instant, but a grid or zonal-statistics layer can carry dozens to hundreds of derived numeric columns over up to 100,000 rows — uncapped, that is hundreds of millions of pure-Python operations run synchronously on the UI thread, which can read as QGIS freezing or being killed outright rather than a slow click. The scan is now bounded to an evenly-sampled subset of rows and the first 40 numeric fields, so Suggest stays fast and safe regardless of the layer's width or height.

## [0.15.3] - 2026-08-12

### Changed
- **The Map diagrams tab is now labelled "Diagrams" in the tab strip.** Even with 0.15.2's wider, evenly-shared ribbon, the full "Map diagrams" label could still run tight against real desktop font metrics on a narrower dock. A shorter label removes the dependency on exact dock width or font rendering entirely — the tab's own card and the guide still say "Map diagrams" in full. A text-elide fallback ("…") is also set, so any future overflow degrades gracefully instead of silently clipping.

## [0.15.2] - 2026-08-12

### Changed
- **The tab ribbon (Charts / Map diagrams / Labels) now fills its full width.** Each tab used to be sized only to its own text plus a little padding; the three now stretch evenly to use the whole row, so the longest label ("Map diagrams") gets generous room instead of a tight fit.
- **Render chart gets a visual accent.** The button carries a soft salmon ("yavru ağzı") stroke around its usual teal fill, so the studio's single most-used action stands out from the row of export/suggest buttons around it.

## [0.15.1] - 2026-08-12

### Fixed
- **The dock content was squashed instead of scrolling on a short panel.** Docking the studio narrow/short (or on a small screen) simply compressed every row instead of letting you reach the rest — the panel is now wrapped in a scroll area, so it still stretches to fill a tall dock exactly as before, but scrolls when there isn't enough height instead of clipping the bottom rows away.
- **The selected tab's label looked clipped/unreadable.** `QTabBar::tab:selected` set a bolder font weight than the unselected tabs, but Qt sizes each tab's box once from its normal-weight text and does not re-lay it out on a pseudo-state change — so the wider bold glyphs of the active tab (worst on "Map diagrams") overflowed the box they were already sized for. All three tabs now use the same font weight, so the active tab is still clearly highlighted (background + colour) but never grows past its own label.

## [0.15.0] - 2026-08-11

### Fixed
- **Toolbar icon needed two clicks to open the studio.** `iface.addDockWidget()` already makes a freshly created dock visible, so the old toggle handler's `setVisible(not isVisible())` ran against an already-visible dock on that very first click and immediately hid it again — the user had to click the icon a second time to actually see the panel. The first click now always shows the dock; every click after that toggles normally.

### Added
- **Proportional-symbol map diagrams.** The Map diagrams tab has a new "Size by" field: pick a numeric field and every feature's diagram is linearly scaled between a small and a full-size diagram by that field's value (backed by QGIS's native `QgsLinearlyInterpolatedDiagramRenderer`), instead of every feature drawing the same fixed size — the classic proportional-symbol map. Leave it empty for the previous fixed-size behaviour.
- **Diagram opacity control** in the Map diagrams tab (was already supported by the renderer but never exposed).
- **Avoid overlaps** checkbox for map diagrams: lets QGIS drop diagrams that would collide instead of always drawing every one of them regardless of space.
- **Chip label preset**: a new rounded background badge behind the label text, alongside the existing Clean / Strong halo / Bold / Plain presets.

## [0.14.4] - 2026-08-07

- Added online user manual link (https://yusufeminoglu.github.io/zero2viz/) and GitHub repository star call-to-action.

## [0.14.3] - 2026-08-07

- Expand reference manual 3x with theory, math, 10 DOI refs

All notable changes to **02viz - Geospatial Visualization Studio** are documented here.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · versioning: [SemVer](https://semver.org/).

## [0.14.0] - 2026-07-29

### Added

- **Reviewed SmartModeler bridge.** SmartModeler GIS can now open 02viz for one
  exact live project vector-layer id and invoke the existing fully offline
  smart suggestion path after the user approves a `plugin_action` card. 02viz
  selects the layer, chooses a suitable chart from its local field statistics,
  and renders it in the dock. The bridge accepts no path, URL, export target,
  custom Vega-Lite specification, expression, or arbitrary method name, and it
  returns no feature values.

## [0.13.0] - 2026-07-19

### Added
- **Reusable chart presets.** Save a named chart setup and recall it across QGIS sessions, including the engine and chart type, field bindings, aggregation and sorting, animation, selection scope, theme or custom palette, reference overlays, and custom Vega-Lite JSON. Loading against another layer clears unavailable fields and reports them instead of failing.

## [0.12.0] - 2026-07-14

### Added
- **Reference & statistics overlays.** Bar, line, area, scatter and bubble charts can now carry horizontal guide lines and shaded bands on the value axis: the **mean**, the **median**, a **target** value you type, a **±1σ** band (mean ± one standard deviation) and the **inter-quartile** band (Q1–Q3). Turn any combination on from a *Reference:* row in the Charts tab. The values are computed in pure Python from the plotted numbers (`core/overlays.py`) and drawn identically by every engine — ECharts mark-lines/areas, Plotly shapes, Vega-Lite rule/rect layers and matplotlib `axhline`/`axhspan` — so they read the same in light and dark themes and export with the chart. Overlays are skipped while a chart is animating (the play axis tells its own story).

### Changed
- **The studio no longer runs pip.** When the optional matplotlib/seaborn engine is missing, the dock now shows the exact install command to run yourself (with a Copy button) instead of shelling out to `pip install`. A QGIS plugin should not execute a package manager; this keeps 02viz offline and side-effect free and lets it pass the QGIS Plugin Hub security scan with zero findings.

### Fixed
- Replaced the remaining bare `try/except: pass` blocks with `contextlib.suppress`, clearing the last Bandit warnings so the security scan is clean.

## [0.11.1] - 2026-07-10

### Changed
- Remove the top-level "&02viz" QGIS menu registration; the studio now only adds its toggle icon to its own toolbar, so it no longer shows up as its own menu tab next to Help.

### Added
- Remember the last folder used to load an external table or export a chart as HTML/PDF, across QGIS sessions.

## [0.11.0] - 2026-07-10

- Added a validated custom Vega-Lite JSON editor with offline named-dataset injection and graceful parse errors.
- Added SVG, PNG and PDF export actions, including native QGIS PDF rendering.
- Added an Explore tile picker and pure profile section filtering.
- Extended cross-filter ids to line and area symbols and treemap/sunburst nodes.
- Refreshed the guide, README and release icon for the 0.11.0 workflow.
## [0.10.2] - 2026-06-18

- docs: add CITATION.cff for Zenodo DOI integration

## [0.10.1] - 2026-06-16

- **Hub upload compatibility fix.** `metadata.txt` no longer contains a raw percent sign in the long Hub description/changelog text. QGIS Plugin Hub parses metadata with INI interpolation rules, so `missing %` caused the upload parser to fail before reading the package. Plugin code and features are unchanged from 0.10.0.

## [0.10.0] - 2026-06-16

- **Map diagrams can normalise their fields.** A new *Normalize* control rewrites each diagram field as an expression so fields on very different scales become comparable on every feature, instead of one big-number field swamping the rest. **Min–max (0–1)** is the safe default for pie/bar; **Z-score** standardises (great for bars; can be negative); **Log** compresses heavy tails. Each field's min/max/mean/std are computed from the (optionally selected) features and baked into the diagram's category expressions — **nothing is written to your data**. A live hint warns when Z-score is paired with a pie/stacked diagram (which can't draw negative angles).
- **Labels are now expression-driven.** Beyond a single field you can **round** numbers, add a **thousands separator**, stack a **second field on its own line** (a real newline via `char(10)`), add a **prefix/suffix** or units, change **case**, **word-wrap**, or type **any QGIS expression** in an advanced box that overrides the controls. A live **preview** shows the exact expression and a sample from the first feature, and numeric formatting is applied **only to numeric fields**, so a name on a second line is never wrapped in `round()`. Built on `QgsPalLayerSettings` expressions (`core/expressions.py`).
- **A built-in, offline user guide (❔ Guide).** A designed, self-contained HTML guide covers every surface — engines and the 17 chart types, animation, Explore, map-diagram **normalisation** (with worked examples), **copy-ready label-expression recipes**, the smart assistant, troubleshooting — plus **copy-ready prompts for an external AI assistant** (ChatGPT/Claude) for those who want extra help. No JavaScript, so it renders on every QGIS web backend and exports/opens anywhere. When opened from the dock it includes a personalised *“For your current layer”* section.
- **Smart suggestions (💡 Suggest), fully offline.** The dock reads the active layer's fields and picks the most insightful chart — a correlated-pair scatter with a trend line, a mean-by-category bar, a count bar or a histogram — configures the controls and renders it, telling you *why*. No account, no internet, no new dependencies (`core/assistant.py`).
- **Explore, levelled up.** The dashboard adds a collapsible **field-summary table** (type · missing % · distinct · range/top per field), an overall **completeness** KPI, a **normalised box plot** putting every numeric field on one 0–1 axis (the same comparability idea as the map-diagram normaliser), and deeper **insights** — dominant-category share, range, **skew with a log-transform hint**, **outliers** (1.5×IQR), near-constant and mostly-empty fields, and a couple more notable correlations.
- Verified end-to-end on **QGIS 3.44** and **QGIS 4**: expression labels evaluate to multi-line, formatted text; all four normalisation expressions parse and evaluate; the richer profile/dashboard build; the assistant and guide produce the expected output; and the dock wiring (label/diagram apply, Suggest, hints) was driven offscreen. No regression in the 48 static + 12 animated engine pages or the existing profile/dashboard tests.

## [0.9.2] - 2026-06-16

- **Plotly and Vega-Lite no longer leave a blank panel on QGIS builds without QtWebEngine.** When a QGIS build ships no QtWebEngine, the embedded panel falls back to the legacy QtWebKit viewer — and that old viewer cannot run the modern JavaScript (ES6+) that Plotly.js and Vega-Lite require, so their charts stayed blank in the dock even though they exported and opened correctly in a browser. ECharts and the matplotlib image engine were unaffected (they run on QtWebKit). The dock now detects the QtWebKit viewer and, for Plotly/Vega-Lite, shows a short explainer in the panel instead of a silent blank: your chart is still built — one click on **↗** opens it in your system browser, or use **Export HTML**. For a chart that renders inside the dock, switch to the **ECharts** engine, or install QtWebEngine for QGIS.
- Root-caused in real QGIS: under QtWebKit the engines fail with `ReferenceError: Can't find variable: Plotly` / `vega` (the bundles never parse), while ECharts renders normally; under QtWebEngine (QGIS 4 / Qt6) all engines render. Chart output, the engines themselves and exports are unchanged — this only affects what the embedded panel shows on a QtWebKit-only QGIS.

## [0.9.1] - 2026-06-16

- **Readable on QGIS 4 (Qt6).** The studio panel now pins its own light colours for every control, so it reads identically under any QGIS theme. On QGIS 4 the dark application palette bled into the parts the panel didn't explicitly colour: the drop-down lists rendered on a near-black background and the field labels and check-box text faded into the white cards. Combo pop-ups, line edits, spin boxes, the diagram field list, form labels, check boxes and tool-tips are now explicitly styled — white fields, dark text, teal selection — independent of the host palette. QGIS 3.x looked correct before (its palette is light) and is unchanged.
- The fix is purely the dock's stylesheet; the chart engines, rendering and exports are untouched. Re-verified end-to-end on **QGIS 4.0.2** and **QGIS 3.44**: all four engines render every supported type (ECharts 17, Plotly 17, Vega-Lite 14, matplotlib 11) plus the 12 animated pages, with zero JS exceptions in headless Chrome; the panel and an open drop-down were also grabbed under a simulated dark palette to confirm white fields and dark, legible text.

## [0.9.0] - 2026-06-16

- **Animated charts — a play axis.** Pick an *Animate by ▶* field (typically a year or sequence) and the chart plays through that field's values: a **bar-chart race**, **Gapminder-style bubbles**, or composition/trends unfolding over time. Available for **bar, line, area, scatter, bubble and pie** in the two interactive engines — **ECharts** (a timeline with auto-play) and **Plotly** (a slider with play / pause). A *Play speed* control sets the pace; the play axis greys out for engines and chart types that cannot animate (Vega-Lite, matplotlib, and types like box/heatmap/violin), consistent with the existing engine-first gating.
- **Things animate in place, not jump.** Every frame shares one axis: categories are merged into a stable, deterministically ordered union (a district keeps its slot and colour), the value axis is fixed to the global range across all frames, bubble sizes are scaled once globally so a value maps to the same radius throughout, and grouped series keep a consistent colour order. The current frame is shown as a subtitle (ECharts) and on the slider (Plotly).
- **Still linked to the map.** Animated bars and points carry their feature ids per frame, so clicking one during playback still selects the matching features on the canvas (cross-filter dimming pauses while animating, since each frame redraws the whole chart).
- **No new dependencies.** The frame builder is pure Python (`transform.build_frames` / `frame_groups` / `union_categories` / `align_values`); the vendored ECharts and Plotly engines do the rest entirely offline, and an animated chart still exports as one self-contained HTML file (with its play controls) like any other.
- Verified headless: real-QGIS checks for the frame builder (numeric/lexicographic frame ordering, union axis, global bounds, per-frame ids) and 12 animated engine×type pages, plus 12 animated pages in headless Chrome — auto-play stepping, slider/play controls present, zero JS exceptions; the bar-chart race, Gapminder bubbles, animated pie and lines eyeballed. No regression in the 48 static pages.

## [0.8.0] - 2026-06-13

- **One dock, three tabs** — the studio is now organised as **Charts · Map diagrams · Labels**, all sharing a single layer selector above the tabs. Same purpose throughout — turn a layer's data into an elegant visual — across three output surfaces.
- **Labels tab** — one click turns a field into well-placed, publication-grade labels with a preset (clean subtle-halo / strong halo / bold / plain), geometry-aware placement, built on native `QgsPalLayerSettings` (`core/labels.py`). Prints and exports like any QGIS labeling.
- **Embedded colour editor** — the palette is now an **inline swatch strip** in the Charts tab: click a swatch to recolour it, `+`/`−` to resize the palette, any edit switches to a custom palette — no modal dialog. Added a **chart-title override** field. (The old pop-up palette editor is gone.)
- **Optional advanced engine: matplotlib / seaborn** — a fourth engine renders the spec to **publication-grade static figures** (eleven chart types) and embeds them as a PNG in the same HTML shell, so the viewer and one-file export work unchanged. It appears in the engine picker; when its libraries are missing the dock offers a **one-click install** into the QGIS Python (`python -m pip install --user`, explicit consent only — `core/requirements.py`). The vendored JS engines stay zero-dependency and fully offline; this is the opt-in print/publication path (no chart→map interactivity on static images).
- **Zero2Visual** — the plugin's motto (“from zero to elegant visuals, fast”) now reads in the dock header and About box; the Hub name and "02viz" branding are unchanged.
- Verified headless: 86 checks on real QGIS Python (incl. the matplotlib engine across 11 types, on-canvas labels and the dependency detector) and 50 interactive chart pages in headless Chrome with zero JS exceptions; the matplotlib figures eyeballed.

## [0.7.0] - 2026-06-13

- **Map diagrams (on-canvas charts)** — a new *Map diagrams…* dialog draws native QGIS **pie / bar / stacked-bar / text** diagrams on every feature, directly on the map canvas, sized in millimetres and coloured with the studio palette. Built on `QgsDiagramRenderer`, so the diagrams print, export to print layouts and follow the layer like any other symbology. Numeric fields are pre-ticked (identifier columns skipped); attribute-only tables are detected and declined.
- **Custom colour palettes** — the *Colors* selector gains a **Custom…** entry that opens a swatch editor (add / remove / recolour via the system colour picker, seeded from the active palette). The result is written straight into the theme palette, so it recolours ECharts, Plotly and Vega-Lite identically — single charts and Explore dashboards alike.
- **Fixed: charts blank in the dock but fine on export** — the embedded viewer gave the chart container no definite height until after its first layout pass, so ECharts/Plotly/Vega measured a height of 0 and painted nothing (while export-to-browser worked). The chart box is now absolutely sized and re-fits once the view settles; the dock also nudges a resize on load. Added an **↗ open-in-browser** escape hatch and surfaced the active web backend (webengine / webkit) in the status line.
- **Engine-first workflow** — the dock now asks for the **Engine first**, then the chart **Type**, with unsupported types greyed out for the chosen renderer from the start.
- **Explore ignores identifier columns** — `fid`, `id`, `gid`, `oid`, `uuid`, `objectid`, `*_id`, and provider primary keys are no longer profiled into meaningless histograms or count bars on the dashboard.
- **Publication-grade visual polish** — one shared type system across all three engines, soft dashed horizontal gridlines (no vertical chart-junk), clean card-style tooltips, rounded bar tops and minimal value axes — output reads at Tableau quality.
- Verified headless: 73 checks on real QGIS Python (incl. the on-canvas diagram renderer and the identifier-column filter) and 50 chart pages in headless Chrome with zero JS exceptions; the polished output eyeballed across engines and themes.

## [0.6.0] - 2026-06-12

- **Six new advanced chart types** (17 total): **Mean ± σ band** (line with a shaded ±1 standard-deviation envelope), **Mean ± σ bars** (bars with std-dev whiskers), **Density (KDE)** (Gaussian kernel density curves, optionally one per group), **Violin plot** (mirrored KDE shapes with median dots), **Radar / spider** (multi-axis comparison with per-axis scaling) and **Pareto (80/20)** (descending bars plus a cumulative-share line on a second axis). All statistics — sample standard deviation, Silverman-bandwidth KDE, violin polygons, cumulative shares — are computed in pure Python and rendered by all three engines from one spec; only radar is greyed out for Vega-Lite (the grammar has no polar coordinates).
- **Color palettes** — a new *Colors* selector with 8 curated palettes (Vivid, Colorblind safe, Viridis, Sunset, Ocean, Earth, Berry, Grayscale print). The chosen palette overrides the theme palette identically in ECharts, Plotly and Vega-Lite, for single charts and Explore dashboards alike.
- Engine correctness fixes caught during visual verification: ECharts custom-series whiskers and violins now set explicit axis extents (custom series don't drive autoscaling, so +σ caps and violin tails were clipped) and error whiskers use a contrasting colour; Vega-Lite multi-series density sets `stack: null` (stacked-area zero-imputation turned smooth KDE curves into a sawtooth) and the violin ranged area dropped its `order` channel (it faceted every violin into degenerate per-row paths).
- Verified headless: 71 checks on real QGIS Python and 50 chart pages in headless Chrome with zero JS exceptions; every new engine×type screenshot eyeballed.

## [0.5.0] - 2026-06-12

- **Third engine: Vega-Lite** — vendored `vega` + `vega-lite` (BSD-3, compiled in the page, no vega-embed), fully offline. Renders 9 of the 11 chart types from the same spec contract (treemap/sunburst are not part of the Vega-Lite grammar), including layered box plots from precomputed quartiles and labelled heatmaps. Chart→map clicks and map→chart cross-filter dimming work exactly as in the other engines.
- **Engine-aware chart types** — engines declare what they can draw (`ChartEngine.supports`); the dock greys out unsupported types and jumps to the nearest supported one.
- **Heatmap label contrast fixed in all engines** — on sequential ramps, low-value cells are light, so white labels were invisible there; white is now used only on dark cells (both extremes on diverging ramps, upper end on sequential ones).

## [0.4.0] - 2026-06-12

- **Map → chart cross-filter**: selecting features on the canvas instantly dims every non-selected bar, slice and point — in the single chart and across all dashboard tiles — without a re-render (ECharts per-item opacity, Plotly native `selectedpoints`). A freshly rendered chart immediately reflects the current selection.
- **Crash-safe selection bridge**: chart clicks now reach QGIS through the page title (`titleChanged`) instead of `addToJavaScriptWindowObject`/`QWebChannel`, fixing an access-violation crash on QGIS builds that ship the legacy QtWebKit stack. One code path for WebKit and WebEngine; vendored `qwebchannel.js` removed.
- The chart→map bridge logic is now covered by headless real-QGIS tests (38 checks) and the cross-filter by the headless-Chrome harness (24 pages).

## [0.3.1] - 2026-06-12

- Package directory renamed from `02viz` to `zero2viz`: the QGIS Plugin Hub requires the zip's top-level directory to be a valid Python identifier (PEP 8), and the digit-first name was rejected at upload. The displayed plugin name, features and behaviour are unchanged.

## [0.3.0] - 2026-06-12

- ✨ **Explore**: one click profiles every field of a layer and builds a complete interactive dashboard — KPI cards, a count bar per categorical field, a histogram per numeric field, a Pearson correlation matrix (diverging colors), the strongest-relationship scatter with trend line, and plain-English insight chips. Exports as a single HTML file; every chart stays clickable (chart → map selection).
- Honest axes: bar, area and histogram value axes now always start at zero (a category could previously disappear).
- Heatmap polish: per-cell value labels with automatic contrast (white on intense cells) and a diverging red-teal ramp for correlation matrices in both engines.
- Human number formatting in titles and insights (219,250 instead of 2.192e+05).

## [0.2.0] - 2026-06-12

- Second rendering engine: Plotly.js (vendored, MIT) — switch engines per chart, same spec.
- Five new chart types: area (stackable), bubble, heatmap (matrix), treemap, sunburst — 11 total.
- Chart → map selection: clicking a bar, slice or point selects the matching features on the canvas (QtWebKit window-object bridge + QtWebEngine QWebChannel bridge).
- Live mode: optionally re-render the chart on every canvas selection change (with a loop guard for chart-driven selections).
- Group / Color-by field: grouped or stacked multi-series bars, multi-line, multi-area, colored scatter series.
- Data shaping: Top-N with "Other" collapse, value sorting, least-squares trend line, sqrt-scaled bubble sizes.
- Four themes (Studio Light, Ink Dark, Soft Pastel, Bold Print) applied consistently across both engines.
- Verified headless: 31 checks on real QGIS Python + all 22 engine×type combinations rendered in headless Chrome with zero JS errors.

## [0.1.0] - 2026-06-12

- Chart studio MVP: bar, line, scatter, histogram, pie/donut and box plot rendered by a vendored Apache ECharts engine (interactive HTML, fully offline).
- Data binding: any vector layer or table, selected-features-only mode, external CSV/XLSX/ODS tables via OGR.
- Pure-Python aggregation (count/sum/mean/median/min/max), histogram binning, box-plot quartiles.
- Embedded viewer with WebEngine → WebKit → system-browser fallback chain; one-file interactive HTML export.
