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.
Files changed (52) hide show
  1. plotaviz-0.1.0/LICENSE +21 -0
  2. plotaviz-0.1.0/PKG-INFO +410 -0
  3. plotaviz-0.1.0/README.md +356 -0
  4. plotaviz-0.1.0/plotaviz/__init__.py +19 -0
  5. plotaviz-0.1.0/plotaviz/core/__init__.py +53 -0
  6. plotaviz-0.1.0/plotaviz/core/analysis.py +230 -0
  7. plotaviz-0.1.0/plotaviz/core/codegen.py +482 -0
  8. plotaviz-0.1.0/plotaviz/core/errors.py +65 -0
  9. plotaviz-0.1.0/plotaviz/core/exporter.py +145 -0
  10. plotaviz-0.1.0/plotaviz/core/llm/__init__.py +211 -0
  11. plotaviz-0.1.0/plotaviz/core/llm/anthropic.py +61 -0
  12. plotaviz-0.1.0/plotaviz/core/llm/base.py +373 -0
  13. plotaviz-0.1.0/plotaviz/core/llm/gemini.py +51 -0
  14. plotaviz-0.1.0/plotaviz/core/llm/ollama.py +113 -0
  15. plotaviz-0.1.0/plotaviz/core/llm/openai.py +58 -0
  16. plotaviz-0.1.0/plotaviz/core/loader.py +366 -0
  17. plotaviz-0.1.0/plotaviz/core/plotter.py +790 -0
  18. plotaviz-0.1.0/plotaviz/core/preprocess.py +836 -0
  19. plotaviz-0.1.0/plotaviz/core/profiler.py +509 -0
  20. plotaviz-0.1.0/plotaviz/core/rules.yaml +190 -0
  21. plotaviz-0.1.0/plotaviz/core/selector.py +495 -0
  22. plotaviz-0.1.0/plotaviz/core/session.py +174 -0
  23. plotaviz-0.1.0/plotaviz/core/spec.py +236 -0
  24. plotaviz-0.1.0/plotaviz/main.py +329 -0
  25. plotaviz-0.1.0/plotaviz/ui/__init__.py +23 -0
  26. plotaviz-0.1.0/plotaviz/ui/export_dialog.py +228 -0
  27. plotaviz-0.1.0/plotaviz/ui/filter_panel.py +273 -0
  28. plotaviz-0.1.0/plotaviz/ui/interactive_view.py +210 -0
  29. plotaviz-0.1.0/plotaviz/ui/main_window.py +859 -0
  30. plotaviz-0.1.0/plotaviz/ui/nl_query_bar.py +219 -0
  31. plotaviz-0.1.0/plotaviz/ui/settings_dialog.py +313 -0
  32. plotaviz-0.1.0/plotaviz/ui/table_model.py +184 -0
  33. plotaviz-0.1.0/plotaviz/ui/type_override.py +159 -0
  34. plotaviz-0.1.0/plotaviz/ui/workers.py +222 -0
  35. plotaviz-0.1.0/plotaviz.egg-info/PKG-INFO +410 -0
  36. plotaviz-0.1.0/plotaviz.egg-info/SOURCES.txt +50 -0
  37. plotaviz-0.1.0/plotaviz.egg-info/dependency_links.txt +1 -0
  38. plotaviz-0.1.0/plotaviz.egg-info/entry_points.txt +2 -0
  39. plotaviz-0.1.0/plotaviz.egg-info/requires.txt +34 -0
  40. plotaviz-0.1.0/plotaviz.egg-info/top_level.txt +1 -0
  41. plotaviz-0.1.0/pyproject.toml +114 -0
  42. plotaviz-0.1.0/setup.cfg +4 -0
  43. plotaviz-0.1.0/tests/test_cli.py +323 -0
  44. plotaviz-0.1.0/tests/test_codegen.py +182 -0
  45. plotaviz-0.1.0/tests/test_llm.py +307 -0
  46. plotaviz-0.1.0/tests/test_loader.py +163 -0
  47. plotaviz-0.1.0/tests/test_plotter.py +254 -0
  48. plotaviz-0.1.0/tests/test_preprocess.py +279 -0
  49. plotaviz-0.1.0/tests/test_profiler.py +203 -0
  50. plotaviz-0.1.0/tests/test_selector.py +223 -0
  51. plotaviz-0.1.0/tests/test_session.py +177 -0
  52. 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.
@@ -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
+ [![CI](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml/badge.svg)](https://github.com/saadibnainan/plotaviz/actions/workflows/ci.yml)
58
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
59
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
60
+ [![Qt: LGPLv3](https://img.shields.io/badge/Qt-LGPLv3-orange)](THIRD_PARTY_LICENSES.md)
61
+ [![Code style: ruff](https://img.shields.io/badge/style-ruff-261230)](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
+ | ![Main window](docs/screenshots/main-window.png) | ![Recommendations](docs/screenshots/recommendations.png) |
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).