plotlet 0.1.0__tar.gz → 0.1.3__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 (35) hide show
  1. {plotlet-0.1.0/src/plotlet.egg-info → plotlet-0.1.3}/PKG-INFO +48 -9
  2. {plotlet-0.1.0 → plotlet-0.1.3}/README.md +47 -8
  3. {plotlet-0.1.0 → plotlet-0.1.3}/pyproject.toml +1 -1
  4. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/__init__.py +8 -2
  5. plotlet-0.1.3/src/plotlet/_cm_data.py +189 -0
  6. plotlet-0.1.3/src/plotlet/_png.py +38 -0
  7. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/_spec.py +2 -0
  8. plotlet-0.1.3/src/plotlet/artists.py +314 -0
  9. plotlet-0.1.3/src/plotlet/builtin_artists.py +254 -0
  10. plotlet-0.1.3/src/plotlet/chart.py +337 -0
  11. plotlet-0.1.3/src/plotlet/colormaps.py +50 -0
  12. plotlet-0.1.3/src/plotlet/core.py +581 -0
  13. plotlet-0.1.3/src/plotlet/layout.py +530 -0
  14. plotlet-0.1.3/src/plotlet/legend.py +349 -0
  15. plotlet-0.1.3/src/plotlet/registry.py +74 -0
  16. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/scales.py +14 -7
  17. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/spec.json +20 -4
  18. {plotlet-0.1.0 → plotlet-0.1.3/src/plotlet.egg-info}/PKG-INFO +48 -9
  19. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet.egg-info/SOURCES.txt +10 -1
  20. plotlet-0.1.3/tests/test_chart.py +279 -0
  21. plotlet-0.1.3/tests/test_legend.py +131 -0
  22. plotlet-0.1.3/tests/test_subplots.py +306 -0
  23. plotlet-0.1.0/src/plotlet/artists.py +0 -154
  24. plotlet-0.1.0/src/plotlet/chart.py +0 -150
  25. plotlet-0.1.0/src/plotlet/core.py +0 -336
  26. plotlet-0.1.0/tests/test_chart.py +0 -109
  27. {plotlet-0.1.0 → plotlet-0.1.3}/LICENSE +0 -0
  28. {plotlet-0.1.0 → plotlet-0.1.3}/setup.cfg +0 -0
  29. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/colors.py +0 -0
  30. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/font.py +0 -0
  31. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet/fonts/DejaVuSans.ttf +0 -0
  32. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet.egg-info/dependency_links.txt +0 -0
  33. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet.egg-info/requires.txt +0 -0
  34. {plotlet-0.1.0 → plotlet-0.1.3}/src/plotlet.egg-info/top_level.txt +0 -0
  35. {plotlet-0.1.0 → plotlet-0.1.3}/tests/test_old.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plotlet
3
- Version: 0.1.0
3
+ Version: 0.1.3
4
4
  Summary: Small, hackable Python library that emits matplotlib-style SVG plots.
5
5
  Author: gitbamboo42
6
6
  License-Expression: MIT
@@ -33,7 +33,7 @@ A small, hackable Python library that emits matplotlib-style SVG plots.
33
33
 
34
34
  ## Why
35
35
 
36
- matplotlib is the right tool when you want the kitchen sink. plotlet's niche is **custom plot types** — genome tracks, Manhattan plots, phylogenetic trees, anything matplotlib's extension API makes painful. The whole library is ~700 lines of Python with a deliberately tiny, exposed core: adding a new plot type is a 3-step recipe, not an architecture project.
36
+ matplotlib is the right tool when you want the kitchen sink. plotlet's niche is **custom plot types** — genome tracks, Manhattan plots, phylogenetic trees, anything matplotlib's extension API makes painful. The whole library has a deliberately tiny, exposed core: adding a new plot type is a 3-step recipe, not an architecture project.
37
37
 
38
38
  It's a **scaffold, not a feature catalog**: the core ships ~5 standard plots and the infrastructure for extending. Custom plot types live in your own project (or [`cookbook/`](cookbook/)), not upstream. See [docs/PHILOSOPHY.md](docs/PHILOSOPHY.md) for the full framing.
39
39
 
@@ -53,12 +53,8 @@ c # auto-renders in Jupyter
53
53
 
54
54
  ## Install
55
55
 
56
- Not on PyPI yet — clone and install editable:
57
-
58
56
  ```bash
59
- git clone <repo>
60
- cd plotlet
61
- pip install -e .
57
+ pip install plotlet
62
58
  ```
63
59
 
64
60
  ## Properties
@@ -68,6 +64,7 @@ pip install -e .
68
64
  - **Cross-machine reproducible.** Bundled DejaVu Sans + text-as-paths means rendering is identical on Linux, macOS, Windows, headless CI.
69
65
  - **Jupyter-native.** `Figure._repr_html_` auto-renders the last expression in a cell.
70
66
  - **Tiny output.** Each plot is ~50 KB SVG, self-contained.
67
+ - **Compositional.** Multi-panel layouts via `|`, `/`, `pt.grid`; share scales with `share_x=` / `share_y=`; layout-level legend with `pt.legend()` covering both discrete swatches and continuous gradients (the colorbar).
71
68
 
72
69
  ## API
73
70
 
@@ -77,7 +74,11 @@ pip install -e .
77
74
 
78
75
  Pass at construction (`pt.chart(data, title=..., grid=True, ...)`) or as chained setters (`c.title(...)`, etc.):
79
76
 
80
- `title`, `xlabel`, `ylabel`, `xlim=(a, b)`, `ylim=(a, b)`, `xscale="log"|"linear"`, `yscale=...`, `grid=True/False`, `legend=True/False`, `width`, `height`
77
+ `title`, `xlabel`, `ylabel`, `xlim=(a, b)`, `ylim=(a, b)`, `xscale="linear"|"log"|"category"` (chained: `c.xscale("category", order=[...], padding=0)`), `yscale=...`, `grid=True/False`, `legend=True/False`, `width`, `height`
78
+
79
+ String-valued data on either axis (`scatter(["a","b","c"], ...)`, `bar`, …) auto-switches to a categorical scale, alphabetical by default. `padding=0` makes category bands contiguous (heatmap-track look).
80
+
81
+ Tick customization: `c.xticks([0, 5, 10], ["A","B","C"], rotation=45, fontsize=12, direction="out", marks=False)`. Pass `[]` to hide. `yticks(...)` works the same way.
81
82
 
82
83
  ### Mark methods
83
84
 
@@ -88,8 +89,45 @@ Pass at construction (`pt.chart(data, title=..., grid=True, ...)`) or as chained
88
89
  | `.bar(x=, y=, **opts)` | `color`, `label`, `alpha` |
89
90
  | `.hist(x=, **opts)` | `bins`, `color`, `alpha`, `label` |
90
91
  | `.fill_between(x=, y1=, y2=, **opts)` | `color`, `alpha`, `label` |
92
+ | `.axhline(y, **opts)` / `.axvline(x, **opts)` | `color`, `linewidth`, `linestyle`, `alpha`, `label`, axes-fraction `xmin`/`xmax` (or `ymin`/`ymax`) |
93
+ | `.axhspan(ymin, ymax, **opts)` / `.axvspan(xmin, xmax, **opts)` | `color`, `alpha`, `label`, axes-fraction `xmin`/`xmax` (or `ymin`/`ymax`) |
94
+ | `.imshow(data, **opts)` | `cmap` (any matplotlib name, default `"viridis"`), `vmin`, `vmax`, `extent=(left, right, bottom, top)` |
95
+
96
+ `hue=<col>` (on `.line` / `.scatter`) splits into one call per unique value with auto-labels and tab10 colors. Reference lines and spans default to black; spans use `alpha=0.2`. They're drawn outside the data color cycle and don't participate in autoscaling — they're decorations on the frame, not data.
97
+
98
+ `.imshow(data)` renders a 2-D array as a colored grid. Small grids (`nrows × ncols ≤ 10000`) emit one `<rect>` per cell and stay vector-clean at any zoom; larger grids encode as a single base64 PNG and quantize to 256 levels. Image row 0 is rendered at the top of its rectangle; the y axis stays Cartesian (small at bottom). All ~180 matplotlib colormaps are vendored — see `pt.list_colormaps()`.
99
+
100
+ ### Subplots
101
+
102
+ Compose multi-panel layouts with operators on `Chart`:
103
+
104
+ ```python
105
+ a | b # side-by-side
106
+ a / b # stacked
107
+ a | b | c # left-fold flatten — one row of three, not nested
108
+
109
+ pt.grid([[a, b], # 2-D grid; cells may be `None`
110
+ [c, d]])
111
+
112
+ # Share x or y across panels — collapses the gap between them
113
+ # and forces both onto the source's scale.
114
+ top = pt.chart()
115
+ main = pt.chart(share_x=top)
116
+ top / main # vertically stacked, x-axis joined
117
+
118
+ # Layout-level legend (covers colorbar and discrete swatches in
119
+ # one constructor — geometry follows from the source's color mapping).
120
+ hm = pt.chart(); hm.imshow(matrix, cmap="viridis")
121
+ hm | pt.legend(hm) # heatmap + colorbar (gradient strip)
122
+
123
+ # Multi-source: groups by chart, using each chart's title as
124
+ # section header. `names={chart: "Override"}` renames a header,
125
+ # `names={chart: None}` hides it, `group_by_chart=False` flattens.
126
+ (hm | top) | pt.legend() # auto-collects from siblings
127
+ parent = a | b; parent.legend() # sugar for parent | pt.legend()
128
+ ```
91
129
 
92
- `hue=<col>` (on `.line` / `.scatter`) splits into one call per unique value with auto-labels and tab10 colors.
130
+ A composed chart owns its children; render the parent (`(a | b).show()` or `.to_svg()` / `.save_svg(...)`). Calling `.show()` on a child raises. See [`docs/SUBPLOTS.md`](docs/SUBPLOTS.md) for the design rationale.
93
131
 
94
132
  ### Render / save
95
133
 
@@ -117,6 +155,7 @@ plotlet's central hackability claim: a custom plot type is a 3-step recipe (~50
117
155
  python tests/test_chart.py # check vs. committed baselines
118
156
  python tests/test_chart.py --update # regenerate (review the diff!)
119
157
  python tests/test_chart.py --gallery # build tests/baseline_images/chart/index.html
158
+ python tests/test_subplots.py # subplot baselines + composition invariants
120
159
  ```
121
160
 
122
161
  ## Non-goals
@@ -4,7 +4,7 @@ A small, hackable Python library that emits matplotlib-style SVG plots.
4
4
 
5
5
  ## Why
6
6
 
7
- matplotlib is the right tool when you want the kitchen sink. plotlet's niche is **custom plot types** — genome tracks, Manhattan plots, phylogenetic trees, anything matplotlib's extension API makes painful. The whole library is ~700 lines of Python with a deliberately tiny, exposed core: adding a new plot type is a 3-step recipe, not an architecture project.
7
+ matplotlib is the right tool when you want the kitchen sink. plotlet's niche is **custom plot types** — genome tracks, Manhattan plots, phylogenetic trees, anything matplotlib's extension API makes painful. The whole library has a deliberately tiny, exposed core: adding a new plot type is a 3-step recipe, not an architecture project.
8
8
 
9
9
  It's a **scaffold, not a feature catalog**: the core ships ~5 standard plots and the infrastructure for extending. Custom plot types live in your own project (or [`cookbook/`](cookbook/)), not upstream. See [docs/PHILOSOPHY.md](docs/PHILOSOPHY.md) for the full framing.
10
10
 
@@ -24,12 +24,8 @@ c # auto-renders in Jupyter
24
24
 
25
25
  ## Install
26
26
 
27
- Not on PyPI yet — clone and install editable:
28
-
29
27
  ```bash
30
- git clone <repo>
31
- cd plotlet
32
- pip install -e .
28
+ pip install plotlet
33
29
  ```
34
30
 
35
31
  ## Properties
@@ -39,6 +35,7 @@ pip install -e .
39
35
  - **Cross-machine reproducible.** Bundled DejaVu Sans + text-as-paths means rendering is identical on Linux, macOS, Windows, headless CI.
40
36
  - **Jupyter-native.** `Figure._repr_html_` auto-renders the last expression in a cell.
41
37
  - **Tiny output.** Each plot is ~50 KB SVG, self-contained.
38
+ - **Compositional.** Multi-panel layouts via `|`, `/`, `pt.grid`; share scales with `share_x=` / `share_y=`; layout-level legend with `pt.legend()` covering both discrete swatches and continuous gradients (the colorbar).
42
39
 
43
40
  ## API
44
41
 
@@ -48,7 +45,11 @@ pip install -e .
48
45
 
49
46
  Pass at construction (`pt.chart(data, title=..., grid=True, ...)`) or as chained setters (`c.title(...)`, etc.):
50
47
 
51
- `title`, `xlabel`, `ylabel`, `xlim=(a, b)`, `ylim=(a, b)`, `xscale="log"|"linear"`, `yscale=...`, `grid=True/False`, `legend=True/False`, `width`, `height`
48
+ `title`, `xlabel`, `ylabel`, `xlim=(a, b)`, `ylim=(a, b)`, `xscale="linear"|"log"|"category"` (chained: `c.xscale("category", order=[...], padding=0)`), `yscale=...`, `grid=True/False`, `legend=True/False`, `width`, `height`
49
+
50
+ String-valued data on either axis (`scatter(["a","b","c"], ...)`, `bar`, …) auto-switches to a categorical scale, alphabetical by default. `padding=0` makes category bands contiguous (heatmap-track look).
51
+
52
+ Tick customization: `c.xticks([0, 5, 10], ["A","B","C"], rotation=45, fontsize=12, direction="out", marks=False)`. Pass `[]` to hide. `yticks(...)` works the same way.
52
53
 
53
54
  ### Mark methods
54
55
 
@@ -59,8 +60,45 @@ Pass at construction (`pt.chart(data, title=..., grid=True, ...)`) or as chained
59
60
  | `.bar(x=, y=, **opts)` | `color`, `label`, `alpha` |
60
61
  | `.hist(x=, **opts)` | `bins`, `color`, `alpha`, `label` |
61
62
  | `.fill_between(x=, y1=, y2=, **opts)` | `color`, `alpha`, `label` |
63
+ | `.axhline(y, **opts)` / `.axvline(x, **opts)` | `color`, `linewidth`, `linestyle`, `alpha`, `label`, axes-fraction `xmin`/`xmax` (or `ymin`/`ymax`) |
64
+ | `.axhspan(ymin, ymax, **opts)` / `.axvspan(xmin, xmax, **opts)` | `color`, `alpha`, `label`, axes-fraction `xmin`/`xmax` (or `ymin`/`ymax`) |
65
+ | `.imshow(data, **opts)` | `cmap` (any matplotlib name, default `"viridis"`), `vmin`, `vmax`, `extent=(left, right, bottom, top)` |
66
+
67
+ `hue=<col>` (on `.line` / `.scatter`) splits into one call per unique value with auto-labels and tab10 colors. Reference lines and spans default to black; spans use `alpha=0.2`. They're drawn outside the data color cycle and don't participate in autoscaling — they're decorations on the frame, not data.
68
+
69
+ `.imshow(data)` renders a 2-D array as a colored grid. Small grids (`nrows × ncols ≤ 10000`) emit one `<rect>` per cell and stay vector-clean at any zoom; larger grids encode as a single base64 PNG and quantize to 256 levels. Image row 0 is rendered at the top of its rectangle; the y axis stays Cartesian (small at bottom). All ~180 matplotlib colormaps are vendored — see `pt.list_colormaps()`.
70
+
71
+ ### Subplots
72
+
73
+ Compose multi-panel layouts with operators on `Chart`:
74
+
75
+ ```python
76
+ a | b # side-by-side
77
+ a / b # stacked
78
+ a | b | c # left-fold flatten — one row of three, not nested
79
+
80
+ pt.grid([[a, b], # 2-D grid; cells may be `None`
81
+ [c, d]])
82
+
83
+ # Share x or y across panels — collapses the gap between them
84
+ # and forces both onto the source's scale.
85
+ top = pt.chart()
86
+ main = pt.chart(share_x=top)
87
+ top / main # vertically stacked, x-axis joined
88
+
89
+ # Layout-level legend (covers colorbar and discrete swatches in
90
+ # one constructor — geometry follows from the source's color mapping).
91
+ hm = pt.chart(); hm.imshow(matrix, cmap="viridis")
92
+ hm | pt.legend(hm) # heatmap + colorbar (gradient strip)
93
+
94
+ # Multi-source: groups by chart, using each chart's title as
95
+ # section header. `names={chart: "Override"}` renames a header,
96
+ # `names={chart: None}` hides it, `group_by_chart=False` flattens.
97
+ (hm | top) | pt.legend() # auto-collects from siblings
98
+ parent = a | b; parent.legend() # sugar for parent | pt.legend()
99
+ ```
62
100
 
63
- `hue=<col>` (on `.line` / `.scatter`) splits into one call per unique value with auto-labels and tab10 colors.
101
+ A composed chart owns its children; render the parent (`(a | b).show()` or `.to_svg()` / `.save_svg(...)`). Calling `.show()` on a child raises. See [`docs/SUBPLOTS.md`](docs/SUBPLOTS.md) for the design rationale.
64
102
 
65
103
  ### Render / save
66
104
 
@@ -88,6 +126,7 @@ plotlet's central hackability claim: a custom plot type is a 3-step recipe (~50
88
126
  python tests/test_chart.py # check vs. committed baselines
89
127
  python tests/test_chart.py --update # regenerate (review the diff!)
90
128
  python tests/test_chart.py --gallery # build tests/baseline_images/chart/index.html
129
+ python tests/test_subplots.py # subplot baselines + composition invariants
91
130
  ```
92
131
 
93
132
  ## Non-goals
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plotlet"
7
- version = "0.1.0"
7
+ version = "0.1.3"
8
8
  description = "Small, hackable Python library that emits matplotlib-style SVG plots."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -16,8 +16,14 @@ Chained API (legacy, still supported):
16
16
  """
17
17
  from ._spec import SPEC
18
18
  from .colors import TAB10, colors
19
+ from .colormaps import colormap, list_colormaps
19
20
  from .core import Figure, figure
20
21
  from .chart import Chart, chart
22
+ from .layout import grid
23
+ from .legend import legend
24
+ from .registry import ArtistSpec, add_artist
21
25
 
22
- __all__ = ["chart", "Chart", "figure", "Figure", "SPEC", "TAB10", "colors"]
23
- __version__ = "0.1.0"
26
+ __all__ = ["chart", "Chart", "figure", "Figure", "SPEC", "TAB10", "colors",
27
+ "colormap", "list_colormaps", "grid", "legend",
28
+ "ArtistSpec", "add_artist"]
29
+ __version__ = "0.1.3"