plotaviz 0.1.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.
- plotaviz-0.1.0/LICENSE +21 -0
- plotaviz-0.1.0/PKG-INFO +410 -0
- plotaviz-0.1.0/README.md +356 -0
- plotaviz-0.1.0/plotaviz/__init__.py +19 -0
- plotaviz-0.1.0/plotaviz/core/__init__.py +53 -0
- plotaviz-0.1.0/plotaviz/core/analysis.py +230 -0
- plotaviz-0.1.0/plotaviz/core/codegen.py +482 -0
- plotaviz-0.1.0/plotaviz/core/errors.py +65 -0
- plotaviz-0.1.0/plotaviz/core/exporter.py +145 -0
- plotaviz-0.1.0/plotaviz/core/llm/__init__.py +211 -0
- plotaviz-0.1.0/plotaviz/core/llm/anthropic.py +61 -0
- plotaviz-0.1.0/plotaviz/core/llm/base.py +373 -0
- plotaviz-0.1.0/plotaviz/core/llm/gemini.py +51 -0
- plotaviz-0.1.0/plotaviz/core/llm/ollama.py +113 -0
- plotaviz-0.1.0/plotaviz/core/llm/openai.py +58 -0
- plotaviz-0.1.0/plotaviz/core/loader.py +366 -0
- plotaviz-0.1.0/plotaviz/core/plotter.py +790 -0
- plotaviz-0.1.0/plotaviz/core/preprocess.py +836 -0
- plotaviz-0.1.0/plotaviz/core/profiler.py +509 -0
- plotaviz-0.1.0/plotaviz/core/rules.yaml +190 -0
- plotaviz-0.1.0/plotaviz/core/selector.py +495 -0
- plotaviz-0.1.0/plotaviz/core/session.py +174 -0
- plotaviz-0.1.0/plotaviz/core/spec.py +236 -0
- plotaviz-0.1.0/plotaviz/main.py +329 -0
- plotaviz-0.1.0/plotaviz/ui/__init__.py +23 -0
- plotaviz-0.1.0/plotaviz/ui/export_dialog.py +228 -0
- plotaviz-0.1.0/plotaviz/ui/filter_panel.py +273 -0
- plotaviz-0.1.0/plotaviz/ui/interactive_view.py +210 -0
- plotaviz-0.1.0/plotaviz/ui/main_window.py +859 -0
- plotaviz-0.1.0/plotaviz/ui/nl_query_bar.py +219 -0
- plotaviz-0.1.0/plotaviz/ui/settings_dialog.py +313 -0
- plotaviz-0.1.0/plotaviz/ui/table_model.py +184 -0
- plotaviz-0.1.0/plotaviz/ui/type_override.py +159 -0
- plotaviz-0.1.0/plotaviz/ui/workers.py +222 -0
- plotaviz-0.1.0/plotaviz.egg-info/PKG-INFO +410 -0
- plotaviz-0.1.0/plotaviz.egg-info/SOURCES.txt +50 -0
- plotaviz-0.1.0/plotaviz.egg-info/dependency_links.txt +1 -0
- plotaviz-0.1.0/plotaviz.egg-info/entry_points.txt +2 -0
- plotaviz-0.1.0/plotaviz.egg-info/requires.txt +34 -0
- plotaviz-0.1.0/plotaviz.egg-info/top_level.txt +1 -0
- plotaviz-0.1.0/pyproject.toml +114 -0
- plotaviz-0.1.0/setup.cfg +4 -0
- plotaviz-0.1.0/tests/test_cli.py +323 -0
- plotaviz-0.1.0/tests/test_codegen.py +182 -0
- plotaviz-0.1.0/tests/test_llm.py +307 -0
- plotaviz-0.1.0/tests/test_loader.py +163 -0
- plotaviz-0.1.0/tests/test_plotter.py +254 -0
- plotaviz-0.1.0/tests/test_preprocess.py +279 -0
- plotaviz-0.1.0/tests/test_profiler.py +203 -0
- plotaviz-0.1.0/tests/test_selector.py +223 -0
- plotaviz-0.1.0/tests/test_session.py +177 -0
- plotaviz-0.1.0/tests/test_spec.py +146 -0
plotaviz-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohammad Saad Ibna Inan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
plotaviz-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plotaviz
|
|
3
|
+
Version: 0.1.0
|
|
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
|
+
Author: PlotaViz contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/saadibnainan/plotaviz
|
|
8
|
+
Project-URL: Issues, https://github.com/saadibnainan/plotaviz/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/saadibnainan/plotaviz/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: data-visualization,data-analysis,pyside6,qt,pandas,polars,plotly,matplotlib,desktop-app,llm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: PySide6>=6.6
|
|
24
|
+
Requires-Dist: pandas>=2.1
|
|
25
|
+
Requires-Dist: numpy>=1.26
|
|
26
|
+
Requires-Dist: polars>=0.20
|
|
27
|
+
Requires-Dist: pyarrow>=14
|
|
28
|
+
Requires-Dist: plotly>=5.18
|
|
29
|
+
Requires-Dist: matplotlib>=3.8
|
|
30
|
+
Requires-Dist: openpyxl>=3.1
|
|
31
|
+
Requires-Dist: keyring>=24
|
|
32
|
+
Requires-Dist: Jinja2>=3.1
|
|
33
|
+
Requires-Dist: PyYAML>=6.0
|
|
34
|
+
Provides-Extra: fast
|
|
35
|
+
Requires-Dist: pyqtgraph>=0.13; extra == "fast"
|
|
36
|
+
Provides-Extra: llm
|
|
37
|
+
Requires-Dist: anthropic>=0.34; extra == "llm"
|
|
38
|
+
Requires-Dist: openai>=1.40; extra == "llm"
|
|
39
|
+
Requires-Dist: google-genai>=0.3; extra == "llm"
|
|
40
|
+
Requires-Dist: httpx>=0.27; extra == "llm"
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest-qt>=4.4; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
45
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
46
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
47
|
+
Requires-Dist: pandas-stubs; extra == "dev"
|
|
48
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
49
|
+
Requires-Dist: pre-commit>=3.8; extra == "dev"
|
|
50
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
51
|
+
Provides-Extra: build
|
|
52
|
+
Requires-Dist: pyinstaller>=6.6; extra == "build"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# PlotaViz
|
|
56
|
+
|
|
57
|
+
[](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml)
|
|
58
|
+
[](https://www.python.org/downloads/)
|
|
59
|
+
[](LICENSE)
|
|
60
|
+
[](THIRD_PARTY_LICENSES.md)
|
|
61
|
+
[](https://docs.astral.sh/ruff/)
|
|
62
|
+
|
|
63
|
+
**A cross-platform desktop app that works out the right chart for your data, draws it, and hands
|
|
64
|
+
you the Python code that reproduces it.**
|
|
65
|
+
|
|
66
|
+
Open a CSV. PlotaViz cleans it, works out what each column actually is, ranks the charts that suit
|
|
67
|
+
the data — and tells you *why* it picked each one. Then it exports the image, or the standalone
|
|
68
|
+
script.
|
|
69
|
+
|
|
70
|
+
It runs entirely offline. An LLM is optional and only ever adds two things: a second opinion when
|
|
71
|
+
the ranking is close, and a query bar you can type "revenue by region over time" into.
|
|
72
|
+
|
|
73
|
+
<!-- Screenshots go here. For a GUI project this is the single biggest factor in whether anyone
|
|
74
|
+
tries it, so add them as soon as there is a working chart to show. -->
|
|
75
|
+
|
|
76
|
+
| | |
|
|
77
|
+
|---|---|
|
|
78
|
+
|  |  |
|
|
79
|
+
| *Preview, cleaning report, and the chart* | *Ranked alternatives, each with its reasoning* |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Why it exists
|
|
84
|
+
|
|
85
|
+
Most plotting tools make you decide the chart first and then fight the syntax. PlotaViz inverts
|
|
86
|
+
that: describe nothing, get a ranked set of charts that suit the shape of your data, and switch
|
|
87
|
+
between them in one click. The parts that usually go wrong are treated as first-class problems:
|
|
88
|
+
|
|
89
|
+
- **Type inference is wrong constantly.** IDs read as measures, dates read as text. So the
|
|
90
|
+
inferred types are shown up front and are editable *before* analysis proceeds.
|
|
91
|
+
- **Auto-generated charts hide their reasoning.** Every recommendation carries a plain-language
|
|
92
|
+
justification, and the alternatives are real charts you can switch to, not a dropdown.
|
|
93
|
+
- **Big data silently breaks charts.** Above ~100k points a scatter freezes a browser view. PlotaViz
|
|
94
|
+
downsamples (LTTB for time series) and says *"showing a sample of 100,000 of 8,400,000 points"*
|
|
95
|
+
on the chart and in the export.
|
|
96
|
+
- **You can't take the result anywhere.** Export the Python and it runs without PlotaViz installed.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Install
|
|
101
|
+
|
|
102
|
+
Python 3.11 or newer.
|
|
103
|
+
|
|
104
|
+
### From source (all platforms)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
git clone https://github.com/saadibnainan/plotaviz.git
|
|
108
|
+
cd plotaviz
|
|
109
|
+
python3 -m venv .venv
|
|
110
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
111
|
+
pip install -e .
|
|
112
|
+
plotaviz
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### macOS
|
|
116
|
+
|
|
117
|
+
Apple Silicon and Intel are both supported.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
brew install python@3.11 # if you need it
|
|
121
|
+
pip install -e .
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
A prebuilt `.app` is attached to each [release](https://github.com/saadibnainan/plotaviz/releases).
|
|
125
|
+
Builds are not yet notarized, so the first launch needs **right-click → Open**.
|
|
126
|
+
|
|
127
|
+
To build one yourself:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
make build-macos # produces dist/PlotaViz.app
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Linux
|
|
134
|
+
|
|
135
|
+
Qt needs a few system libraries that pip cannot install for you:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Debian / Ubuntu
|
|
139
|
+
sudo apt install python3-venv libegl1 libxkbcommon-x11-0 libxcb-cursor0 \
|
|
140
|
+
libxcb-icccm4 libxcb-keysyms1 libxcb-shape0
|
|
141
|
+
|
|
142
|
+
# Fedora
|
|
143
|
+
sudo dnf install python3-devel libglvnd-egl xcb-util-cursor libxkbcommon-x11
|
|
144
|
+
|
|
145
|
+
# Arch
|
|
146
|
+
sudo pacman -S python libxkbcommon-x11 xcb-util-cursor
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Then either `pip install -e .`, or grab the **AppImage** from the releases page:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
chmod +x PlotaViz-*.AppImage
|
|
153
|
+
./PlotaViz-*.AppImage
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
To build one: `make build-appimage`. Recipes for `.deb`, `.rpm`, and an **AUR PKGBUILD** are in
|
|
157
|
+
[`scripts/build_appimage.sh`](scripts/build_appimage.sh).
|
|
158
|
+
|
|
159
|
+
### Optional extras
|
|
160
|
+
|
|
161
|
+
```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
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Quickstart
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
plotaviz # open the app
|
|
173
|
+
plotaviz samples/sales_timeseries.csv # open the app with a file
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
1. Drag a dataset in, or use **File → Open**.
|
|
177
|
+
2. Read the **cleaning report** — what was renamed, filled, deduplicated, flagged.
|
|
178
|
+
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.
|
|
180
|
+
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.
|
|
183
|
+
|
|
184
|
+
### Command line
|
|
185
|
+
|
|
186
|
+
`core/` is completely headless, so the whole pipeline works without a display — useful in a
|
|
187
|
+
Makefile, a cron job, or CI.
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# What is in this file?
|
|
191
|
+
plotaviz --input data.csv --describe
|
|
192
|
+
|
|
193
|
+
# What should I plot?
|
|
194
|
+
plotaviz --input data.csv --recommend
|
|
195
|
+
|
|
196
|
+
# Just make the chart
|
|
197
|
+
plotaviz --input data.csv --auto --export chart.png
|
|
198
|
+
|
|
199
|
+
# Give me the code instead
|
|
200
|
+
plotaviz --input data.csv --auto --export-code plot.py --code-flavour plotly
|
|
201
|
+
|
|
202
|
+
# Take control
|
|
203
|
+
plotaviz --input data.csv --chart box --x region --y revenue \
|
|
204
|
+
--query "revenue > 1000" --export chart.pdf --dpi 300 --size 12x8
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`--json` makes `--describe` and `--recommend` machine-readable.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## How it decides
|
|
212
|
+
|
|
213
|
+
Two layers, deliberately separate.
|
|
214
|
+
|
|
215
|
+
**Rules** ([`plotaviz/core/rules.yaml`](plotaviz/core/rules.yaml)) map a data *shape* to candidate
|
|
216
|
+
charts. They are broad on purpose — a date column plus a measure proposes line, area, and scatter,
|
|
217
|
+
and does not try to pick between them:
|
|
218
|
+
|
|
219
|
+
| Shape | Candidates |
|
|
220
|
+
|---|---|
|
|
221
|
+
| 1 numeric | histogram, KDE |
|
|
222
|
+
| 1 categorical | bar (low cardinality), treemap (high) |
|
|
223
|
+
| 2 numeric | scatter, with correlation and trendline |
|
|
224
|
+
| numeric × categorical | bar, box, violin |
|
|
225
|
+
| datetime × numeric | line, area |
|
|
226
|
+
| 2 categorical | grouped/stacked bar, heatmap |
|
|
227
|
+
| many numeric | correlation heatmap, pair plot |
|
|
228
|
+
|
|
229
|
+
**Scoring** then ranks those candidates against your actual data — cardinality, missingness,
|
|
230
|
+
distribution skew, correlation strength, readability limits. This is where *"you have 400
|
|
231
|
+
categories, a bar chart will be unreadable"* gets expressed, as a penalty rather than a
|
|
232
|
+
prohibition.
|
|
233
|
+
|
|
234
|
+
The output is a **chart spec**: the single contract that the renderer, the code generator, the
|
|
235
|
+
session file, and the LLM layer all consume. There is no other way to describe a chart in this
|
|
236
|
+
codebase.
|
|
237
|
+
|
|
238
|
+
### Extending the rules
|
|
239
|
+
|
|
240
|
+
Adding a chart usually means editing YAML, not Python:
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
rules:
|
|
244
|
+
- name: datetime_numeric
|
|
245
|
+
requires: { datetime: 1, numeric: 1 }
|
|
246
|
+
candidates:
|
|
247
|
+
- chart: line
|
|
248
|
+
base: 0.94
|
|
249
|
+
map: { x: datetime.0, y: numeric.0, color: "?categorical.0" }
|
|
250
|
+
why: "A date column paired with a measure is a time series."
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`numeric.0` means "the most promising numeric column"; a `?` prefix makes a slot optional. Weights
|
|
254
|
+
and readability caps live under `scoring:` in the same file. See
|
|
255
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for the whole procedure.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## The LLM layer is optional
|
|
260
|
+
|
|
261
|
+
**PlotaViz works fully offline with no provider configured.** The rules engine answers instantly,
|
|
262
|
+
and it is the fallback whenever a model call fails, times out, or returns something that does not
|
|
263
|
+
validate. A model is never on the critical path.
|
|
264
|
+
|
|
265
|
+
When you do configure one, it does two jobs:
|
|
266
|
+
|
|
267
|
+
1. Breaks a tie when the local scores are close enough that the ranking is a coin flip.
|
|
268
|
+
2. Powers the natural-language query bar.
|
|
269
|
+
|
|
270
|
+
Both return a **structured chart spec (JSON), never executable code.** The spec is validated
|
|
271
|
+
against your real column names before anything renders; a hallucinated column is a clear error
|
|
272
|
+
message, not a crash.
|
|
273
|
+
|
|
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.
|
|
276
|
+
|
|
277
|
+
**Where keys live:** your OS keychain, via `keyring`. Never a config file, never a session file,
|
|
278
|
+
never the repo. Keys are redacted from logs and error messages.
|
|
279
|
+
|
|
280
|
+
### Local models with Ollama (nothing leaves your machine)
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# install ollama from https://ollama.com, then
|
|
284
|
+
ollama pull llama3.1
|
|
285
|
+
ollama serve
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
In **Settings → LLM provider**, choose **Ollama**. No API key, no network, no consent prompt —
|
|
289
|
+
this is the right choice for sensitive data.
|
|
290
|
+
|
|
291
|
+
Hosted providers: Anthropic (Claude), OpenAI, and Google Gemini. Install with
|
|
292
|
+
`pip install -e ".[llm]"`, then paste a key in Settings.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Features
|
|
297
|
+
|
|
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.
|
|
300
|
+
- **Cleaning** — an ordered, replayable step list: name normalization, type coercion,
|
|
301
|
+
missing-value strategies, IQR/z-score outlier flagging (non-destructive by default),
|
|
302
|
+
deduplication. Every step reports what it changed.
|
|
303
|
+
- **Type override** — inferred roles shown and editable before analysis proceeds.
|
|
304
|
+
- **Filters** — range widgets, multi-selects, date ranges, and a raw pandas-query bar. Filters are
|
|
305
|
+
pipeline steps, so they serialize into sessions and generated code for free.
|
|
306
|
+
- **Charts** — 15 types, interactive via Plotly in a WebEngine view, with a matplotlib canvas
|
|
307
|
+
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.
|
|
310
|
+
- **Sessions** — `.pviz` files store the recipe, not the data, and warn if the source changed.
|
|
311
|
+
- **Guardrails** — automatic downsampling with a visible notice, top-N category capping,
|
|
312
|
+
virtualized preview, debounced re-render.
|
|
313
|
+
|
|
314
|
+
### Sample datasets
|
|
315
|
+
|
|
316
|
+
Five, each exercising a different path through the selector:
|
|
317
|
+
|
|
318
|
+
| File | Exercises |
|
|
319
|
+
|---|---|
|
|
320
|
+
| `sales_timeseries.csv` | time series; messy names, missing values, duplicates |
|
|
321
|
+
| `iris_like.csv` | correlated numeric pairs → scatter, correlation heatmap |
|
|
322
|
+
| `survey_responses.csv` | two categorical dimensions → grouped bar, heatmap |
|
|
323
|
+
| `sensor_readings.csv` | one skewed numeric column with real outliers → histogram, box |
|
|
324
|
+
| `city_population.json` | JSON loading, high-cardinality categorical → treemap |
|
|
325
|
+
|
|
326
|
+
Regenerate with `make samples`.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Architecture
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
plotaviz/
|
|
334
|
+
├── main.py # entry point; GUI or CLI
|
|
335
|
+
├── ui/ # PySide6 — may import Qt
|
|
336
|
+
│ ├── main_window.py # layout and wiring; no analysis logic
|
|
337
|
+
│ ├── interactive_view.py # ALL QtWebEngine use is isolated here
|
|
338
|
+
│ ├── nl_query_bar.py # natural-language input + editable interpretation
|
|
339
|
+
│ ├── filter_panel.py # per-column filters + query bar
|
|
340
|
+
│ ├── type_override.py # correct inferred column types
|
|
341
|
+
│ ├── export_dialog.py # format, DPI, size, code flavour
|
|
342
|
+
│ ├── settings_dialog.py # provider, keys, thresholds
|
|
343
|
+
│ ├── table_model.py # virtualized preview
|
|
344
|
+
│ └── workers.py # QThread plumbing, progress, cancellation
|
|
345
|
+
└── core/ # HEADLESS — no Qt anywhere, unit-tested
|
|
346
|
+
├── loader.py # file → DataFrame (pandas or polars)
|
|
347
|
+
├── preprocess.py # the replayable step list
|
|
348
|
+
├── profiler.py # column roles + statistics
|
|
349
|
+
├── selector.py # rules + scoring engine
|
|
350
|
+
├── rules.yaml # the editable half of selection
|
|
351
|
+
├── spec.py # ChartSpec — the shared contract
|
|
352
|
+
├── plotter.py # Plotly + matplotlib, and the guardrails
|
|
353
|
+
├── codegen.py # standalone script generation
|
|
354
|
+
├── exporter.py # PNG/SVG/PDF/HTML
|
|
355
|
+
├── session.py # .pviz save/load
|
|
356
|
+
├── analysis.py # orchestration facade shared by GUI and CLI
|
|
357
|
+
└── llm/ # pluggable providers behind one ABC
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Two invariants hold the design together:
|
|
361
|
+
|
|
362
|
+
- **`core/` never imports Qt.** This is what makes the CLI nearly free and the engine testable —
|
|
363
|
+
and it is [checked by a test](tests/test_cli.py), not just by convention.
|
|
364
|
+
- **Preprocessing is a list of steps, not mutations.** One design gives undo/redo, session replay,
|
|
365
|
+
and code generation at once.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Development
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
make dev # venv + dev extras + pre-commit hooks
|
|
373
|
+
make test # pytest
|
|
374
|
+
make lint # ruff check + ruff format --check + mypy plotaviz/core
|
|
375
|
+
make run # launch the app
|
|
376
|
+
make samples # regenerate sample datasets
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
The test suite covers loading, step replay and serialization, profiling and identifier detection,
|
|
380
|
+
selector scoring, spec validation, both renderers, session round-trips, the mocked LLM provider
|
|
381
|
+
contract, and — for every chart type — that the **generated script actually executes and produces
|
|
382
|
+
an image**.
|
|
383
|
+
|
|
384
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for adding selector rules and LLM providers.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Roadmap
|
|
389
|
+
|
|
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.
|
|
393
|
+
|
|
394
|
+
Explicitly out of scope for v1: plugin architecture, localization, real-time streaming, and live
|
|
395
|
+
database connectors.
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Licensing
|
|
400
|
+
|
|
401
|
+
PlotaViz is **MIT** licensed (see [LICENSE](LICENSE)).
|
|
402
|
+
|
|
403
|
+
It uses **PySide6 (Qt), which is LGPLv3**. Distributed bundles link Qt dynamically so it can be
|
|
404
|
+
relinked, and ship attribution. If you redistribute a build, keep
|
|
405
|
+
[THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md) with it — that file covers the Qt obligation
|
|
406
|
+
and credits Plotly (MIT), matplotlib, pandas, polars, Apache Arrow, and the rest.
|
|
407
|
+
|
|
408
|
+
Qt is a trademark of The Qt Company Ltd. PlotaViz is not affiliated with or endorsed by them.
|
|
409
|
+
|
|
410
|
+
Security policy and vulnerability reporting: [SECURITY.md](SECURITY.md).
|