ggplot2-python 4.0.2.9000__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 (56) hide show
  1. ggplot2_python-4.0.2.9000/.gitattributes +15 -0
  2. ggplot2_python-4.0.2.9000/.gitignore +31 -0
  3. ggplot2_python-4.0.2.9000/LICENSE +3 -0
  4. ggplot2_python-4.0.2.9000/PKG-INFO +179 -0
  5. ggplot2_python-4.0.2.9000/README.md +129 -0
  6. ggplot2_python-4.0.2.9000/ggplot2_py/__init__.py +852 -0
  7. ggplot2_python-4.0.2.9000/ggplot2_py/_compat.py +475 -0
  8. ggplot2_python-4.0.2.9000/ggplot2_py/_plugins.py +129 -0
  9. ggplot2_python-4.0.2.9000/ggplot2_py/_utils.py +544 -0
  10. ggplot2_python-4.0.2.9000/ggplot2_py/aes.py +586 -0
  11. ggplot2_python-4.0.2.9000/ggplot2_py/annotation.py +540 -0
  12. ggplot2_python-4.0.2.9000/ggplot2_py/coord.py +2108 -0
  13. ggplot2_python-4.0.2.9000/ggplot2_py/coords/__init__.py +49 -0
  14. ggplot2_python-4.0.2.9000/ggplot2_py/datasets.py +265 -0
  15. ggplot2_python-4.0.2.9000/ggplot2_py/draw_key.py +454 -0
  16. ggplot2_python-4.0.2.9000/ggplot2_py/facet.py +1456 -0
  17. ggplot2_python-4.0.2.9000/ggplot2_py/fortify.py +95 -0
  18. ggplot2_python-4.0.2.9000/ggplot2_py/geom.py +4516 -0
  19. ggplot2_python-4.0.2.9000/ggplot2_py/geoms/__init__.py +12 -0
  20. ggplot2_python-4.0.2.9000/ggplot2_py/ggproto.py +279 -0
  21. ggplot2_python-4.0.2.9000/ggplot2_py/guide.py +2925 -0
  22. ggplot2_python-4.0.2.9000/ggplot2_py/guide_axis.py +615 -0
  23. ggplot2_python-4.0.2.9000/ggplot2_py/guide_colourbar.py +657 -0
  24. ggplot2_python-4.0.2.9000/ggplot2_py/guide_legend.py +1061 -0
  25. ggplot2_python-4.0.2.9000/ggplot2_py/guides/__init__.py +8 -0
  26. ggplot2_python-4.0.2.9000/ggplot2_py/labeller.py +296 -0
  27. ggplot2_python-4.0.2.9000/ggplot2_py/labels.py +309 -0
  28. ggplot2_python-4.0.2.9000/ggplot2_py/layer.py +954 -0
  29. ggplot2_python-4.0.2.9000/ggplot2_py/layout.py +754 -0
  30. ggplot2_python-4.0.2.9000/ggplot2_py/limits.py +314 -0
  31. ggplot2_python-4.0.2.9000/ggplot2_py/plot.py +1401 -0
  32. ggplot2_python-4.0.2.9000/ggplot2_py/plot_render.py +866 -0
  33. ggplot2_python-4.0.2.9000/ggplot2_py/position.py +1269 -0
  34. ggplot2_python-4.0.2.9000/ggplot2_py/protocols.py +171 -0
  35. ggplot2_python-4.0.2.9000/ggplot2_py/py.typed +0 -0
  36. ggplot2_python-4.0.2.9000/ggplot2_py/qplot.py +233 -0
  37. ggplot2_python-4.0.2.9000/ggplot2_py/resources/diamonds.csv +53941 -0
  38. ggplot2_python-4.0.2.9000/ggplot2_py/resources/economics.csv +575 -0
  39. ggplot2_python-4.0.2.9000/ggplot2_py/resources/economics_long.csv +2871 -0
  40. ggplot2_python-4.0.2.9000/ggplot2_py/resources/faithfuld.csv +5626 -0
  41. ggplot2_python-4.0.2.9000/ggplot2_py/resources/luv_colours.csv +658 -0
  42. ggplot2_python-4.0.2.9000/ggplot2_py/resources/midwest.csv +438 -0
  43. ggplot2_python-4.0.2.9000/ggplot2_py/resources/mpg.csv +235 -0
  44. ggplot2_python-4.0.2.9000/ggplot2_py/resources/msleep.csv +84 -0
  45. ggplot2_python-4.0.2.9000/ggplot2_py/resources/presidential.csv +13 -0
  46. ggplot2_python-4.0.2.9000/ggplot2_py/resources/seals.csv +1156 -0
  47. ggplot2_python-4.0.2.9000/ggplot2_py/resources/txhousing.csv +8603 -0
  48. ggplot2_python-4.0.2.9000/ggplot2_py/save.py +316 -0
  49. ggplot2_python-4.0.2.9000/ggplot2_py/scale.py +2727 -0
  50. ggplot2_python-4.0.2.9000/ggplot2_py/scales/__init__.py +4252 -0
  51. ggplot2_python-4.0.2.9000/ggplot2_py/stat.py +6071 -0
  52. ggplot2_python-4.0.2.9000/ggplot2_py/stats/__init__.py +9 -0
  53. ggplot2_python-4.0.2.9000/ggplot2_py/theme.py +490 -0
  54. ggplot2_python-4.0.2.9000/ggplot2_py/theme_defaults.py +1350 -0
  55. ggplot2_python-4.0.2.9000/ggplot2_py/theme_elements.py +2052 -0
  56. ggplot2_python-4.0.2.9000/pyproject.toml +88 -0
@@ -0,0 +1,15 @@
1
+ # GitHub language statistics: only count Python
2
+ *.py linguist-detectable
3
+ *.ipynb linguist-documentation
4
+ *.html linguist-documentation
5
+ *.css linguist-documentation
6
+ *.js linguist-documentation
7
+ *.json linguist-documentation
8
+ *.yml linguist-documentation
9
+ *.yaml linguist-documentation
10
+ *.md linguist-documentation
11
+ *.R linguist-documentation
12
+ *.csv linguist-documentation
13
+ site/** linguist-documentation
14
+ docs/** linguist-documentation
15
+ tutorials/** linguist-documentation
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ .tox/
12
+
13
+ # Compiled extensions
14
+ *.so
15
+ *.pyd
16
+ *.dylib
17
+
18
+ # IDE
19
+ .idea/
20
+ .vscode/
21
+ *.swp
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+ .coverage
27
+
28
+ # Docs build
29
+ site/
30
+ .cache/
31
+ .ipynb_checkpoints/
@@ -0,0 +1,3 @@
1
+ # MIT
2
+
3
+ See DESCRIPTION from R package.
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: ggplot2-python
3
+ Version: 4.0.2.9000
4
+ Summary: Python port of the R ggplot2 package (tracks R ggplot2 4.0.2.9000)
5
+ Project-URL: Homepage, https://github.com/Bio-Babel/ggplot2-python
6
+ Project-URL: Repository, https://github.com/Bio-Babel/ggplot2-python
7
+ Project-URL: Issues, https://github.com/Bio-Babel/ggplot2-python/issues
8
+ Project-URL: Documentation, https://github.com/Bio-Babel/ggplot2-python#readme
9
+ Author-email: Jeffery Liu <jeffliu.lucky@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: R-port,data-visualization,ggplot2,grammar-of-graphics,plotting,statistical-graphics,visualization
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: Microsoft :: Windows
19
+ Classifier: Operating System :: POSIX :: Linux
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Scientific/Engineering :: Visualization
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: contourpy>=1.0
28
+ Requires-Dist: geopandas>=0.12
29
+ Requires-Dist: gtable-python>=0.3.6
30
+ Requires-Dist: matplotlib>=3.6
31
+ Requires-Dist: numpy>=1.24
32
+ Requires-Dist: pandas>=1.5
33
+ Requires-Dist: pillow>=9.0
34
+ Requires-Dist: rgrid-python>=4.5.3
35
+ Requires-Dist: scales-python>=1.4.0
36
+ Requires-Dist: scipy>=1.10
37
+ Requires-Dist: statsmodels>=0.13
38
+ Provides-Extra: dev
39
+ Requires-Dist: build; extra == 'dev'
40
+ Requires-Dist: pytest; extra == 'dev'
41
+ Requires-Dist: pytest-cov; extra == 'dev'
42
+ Requires-Dist: ruff; extra == 'dev'
43
+ Requires-Dist: twine; extra == 'dev'
44
+ Provides-Extra: docs
45
+ Requires-Dist: mkdocs; extra == 'docs'
46
+ Requires-Dist: mkdocs-jupyter; extra == 'docs'
47
+ Requires-Dist: mkdocs-material; extra == 'docs'
48
+ Requires-Dist: mkdocstrings[python]; extra == 'docs'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # ggplot2_py <a href="https://github.com/R2pyBioinformatics/ggplot2_py"><img src="assets/ggplot2_py_logo.png" align="right" height="138" alt="ggplot2_py logo" /></a>
52
+
53
+ AI-assisted Python port of the R **ggplot2** package — Create Elegant Data Visualisations Using the Grammar of Graphics.
54
+
55
+ ## Overview
56
+
57
+ ggplot2_py 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.
58
+
59
+ Beyond a direct port, ggplot2_py adds **Python-exclusive features** that extend the Grammar of Graphics with Python-native idioms while preserving full orthogonality of GOG components.
60
+
61
+ ## Python-Exclusive Features
62
+
63
+ These capabilities have no R equivalent and leverage Python-specific language features:
64
+
65
+ | Feature | Python mechanism | What it enables |
66
+ |---------|-----------------|-----------------|
67
+ | **Callable `aes()` expressions** | First-class functions / lambdas | `aes(y=lambda d: np.log(d["mpg"]))` — inline data transforms without pre-computing columns |
68
+ | **`after_stat()` / `after_scale()` callables** | Same | `after_stat(lambda d: d["count"] / d["count"].sum())` — arbitrary expressions at each pipeline stage |
69
+ | **`singledispatch` extensibility** | `functools.singledispatch` | `@update_ggplot.register(MyClass)` — any Python class can be added to a plot with `+` |
70
+ | **Build hooks** | Dict-keyed callback lists | `plot.add_build_hook("after", BuildStage.COMPUTE_STAT, fn)` — intercept data at any of 16 named pipeline stages |
71
+ | **Auto-registration** | `__init_subclass__` | `class GeomStar(Geom): ...` auto-registers; no manual wiring needed |
72
+ | **Protocol contracts** | `typing.Protocol` | `isinstance(my_geom, GeomProtocol)` — structural type checking for extensions |
73
+ | **Scoped defaults** | `contextvars.ContextVar` | `with ggplot_defaults(theme=theme_minimal()): ...` — thread-safe scoped defaults |
74
+
75
+ ## Installation
76
+
77
+ ```bash
78
+ # From PyPI
79
+ pip install ggplot2-python
80
+ ```
81
+
82
+ For a local development:
83
+
84
+ ```bash
85
+ git clone https://github.com/Bio-Babel/ggplot2-python.git
86
+ cd ggplot2_py
87
+ pip install -e ".[dev]"
88
+ ```
89
+
90
+ ## Quick Start
91
+
92
+ ```python
93
+ from ggplot2_py import *
94
+ from ggplot2_py.datasets import mpg
95
+
96
+ (ggplot(mpg, aes(x="displ", y="hwy", colour="class"))
97
+ + geom_point()
98
+ + geom_smooth(method="lm")
99
+ + facet_wrap("drv")
100
+ + theme_minimal()
101
+ + labs(title="Engine Displacement vs Highway MPG"))
102
+ ```
103
+
104
+ ### Callable expressions in aes (Python-exclusive)
105
+
106
+ ```python
107
+ import numpy as np
108
+ from ggplot2_py import ggplot, aes, geom_point, geom_histogram, after_stat
109
+
110
+ # Inline data transform — no need to pre-compute a column
111
+ ggplot(mpg, aes(x=lambda d: np.log(d["displ"]), y="hwy")) + geom_point()
112
+
113
+ # Normalised histogram — callable in after_stat
114
+ (ggplot(mpg, aes(x="hwy"))
115
+ + geom_histogram(aes(y=after_stat(lambda d: d["count"] / d["count"].sum())), bins=15))
116
+ ```
117
+
118
+ ### Extending with custom types (Python-exclusive)
119
+
120
+ ```python
121
+ from ggplot2_py import update_ggplot
122
+
123
+ class Watermark:
124
+ def __init__(self, text): self.text = text
125
+
126
+ @update_ggplot.register(Watermark)
127
+ def _add_watermark(obj, plot, object_name=""):
128
+ plot.labels["caption"] = f"[{obj.text}]"
129
+ return plot
130
+
131
+ # Now use with +
132
+ ggplot(mpg, aes("displ", "hwy")) + geom_point() + Watermark("DRAFT")
133
+ ```
134
+
135
+ ### Scoped defaults (Python-exclusive)
136
+
137
+ ```python
138
+ from ggplot2_py import ggplot_defaults
139
+
140
+ with ggplot_defaults(theme=theme_minimal()):
141
+ p1 = ggplot(df, aes("x", "y")) + geom_point() # theme_minimal applied
142
+ p2 = ggplot(df, aes("x", "y")) + geom_bar() # theme_minimal applied
143
+ # Outside: no defaults
144
+ ```
145
+
146
+ ## Tutorials
147
+
148
+ ### User Tutorials
149
+ - [Getting Started](tutorials/ggplot2.ipynb) — core concepts: data, aes, geoms, stats, scales, facets, coords, themes
150
+ - [Geom Gallery](tutorials/geoms_gallery.ipynb) — boxplot, violin, density, tile, hex and combinations
151
+ - [Labels & Facets](tutorials/labels_and_facets.ipynb) — axis titles, plot title/subtitle/caption, facet strip labels
152
+ - [Aesthetic Specs](tutorials/aesthetic_specs.ipynb) — colour, fill, alpha, linetype, shape, size, colour scales
153
+ - [Extending ggplot2](tutorials/extending_ggplot2.ipynb) — custom stats, geoms, themes via ggproto
154
+
155
+ ### Python-Exclusive Feature Tutorials
156
+ - [Callable aes Expressions](tutorials/aes_expressions.ipynb) — lambdas in `aes()`, `after_stat()`, `after_scale()`, `stage()`
157
+ - [Extensible Pipeline](tutorials/pipeline_dispatch.ipynb) — `singledispatch` registration, custom types with `+`
158
+ - [Build Hooks](tutorials/build_hooks.ipynb) — intercepting the 16-stage build pipeline
159
+
160
+ ### Developer Guide
161
+ - [Developer Guide: Extending ggplot2_py](tutorials/developer_guide.ipynb) — comprehensive guide covering ggproto system, custom Stat/Geom creation, Protocol contracts, singledispatch, hooks, auto-registration, context manager, and packaging
162
+
163
+ ## Extension Architecture
164
+
165
+ ggplot2_py is designed as an **extensible platform**. The following table summarises all extension points:
166
+
167
+ | Extension point | Mechanism | How to use |
168
+ |----------------|-----------|-----------|
169
+ | Custom Stat | Subclass `Stat` | Override `compute_group()` — auto-registered via `__init_subclass__` |
170
+ | Custom Geom | Subclass `Geom` | Override `draw_panel()` — auto-registered |
171
+ | Custom Scale | Subclass `ScaleContinuous` / `ScaleDiscrete` | Implement `train()`, `map()`, `get_breaks()` |
172
+ | Custom Coord | Subclass `Coord` | Override `transform()`, `setup_panel_params()` |
173
+ | Custom Facet | Subclass `Facet` | Override `compute_layout()`, `map_data()` |
174
+ | Custom Position | Subclass `Position` | Override `compute_layer()` — auto-registered |
175
+ | Custom `+` types | `@update_ggplot.register(MyClass)` | Register any Python class for the `+` operator |
176
+ | Custom plot types | `@ggplot_build.register(MyPlot)` | Override the entire build pipeline |
177
+ | Build hooks | `plot.add_build_hook(timing, stage, fn)` | Intercept data at any pipeline stage |
178
+ | Protocol validation | `isinstance(obj, GeomProtocol)` | Verify structural conformance |
179
+ | Scoped defaults | `with ggplot_defaults(theme=...):` | Thread-safe scoped defaults |
@@ -0,0 +1,129 @@
1
+ # ggplot2_py <a href="https://github.com/R2pyBioinformatics/ggplot2_py"><img src="assets/ggplot2_py_logo.png" align="right" height="138" alt="ggplot2_py logo" /></a>
2
+
3
+ AI-assisted Python port of the R **ggplot2** package — Create Elegant Data Visualisations Using the Grammar of Graphics.
4
+
5
+ ## Overview
6
+
7
+ ggplot2_py 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.
8
+
9
+ Beyond a direct port, ggplot2_py adds **Python-exclusive features** that extend the Grammar of Graphics with Python-native idioms while preserving full orthogonality of GOG components.
10
+
11
+ ## Python-Exclusive Features
12
+
13
+ These capabilities have no R equivalent and leverage Python-specific language features:
14
+
15
+ | Feature | Python mechanism | What it enables |
16
+ |---------|-----------------|-----------------|
17
+ | **Callable `aes()` expressions** | First-class functions / lambdas | `aes(y=lambda d: np.log(d["mpg"]))` — inline data transforms without pre-computing columns |
18
+ | **`after_stat()` / `after_scale()` callables** | Same | `after_stat(lambda d: d["count"] / d["count"].sum())` — arbitrary expressions at each pipeline stage |
19
+ | **`singledispatch` extensibility** | `functools.singledispatch` | `@update_ggplot.register(MyClass)` — any Python class can be added to a plot with `+` |
20
+ | **Build hooks** | Dict-keyed callback lists | `plot.add_build_hook("after", BuildStage.COMPUTE_STAT, fn)` — intercept data at any of 16 named pipeline stages |
21
+ | **Auto-registration** | `__init_subclass__` | `class GeomStar(Geom): ...` auto-registers; no manual wiring needed |
22
+ | **Protocol contracts** | `typing.Protocol` | `isinstance(my_geom, GeomProtocol)` — structural type checking for extensions |
23
+ | **Scoped defaults** | `contextvars.ContextVar` | `with ggplot_defaults(theme=theme_minimal()): ...` — thread-safe scoped defaults |
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ # From PyPI
29
+ pip install ggplot2-python
30
+ ```
31
+
32
+ For a local development:
33
+
34
+ ```bash
35
+ git clone https://github.com/Bio-Babel/ggplot2-python.git
36
+ cd ggplot2_py
37
+ pip install -e ".[dev]"
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ from ggplot2_py import *
44
+ from ggplot2_py.datasets import mpg
45
+
46
+ (ggplot(mpg, aes(x="displ", y="hwy", colour="class"))
47
+ + geom_point()
48
+ + geom_smooth(method="lm")
49
+ + facet_wrap("drv")
50
+ + theme_minimal()
51
+ + labs(title="Engine Displacement vs Highway MPG"))
52
+ ```
53
+
54
+ ### Callable expressions in aes (Python-exclusive)
55
+
56
+ ```python
57
+ import numpy as np
58
+ from ggplot2_py import ggplot, aes, geom_point, geom_histogram, after_stat
59
+
60
+ # Inline data transform — no need to pre-compute a column
61
+ ggplot(mpg, aes(x=lambda d: np.log(d["displ"]), y="hwy")) + geom_point()
62
+
63
+ # Normalised histogram — callable in after_stat
64
+ (ggplot(mpg, aes(x="hwy"))
65
+ + geom_histogram(aes(y=after_stat(lambda d: d["count"] / d["count"].sum())), bins=15))
66
+ ```
67
+
68
+ ### Extending with custom types (Python-exclusive)
69
+
70
+ ```python
71
+ from ggplot2_py import update_ggplot
72
+
73
+ class Watermark:
74
+ def __init__(self, text): self.text = text
75
+
76
+ @update_ggplot.register(Watermark)
77
+ def _add_watermark(obj, plot, object_name=""):
78
+ plot.labels["caption"] = f"[{obj.text}]"
79
+ return plot
80
+
81
+ # Now use with +
82
+ ggplot(mpg, aes("displ", "hwy")) + geom_point() + Watermark("DRAFT")
83
+ ```
84
+
85
+ ### Scoped defaults (Python-exclusive)
86
+
87
+ ```python
88
+ from ggplot2_py import ggplot_defaults
89
+
90
+ with ggplot_defaults(theme=theme_minimal()):
91
+ p1 = ggplot(df, aes("x", "y")) + geom_point() # theme_minimal applied
92
+ p2 = ggplot(df, aes("x", "y")) + geom_bar() # theme_minimal applied
93
+ # Outside: no defaults
94
+ ```
95
+
96
+ ## Tutorials
97
+
98
+ ### User Tutorials
99
+ - [Getting Started](tutorials/ggplot2.ipynb) — core concepts: data, aes, geoms, stats, scales, facets, coords, themes
100
+ - [Geom Gallery](tutorials/geoms_gallery.ipynb) — boxplot, violin, density, tile, hex and combinations
101
+ - [Labels & Facets](tutorials/labels_and_facets.ipynb) — axis titles, plot title/subtitle/caption, facet strip labels
102
+ - [Aesthetic Specs](tutorials/aesthetic_specs.ipynb) — colour, fill, alpha, linetype, shape, size, colour scales
103
+ - [Extending ggplot2](tutorials/extending_ggplot2.ipynb) — custom stats, geoms, themes via ggproto
104
+
105
+ ### Python-Exclusive Feature Tutorials
106
+ - [Callable aes Expressions](tutorials/aes_expressions.ipynb) — lambdas in `aes()`, `after_stat()`, `after_scale()`, `stage()`
107
+ - [Extensible Pipeline](tutorials/pipeline_dispatch.ipynb) — `singledispatch` registration, custom types with `+`
108
+ - [Build Hooks](tutorials/build_hooks.ipynb) — intercepting the 16-stage build pipeline
109
+
110
+ ### Developer Guide
111
+ - [Developer Guide: Extending ggplot2_py](tutorials/developer_guide.ipynb) — comprehensive guide covering ggproto system, custom Stat/Geom creation, Protocol contracts, singledispatch, hooks, auto-registration, context manager, and packaging
112
+
113
+ ## Extension Architecture
114
+
115
+ ggplot2_py is designed as an **extensible platform**. The following table summarises all extension points:
116
+
117
+ | Extension point | Mechanism | How to use |
118
+ |----------------|-----------|-----------|
119
+ | Custom Stat | Subclass `Stat` | Override `compute_group()` — auto-registered via `__init_subclass__` |
120
+ | Custom Geom | Subclass `Geom` | Override `draw_panel()` — auto-registered |
121
+ | Custom Scale | Subclass `ScaleContinuous` / `ScaleDiscrete` | Implement `train()`, `map()`, `get_breaks()` |
122
+ | Custom Coord | Subclass `Coord` | Override `transform()`, `setup_panel_params()` |
123
+ | Custom Facet | Subclass `Facet` | Override `compute_layout()`, `map_data()` |
124
+ | Custom Position | Subclass `Position` | Override `compute_layer()` — auto-registered |
125
+ | Custom `+` types | `@update_ggplot.register(MyClass)` | Register any Python class for the `+` operator |
126
+ | Custom plot types | `@ggplot_build.register(MyPlot)` | Override the entire build pipeline |
127
+ | Build hooks | `plot.add_build_hook(timing, stage, fn)` | Intercept data at any pipeline stage |
128
+ | Protocol validation | `isinstance(obj, GeomProtocol)` | Verify structural conformance |
129
+ | Scoped defaults | `with ggplot_defaults(theme=...):` | Thread-safe scoped defaults |