pytae 3.2.0__tar.gz → 3.3.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.
- {pytae-3.2.0 → pytae-3.3.0}/CHANGELOG.md +16 -0
- pytae-3.3.0/CONTRIBUTING.md +10 -0
- {pytae-3.2.0 → pytae-3.3.0}/PKG-INFO +25 -22
- {pytae-3.2.0 → pytae-3.3.0}/README.md +24 -21
- {pytae-3.2.0 → pytae-3.3.0}/docs/CLI.md +90 -2
- pytae-3.3.0/docs/CLI_MULTI_FILE.md +86 -0
- {pytae-3.2.0 → pytae-3.3.0}/docs/LIBRARY.md +1 -1
- pytae-3.3.0/docs/PLOTTING.md +158 -0
- pytae-3.3.0/docs/images/plotting_bar.png +0 -0
- pytae-3.3.0/docs/images/plotting_dashboard.png +0 -0
- pytae-3.3.0/docs/images/plotting_dashboard_enhanced.png +0 -0
- pytae-3.3.0/docs/images/plotting_pie.png +0 -0
- pytae-3.3.0/docs/images/plotting_scatter.png +0 -0
- pytae-3.3.0/docs/images/plotting_secondary_axis.png +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/pyproject.toml +1 -1
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/cli.py +233 -553
- pytae-3.3.0/src/pytae/cli_parsing.py +563 -0
- pytae-3.3.0/src/pytae/cli_pipeline.py +236 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_cli_order.py +448 -1
- {pytae-3.2.0 → pytae-3.3.0}/.githooks/pre-commit +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/.github/workflows/ci.yml +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/.gitignore +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/LICENSE +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/agg_df.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/more_plots.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/other_utilities.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/plotter.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/qry.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/select.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/notebooks/shape.ipynb +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/scripts/run_notebooks.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/__init__.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/agg_df.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/anagrams.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/anscombe.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/attention.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/brain_networks.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/car_crashes.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/diamonds.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/dots.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/dowjones.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/exercise.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/flights.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/fmri.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/geyser.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/glue.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/healthexp.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/iris.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/mpg.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/penguins.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/planets.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/seaice.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/taxis.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/tips.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/datasets/titanic.parquet +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/other_utilities.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/plotting.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/qry.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/readers.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/select.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/src/pytae/shape.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/conftest.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_agg_df.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_cli_sample_datasets.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_import.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_plotter.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_qry.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_readers.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_select.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_shape.py +0 -0
- {pytae-3.2.0 → pytae-3.3.0}/tests/test_utilities.py +0 -0
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.3.0] - 2026-09-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `-replace` flag: replace values at a point in the pipeline (pandas `replace()`). Value is `key=value` tokens: `v=` (required) an `old:new` mapping, `c=` (optional) restrict to specific columns, `exact=` (optional bool, default `true`) — `true` matches whole cell values, `false` matches a substring anywhere in the cell.
|
|
9
|
+
- `-clean_columns` flag: clean column header names, in a fixed order (`strip` -> `strip_special` -> `squeeze` -> `fill` -> `case` -> `dedupe`). Booleans accept a bare key as shorthand for `=true`; `fill` defaults to `'_'` when bare; `case` (`lower`/`upper`/`proper`) always needs a value.
|
|
10
|
+
- `-file`/`-merge`/`-concat` flags: a new multi-file pipeline mode. `-file "path1=alias1; path2=alias2"` loads two or more named files (with optional per-file `,dlim=`/`,encoding=` overrides) instead of the positional `path`; `-merge` (pandas `merge()`, repeatable) or `-concat` (pandas `concat()`, always resets the index, repeatable) then combine them — both accept the literal alias `df` to fold in one more file onto the running result. See `docs/CLI_MULTI_FILE.md`.
|
|
11
|
+
- `-sql` extended: usable as the founding op in `-file` mode instead of `-merge`/`-concat`, with every `-file` alias registered as its own queryable duckdb table (in addition to `df`, once something has produced a current view).
|
|
12
|
+
- `docs/CLI_MULTI_FILE.md`: dedicated reference for `-file`/`-merge`/`-concat`.
|
|
13
|
+
- `docs/PLOTTING.md`: dedicated `Plotter` reference with rendered example images (scatter, grouped bar, pie, secondary axis, multi-panel mosaic dashboard, post-`finalize()` axis looping) using pytae's bundled sample datasets.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- The positional `path` argument is now optional — required only when not using `-file`; `-file` and the positional `path` are mutually exclusive.
|
|
17
|
+
- `src/pytae/cli.py` split into `cli.py` (argparse + main loop), `cli_parsing.py` (flag-value parsers), and `cli_pipeline.py` (`_Pipeline` + ordered argparse actions) — internal refactor, no behavior change.
|
|
18
|
+
- `README.md` restructured into three top-level sections, in order: CLI, Plotting, Library.
|
|
19
|
+
- `docs/CLI.md`: intro updated to mention `-replace`/`-clean_columns`/`-merge`/`-concat`; its Plotting and Multi-file sections now summarize and link out to the new dedicated `docs/PLOTTING.md`/`docs/CLI_MULTI_FILE.md` pages instead of holding the full reference inline.
|
|
20
|
+
|
|
5
21
|
## [3.2.0] - 2026-09-13
|
|
6
22
|
|
|
7
23
|
### Added
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
pip install -e ".[dev,notebooks]"
|
|
5
|
+
pytest # unit tests
|
|
6
|
+
git config core.hooksPath .githooks # run notebooks/*.ipynb before each commit
|
|
7
|
+
python scripts/run_notebooks.py # or run the notebook check manually
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Notebooks are intentionally not part of the `pytest` suite (they're slower and exercise plotting/IO end-to-end); the pre-commit hook is the enforcement point instead.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pytae
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: A package to enhance common tasks in data and plotting
|
|
5
5
|
Project-URL: Homepage, https://github.com/maddytae/pytae
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/maddytae/pytae/issues
|
|
@@ -49,39 +49,42 @@ Pandas extensions for everyday data-science tasks (filtering, selection, reshapi
|
|
|
49
49
|
pip install pytae
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
## Library
|
|
53
|
-
|
|
54
|
-
Pandas extensions registered on `pd.DataFrame` — import `pytae` and the methods attach automatically.
|
|
55
|
-
|
|
56
|
-
- **Plotting** — `Plotter`: method-chainable plots on `pandas.plot` (`pip install pytae[plot]`)
|
|
57
|
-
- **Filtering** — `qry()`: dict-based filters (equality, lists, `in`/`not in`, comparisons, intervals)
|
|
58
|
-
- **Selection** — `select()`: columns by name, regex, dtype, or name pattern
|
|
59
|
-
- **Reshaping** — `long()` / `wide()`: melt numeric columns to rows, pivot back to columns
|
|
60
|
-
- **Aggregation** — `agg_df()`: auto-detects group columns and aggregates the rest
|
|
61
|
-
- **Utilities** — `to_clip()`, `handle_missing()`, `cols()`, `group_x()`
|
|
62
|
-
|
|
63
|
-
See [docs/LIBRARY.md](https://github.com/maddytae/pytae/blob/master/docs/LIBRARY.md) for examples of each.
|
|
64
|
-
|
|
65
52
|
## CLI
|
|
66
53
|
|
|
67
54
|
```bash
|
|
68
55
|
pytae data.parquet -head
|
|
69
56
|
pytae data.parquet -qry "'species': 'Adelie'" -select species,body_mass_g -convert -o subset.csv
|
|
70
57
|
pytae data.parquet -sql "select species, avg(body_mass_g) from df group by species"
|
|
58
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" -merge "left=df1,right=df2,on='id'"
|
|
71
59
|
```
|
|
72
60
|
|
|
73
|
-
See [docs/CLI.md](https://github.com/maddytae/pytae/blob/master/docs/CLI.md) for the full flag reference.
|
|
61
|
+
See [docs/CLI.md](https://github.com/maddytae/pytae/blob/master/docs/CLI.md) for the full flag reference, and [docs/CLI_MULTI_FILE.md](https://github.com/maddytae/pytae/blob/master/docs/CLI_MULTI_FILE.md) for `-file`/`-merge`/`-concat`.
|
|
74
62
|
|
|
75
|
-
##
|
|
63
|
+
## Plotting
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
`Plotter`: method-chainable plots on top of `pandas.plot()` (`pip install pytae[plot]`).
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from pytae.plotting import Plotter
|
|
69
|
+
|
|
70
|
+
Plotter().data(penguins).plot(
|
|
71
|
+
x="bill_length_mm", y="bill_depth_mm", kind="scatter", by="species"
|
|
72
|
+
).finalize()
|
|
82
73
|
```
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
See [docs/PLOTTING.md](https://github.com/maddytae/pytae/blob/master/docs/PLOTTING.md) for more examples with sample data.
|
|
76
|
+
|
|
77
|
+
## Library
|
|
78
|
+
|
|
79
|
+
Pandas extensions registered on `pd.DataFrame` — import `pytae` and the methods attach automatically.
|
|
80
|
+
|
|
81
|
+
- **Filtering** — `qry()`: dict-based filters (equality, lists, `in`/`not in`, comparisons, intervals)
|
|
82
|
+
- **Selection** — `select()`: columns by name, regex, dtype, or name pattern
|
|
83
|
+
- **Reshaping** — `long()` / `wide()`: melt numeric columns to rows, pivot back to columns
|
|
84
|
+
- **Aggregation** — `agg_df()`: auto-detects group columns and aggregates the rest
|
|
85
|
+
- **Utilities** — `to_clip()`, `handle_missing()`, `cols()`, `group_x()`
|
|
86
|
+
|
|
87
|
+
See [docs/LIBRARY.md](https://github.com/maddytae/pytae/blob/master/docs/LIBRARY.md) for examples of each.
|
|
85
88
|
|
|
86
89
|
## License
|
|
87
90
|
|
|
@@ -13,39 +13,42 @@ Pandas extensions for everyday data-science tasks (filtering, selection, reshapi
|
|
|
13
13
|
pip install pytae
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
## Library
|
|
17
|
-
|
|
18
|
-
Pandas extensions registered on `pd.DataFrame` — import `pytae` and the methods attach automatically.
|
|
19
|
-
|
|
20
|
-
- **Plotting** — `Plotter`: method-chainable plots on `pandas.plot` (`pip install pytae[plot]`)
|
|
21
|
-
- **Filtering** — `qry()`: dict-based filters (equality, lists, `in`/`not in`, comparisons, intervals)
|
|
22
|
-
- **Selection** — `select()`: columns by name, regex, dtype, or name pattern
|
|
23
|
-
- **Reshaping** — `long()` / `wide()`: melt numeric columns to rows, pivot back to columns
|
|
24
|
-
- **Aggregation** — `agg_df()`: auto-detects group columns and aggregates the rest
|
|
25
|
-
- **Utilities** — `to_clip()`, `handle_missing()`, `cols()`, `group_x()`
|
|
26
|
-
|
|
27
|
-
See [docs/LIBRARY.md](https://github.com/maddytae/pytae/blob/master/docs/LIBRARY.md) for examples of each.
|
|
28
|
-
|
|
29
16
|
## CLI
|
|
30
17
|
|
|
31
18
|
```bash
|
|
32
19
|
pytae data.parquet -head
|
|
33
20
|
pytae data.parquet -qry "'species': 'Adelie'" -select species,body_mass_g -convert -o subset.csv
|
|
34
21
|
pytae data.parquet -sql "select species, avg(body_mass_g) from df group by species"
|
|
22
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" -merge "left=df1,right=df2,on='id'"
|
|
35
23
|
```
|
|
36
24
|
|
|
37
|
-
See [docs/CLI.md](https://github.com/maddytae/pytae/blob/master/docs/CLI.md) for the full flag reference.
|
|
25
|
+
See [docs/CLI.md](https://github.com/maddytae/pytae/blob/master/docs/CLI.md) for the full flag reference, and [docs/CLI_MULTI_FILE.md](https://github.com/maddytae/pytae/blob/master/docs/CLI_MULTI_FILE.md) for `-file`/`-merge`/`-concat`.
|
|
38
26
|
|
|
39
|
-
##
|
|
27
|
+
## Plotting
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
`Plotter`: method-chainable plots on top of `pandas.plot()` (`pip install pytae[plot]`).
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from pytae.plotting import Plotter
|
|
33
|
+
|
|
34
|
+
Plotter().data(penguins).plot(
|
|
35
|
+
x="bill_length_mm", y="bill_depth_mm", kind="scatter", by="species"
|
|
36
|
+
).finalize()
|
|
46
37
|
```
|
|
47
38
|
|
|
48
|
-
|
|
39
|
+
See [docs/PLOTTING.md](https://github.com/maddytae/pytae/blob/master/docs/PLOTTING.md) for more examples with sample data.
|
|
40
|
+
|
|
41
|
+
## Library
|
|
42
|
+
|
|
43
|
+
Pandas extensions registered on `pd.DataFrame` — import `pytae` and the methods attach automatically.
|
|
44
|
+
|
|
45
|
+
- **Filtering** — `qry()`: dict-based filters (equality, lists, `in`/`not in`, comparisons, intervals)
|
|
46
|
+
- **Selection** — `select()`: columns by name, regex, dtype, or name pattern
|
|
47
|
+
- **Reshaping** — `long()` / `wide()`: melt numeric columns to rows, pivot back to columns
|
|
48
|
+
- **Aggregation** — `agg_df()`: auto-detects group columns and aggregates the rest
|
|
49
|
+
- **Utilities** — `to_clip()`, `handle_missing()`, `cols()`, `group_x()`
|
|
50
|
+
|
|
51
|
+
See [docs/LIBRARY.md](https://github.com/maddytae/pytae/blob/master/docs/LIBRARY.md) for examples of each.
|
|
49
52
|
|
|
50
53
|
## License
|
|
51
54
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pytae — CLI Reference
|
|
2
2
|
|
|
3
|
-
Inspect and convert tabular files (`.parquet`, `.csv`, `.txt`, `.dat`, `.sas7bdat`). The CLI
|
|
3
|
+
Inspect and convert tabular files (`.parquet`, `.csv`, `.txt`, `.dat`, `.sas7bdat`). The CLI mirrors pytae's own library verbs — `qry()`, `select()`, `agg_df()`, `group_x()`, `handle_missing()`, `long()`, `wide()` — plus CLI-native operations like value replacement (`-replace`), header cleanup (`-clean_columns`), and multi-file merges/concats (`-file`/`-merge`/`-concat`).
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ Inspect and convert tabular files (`.parquet`, `.csv`, `.txt`, `.dat`, `.sas7bda
|
|
|
9
9
|
- [Column selection — `-select`](#select)
|
|
10
10
|
- [Row filtering — `-qry` / `-query`](#filtering)
|
|
11
11
|
- [SQL — `-sql`](#sql)
|
|
12
|
+
- [Value replacement — `-replace`](#replace)
|
|
12
13
|
- [Aggregation (auto group columns) — `-agg_df`](#agg-df)
|
|
13
14
|
- [Aggregation (explicit group columns) — `-group_by` + `-agg`](#group-by-agg)
|
|
14
15
|
- [Broadcast — `-group_x`](#group-x)
|
|
@@ -17,8 +18,10 @@ Inspect and convert tabular files (`.parquet`, `.csv`, `.txt`, `.dat`, `.sas7bda
|
|
|
17
18
|
- [Listing — `-cols` / `-dtype` / `-nulls`](#listing)
|
|
18
19
|
- [Sorting rows — `-sort_by`](#sort-by)
|
|
19
20
|
- [Missing values — `-handle_missing`](#handle-missing)
|
|
21
|
+
- [Header cleanup — `-clean_columns`](#clean-columns)
|
|
20
22
|
- [Reshape — `-long` / `-wide`](#reshape)
|
|
21
23
|
- [Cross-tabulation — `-crosstab`](#crosstab)
|
|
24
|
+
- [Multi-file operations — `-file` / `-merge` / `-concat`](CLI_MULTI_FILE.md)
|
|
22
25
|
- [Conversion — `-convert` / `-rename`](#convert)
|
|
23
26
|
- [Display extras](#display-extras)
|
|
24
27
|
- [Pandas defaults vs pytae-specific](#pandas-vs-pytae)
|
|
@@ -230,6 +233,32 @@ Mixing a spaced identifier and a string literal in one `-sql` value means the sh
|
|
|
230
233
|
|
|
231
234
|
---
|
|
232
235
|
|
|
236
|
+
<a id="replace"></a>
|
|
237
|
+
## Value replacement — `-replace`
|
|
238
|
+
|
|
239
|
+
`-replace` swaps cell values at this point in the pipeline, same as `df.replace()`. Its value is `key=value` tokens (comma-separated, quote a value if it needs an internal comma — same convention as `-crosstab`'s `index=`):
|
|
240
|
+
|
|
241
|
+
- `v=` (**required**) — the `old:new` mapping, comma-separated pairs, e.g. `v='old:new,alpha:bravo'`.
|
|
242
|
+
- `c=` (optional) — restrict the replace to specific columns, e.g. `c='col a,col b'`. Omit it to replace across every column, like plain `df.replace()`.
|
|
243
|
+
- `exact=` (optional, `true`/`false`, default `true`) — `true` only replaces a cell whose **entire value** matches a key exactly; `false` replaces a key **anywhere it occurs as a substring**, leaving the rest of the cell untouched (keys are escaped so they're matched literally, not as regex patterns).
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# whole df, exact match only
|
|
247
|
+
pytae data.parquet -replace "v='a magician:the magic,alpha:bravo'"
|
|
248
|
+
|
|
249
|
+
# only touch col a and colb
|
|
250
|
+
pytae data.parquet -replace "c='col a,colb',v='a magician:the magic,alpha:bravo'"
|
|
251
|
+
|
|
252
|
+
# substring match: replaces the key wherever it appears inside a cell
|
|
253
|
+
pytae data.parquet -replace "v='a magician:the magic,alpha:bravo',exact=false"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
With `exact=true` (default), a cell like `"not a magician exactly"` is left unchanged because it isn't *exactly* `"a magician"`. With `exact=false`, that same cell becomes `"not the magic exactly"` — but watch out for partial-word matches: a short key like `alpha` will also match inside `"analphabet"`, turning it into `"anbravobet"`.
|
|
257
|
+
|
|
258
|
+
Chains like any other op — runs on the current view and replaces it, so put `-replace` before/after `-select`/`-qry` depending on whether you want it scoped to a narrower view.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
233
262
|
<a id="agg-df"></a>
|
|
234
263
|
## Aggregation (auto group columns) — `-agg_df`
|
|
235
264
|
|
|
@@ -396,6 +425,43 @@ pytae penguins.parquet -handle_missing NA -select species,sex -value_counts
|
|
|
396
425
|
|
|
397
426
|
---
|
|
398
427
|
|
|
428
|
+
<a id="clean-columns"></a>
|
|
429
|
+
## Header cleanup — `-clean_columns`
|
|
430
|
+
|
|
431
|
+
`-clean_columns` cleans up messy column **header names** (not cell values — see [`-replace`](#replace) for that). Its value is `key[=value]` tokens, comma-separated, applied in a fixed order regardless of how you write them: **strip → strip_special → squeeze → fill → case → dedupe**.
|
|
432
|
+
|
|
433
|
+
| Key | Type | Bare (no `=value`) | Default when omitted |
|
|
434
|
+
|---|---|---|---|
|
|
435
|
+
| `strip` | bool | means `true` | `false` — trims leading/trailing whitespace |
|
|
436
|
+
| `strip_special` | bool | means `true` | `false` — removes anything that isn't a letter, digit, underscore, or whitespace (e.g. `%`, `$`, `#`, `!`, parentheses) |
|
|
437
|
+
| `squeeze` | bool | means `true` | `false` — collapses runs of internal whitespace to a single space |
|
|
438
|
+
| `fill` | string | defaults to `'_'` | omit the key entirely for **no fill** (whitespace left as-is) |
|
|
439
|
+
| `case` | `lower`\|`upper`\|`proper` | **not allowed** — always needs a value | omitted — case left unchanged |
|
|
440
|
+
| `dedupe` | bool | means `true` | `false` — numbers collisions after cleaning: `revenue`, `revenue_1`, `revenue_2`, … |
|
|
441
|
+
|
|
442
|
+
`fill` replaces **each individual whitespace character** with the fill string — not each *run* of whitespace. That means `"col b"` (3 spaces) with `fill` alone becomes `"col___b"` (3 underscores); add `squeeze` first to collapse it to one separator instead.
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
# strip ends, fill remaining whitespace with '_' (default), lowercase
|
|
446
|
+
pytae data.parquet -clean_columns "strip,fill,case=lower"
|
|
447
|
+
|
|
448
|
+
# custom fill character instead of the default '_'
|
|
449
|
+
pytae data.parquet -clean_columns "fill='$'" # "col a" -> "col$a"
|
|
450
|
+
|
|
451
|
+
# Proper/Title Case, no fill (spaces are left alone)
|
|
452
|
+
pytae data.parquet -clean_columns "case=proper" # "col a" -> "Col A"
|
|
453
|
+
|
|
454
|
+
# collapse repeated internal whitespace and strip punctuation before filling,
|
|
455
|
+
# then number any resulting duplicate names
|
|
456
|
+
pytae data.parquet -clean_columns "strip,squeeze,strip_special,fill,case=lower,dedupe=true"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
With the last example, headers `" Col A "`, `"col b"`, `"Col A"`, `"100% Match!"` become `col_a`, `col_b`, `col_a_1` (deduped against the first `col_a`), and `100_match` (the `%`/`!` punctuation is stripped by `strip_special` before the remaining space is filled).
|
|
460
|
+
|
|
461
|
+
Chains like any other op — runs on the current view and replaces its column names, so put it before/after `-select` depending on whether you want to select by the original or cleaned names.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
399
465
|
<a id="reshape"></a>
|
|
400
466
|
## Reshape — `-long` / `-wide`
|
|
401
467
|
|
|
@@ -463,6 +529,18 @@ pytae penguins.parquet -crosstab "index='species',columns='sex'" -dropna false
|
|
|
463
529
|
|
|
464
530
|
---
|
|
465
531
|
|
|
532
|
+
<a id="merge"></a>
|
|
533
|
+
## Multi-file operations — `-file` / `-merge` / `-concat`
|
|
534
|
+
|
|
535
|
+
Everything above operates on **one** file (the positional `path`). `-file` + `-merge`/`-concat`/`-sql` are a separate mode for combining **two or more named files** into a single pipeline, replacing the positional `path` entirely. See **[docs/CLI_MULTI_FILE.md](CLI_MULTI_FILE.md)** for the full reference and examples.
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" \
|
|
539
|
+
-merge "left=df1,right=df2,on='col a:cola,colb:colb',how=inner"
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
466
544
|
<a id="convert"></a>
|
|
467
545
|
## Conversion — `-convert` / `-rename`
|
|
468
546
|
|
|
@@ -702,7 +780,9 @@ pytae 'folder/*.parquet' -convert
|
|
|
702
780
|
| `-select SPEC` | Restrict columns at this point in the pipeline (union in one spec; repeat to filter remaining) |
|
|
703
781
|
| `-qry CONDITIONS` | Filter rows at this point (`df.qry()`); surrounding `{}` optional |
|
|
704
782
|
| `-query EXPR` | Filter rows at this point (`df.query()`) |
|
|
705
|
-
| `-sql QUERY` | Run a SQL query at this point via duckdb; view is table `df` |
|
|
783
|
+
| `-sql QUERY` | Run a SQL query at this point via duckdb; view is table `df` (in `-file` mode, each alias is also queryable, and may be used instead of `-merge`/`-concat`) |
|
|
784
|
+
| `-replace KEY=VALUE,...` | Replace values at this point (`df.replace()`); `v=` required, `c=`/`exact=` optional |
|
|
785
|
+
| `-clean_columns KEY=VALUE,...` | Clean header names, in order strip -> strip_special -> squeeze -> fill -> case -> dedupe |
|
|
706
786
|
| `-sort_by COLUMNS [asc\|desc]` | Sort rows (default: ascending) |
|
|
707
787
|
|
|
708
788
|
**Aggregate & reshape**
|
|
@@ -719,6 +799,14 @@ pytae 'folder/*.parquet' -convert
|
|
|
719
799
|
| `-crosstab KEY=VALUE,...` | Cross-tabulate into a matrix (`index` comma-separated list, `columns` single column, optional `values`+`aggfunc`, `normalize`, `margins`, `margins_name`) |
|
|
720
800
|
| `-dropna true\|false` | Drop NA keys for `-agg_df`/`-agg`/`-value_counts`/`-crosstab` (default true) |
|
|
721
801
|
|
|
802
|
+
**Multi-file operations**
|
|
803
|
+
|
|
804
|
+
| Flag | Description |
|
|
805
|
+
|---|---|
|
|
806
|
+
| `-file PATH=ALIAS;...` | Load named files instead of the positional `path`; `;`-separated, each optionally followed by `,dlim=`/`,encoding=`; requires `-merge`, `-concat`, or `-sql` as the first op |
|
|
807
|
+
| `-merge KEY=VALUE,...` | Join `-file` aliases (`left`, `right`, `on`, optional `how` default `inner`, optional `validate`); repeatable, `left=`/`right=` accept `df` for the running result; or use `-sql` instead |
|
|
808
|
+
| `-concat KEY=VALUE,...` | Stack `-file` aliases row-wise (`frames=`, an ordered list, accepts `df` for the running result); repeatable; always resets the index |
|
|
809
|
+
|
|
722
810
|
**Convert & I/O**
|
|
723
811
|
|
|
724
812
|
| Flag | Description |
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# pytae — Multi-file operations (`-file` / `-merge` / `-concat`)
|
|
2
|
+
|
|
3
|
+
See [CLI Reference](CLI.md) for everything else. This page covers `-file`-based multi-file mode — loading **two or more named files** into a single pipeline instead of the usual one (the positional `path`).
|
|
4
|
+
|
|
5
|
+
`-file` is a separate mode, paired with `-merge` (join), `-concat` (stack), or `-sql` (raw SQL) as the founding op. `-file` **replaces** the positional `path` entirely — you can't mix a positional path with `-file`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" \
|
|
9
|
+
-merge "left=df1,right=df2,on='col a:cola,colb:colb',how=inner"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## `-file` — load named inputs
|
|
13
|
+
|
|
14
|
+
Value is `;`-separated entries (at least two — any number is fine), each `PATH=ALIAS` optionally followed by `,dlim=`/`,encoding=` overrides for reading *that* file (handy when joining mismatched formats, e.g. a pipe-delimited `.txt` with a `.csv`):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" ...
|
|
18
|
+
pytae -file "a.csv=a; b.csv=b; c.csv=c" ... # three (or more) files are fine
|
|
19
|
+
pytae -file "sales.txt=sales,dlim='|'; customers.csv=customers,encoding='latin-1'" ...
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## `-merge` — join `-file` aliases
|
|
23
|
+
|
|
24
|
+
Must be the **first** operation when `-file` is used, unless [`-sql`](#sql-alternative) or `-concat` starts it instead. **Repeatable** — each occurrence runs one more `pd.merge()`, so you can fold in one file at a time. Value is `key=value` tokens:
|
|
25
|
+
|
|
26
|
+
| Key | Required? | Meaning |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `left=` / `right=` | required | a `-file` alias, or the literal `df` for the pipeline's current result so far (only valid once something earlier has produced one) |
|
|
29
|
+
| `on=` | required | shared join column(s) (comma list) when names match on both sides, or `left:right` pairs when they differ — **quote the whole value** if it has more than one column/pair, e.g. `on='col a:cola,colb:colb'` |
|
|
30
|
+
| `how=` | optional (default `inner`) | `inner`/`left`/`right`/`outer`/`cross`, passed straight to pandas `merge()` |
|
|
31
|
+
| `validate=` | optional | e.g. `one_to_one`/`one_to_many`/`many_to_one`/`many_to_many`, passed straight to pandas `merge()` |
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# join column names differ between the two files
|
|
35
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" \
|
|
36
|
+
-merge "left=df1,right=df2,on='col a:cola',how=inner"
|
|
37
|
+
|
|
38
|
+
# join column name is shared, outer join, then keep going like any other pipeline
|
|
39
|
+
pytae -file "a.csv=a; b.csv=b" -merge "left=a,right=b,on='id',how=outer" -select id,x,y -shape
|
|
40
|
+
|
|
41
|
+
# validate the join is truly one-to-one, erroring otherwise
|
|
42
|
+
pytae -file "a.csv=a; b.csv=b" -merge "left=a,right=b,on='id',validate=one_to_one"
|
|
43
|
+
|
|
44
|
+
# fold a third file in: (a ⋈ b) ⋈ c — 'df' means "the result so far"
|
|
45
|
+
pytae -file "a.csv=a; b.csv=b; c.csv=c" \
|
|
46
|
+
-merge "left=a,right=b,on='id'" \
|
|
47
|
+
-merge "left=df,right=c,on='id'"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## `-concat` — stack `-file` aliases (pandas `concat()`)
|
|
51
|
+
|
|
52
|
+
Must be the **first** operation when `-file` is used, unless `-merge` or [`-sql`](#sql-alternative) starts it instead. **Repeatable**, and its `frames=` list already accepts more than two names in one call. The index is always reset (`ignore_index=True`) — not configurable, always on. Value is `key=value` tokens:
|
|
53
|
+
|
|
54
|
+
| Key | Required? | Meaning |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `frames=` | required | an ordered, comma-separated list of `-file` aliases (or `df` for the pipeline's current result so far) — **quote the whole value**, e.g. `frames='df1,df2,df3'` |
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# stack three files in one call
|
|
60
|
+
pytae -file "a.csv=a; b.csv=b; c.csv=c" -concat "frames='a,b,c'"
|
|
61
|
+
|
|
62
|
+
# or stack incrementally, folding more files onto the running result
|
|
63
|
+
pytae -file "a.csv=a; b.csv=b; c.csv=c" -concat "frames='a,b'" -concat "frames='df,c'"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
<a id="sql-alternative"></a>
|
|
67
|
+
## `-sql` as an alternative to `-merge`/`-concat`
|
|
68
|
+
|
|
69
|
+
`-sql` may be used **instead of `-merge`/`-concat`** as the founding op in `-file` mode. Every `-file` alias is registered as its own duckdb table (by its alias name), so you can write the join (or `union all`, for stacking) yourself — more flexible than `-merge`'s/`-concat`'s `key=value` syntax (arbitrary conditions, multiple joins, inline aggregation, …):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pytae -file "data1.parquet=df1; data2.parquet=df2" \
|
|
73
|
+
-sql 'select * from df1 inner join df2 on df1."col a" = df2.cola'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Once something in the pipeline has produced a current view (e.g. after `-merge`/`-concat`, or a later `-sql` call), `df` also becomes queryable — same as single-file mode:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pytae -file "a.csv=a; b.csv=b" -merge "left=a,right=b,on='id'" -sql "select count(*) as n from df"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Notes
|
|
83
|
+
|
|
84
|
+
- `-convert` after a merge/concat requires `-o`/`--output` explicitly (there's no single source file to derive a default `.csv` name from).
|
|
85
|
+
- Glob-pattern batch mode (`pytae 'data/*.parquet' -convert`) is a different, unrelated feature — it can't be combined with `-file`.
|
|
86
|
+
|
|
@@ -11,7 +11,7 @@ penguins = pt.sample("penguins") # or pt.sample_data["penguins"]
|
|
|
11
11
|
|
|
12
12
|
## 1) Plotting — `Plotter`
|
|
13
13
|
|
|
14
|
-
Method-chainable plots on top of `pandas.plot`. Requires matplotlib (`pip install pytae[plot]`). [plotter.ipynb](https://github.com/maddytae/pytae/blob/master/notebooks/plotter.ipynb)
|
|
14
|
+
Method-chainable plots on top of `pandas.plot`. Requires matplotlib (`pip install pytae[plot]`). See **[docs/PLOTTING.md](PLOTTING.md)** for more examples (bar, pie, multi-panel dashboards, …) with sample data, or [plotter.ipynb](https://github.com/maddytae/pytae/blob/master/notebooks/plotter.ipynb) for the full notebook.
|
|
15
15
|
|
|
16
16
|
```python
|
|
17
17
|
from pytae.plotting import Plotter
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# pytae — Plotting (`Plotter`)
|
|
2
|
+
|
|
3
|
+
`Plotter` is a method-chainable wrapper around `pandas.plot()` (which itself wraps matplotlib). Chain `.data()` → `.plot()` → `.plot()` → `.finalize()`; each `.plot()` call remembers the previous call's kwargs unless you change `.data()` or the plot `kind`. Requires matplotlib: `pip install pytae[plot]`.
|
|
4
|
+
|
|
5
|
+
All examples below use pytae's bundled sample datasets (`pytae.sample_data[...]`) — no files to download. See [notebooks/plotter.ipynb](https://github.com/maddytae/pytae/blob/master/notebooks/plotter.ipynb) for the full runnable notebook version, and [docs/LIBRARY.md](LIBRARY.md) for the rest of pytae's library.
|
|
6
|
+
|
|
7
|
+
## Scatter — colored by category
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import pytae as pt
|
|
11
|
+
|
|
12
|
+
penguins = pt.sample_data["penguins"]
|
|
13
|
+
|
|
14
|
+
k = pt.Plotter(figsize=(6, 4.5))
|
|
15
|
+
(k
|
|
16
|
+
.data(penguins)
|
|
17
|
+
.plot(kind="scatter", x="bill_length_mm", y="bill_depth_mm", c="species", cmap="viridis",
|
|
18
|
+
title="Penguin bill dimensions by species")
|
|
19
|
+
.finalize()
|
|
20
|
+
)
|
|
21
|
+
k.fig
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## Grouped bar — aggregated automatically
|
|
27
|
+
|
|
28
|
+
`by=` splits into groups, `aggfunc=` (default `'sum'`) aggregates — no manual `groupby()`/`pivot()` needed:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
tips = pt.sample_data["tips"]
|
|
32
|
+
color = {"Male": "steelblue", "Female": "salmon"}
|
|
33
|
+
|
|
34
|
+
k = pt.Plotter(figsize=(6, 4.5))
|
|
35
|
+
(k
|
|
36
|
+
.data(tips)
|
|
37
|
+
.plot(kind="bar", x="day", y="total_bill", by="sex", aggfunc="mean", color=color,
|
|
38
|
+
title="Average bill by day and sex")
|
|
39
|
+
.finalize()
|
|
40
|
+
)
|
|
41
|
+
k.fig
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
## Secondary axis — two metrics, two scales, one panel
|
|
47
|
+
|
|
48
|
+
Append `^` to a mosaic key (`on='A^'`) to plot on a secondary y-axis that shares the same x-axis as panel `'A'` — useful when two series live on very different scales (here, dollars vs. tip amount):
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
tips = pt.sample_data["tips"]
|
|
52
|
+
|
|
53
|
+
k = pt.Plotter(figsize=(6.5, 4.5))
|
|
54
|
+
(k
|
|
55
|
+
.data(tips)
|
|
56
|
+
.plot(kind="bar", x="day", y="total_bill", aggfunc="mean", color="#c7ddf2", legend=False,
|
|
57
|
+
title="Average bill (bars) vs average tip (line) by day")
|
|
58
|
+
.plot(kind="line", x="day", y="tip", aggfunc="mean", on="A^", color="crimson", marker="o")
|
|
59
|
+
.finalize(consolidate_legends=True, ncols=2, bbox_to_anchor=(0.75, -0.05))
|
|
60
|
+
)
|
|
61
|
+
k.fig
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
The second `.plot()` call reuses `x="day"`/`aggfunc="mean"` from context but targets `on="A^"` instead of `'A'`, so it shares panel `'A'`'s x-axis while getting its own y-scale. Any mosaic panel works this way — `on='B^'`, `on='C^'`, etc. — and `finalize(hide_secondary_y=True)` hides the secondary y-axis's ticks/labels/spine entirely if you only wanted it for scaling, not for display.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
tips = pt.sample_data["tips"]
|
|
70
|
+
color = {"Lunch": "orange", "Dinner": "green"}
|
|
71
|
+
|
|
72
|
+
k = pt.Plotter(figsize=(5, 5))
|
|
73
|
+
(k
|
|
74
|
+
.data(tips)
|
|
75
|
+
.plot(kind="pie", y="tip", by="time", aggfunc="mean", autopct="%1.1f%%", colors=color,
|
|
76
|
+
explode=(0, 0.05), title="Average tip share by meal time")
|
|
77
|
+
.finalize()
|
|
78
|
+
)
|
|
79
|
+
k.fig
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
## Multi-panel dashboard — mosaic layout, mixed plot kinds, consolidated legend
|
|
85
|
+
|
|
86
|
+
Pass a mosaic string to lay out several named axes (`'A'`, `'B'`, …); switch `.data()` between panels and mix plot kinds freely. `finalize(consolidate_legends=True)` merges every panel's legend into one:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
fmri = pt.sample_data["fmri"]
|
|
90
|
+
tips = pt.sample_data["tips"]
|
|
91
|
+
healthexp = pt.sample_data["healthexp"]
|
|
92
|
+
|
|
93
|
+
color = {"cue": "steelblue", "stim": "darkorange"}
|
|
94
|
+
|
|
95
|
+
mosaic = """
|
|
96
|
+
AB
|
|
97
|
+
CD
|
|
98
|
+
"""
|
|
99
|
+
k = pt.Plotter(mosaic, figsize=(9, 7))
|
|
100
|
+
(k
|
|
101
|
+
.data(fmri)
|
|
102
|
+
.plot(x="timepoint", y="signal", by="event", aggfunc="mean", kind="line", color=color,
|
|
103
|
+
on="A", title="Signal over time by event")
|
|
104
|
+
.data(tips)
|
|
105
|
+
.plot(kind="scatter", x="total_bill", y="tip", c="size", cmap="viridis", on="B",
|
|
106
|
+
title="Tip vs bill, colored by party size")
|
|
107
|
+
.data(healthexp)
|
|
108
|
+
.plot(kind="area", x="Year", y="Spending_USD", by="Country", aggfunc="mean", on="C",
|
|
109
|
+
legend=False, title="Health spending over time")
|
|
110
|
+
.data(tips)
|
|
111
|
+
.plot(kind="kde", column="tip", by="day", on="D", title="Tip distribution by day")
|
|
112
|
+
.finalize(consolidate_legends=True, ncols=4, bbox_to_anchor=(0.75, -0.02))
|
|
113
|
+
)
|
|
114
|
+
k.fig
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
## Enhancing a plot after `finalize()` — looping over axes
|
|
120
|
+
|
|
121
|
+
`k.axd` is the mosaic-key → `Axes` dict (`k.fig.axes` gives every matplotlib `Axes`, including secondary ones added via `on='X^'`). Once `.finalize()` has run, loop over either to apply the same tweak everywhere — gridlines, tick rotation, reference lines, annotations, anything matplotlib supports directly on an `Axes`:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
# ... continuing from the dashboard above, after .finalize()
|
|
125
|
+
for ax_key, ax in k.axd.items():
|
|
126
|
+
if "^" in ax_key: # skip secondary axes if you only want primaries styled
|
|
127
|
+
continue
|
|
128
|
+
ax.grid(True, alpha=0.3, linestyle="--")
|
|
129
|
+
for label in ax.get_xticklabels():
|
|
130
|
+
label.set_rotation(30)
|
|
131
|
+
label.set_ha("right")
|
|
132
|
+
|
|
133
|
+
k.fig
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+

|
|
137
|
+
|
|
138
|
+
This is the general escape hatch for anything `Plotter` doesn't expose as a kwarg — since `k.fig`/`k.axd` are plain matplotlib objects, nothing about `Plotter` stops you from dropping into regular matplotlib calls afterward (`ax.axhline()`, `ax.annotate()`, `ax.set_ylim()`, …) before the final `k.fig.savefig(...)`.
|
|
139
|
+
|
|
140
|
+
## Other plot kinds
|
|
141
|
+
|
|
142
|
+
Everything `pandas.plot()` supports works through `.plot(kind=...)`: `line`, `bar`/`barh`, `area`, `hist`, `kde`/`density`, `scatter`, `hexbin`, `pie`. A few notes:
|
|
143
|
+
|
|
144
|
+
- `by=`/`aggfunc=` (default `sum`) auto-aggregate for `line`/`bar`/`barh`/`area`/`pie` — pass `aggregate=False` if your data is already one row per `x`/`by` combination.
|
|
145
|
+
- `hist`/`kde`/`density` take `column=` (the value column) instead of `y=`.
|
|
146
|
+
- `scatter`/`hexbin` don't aggregate; use `c=`/`cmap=` (scatter) or `C=`/`reduce_C_function=` (hexbin) to encode a third variable instead of `by=`.
|
|
147
|
+
- `on='A'` targets a specific mosaic panel; `on='A^'` plots on a secondary y-axis sharing panel `'A'`'s x-axis.
|
|
148
|
+
- `style=`/`width=` (dicts keyed by series name) set per-line dash style/line width on `line` plots — set once via `.plot()`, not as a matplotlib property afterward.
|
|
149
|
+
|
|
150
|
+
## `finalize()` options
|
|
151
|
+
|
|
152
|
+
| Option | Effect |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `consolidate_legends` | One merged legend across all panels instead of per-panel legends |
|
|
155
|
+
| `bbox_to_anchor`, `ncols` | Position/columns for the consolidated legend |
|
|
156
|
+
| `legend`, `legend_primary`, `legend_secondary` | Master switch, and per-axis-type switches for primary vs. secondary (`^`) axes |
|
|
157
|
+
| `legend_loc`, `legend_frameon` | Location and frame for per-panel legends |
|
|
158
|
+
| `hide_secondary_y` | Hide tick labels/spine on secondary (`^`) axes |
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytae"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.3.0"
|
|
8
8
|
description = "A package to enhance common tasks in data and plotting"
|
|
9
9
|
authors = [{ name = "Madhukar Kumar Jha", email = "madhukar.k.jha@gmail.com" }]
|
|
10
10
|
readme = "README.md"
|