ggplot2-python 4.0.2.9000.post2__tar.gz → 4.0.2.9000.post4__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.
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/PKG-INFO +49 -8
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/README.md +48 -7
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/__init__.py +112 -10
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/_compat.py +53 -6
- ggplot2_python-4.0.2.9000.post4/ggplot2_py/_defaults.py +169 -0
- ggplot2_python-4.0.2.9000.post4/ggplot2_py/_make_constructor.py +440 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/_utils.py +243 -16
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/aes.py +56 -14
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/annotation.py +21 -30
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/facet.py +786 -219
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/geom.py +54 -30
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/guide.py +12 -5
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/guide_axis.py +62 -47
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/guide_colourbar.py +53 -7
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/guide_legend.py +41 -33
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/layer.py +17 -3
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/plot.py +181 -42
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/plot_render.py +502 -91
- ggplot2_python-4.0.2.9000.post4/ggplot2_py/protocols.py +202 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/save.py +8 -3
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/scale.py +162 -4
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/scales/__init__.py +25 -3
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/stat.py +21 -4
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/theme_defaults.py +13 -12
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/theme_elements.py +48 -8
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/pyproject.toml +1 -1
- ggplot2_python-4.0.2.9000.post2/ggplot2_py/protocols.py +0 -171
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/.gitattributes +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/.gitignore +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/LICENSE +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/_plugins.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/autoplot.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/coord.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/coords/__init__.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/datasets.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/draw_key.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/fortify.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/geoms/__init__.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/ggproto.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/guides/__init__.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/labeller.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/labels.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/layout.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/limits.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/position.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/py.typed +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/qplot.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/diamonds.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/economics.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/economics_long.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/faithfuld.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/luv_colours.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/midwest.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/mpg.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/msleep.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/presidential.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/seals.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/resources/txhousing.csv +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/stats/__init__.py +0 -0
- {ggplot2_python-4.0.2.9000.post2 → ggplot2_python-4.0.2.9000.post4}/ggplot2_py/theme.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ggplot2-python
|
|
3
|
-
Version: 4.0.2.9000.
|
|
3
|
+
Version: 4.0.2.9000.post4
|
|
4
4
|
Summary: Python port of the R ggplot2 package (tracks R ggplot2 4.0.2.9000)
|
|
5
5
|
Project-URL: Homepage, https://github.com/Bio-Babel/ggplot2-python
|
|
6
6
|
Project-URL: Repository, https://github.com/Bio-Babel/ggplot2-python
|
|
@@ -48,17 +48,17 @@ Requires-Dist: mkdocs-material; extra == 'docs'
|
|
|
48
48
|
Requires-Dist: mkdocstrings[python]; extra == 'docs'
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
50
50
|
|
|
51
|
-
#
|
|
51
|
+
# ggplot2-python <a href="https://github.com/Bio-Babel/ggplot2-python"><img src="assets/ggplot2_py_logo.png" align="right" height="138" alt="ggplot2-python logo" /></a>
|
|
52
52
|
|
|
53
53
|
[](https://pypi.org/project/ggplot2-python/)
|
|
54
54
|
|
|
55
|
-
AI-assisted
|
|
55
|
+
AI-assisted port of the python **ggplot2** package — Create Elegant Data Visualisations Using the Grammar of Graphics.
|
|
56
56
|
|
|
57
57
|
## Overview
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
ggplot2-python implements the grammar of graphics in Python, faithfully porting R's ggplot2 using pandas DataFrames as the data container and a Cairo-based rendering backend. It supports 47 geoms, 32 stats, faceting, coordinate systems, themes, guides, and 130+ scales.
|
|
60
60
|
|
|
61
|
-
Beyond a direct port,
|
|
61
|
+
Beyond a direct port, ggplot2-python adds **Python-exclusive features** that extend the Grammar of Graphics with Python-native idioms while preserving full orthogonality of GOG components.
|
|
62
62
|
|
|
63
63
|
## Python-Exclusive Features
|
|
64
64
|
|
|
@@ -73,6 +73,7 @@ These capabilities have no R equivalent and leverage Python-specific language fe
|
|
|
73
73
|
| **Auto-registration** | `__init_subclass__` | `class GeomStar(Geom): ...` auto-registers; no manual wiring needed |
|
|
74
74
|
| **Protocol contracts** | `typing.Protocol` | `isinstance(my_geom, GeomProtocol)` — structural type checking for extensions |
|
|
75
75
|
| **Scoped defaults** | `contextvars.ContextVar` | `with ggplot_defaults(theme=theme_minimal()): ...` — thread-safe scoped defaults |
|
|
76
|
+
| **Functional composition** | `sum` / `reduce` over `__add__` | `sum(parts, start=ggplot(data))` — compose plots without the `+` operator, useful for programmatic plot construction |
|
|
76
77
|
|
|
77
78
|
## Installation
|
|
78
79
|
|
|
@@ -85,7 +86,7 @@ For a local development:
|
|
|
85
86
|
|
|
86
87
|
```bash
|
|
87
88
|
git clone https://github.com/Bio-Babel/ggplot2-python.git
|
|
88
|
-
cd
|
|
89
|
+
cd ggplot2-python
|
|
89
90
|
pip install -e ".[dev]"
|
|
90
91
|
```
|
|
91
92
|
|
|
@@ -145,6 +146,46 @@ with ggplot_defaults(theme=theme_minimal()):
|
|
|
145
146
|
# Outside: no defaults
|
|
146
147
|
```
|
|
147
148
|
|
|
149
|
+
### Functional composition with `sum()` / `reduce()` (Python-exclusive)
|
|
150
|
+
|
|
151
|
+
The `+` operator is the canonical ggplot2 syntax. Because `GGPlot.__add__` is defined and every component family is registered with
|
|
152
|
+
the `update_ggplot` singledispatch generic, **Python's iterable-composition
|
|
153
|
+
idioms also work directly** — useful for programmatic plot building, list
|
|
154
|
+
comprehensions, or just function-style code:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# 1) `sum(parts, start=ggplot(data))` — the canonical function-style form
|
|
158
|
+
def fnplot(data, *parts):
|
|
159
|
+
return sum(parts, start=ggplot(data))
|
|
160
|
+
|
|
161
|
+
fnplot(
|
|
162
|
+
mpg,
|
|
163
|
+
aes(x="displ", y="hwy", colour="class"),
|
|
164
|
+
geom_point(),
|
|
165
|
+
geom_smooth(method="lm"),
|
|
166
|
+
facet_wrap("drv"),
|
|
167
|
+
theme_minimal(),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# 2) `sum` over an iterable, no helper needed:
|
|
171
|
+
sum(
|
|
172
|
+
[aes(x="displ", y="hwy"), geom_point(), theme_minimal()],
|
|
173
|
+
start=ggplot(mpg),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# 3) `functools.reduce` — the canonical Python composition operator:
|
|
177
|
+
from functools import reduce
|
|
178
|
+
from operator import add
|
|
179
|
+
reduce(add, [aes(x="displ", y="hwy"), geom_point(), theme_minimal()], ggplot(mpg))
|
|
180
|
+
|
|
181
|
+
# 4) List on the RHS of `+` — recursive add via the list-dispatch:
|
|
182
|
+
ggplot(mpg, aes("displ", "hwy")) + [geom_point(), geom_smooth(), theme_minimal()]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
> One caveat: Python's built-in `sum` has the signature
|
|
186
|
+
> `sum(iterable, /, start=0)` — it accepts *one* iterable plus an optional
|
|
187
|
+
> `start`, **not** variadic arguments. `sum(a, b, c, d)` raises `TypeError`;
|
|
188
|
+
|
|
148
189
|
## Tutorials
|
|
149
190
|
|
|
150
191
|
### User Tutorials
|
|
@@ -160,11 +201,11 @@ with ggplot_defaults(theme=theme_minimal()):
|
|
|
160
201
|
- [Build Hooks](tutorials/build_hooks.ipynb) — intercepting the 16-stage build pipeline
|
|
161
202
|
|
|
162
203
|
### Developer Guide
|
|
163
|
-
- [Developer Guide: Extending
|
|
204
|
+
- [Developer Guide: Extending ggplot2-python](tutorials/developer_guide.ipynb) — comprehensive guide covering ggproto system, custom Stat/Geom creation, Protocol contracts, singledispatch, hooks, auto-registration, context manager, and packaging
|
|
164
205
|
|
|
165
206
|
## Extension Architecture
|
|
166
207
|
|
|
167
|
-
|
|
208
|
+
ggplot2-python is designed as an **extensible platform**. The following table summarises all extension points:
|
|
168
209
|
|
|
169
210
|
| Extension point | Mechanism | How to use |
|
|
170
211
|
|----------------|-----------|-----------|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ggplot2-python <a href="https://github.com/Bio-Babel/ggplot2-python"><img src="assets/ggplot2_py_logo.png" align="right" height="138" alt="ggplot2-python logo" /></a>
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/ggplot2-python/)
|
|
4
4
|
|
|
5
|
-
AI-assisted
|
|
5
|
+
AI-assisted port of the python **ggplot2** package — Create Elegant Data Visualisations Using the Grammar of Graphics.
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
ggplot2-python implements the grammar of graphics in Python, faithfully porting R's ggplot2 using pandas DataFrames as the data container and a Cairo-based rendering backend. It supports 47 geoms, 32 stats, faceting, coordinate systems, themes, guides, and 130+ scales.
|
|
10
10
|
|
|
11
|
-
Beyond a direct port,
|
|
11
|
+
Beyond a direct port, ggplot2-python adds **Python-exclusive features** that extend the Grammar of Graphics with Python-native idioms while preserving full orthogonality of GOG components.
|
|
12
12
|
|
|
13
13
|
## Python-Exclusive Features
|
|
14
14
|
|
|
@@ -23,6 +23,7 @@ These capabilities have no R equivalent and leverage Python-specific language fe
|
|
|
23
23
|
| **Auto-registration** | `__init_subclass__` | `class GeomStar(Geom): ...` auto-registers; no manual wiring needed |
|
|
24
24
|
| **Protocol contracts** | `typing.Protocol` | `isinstance(my_geom, GeomProtocol)` — structural type checking for extensions |
|
|
25
25
|
| **Scoped defaults** | `contextvars.ContextVar` | `with ggplot_defaults(theme=theme_minimal()): ...` — thread-safe scoped defaults |
|
|
26
|
+
| **Functional composition** | `sum` / `reduce` over `__add__` | `sum(parts, start=ggplot(data))` — compose plots without the `+` operator, useful for programmatic plot construction |
|
|
26
27
|
|
|
27
28
|
## Installation
|
|
28
29
|
|
|
@@ -35,7 +36,7 @@ For a local development:
|
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
38
|
git clone https://github.com/Bio-Babel/ggplot2-python.git
|
|
38
|
-
cd
|
|
39
|
+
cd ggplot2-python
|
|
39
40
|
pip install -e ".[dev]"
|
|
40
41
|
```
|
|
41
42
|
|
|
@@ -95,6 +96,46 @@ with ggplot_defaults(theme=theme_minimal()):
|
|
|
95
96
|
# Outside: no defaults
|
|
96
97
|
```
|
|
97
98
|
|
|
99
|
+
### Functional composition with `sum()` / `reduce()` (Python-exclusive)
|
|
100
|
+
|
|
101
|
+
The `+` operator is the canonical ggplot2 syntax. Because `GGPlot.__add__` is defined and every component family is registered with
|
|
102
|
+
the `update_ggplot` singledispatch generic, **Python's iterable-composition
|
|
103
|
+
idioms also work directly** — useful for programmatic plot building, list
|
|
104
|
+
comprehensions, or just function-style code:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
# 1) `sum(parts, start=ggplot(data))` — the canonical function-style form
|
|
108
|
+
def fnplot(data, *parts):
|
|
109
|
+
return sum(parts, start=ggplot(data))
|
|
110
|
+
|
|
111
|
+
fnplot(
|
|
112
|
+
mpg,
|
|
113
|
+
aes(x="displ", y="hwy", colour="class"),
|
|
114
|
+
geom_point(),
|
|
115
|
+
geom_smooth(method="lm"),
|
|
116
|
+
facet_wrap("drv"),
|
|
117
|
+
theme_minimal(),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# 2) `sum` over an iterable, no helper needed:
|
|
121
|
+
sum(
|
|
122
|
+
[aes(x="displ", y="hwy"), geom_point(), theme_minimal()],
|
|
123
|
+
start=ggplot(mpg),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# 3) `functools.reduce` — the canonical Python composition operator:
|
|
127
|
+
from functools import reduce
|
|
128
|
+
from operator import add
|
|
129
|
+
reduce(add, [aes(x="displ", y="hwy"), geom_point(), theme_minimal()], ggplot(mpg))
|
|
130
|
+
|
|
131
|
+
# 4) List on the RHS of `+` — recursive add via the list-dispatch:
|
|
132
|
+
ggplot(mpg, aes("displ", "hwy")) + [geom_point(), geom_smooth(), theme_minimal()]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> One caveat: Python's built-in `sum` has the signature
|
|
136
|
+
> `sum(iterable, /, start=0)` — it accepts *one* iterable plus an optional
|
|
137
|
+
> `start`, **not** variadic arguments. `sum(a, b, c, d)` raises `TypeError`;
|
|
138
|
+
|
|
98
139
|
## Tutorials
|
|
99
140
|
|
|
100
141
|
### User Tutorials
|
|
@@ -110,11 +151,11 @@ with ggplot_defaults(theme=theme_minimal()):
|
|
|
110
151
|
- [Build Hooks](tutorials/build_hooks.ipynb) — intercepting the 16-stage build pipeline
|
|
111
152
|
|
|
112
153
|
### Developer Guide
|
|
113
|
-
- [Developer Guide: Extending
|
|
154
|
+
- [Developer Guide: Extending ggplot2-python](tutorials/developer_guide.ipynb) — comprehensive guide covering ggproto system, custom Stat/Geom creation, Protocol contracts, singledispatch, hooks, auto-registration, context manager, and packaging
|
|
114
155
|
|
|
115
156
|
## Extension Architecture
|
|
116
157
|
|
|
117
|
-
|
|
158
|
+
ggplot2-python is designed as an **extensible platform**. The following table summarises all extension points:
|
|
118
159
|
|
|
119
160
|
| Extension point | Mechanism | How to use |
|
|
120
161
|
|----------------|-----------|-----------|
|
|
@@ -7,7 +7,7 @@ approach to creating statistical visualizations.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
__version__ = "4.0.2.9000.
|
|
10
|
+
__version__ = "4.0.2.9000.post4"
|
|
11
11
|
__r_commit__ = "c02c05a"
|
|
12
12
|
|
|
13
13
|
# ---------------------------------------------------------------------------
|
|
@@ -153,6 +153,10 @@ from ggplot2_py.geom import (
|
|
|
153
153
|
GeomQuantile,
|
|
154
154
|
GeomJitter,
|
|
155
155
|
GeomSf,
|
|
156
|
+
GeomCustomAnn,
|
|
157
|
+
GeomLogticks,
|
|
158
|
+
GeomRasterAnn,
|
|
159
|
+
translate_shape_string,
|
|
156
160
|
geom_point,
|
|
157
161
|
geom_path,
|
|
158
162
|
geom_line,
|
|
@@ -420,12 +424,14 @@ from ggplot2_py.scales import (
|
|
|
420
424
|
scale_size_datetime,
|
|
421
425
|
scale_radius,
|
|
422
426
|
scale_shape,
|
|
427
|
+
scale_shape_continuous,
|
|
423
428
|
scale_shape_discrete,
|
|
424
429
|
scale_shape_binned,
|
|
425
430
|
scale_shape_identity,
|
|
426
431
|
scale_shape_manual,
|
|
427
432
|
scale_shape_ordinal,
|
|
428
433
|
scale_linetype,
|
|
434
|
+
scale_linetype_continuous,
|
|
429
435
|
scale_linetype_discrete,
|
|
430
436
|
scale_linetype_binned,
|
|
431
437
|
scale_linetype_identity,
|
|
@@ -492,7 +498,11 @@ from ggplot2_py.facet import (
|
|
|
492
498
|
facet_grid,
|
|
493
499
|
facet_wrap,
|
|
494
500
|
is_facet,
|
|
501
|
+
wrap_dims,
|
|
502
|
+
max_height,
|
|
503
|
+
max_width,
|
|
495
504
|
)
|
|
505
|
+
from ggplot2_py.layout import Layout
|
|
496
506
|
|
|
497
507
|
# ---------------------------------------------------------------------------
|
|
498
508
|
# Position adjustments
|
|
@@ -549,6 +559,14 @@ from ggplot2_py.guide import (
|
|
|
549
559
|
guide_none,
|
|
550
560
|
guides,
|
|
551
561
|
is_guide,
|
|
562
|
+
is_guides,
|
|
563
|
+
new_guide,
|
|
564
|
+
old_guide,
|
|
565
|
+
guide_geom,
|
|
566
|
+
guide_train,
|
|
567
|
+
guide_merge,
|
|
568
|
+
guide_transform,
|
|
569
|
+
guide_gengrob,
|
|
552
570
|
)
|
|
553
571
|
|
|
554
572
|
# ---------------------------------------------------------------------------
|
|
@@ -567,6 +585,7 @@ from ggplot2_py.theme import (
|
|
|
567
585
|
reset_theme_settings,
|
|
568
586
|
update_theme,
|
|
569
587
|
replace_theme,
|
|
588
|
+
from_theme,
|
|
570
589
|
)
|
|
571
590
|
from ggplot2_py.theme_elements import (
|
|
572
591
|
Element,
|
|
@@ -582,6 +601,7 @@ from ggplot2_py.theme_elements import (
|
|
|
582
601
|
el_def,
|
|
583
602
|
merge_element,
|
|
584
603
|
is_theme_element,
|
|
604
|
+
is_margin,
|
|
585
605
|
Margin,
|
|
586
606
|
margin,
|
|
587
607
|
margin_auto,
|
|
@@ -603,6 +623,17 @@ from ggplot2_py.theme_defaults import (
|
|
|
603
623
|
theme_classic,
|
|
604
624
|
theme_void,
|
|
605
625
|
theme_test,
|
|
626
|
+
theme_sub_axis,
|
|
627
|
+
theme_sub_axis_x,
|
|
628
|
+
theme_sub_axis_y,
|
|
629
|
+
theme_sub_axis_top,
|
|
630
|
+
theme_sub_axis_bottom,
|
|
631
|
+
theme_sub_axis_left,
|
|
632
|
+
theme_sub_axis_right,
|
|
633
|
+
theme_sub_legend,
|
|
634
|
+
theme_sub_panel,
|
|
635
|
+
theme_sub_plot,
|
|
636
|
+
theme_sub_strip,
|
|
606
637
|
)
|
|
607
638
|
|
|
608
639
|
# ---------------------------------------------------------------------------
|
|
@@ -668,7 +699,19 @@ from ggplot2_py.autoplot import autoplot, autolayer
|
|
|
668
699
|
# ---------------------------------------------------------------------------
|
|
669
700
|
# Utility re-exports (matching R namespace)
|
|
670
701
|
# ---------------------------------------------------------------------------
|
|
671
|
-
from ggplot2_py._utils import
|
|
702
|
+
from ggplot2_py._utils import (
|
|
703
|
+
resolution, remove_missing,
|
|
704
|
+
cut_interval, cut_number, cut_width,
|
|
705
|
+
transform_position, fill_alpha, pattern_alpha,
|
|
706
|
+
)
|
|
707
|
+
from ggplot2_py._defaults import (
|
|
708
|
+
update_geom_defaults, update_stat_defaults,
|
|
709
|
+
reset_geom_defaults, reset_stat_defaults,
|
|
710
|
+
get_geom_defaults,
|
|
711
|
+
)
|
|
712
|
+
from ggplot2_py._make_constructor import make_constructor
|
|
713
|
+
# zeroGrob alias for R parity (ggplot2 imports it from grid)
|
|
714
|
+
from grid_py import null_grob as zeroGrob
|
|
672
715
|
|
|
673
716
|
# grid re-exports (matching R: importFrom(grid, unit, arrow))
|
|
674
717
|
from grid_py import Unit as unit, arrow
|
|
@@ -739,6 +782,9 @@ __all__ = [
|
|
|
739
782
|
"geom_sf", "geom_sf_label", "geom_sf_text",
|
|
740
783
|
"geom_qq", "geom_qq_line",
|
|
741
784
|
"is_geom",
|
|
785
|
+
"GeomMap", "GeomQuantile",
|
|
786
|
+
"GeomCustomAnn", "GeomLogticks", "GeomRasterAnn",
|
|
787
|
+
"translate_shape_string",
|
|
742
788
|
# Stat classes
|
|
743
789
|
"Stat", "StatIdentity", "StatBin", "StatCount", "StatDensity",
|
|
744
790
|
"StatSmooth", "StatBoxplot", "StatSummary", "StatSummaryBin",
|
|
@@ -796,21 +842,51 @@ __all__ = [
|
|
|
796
842
|
"scale_color_viridis_c", "scale_color_viridis_d",
|
|
797
843
|
"scale_color_grey", "scale_color_identity", "scale_color_manual",
|
|
798
844
|
"scale_alpha", "scale_alpha_continuous", "scale_alpha_discrete",
|
|
845
|
+
"scale_alpha_binned", "scale_alpha_identity", "scale_alpha_manual",
|
|
846
|
+
"scale_alpha_ordinal", "scale_alpha_date", "scale_alpha_datetime",
|
|
799
847
|
"scale_size", "scale_size_continuous", "scale_size_area",
|
|
800
|
-
"
|
|
801
|
-
"
|
|
802
|
-
"
|
|
848
|
+
"scale_size_binned", "scale_size_binned_area",
|
|
849
|
+
"scale_size_discrete", "scale_size_identity", "scale_size_manual",
|
|
850
|
+
"scale_size_ordinal", "scale_size_date", "scale_size_datetime",
|
|
851
|
+
"scale_radius",
|
|
852
|
+
"scale_shape", "scale_shape_continuous", "scale_shape_discrete",
|
|
853
|
+
"scale_shape_binned", "scale_shape_identity", "scale_shape_manual",
|
|
854
|
+
"scale_shape_ordinal",
|
|
855
|
+
"scale_linetype", "scale_linetype_continuous", "scale_linetype_discrete",
|
|
856
|
+
"scale_linetype_binned", "scale_linetype_identity", "scale_linetype_manual",
|
|
857
|
+
"scale_linewidth", "scale_linewidth_continuous", "scale_linewidth_discrete",
|
|
858
|
+
"scale_linewidth_binned", "scale_linewidth_identity", "scale_linewidth_manual",
|
|
859
|
+
"scale_linewidth_ordinal",
|
|
860
|
+
"scale_linewidth_date", "scale_linewidth_datetime",
|
|
803
861
|
"scale_stroke", "scale_stroke_continuous",
|
|
862
|
+
# Binned / stepped / fermenter / distiller / ordinal / date colour & fill scales
|
|
863
|
+
"scale_colour_binned", "scale_colour_distiller", "scale_colour_fermenter",
|
|
864
|
+
"scale_colour_ordinal", "scale_colour_steps", "scale_colour_steps2",
|
|
865
|
+
"scale_colour_stepsn", "scale_colour_viridis_b",
|
|
866
|
+
"scale_colour_date", "scale_colour_datetime",
|
|
867
|
+
"scale_color_binned", "scale_color_distiller", "scale_color_fermenter",
|
|
868
|
+
"scale_color_ordinal", "scale_color_steps", "scale_color_steps2",
|
|
869
|
+
"scale_color_stepsn", "scale_color_viridis_b",
|
|
870
|
+
"scale_color_date", "scale_color_datetime",
|
|
871
|
+
"scale_fill_binned", "scale_fill_distiller", "scale_fill_fermenter",
|
|
872
|
+
"scale_fill_ordinal", "scale_fill_steps", "scale_fill_steps2",
|
|
873
|
+
"scale_fill_stepsn", "scale_fill_viridis_b",
|
|
874
|
+
"scale_fill_date", "scale_fill_datetime",
|
|
875
|
+
# Time / identity / manual variants
|
|
876
|
+
"scale_x_time", "scale_y_time",
|
|
877
|
+
"scale_continuous_identity", "scale_discrete_identity", "scale_discrete_manual",
|
|
804
878
|
# Coords
|
|
805
879
|
"Coord", "CoordCartesian", "CoordFixed", "CoordFlip",
|
|
806
880
|
"CoordPolar", "CoordQuickmap", "CoordRadial", "CoordTrans", "CoordTransform",
|
|
807
881
|
"coord_cartesian", "coord_equal", "coord_fixed", "coord_flip",
|
|
808
882
|
"coord_polar", "coord_quickmap", "coord_radial", "coord_sf", "coord_trans", "coord_transform",
|
|
809
883
|
"CoordSf",
|
|
810
|
-
"coord_munch", "is_coord",
|
|
884
|
+
"coord_munch", "is_coord", "sf_transform_xy",
|
|
811
885
|
# Facets
|
|
812
886
|
"Facet", "FacetNull", "FacetGrid", "FacetWrap",
|
|
813
|
-
"facet_null", "facet_grid", "facet_wrap", "is_facet",
|
|
887
|
+
"facet_null", "facet_grid", "facet_wrap", "is_facet", "wrap_dims",
|
|
888
|
+
"max_height", "max_width",
|
|
889
|
+
"Layout",
|
|
814
890
|
# Positions
|
|
815
891
|
"Position", "PositionIdentity", "PositionDodge", "PositionDodge2",
|
|
816
892
|
"PositionJitter", "PositionJitterdodge", "PositionNudge",
|
|
@@ -826,20 +902,31 @@ __all__ = [
|
|
|
826
902
|
"guide_old_colourbar", "guide_old_colorbar",
|
|
827
903
|
"guide_coloursteps", "guide_colorsteps", "guide_bins",
|
|
828
904
|
"guide_custom", "guide_none", "guides", "is_guide",
|
|
905
|
+
"guide_axis_logticks", "guide_axis_stack", "guide_axis_theta",
|
|
906
|
+
"is_guides", "new_guide", "old_guide",
|
|
907
|
+
"guide_geom", "guide_train", "guide_merge", "guide_transform",
|
|
908
|
+
"guide_gengrob",
|
|
829
909
|
# Themes
|
|
830
910
|
"theme", "is_theme", "complete_theme",
|
|
831
911
|
"theme_get", "theme_set", "theme_update", "theme_replace",
|
|
832
912
|
"set_theme", "get_theme", "reset_theme_settings",
|
|
913
|
+
"update_theme", "replace_theme", "from_theme",
|
|
833
914
|
"Element", "element_blank", "element_line", "element_rect",
|
|
834
915
|
"element_text", "element_point", "element_polygon", "element_geom",
|
|
835
916
|
"element_grob", "element_render", "merge_element",
|
|
836
|
-
"
|
|
917
|
+
"el_def", "is_theme_element", "is_margin",
|
|
918
|
+
"Margin", "margin", "margin_auto", "margin_part", "Rel", "rel",
|
|
837
919
|
"calc_element", "get_element_tree", "register_theme_elements",
|
|
838
920
|
"theme_grey", "theme_gray", "theme_bw", "theme_linedraw",
|
|
839
921
|
"theme_light", "theme_dark", "theme_minimal", "theme_classic",
|
|
840
922
|
"theme_void", "theme_test",
|
|
923
|
+
"theme_sub_axis", "theme_sub_axis_x", "theme_sub_axis_y",
|
|
924
|
+
"theme_sub_axis_top", "theme_sub_axis_bottom",
|
|
925
|
+
"theme_sub_axis_left", "theme_sub_axis_right",
|
|
926
|
+
"theme_sub_legend", "theme_sub_panel", "theme_sub_plot",
|
|
927
|
+
"theme_sub_strip",
|
|
841
928
|
# Labels, limits
|
|
842
|
-
"labs", "xlab", "ylab", "ggtitle",
|
|
929
|
+
"labs", "xlab", "ylab", "ggtitle", "update_labels",
|
|
843
930
|
"lims", "xlim", "ylim", "expand_limits",
|
|
844
931
|
# Annotations
|
|
845
932
|
"annotate", "annotation_custom", "annotation_raster", "annotation_logticks",
|
|
@@ -861,10 +948,25 @@ __all__ = [
|
|
|
861
948
|
"autoplot", "autolayer",
|
|
862
949
|
# Utilities
|
|
863
950
|
"resolution", "remove_missing",
|
|
951
|
+
"cut_interval", "cut_number", "cut_width",
|
|
952
|
+
"transform_position", "fill_alpha", "pattern_alpha",
|
|
953
|
+
"update_geom_defaults", "update_stat_defaults",
|
|
954
|
+
"reset_geom_defaults", "reset_stat_defaults",
|
|
955
|
+
"get_geom_defaults",
|
|
956
|
+
"make_constructor",
|
|
864
957
|
"unit", "arrow", "alpha",
|
|
865
|
-
"PT", "STROKE",
|
|
958
|
+
"PT", "STROKE", "zeroGrob",
|
|
959
|
+
# Submodule namespaces and remaining R-exported helpers already
|
|
960
|
+
# defined at top level (just need to surface for ``import *``).
|
|
961
|
+
"stat", "labeller",
|
|
962
|
+
"derive", "flip_data", "flipped_names", "has_flipped_aes",
|
|
866
963
|
# Plugin discovery
|
|
867
964
|
"discover_extensions", "list_extensions",
|
|
965
|
+
# Python-exclusive extension surface (README quickstart uses
|
|
966
|
+
# ``from ggplot2_py import *``; these would otherwise be invisible)
|
|
967
|
+
"ggplot_defaults", "BuildStage",
|
|
968
|
+
"GeomProtocol", "StatProtocol", "ScaleProtocol",
|
|
969
|
+
"CoordProtocol", "FacetProtocol", "PositionProtocol",
|
|
868
970
|
]
|
|
869
971
|
|
|
870
972
|
# ---------------------------------------------------------------------------
|
|
@@ -32,6 +32,8 @@ __all__ = [
|
|
|
32
32
|
"Waiver",
|
|
33
33
|
"is_waiver",
|
|
34
34
|
"waiver",
|
|
35
|
+
"NA",
|
|
36
|
+
"is_na",
|
|
35
37
|
"caller_arg",
|
|
36
38
|
]
|
|
37
39
|
|
|
@@ -103,22 +105,24 @@ def cli_inform(
|
|
|
103
105
|
call: Optional[str] = None,
|
|
104
106
|
**kwargs: Any,
|
|
105
107
|
) -> None:
|
|
106
|
-
"""Emit an informational message
|
|
108
|
+
"""Emit an informational message via Python's :mod:`warnings`.
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
Mirrors R ``cli::cli_inform`` / ``rlang::inform`` which always write
|
|
111
|
+
to stderr regardless of session type. Routing through ``warnings``
|
|
112
|
+
lets pytest, ``warnings.catch_warnings``, and user filters capture
|
|
113
|
+
or silence the message — matching the way R lets users wrap
|
|
114
|
+
``suppressMessages({...})`` around an expression.
|
|
110
115
|
|
|
111
116
|
Parameters
|
|
112
117
|
----------
|
|
113
118
|
message : str
|
|
114
119
|
Informational message.
|
|
115
120
|
call : str, optional
|
|
116
|
-
Name of the calling function.
|
|
121
|
+
Name of the calling function (unused; matches R signature).
|
|
117
122
|
**kwargs : Any
|
|
118
123
|
Substitution values for placeholders in *message*.
|
|
119
124
|
"""
|
|
120
|
-
|
|
121
|
-
pass
|
|
125
|
+
warnings.warn(message, UserWarning, stacklevel=2)
|
|
122
126
|
|
|
123
127
|
|
|
124
128
|
# ---------------------------------------------------------------------------
|
|
@@ -436,6 +440,49 @@ def waiver() -> Waiver:
|
|
|
436
440
|
return Waiver()
|
|
437
441
|
|
|
438
442
|
|
|
443
|
+
# ---------------------------------------------------------------------------
|
|
444
|
+
# NA sentinel (R parity)
|
|
445
|
+
# ---------------------------------------------------------------------------
|
|
446
|
+
#
|
|
447
|
+
# R distinguishes ``NULL`` (unspecified, inherits from parent) from ``NA``
|
|
448
|
+
# (explicitly absent, must NOT inherit). Python collapses both onto
|
|
449
|
+
# ``None`` by default, which silently breaks theme inheritance — e.g.
|
|
450
|
+
# ``element_rect(fill="grey92", colour=NA)`` should keep the missing
|
|
451
|
+
# border on merge, but Python would replace ``None`` with the parent
|
|
452
|
+
# ``rect`` element's ``"black"``. This sentinel preserves R's NA
|
|
453
|
+
# semantics through ``combine_elements``.
|
|
454
|
+
|
|
455
|
+
class _NA:
|
|
456
|
+
"""Sentinel for R's ``NA`` — explicitly absent, never inherited."""
|
|
457
|
+
|
|
458
|
+
_instance: Optional["_NA"] = None
|
|
459
|
+
|
|
460
|
+
def __new__(cls) -> "_NA":
|
|
461
|
+
if cls._instance is None:
|
|
462
|
+
cls._instance = super().__new__(cls)
|
|
463
|
+
return cls._instance
|
|
464
|
+
|
|
465
|
+
def __repr__(self) -> str:
|
|
466
|
+
return "NA"
|
|
467
|
+
|
|
468
|
+
def __bool__(self) -> bool:
|
|
469
|
+
return False
|
|
470
|
+
|
|
471
|
+
def __eq__(self, other: Any) -> bool:
|
|
472
|
+
return isinstance(other, _NA)
|
|
473
|
+
|
|
474
|
+
def __hash__(self) -> int:
|
|
475
|
+
return 0
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
NA = _NA()
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def is_na(x: Any) -> bool:
|
|
482
|
+
"""Return True iff *x* is the singleton :data:`NA` sentinel."""
|
|
483
|
+
return isinstance(x, _NA)
|
|
484
|
+
|
|
485
|
+
|
|
439
486
|
def is_waiver(x: Any) -> bool:
|
|
440
487
|
"""Check whether *x* is a ``Waiver`` sentinel.
|
|
441
488
|
|