plotaviz 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {plotaviz-0.1.0 → plotaviz-0.2.0}/PKG-INFO +72 -25
  2. {plotaviz-0.1.0 → plotaviz-0.2.0}/README.md +70 -23
  3. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/__init__.py +1 -1
  4. plotaviz-0.2.0/plotaviz/core/analysis.py +766 -0
  5. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/codegen.py +293 -22
  6. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/exporter.py +125 -4
  7. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/__init__.py +12 -5
  8. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/anthropic.py +22 -4
  9. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/base.py +41 -4
  10. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/gemini.py +28 -2
  11. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/ollama.py +26 -3
  12. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/llm/openai.py +23 -3
  13. plotaviz-0.2.0/plotaviz/core/loader.py +683 -0
  14. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/plotter.py +439 -116
  15. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/preprocess.py +264 -32
  16. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/profiler.py +79 -15
  17. plotaviz-0.2.0/plotaviz/core/report.py +314 -0
  18. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/selector.py +12 -3
  19. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/session.py +68 -6
  20. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/spec.py +26 -1
  21. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/main.py +251 -9
  22. plotaviz-0.2.0/plotaviz/ui/cleaning_panel.py +169 -0
  23. plotaviz-0.2.0/plotaviz/ui/customize_panel.py +174 -0
  24. plotaviz-0.2.0/plotaviz/ui/dashboard_view.py +252 -0
  25. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/export_dialog.py +63 -1
  26. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/filter_panel.py +148 -11
  27. plotaviz-0.2.0/plotaviz/ui/import_dialog.py +186 -0
  28. plotaviz-0.2.0/plotaviz/ui/interactive_view.py +385 -0
  29. plotaviz-0.2.0/plotaviz/ui/join_dialog.py +181 -0
  30. plotaviz-0.2.0/plotaviz/ui/main_window.py +1682 -0
  31. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/nl_query_bar.py +19 -5
  32. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/settings_dialog.py +203 -54
  33. plotaviz-0.2.0/plotaviz/ui/table_model.py +344 -0
  34. plotaviz-0.2.0/plotaviz/ui/theme.py +129 -0
  35. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/type_override.py +15 -4
  36. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/workers.py +52 -6
  37. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/PKG-INFO +72 -25
  38. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/SOURCES.txt +18 -1
  39. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/requires.txt +1 -1
  40. {plotaviz-0.1.0 → plotaviz-0.2.0}/pyproject.toml +2 -2
  41. plotaviz-0.2.0/tests/test_audit_regressions.py +413 -0
  42. plotaviz-0.2.0/tests/test_batch1.py +428 -0
  43. plotaviz-0.2.0/tests/test_batch2.py +277 -0
  44. plotaviz-0.2.0/tests/test_batch3.py +391 -0
  45. plotaviz-0.2.0/tests/test_chart_view.py +41 -0
  46. plotaviz-0.2.0/tests/test_dashboard.py +206 -0
  47. plotaviz-0.2.0/tests/test_features.py +321 -0
  48. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_llm.py +2 -1
  49. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_plotter.py +25 -0
  50. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_preprocess.py +7 -1
  51. plotaviz-0.2.0/tests/test_reaudit.py +157 -0
  52. plotaviz-0.2.0/tests/test_small_fixes.py +141 -0
  53. plotaviz-0.2.0/tests/test_ui_regressions.py +249 -0
  54. plotaviz-0.1.0/plotaviz/core/analysis.py +0 -230
  55. plotaviz-0.1.0/plotaviz/core/loader.py +0 -366
  56. plotaviz-0.1.0/plotaviz/ui/interactive_view.py +0 -210
  57. plotaviz-0.1.0/plotaviz/ui/main_window.py +0 -859
  58. plotaviz-0.1.0/plotaviz/ui/table_model.py +0 -184
  59. {plotaviz-0.1.0 → plotaviz-0.2.0}/LICENSE +0 -0
  60. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/__init__.py +0 -0
  61. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/errors.py +0 -0
  62. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/core/rules.yaml +0 -0
  63. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz/ui/__init__.py +0 -0
  64. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/dependency_links.txt +0 -0
  65. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/entry_points.txt +0 -0
  66. {plotaviz-0.1.0 → plotaviz-0.2.0}/plotaviz.egg-info/top_level.txt +0 -0
  67. {plotaviz-0.1.0 → plotaviz-0.2.0}/setup.cfg +0 -0
  68. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_cli.py +0 -0
  69. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_codegen.py +0 -0
  70. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_loader.py +0 -0
  71. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_profiler.py +0 -0
  72. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_selector.py +0 -0
  73. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_session.py +0 -0
  74. {plotaviz-0.1.0 → plotaviz-0.2.0}/tests/test_spec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotaviz
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Cross-platform desktop app that auto-selects and renders the right chart for any dataset — rules + scoring engine with optional LLM assist.
5
5
  Author: PlotaViz contributors
6
6
  License: MIT
@@ -21,7 +21,7 @@ Requires-Python: >=3.11
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: PySide6>=6.6
24
- Requires-Dist: pandas>=2.1
24
+ Requires-Dist: pandas<4,>=2.1
25
25
  Requires-Dist: numpy>=1.26
26
26
  Requires-Dist: polars>=0.20
27
27
  Requires-Dist: pyarrow>=14
@@ -55,6 +55,7 @@ Dynamic: license-file
55
55
  # PlotaViz
56
56
 
57
57
  [![CI](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml/badge.svg)](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml)
58
+ [![PyPI](https://img.shields.io/pypi/v/plotaviz)](https://pypi.org/project/plotaviz/)
58
59
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
59
60
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
60
61
  [![Qt: LGPLv3](https://img.shields.io/badge/Qt-LGPLv3-orange)](THIRD_PARTY_LICENSES.md)
@@ -101,7 +102,14 @@ between them in one click. The parts that usually go wrong are treated as first-
101
102
 
102
103
  Python 3.11 or newer.
103
104
 
104
- ### From source (all platforms)
105
+ ### From PyPI (all platforms)
106
+
107
+ ```bash
108
+ pip install plotaviz
109
+ plotaviz
110
+ ```
111
+
112
+ ### From source (contributing / latest main)
105
113
 
106
114
  ```bash
107
115
  git clone https://github.com/saadibnainan/plotaviz.git
@@ -118,7 +126,7 @@ Apple Silicon and Intel are both supported.
118
126
 
119
127
  ```bash
120
128
  brew install python@3.11 # if you need it
121
- pip install -e .
129
+ pip install plotaviz
122
130
  ```
123
131
 
124
132
  A prebuilt `.app` is attached to each [release](https://github.com/saadibnainan/plotaviz/releases).
@@ -146,7 +154,7 @@ sudo dnf install python3-devel libglvnd-egl xcb-util-cursor libxkbcommon-x11
146
154
  sudo pacman -S python libxkbcommon-x11 xcb-util-cursor
147
155
  ```
148
156
 
149
- Then either `pip install -e .`, or grab the **AppImage** from the releases page:
157
+ Then either `pip install plotaviz`, or grab the **AppImage** from the releases page:
150
158
 
151
159
  ```bash
152
160
  chmod +x PlotaViz-*.AppImage
@@ -159,9 +167,9 @@ To build one: `make build-appimage`. Recipes for `.deb`, `.rpm`, and an **AUR PK
159
167
  ### Optional extras
160
168
 
161
169
  ```bash
162
- pip install -e ".[llm]" # Anthropic / OpenAI / Gemini / Ollama providers
163
- pip install -e ".[fast]" # pyqtgraph fast path for very large numeric plots
164
- pip install -e ".[dev]" # tests, ruff, mypy, pre-commit
170
+ pip install "plotaviz[llm]" # Anthropic / OpenAI / Gemini / Ollama providers
171
+ pip install "plotaviz[fast]" # pyqtgraph fast path for very large numeric plots
172
+ pip install -e ".[dev]" # tests, ruff, mypy, pre-commit — source checkout only
165
173
  ```
166
174
 
167
175
  ---
@@ -173,13 +181,21 @@ plotaviz # open the app
173
181
  plotaviz samples/sales_timeseries.csv # open the app with a file
174
182
  ```
175
183
 
176
- 1. Drag a dataset in, or use **File → Open**.
177
- 2. Read the **cleaning report** — what was renamed, filled, deduplicated, flagged.
184
+ 1. Drag a dataset in, or use **File → Open**. For a semicolon file, a non-UTF-8 export, a title
185
+ row above the header, or a specific Excel sheet, use **File → Open with options…**.
186
+ 2. Read the **cleaning report** — what was renamed, deduplicated, flagged. Change how rows are
187
+ cleaned in the **Cleaning** tab; missing values are left alone unless you choose otherwise.
178
188
  3. Check the **Types** tab and correct anything inference got wrong.
179
- 4. Pick a chart from **Charts**. The reasoning for each is right there.
189
+ 4. Pick a chart from **Charts** — the reasoning for each is right there — or build one in the
190
+ chart row above it (works offline). Adjust title, labels, scales, and colours under
191
+ **Customize**.
180
192
  5. Narrow the data in **Filters** — per-column widgets, or a raw pandas query.
181
- 6. **File → Export** for the image, the interactive HTML, or the Python script.
182
- 7. **File → Save session** writes a `.pviz` file that restores all of it later.
193
+ **Edit → Undo** reverts any filter, type, or cleaning change.
194
+ 6. Several charts worth keeping? **Pin to dashboard** (Ctrl+D) and look at them together on
195
+ the **Dashboard** tab.
196
+ 7. **File → Export** for the image, the interactive HTML, or the Python script — of the chart,
197
+ or of the whole dashboard.
198
+ 8. **File → Save session** writes a `.pviz` file that restores all of it later.
183
199
 
184
200
  ### Command line
185
201
 
@@ -206,6 +222,18 @@ plotaviz --input data.csv --chart box --x region --y revenue \
206
222
 
207
223
  `--json` makes `--describe` and `--recommend` machine-readable.
208
224
 
225
+ ```bash
226
+ # Every CSV in a folder: one chart and one report per file
227
+ plotaviz --input "data/*.csv" --output-dir out --export .png --report .html
228
+
229
+ # A specific Excel sheet, or all sheets stacked with a 'sheet' column
230
+ plotaviz --input book.xlsx --sheet Data --auto --export chart.pdf
231
+ plotaviz --input book.xlsx --sheet '*' --report book.html
232
+
233
+ # Your own chart rules instead of the shipped rules.yaml
234
+ plotaviz --input data.csv --rules my_rules.yaml --recommend
235
+ ```
236
+
209
237
  ---
210
238
 
211
239
  ## How it decides
@@ -271,8 +299,10 @@ Both return a **structured chart spec (JSON), never executable code.** The spec
271
299
  against your real column names before anything renders; a hallucinated column is a clear error
272
300
  message, not a crash.
273
301
 
274
- **What gets sent:** column names, summary statistics, and up to 5 sample rows. Never the dataset.
275
- You are asked for consent before the first remote request.
302
+ **What gets sent:** column names, summary statistics, and up to five example and most-frequent
303
+ values per column — withheld entirely for identifier and free-text columns, which is where names
304
+ and e-mail addresses live. Never the dataset. Nothing goes to a remote provider until you tick
305
+ that provider's consent box in Settings; consent is per provider.
276
306
 
277
307
  **Where keys live:** your OS keychain, via `keyring`. Never a config file, never a session file,
278
308
  never the repo. Keys are redacted from logs and error messages.
@@ -285,8 +315,9 @@ ollama pull llama3.1
285
315
  ollama serve
286
316
  ```
287
317
 
288
- In **Settings → LLM provider**, choose **Ollama**. No API key, no network, no consent prompt —
289
- this is the right choice for sensitive data.
318
+ In **Settings → LLM provider**, choose **Ollama**. With the default `localhost` host there is no
319
+ API key, no network, and no consent prompt — this is the right choice for sensitive data. Point
320
+ it at another machine and it is treated like any remote provider: consent is required.
290
321
 
291
322
  Hosted providers: Anthropic (Claude), OpenAI, and Google Gemini. Install with
292
323
  `pip install -e ".[llm]"`, then paste a key in Settings.
@@ -295,18 +326,35 @@ Hosted providers: Anthropic (Claude), OpenAI, and Google Gemini. Install with
295
326
 
296
327
  ## Features
297
328
 
298
- - **Loading** — CSV, TSV, Excel, JSON, NDJSON, Parquet. Delimiter and encoding sniffing. Files
299
- over a configurable threshold read through polars and profile on a sample.
329
+ - **Loading** — CSV, TSV, Excel, JSON, NDJSON, Parquet. Delimiter, encoding, and European
330
+ decimal-comma detection, with manual import options (delimiter, encoding, decimal/thousands
331
+ marks, header line, Excel sheet). Files over a configurable threshold read through polars and
332
+ profile on a sample.
300
333
  - **Cleaning** — an ordered, replayable step list: name normalization, type coercion,
301
334
  missing-value strategies, IQR/z-score outlier flagging (non-destructive by default),
302
- deduplication. Every step reports what it changed.
335
+ deduplication. Every step reports what it changed; settings and individual steps are editable
336
+ in the Cleaning tab, and every change can be undone.
303
337
  - **Type override** — inferred roles shown and editable before analysis proceeds.
304
338
  - **Filters** — range widgets, multi-selects, date ranges, and a raw pandas-query bar. Filters are
305
339
  pipeline steps, so they serialize into sessions and generated code for free.
306
340
  - **Charts** — 15 types, interactive via Plotly in a WebEngine view, with a matplotlib canvas
307
341
  fallback when WebEngine is unavailable.
308
- - **Export** — PNG, SVG, PDF, JPEG, WebP at up to 1200 DPI; self-contained interactive HTML; or a
309
- standalone Python script in matplotlib or Plotly flavour.
342
+ - **Panels** — split a chart into one small chart per category (Customize → Panels by), when a
343
+ colour split has too many series to tell apart.
344
+ - **Join** — File → Join another dataset adds columns from a second file matched on key columns,
345
+ with a match-rate preview; undoable, saved in sessions, replayed by generated code.
346
+ - **Report** — File → Export report writes one offline HTML page or a PDF: summary, cleaning,
347
+ every column, missing values, correlations, recommended charts with their reasoning, and the
348
+ dashboard. Headless: `plotaviz --input data.csv --report report.html`.
349
+ - **Preview** — sort by any column (the whole dataset, not just the visible rows), search all
350
+ rows, and see a column's statistics.
351
+ - **Appearance** — View → Theme: follow the system, light, or dark. Exports always stay light.
352
+ - **Dashboard** — pin several charts (Ctrl+D) to see a dataset's trend, breakdown, and
353
+ distribution side by side. Tiles redraw from the current filters and cleaning, are saved in the
354
+ session, and export together as one PNG/SVG/PDF grid, one offline HTML page, or one script.
355
+ Headless: `plotaviz --input data.csv --dashboard 4 --export overview.pdf`.
356
+ - **Export** — PNG, SVG, PDF, JPEG, WebP at up to 1200 DPI; self-contained interactive HTML
357
+ (plotly.js embedded, works offline); or a standalone Python script in matplotlib or Plotly flavour.
310
358
  - **Sessions** — `.pviz` files store the recipe, not the data, and warn if the source changed.
311
359
  - **Guardrails** — automatic downsampling with a visible notice, top-N category capping,
312
360
  virtualized preview, debounced re-render.
@@ -387,9 +435,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for adding selector rules and LLM provide
387
435
 
388
436
  ## Roadmap
389
437
 
390
- Designed for, not built yet: auto EDA report export (HTML/PDF), a multi-chart dashboard grid, a
391
- chart customization panel (titles, palettes, axis scales), undo/redo across the step stack,
392
- colorblind-safe palettes and OS-following dark mode, and joining two datasets on a key.
438
+ Everything from the original roadmap is built — see [docs/AUDIT.md](docs/AUDIT.md) for what was
439
+ done and what is deliberately left open.
393
440
 
394
441
  Explicitly out of scope for v1: plugin architecture, localization, real-time streaming, and live
395
442
  database connectors.
@@ -1,6 +1,7 @@
1
1
  # PlotaViz
2
2
 
3
3
  [![CI](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml/badge.svg)](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/plotaviz)](https://pypi.org/project/plotaviz/)
4
5
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
5
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
6
7
  [![Qt: LGPLv3](https://img.shields.io/badge/Qt-LGPLv3-orange)](THIRD_PARTY_LICENSES.md)
@@ -47,7 +48,14 @@ between them in one click. The parts that usually go wrong are treated as first-
47
48
 
48
49
  Python 3.11 or newer.
49
50
 
50
- ### From source (all platforms)
51
+ ### From PyPI (all platforms)
52
+
53
+ ```bash
54
+ pip install plotaviz
55
+ plotaviz
56
+ ```
57
+
58
+ ### From source (contributing / latest main)
51
59
 
52
60
  ```bash
53
61
  git clone https://github.com/saadibnainan/plotaviz.git
@@ -64,7 +72,7 @@ Apple Silicon and Intel are both supported.
64
72
 
65
73
  ```bash
66
74
  brew install python@3.11 # if you need it
67
- pip install -e .
75
+ pip install plotaviz
68
76
  ```
69
77
 
70
78
  A prebuilt `.app` is attached to each [release](https://github.com/saadibnainan/plotaviz/releases).
@@ -92,7 +100,7 @@ sudo dnf install python3-devel libglvnd-egl xcb-util-cursor libxkbcommon-x11
92
100
  sudo pacman -S python libxkbcommon-x11 xcb-util-cursor
93
101
  ```
94
102
 
95
- Then either `pip install -e .`, or grab the **AppImage** from the releases page:
103
+ Then either `pip install plotaviz`, or grab the **AppImage** from the releases page:
96
104
 
97
105
  ```bash
98
106
  chmod +x PlotaViz-*.AppImage
@@ -105,9 +113,9 @@ To build one: `make build-appimage`. Recipes for `.deb`, `.rpm`, and an **AUR PK
105
113
  ### Optional extras
106
114
 
107
115
  ```bash
108
- pip install -e ".[llm]" # Anthropic / OpenAI / Gemini / Ollama providers
109
- pip install -e ".[fast]" # pyqtgraph fast path for very large numeric plots
110
- pip install -e ".[dev]" # tests, ruff, mypy, pre-commit
116
+ pip install "plotaviz[llm]" # Anthropic / OpenAI / Gemini / Ollama providers
117
+ pip install "plotaviz[fast]" # pyqtgraph fast path for very large numeric plots
118
+ pip install -e ".[dev]" # tests, ruff, mypy, pre-commit — source checkout only
111
119
  ```
112
120
 
113
121
  ---
@@ -119,13 +127,21 @@ plotaviz # open the app
119
127
  plotaviz samples/sales_timeseries.csv # open the app with a file
120
128
  ```
121
129
 
122
- 1. Drag a dataset in, or use **File → Open**.
123
- 2. Read the **cleaning report** — what was renamed, filled, deduplicated, flagged.
130
+ 1. Drag a dataset in, or use **File → Open**. For a semicolon file, a non-UTF-8 export, a title
131
+ row above the header, or a specific Excel sheet, use **File → Open with options…**.
132
+ 2. Read the **cleaning report** — what was renamed, deduplicated, flagged. Change how rows are
133
+ cleaned in the **Cleaning** tab; missing values are left alone unless you choose otherwise.
124
134
  3. Check the **Types** tab and correct anything inference got wrong.
125
- 4. Pick a chart from **Charts**. The reasoning for each is right there.
135
+ 4. Pick a chart from **Charts** — the reasoning for each is right there — or build one in the
136
+ chart row above it (works offline). Adjust title, labels, scales, and colours under
137
+ **Customize**.
126
138
  5. Narrow the data in **Filters** — per-column widgets, or a raw pandas query.
127
- 6. **File → Export** for the image, the interactive HTML, or the Python script.
128
- 7. **File → Save session** writes a `.pviz` file that restores all of it later.
139
+ **Edit → Undo** reverts any filter, type, or cleaning change.
140
+ 6. Several charts worth keeping? **Pin to dashboard** (Ctrl+D) and look at them together on
141
+ the **Dashboard** tab.
142
+ 7. **File → Export** for the image, the interactive HTML, or the Python script — of the chart,
143
+ or of the whole dashboard.
144
+ 8. **File → Save session** writes a `.pviz` file that restores all of it later.
129
145
 
130
146
  ### Command line
131
147
 
@@ -152,6 +168,18 @@ plotaviz --input data.csv --chart box --x region --y revenue \
152
168
 
153
169
  `--json` makes `--describe` and `--recommend` machine-readable.
154
170
 
171
+ ```bash
172
+ # Every CSV in a folder: one chart and one report per file
173
+ plotaviz --input "data/*.csv" --output-dir out --export .png --report .html
174
+
175
+ # A specific Excel sheet, or all sheets stacked with a 'sheet' column
176
+ plotaviz --input book.xlsx --sheet Data --auto --export chart.pdf
177
+ plotaviz --input book.xlsx --sheet '*' --report book.html
178
+
179
+ # Your own chart rules instead of the shipped rules.yaml
180
+ plotaviz --input data.csv --rules my_rules.yaml --recommend
181
+ ```
182
+
155
183
  ---
156
184
 
157
185
  ## How it decides
@@ -217,8 +245,10 @@ Both return a **structured chart spec (JSON), never executable code.** The spec
217
245
  against your real column names before anything renders; a hallucinated column is a clear error
218
246
  message, not a crash.
219
247
 
220
- **What gets sent:** column names, summary statistics, and up to 5 sample rows. Never the dataset.
221
- You are asked for consent before the first remote request.
248
+ **What gets sent:** column names, summary statistics, and up to five example and most-frequent
249
+ values per column — withheld entirely for identifier and free-text columns, which is where names
250
+ and e-mail addresses live. Never the dataset. Nothing goes to a remote provider until you tick
251
+ that provider's consent box in Settings; consent is per provider.
222
252
 
223
253
  **Where keys live:** your OS keychain, via `keyring`. Never a config file, never a session file,
224
254
  never the repo. Keys are redacted from logs and error messages.
@@ -231,8 +261,9 @@ ollama pull llama3.1
231
261
  ollama serve
232
262
  ```
233
263
 
234
- In **Settings → LLM provider**, choose **Ollama**. No API key, no network, no consent prompt —
235
- this is the right choice for sensitive data.
264
+ In **Settings → LLM provider**, choose **Ollama**. With the default `localhost` host there is no
265
+ API key, no network, and no consent prompt — this is the right choice for sensitive data. Point
266
+ it at another machine and it is treated like any remote provider: consent is required.
236
267
 
237
268
  Hosted providers: Anthropic (Claude), OpenAI, and Google Gemini. Install with
238
269
  `pip install -e ".[llm]"`, then paste a key in Settings.
@@ -241,18 +272,35 @@ Hosted providers: Anthropic (Claude), OpenAI, and Google Gemini. Install with
241
272
 
242
273
  ## Features
243
274
 
244
- - **Loading** — CSV, TSV, Excel, JSON, NDJSON, Parquet. Delimiter and encoding sniffing. Files
245
- over a configurable threshold read through polars and profile on a sample.
275
+ - **Loading** — CSV, TSV, Excel, JSON, NDJSON, Parquet. Delimiter, encoding, and European
276
+ decimal-comma detection, with manual import options (delimiter, encoding, decimal/thousands
277
+ marks, header line, Excel sheet). Files over a configurable threshold read through polars and
278
+ profile on a sample.
246
279
  - **Cleaning** — an ordered, replayable step list: name normalization, type coercion,
247
280
  missing-value strategies, IQR/z-score outlier flagging (non-destructive by default),
248
- deduplication. Every step reports what it changed.
281
+ deduplication. Every step reports what it changed; settings and individual steps are editable
282
+ in the Cleaning tab, and every change can be undone.
249
283
  - **Type override** — inferred roles shown and editable before analysis proceeds.
250
284
  - **Filters** — range widgets, multi-selects, date ranges, and a raw pandas-query bar. Filters are
251
285
  pipeline steps, so they serialize into sessions and generated code for free.
252
286
  - **Charts** — 15 types, interactive via Plotly in a WebEngine view, with a matplotlib canvas
253
287
  fallback when WebEngine is unavailable.
254
- - **Export** — PNG, SVG, PDF, JPEG, WebP at up to 1200 DPI; self-contained interactive HTML; or a
255
- standalone Python script in matplotlib or Plotly flavour.
288
+ - **Panels** — split a chart into one small chart per category (Customize → Panels by), when a
289
+ colour split has too many series to tell apart.
290
+ - **Join** — File → Join another dataset adds columns from a second file matched on key columns,
291
+ with a match-rate preview; undoable, saved in sessions, replayed by generated code.
292
+ - **Report** — File → Export report writes one offline HTML page or a PDF: summary, cleaning,
293
+ every column, missing values, correlations, recommended charts with their reasoning, and the
294
+ dashboard. Headless: `plotaviz --input data.csv --report report.html`.
295
+ - **Preview** — sort by any column (the whole dataset, not just the visible rows), search all
296
+ rows, and see a column's statistics.
297
+ - **Appearance** — View → Theme: follow the system, light, or dark. Exports always stay light.
298
+ - **Dashboard** — pin several charts (Ctrl+D) to see a dataset's trend, breakdown, and
299
+ distribution side by side. Tiles redraw from the current filters and cleaning, are saved in the
300
+ session, and export together as one PNG/SVG/PDF grid, one offline HTML page, or one script.
301
+ Headless: `plotaviz --input data.csv --dashboard 4 --export overview.pdf`.
302
+ - **Export** — PNG, SVG, PDF, JPEG, WebP at up to 1200 DPI; self-contained interactive HTML
303
+ (plotly.js embedded, works offline); or a standalone Python script in matplotlib or Plotly flavour.
256
304
  - **Sessions** — `.pviz` files store the recipe, not the data, and warn if the source changed.
257
305
  - **Guardrails** — automatic downsampling with a visible notice, top-N category capping,
258
306
  virtualized preview, debounced re-render.
@@ -333,9 +381,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for adding selector rules and LLM provide
333
381
 
334
382
  ## Roadmap
335
383
 
336
- Designed for, not built yet: auto EDA report export (HTML/PDF), a multi-chart dashboard grid, a
337
- chart customization panel (titles, palettes, axis scales), undo/redo across the step stack,
338
- colorblind-safe palettes and OS-following dark mode, and joining two datasets on a key.
384
+ Everything from the original roadmap is built — see [docs/AUDIT.md](docs/AUDIT.md) for what was
385
+ done and what is deliberately left open.
339
386
 
340
387
  Explicitly out of scope for v1: plugin architecture, localization, real-time streaming, and live
341
388
  database connectors.
@@ -13,7 +13,7 @@ The package is split into two halves that must not blur together:
13
13
 
14
14
  from __future__ import annotations
15
15
 
16
- __version__ = "0.1.0"
16
+ __version__ = "0.2.0"
17
17
  __app_name__ = "PlotaViz"
18
18
 
19
19
  __all__ = ["__app_name__", "__version__"]