ggplot2-python 4.0.2.9000__py3-none-any.whl
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_py/__init__.py +852 -0
- ggplot2_py/_compat.py +475 -0
- ggplot2_py/_plugins.py +129 -0
- ggplot2_py/_utils.py +544 -0
- ggplot2_py/aes.py +586 -0
- ggplot2_py/annotation.py +540 -0
- ggplot2_py/coord.py +2108 -0
- ggplot2_py/coords/__init__.py +49 -0
- ggplot2_py/datasets.py +265 -0
- ggplot2_py/draw_key.py +454 -0
- ggplot2_py/facet.py +1456 -0
- ggplot2_py/fortify.py +95 -0
- ggplot2_py/geom.py +4516 -0
- ggplot2_py/geoms/__init__.py +12 -0
- ggplot2_py/ggproto.py +279 -0
- ggplot2_py/guide.py +2925 -0
- ggplot2_py/guide_axis.py +615 -0
- ggplot2_py/guide_colourbar.py +657 -0
- ggplot2_py/guide_legend.py +1061 -0
- ggplot2_py/guides/__init__.py +8 -0
- ggplot2_py/labeller.py +296 -0
- ggplot2_py/labels.py +309 -0
- ggplot2_py/layer.py +954 -0
- ggplot2_py/layout.py +754 -0
- ggplot2_py/limits.py +314 -0
- ggplot2_py/plot.py +1401 -0
- ggplot2_py/plot_render.py +866 -0
- ggplot2_py/position.py +1269 -0
- ggplot2_py/protocols.py +171 -0
- ggplot2_py/py.typed +0 -0
- ggplot2_py/qplot.py +233 -0
- ggplot2_py/resources/diamonds.csv +53941 -0
- ggplot2_py/resources/economics.csv +575 -0
- ggplot2_py/resources/economics_long.csv +2871 -0
- ggplot2_py/resources/faithfuld.csv +5626 -0
- ggplot2_py/resources/luv_colours.csv +658 -0
- ggplot2_py/resources/midwest.csv +438 -0
- ggplot2_py/resources/mpg.csv +235 -0
- ggplot2_py/resources/msleep.csv +84 -0
- ggplot2_py/resources/presidential.csv +13 -0
- ggplot2_py/resources/seals.csv +1156 -0
- ggplot2_py/resources/txhousing.csv +8603 -0
- ggplot2_py/save.py +316 -0
- ggplot2_py/scale.py +2727 -0
- ggplot2_py/scales/__init__.py +4252 -0
- ggplot2_py/stat.py +6071 -0
- ggplot2_py/stats/__init__.py +9 -0
- ggplot2_py/theme.py +490 -0
- ggplot2_py/theme_defaults.py +1350 -0
- ggplot2_py/theme_elements.py +2052 -0
- ggplot2_python-4.0.2.9000.dist-info/METADATA +179 -0
- ggplot2_python-4.0.2.9000.dist-info/RECORD +54 -0
- ggplot2_python-4.0.2.9000.dist-info/WHEEL +4 -0
- ggplot2_python-4.0.2.9000.dist-info/licenses/LICENSE +3 -0
ggplot2_py/protocols.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Structural typing protocols for ggplot2_py GOG components.
|
|
3
|
+
|
|
4
|
+
These :class:`~typing.Protocol` definitions specify the **contracts** that
|
|
5
|
+
custom Geom, Stat, Scale, Coord, Facet, and Position classes should satisfy.
|
|
6
|
+
They are ``@runtime_checkable``, so you can use ``isinstance()`` to verify
|
|
7
|
+
compliance without requiring inheritance from the base classes.
|
|
8
|
+
|
|
9
|
+
This is a **Python-exclusive** feature — R's ggplot2 has no equivalent
|
|
10
|
+
compile-time or runtime contract checking.
|
|
11
|
+
|
|
12
|
+
Usage
|
|
13
|
+
-----
|
|
14
|
+
Mypy / pyright will flag violations statically::
|
|
15
|
+
|
|
16
|
+
class MyStat(Stat):
|
|
17
|
+
required_aes = ("x",)
|
|
18
|
+
# Missing compute_group → type error
|
|
19
|
+
|
|
20
|
+
At runtime you can check::
|
|
21
|
+
|
|
22
|
+
from ggplot2_py.protocols import StatProtocol
|
|
23
|
+
assert isinstance(my_stat, StatProtocol)
|
|
24
|
+
|
|
25
|
+
Notes
|
|
26
|
+
-----
|
|
27
|
+
These protocols describe the *minimum* interface required for each
|
|
28
|
+
component to participate in the GOG pipeline. They do **not** replace
|
|
29
|
+
the base classes (``Geom``, ``Stat``, etc.) — they complement them by
|
|
30
|
+
enabling structural (duck-typed) checking.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from typing import (
|
|
36
|
+
Any,
|
|
37
|
+
Dict,
|
|
38
|
+
List,
|
|
39
|
+
Protocol,
|
|
40
|
+
Sequence,
|
|
41
|
+
Tuple,
|
|
42
|
+
Union,
|
|
43
|
+
runtime_checkable,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
import pandas as pd
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"GeomProtocol",
|
|
50
|
+
"StatProtocol",
|
|
51
|
+
"ScaleProtocol",
|
|
52
|
+
"CoordProtocol",
|
|
53
|
+
"FacetProtocol",
|
|
54
|
+
"PositionProtocol",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
# Geom
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
@runtime_checkable
|
|
63
|
+
class GeomProtocol(Protocol):
|
|
64
|
+
"""Contract for geometry objects.
|
|
65
|
+
|
|
66
|
+
A conforming Geom must declare its aesthetic requirements and provide
|
|
67
|
+
at least ``draw_panel`` or ``draw_group`` for rendering.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
required_aes: Union[Tuple[str, ...], List[str]]
|
|
71
|
+
default_aes: Any # Mapping or dict
|
|
72
|
+
draw_key: Any # callable
|
|
73
|
+
|
|
74
|
+
def setup_params(self, data: pd.DataFrame, params: dict) -> dict: ...
|
|
75
|
+
def setup_data(self, data: pd.DataFrame, params: dict) -> pd.DataFrame: ...
|
|
76
|
+
def draw_panel(self, data: pd.DataFrame, panel_params: dict,
|
|
77
|
+
coord: Any, **kwargs: Any) -> Any: ...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# Stat
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
@runtime_checkable
|
|
85
|
+
class StatProtocol(Protocol):
|
|
86
|
+
"""Contract for statistical transformation objects.
|
|
87
|
+
|
|
88
|
+
A conforming Stat must declare its aesthetic requirements and provide
|
|
89
|
+
``compute_group`` (or ``compute_panel`` / ``compute_layer``).
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
required_aes: Union[Tuple[str, ...], List[str]]
|
|
93
|
+
default_aes: Any
|
|
94
|
+
|
|
95
|
+
def setup_params(self, data: pd.DataFrame, params: dict) -> dict: ...
|
|
96
|
+
def setup_data(self, data: pd.DataFrame, params: dict) -> pd.DataFrame: ...
|
|
97
|
+
def compute_group(self, data: pd.DataFrame, scales: Any,
|
|
98
|
+
**params: Any) -> pd.DataFrame: ...
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Scale
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
@runtime_checkable
|
|
106
|
+
class ScaleProtocol(Protocol):
|
|
107
|
+
"""Contract for scale objects.
|
|
108
|
+
|
|
109
|
+
A conforming Scale mediates between data space and aesthetic space
|
|
110
|
+
via train / transform / map.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
aesthetics: Any # list of str
|
|
114
|
+
|
|
115
|
+
def train(self, x: Any) -> None: ...
|
|
116
|
+
def transform(self, x: Any) -> Any: ...
|
|
117
|
+
def map(self, x: Any) -> Any: ...
|
|
118
|
+
def get_breaks(self) -> Any: ...
|
|
119
|
+
def get_labels(self, breaks: Any = None) -> Any: ...
|
|
120
|
+
def clone(self) -> Any: ...
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# Coord
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
@runtime_checkable
|
|
128
|
+
class CoordProtocol(Protocol):
|
|
129
|
+
"""Contract for coordinate system objects.
|
|
130
|
+
|
|
131
|
+
A conforming Coord transforms data positions into viewport positions
|
|
132
|
+
and renders background / axes.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
def setup_params(self, data: list) -> dict: ...
|
|
136
|
+
def transform(self, data: pd.DataFrame, panel_params: dict) -> pd.DataFrame: ...
|
|
137
|
+
def setup_panel_params(self, scale_x: Any, scale_y: Any,
|
|
138
|
+
params: dict = ...) -> dict: ...
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# ---------------------------------------------------------------------------
|
|
142
|
+
# Facet
|
|
143
|
+
# ---------------------------------------------------------------------------
|
|
144
|
+
|
|
145
|
+
@runtime_checkable
|
|
146
|
+
class FacetProtocol(Protocol):
|
|
147
|
+
"""Contract for faceting specification objects.
|
|
148
|
+
|
|
149
|
+
A conforming Facet computes panel layout and assigns data to panels.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def compute_layout(self, data: list, params: dict) -> pd.DataFrame: ...
|
|
153
|
+
def map_data(self, data: pd.DataFrame, layout: pd.DataFrame,
|
|
154
|
+
params: dict) -> pd.DataFrame: ...
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
# Position
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
@runtime_checkable
|
|
162
|
+
class PositionProtocol(Protocol):
|
|
163
|
+
"""Contract for position adjustment objects.
|
|
164
|
+
|
|
165
|
+
A conforming Position adjusts data coordinates (e.g. dodge, stack)
|
|
166
|
+
after stat computation but before coordinate transformation.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def setup_params(self, data: pd.DataFrame) -> dict: ...
|
|
170
|
+
def compute_layer(self, data: pd.DataFrame, params: dict,
|
|
171
|
+
layout: Any) -> pd.DataFrame: ...
|
ggplot2_py/py.typed
ADDED
|
File without changes
|
ggplot2_py/qplot.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quick plotting shortcut (deprecated).
|
|
3
|
+
|
|
4
|
+
Provides :func:`qplot` / :func:`quickplot` for creating simple plots
|
|
5
|
+
with less typing. This interface is deprecated in favour of the full
|
|
6
|
+
``ggplot() + geom_*()`` pipeline.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import warnings
|
|
12
|
+
from typing import Any, List, Optional, Sequence, Union
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pandas as pd
|
|
16
|
+
|
|
17
|
+
from ggplot2_py._compat import cli_warn
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"qplot",
|
|
21
|
+
"quickplot",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def qplot(
|
|
26
|
+
x: Any = None,
|
|
27
|
+
y: Any = None,
|
|
28
|
+
*,
|
|
29
|
+
data: Optional[pd.DataFrame] = None,
|
|
30
|
+
geom: Union[str, List[str]] = "auto",
|
|
31
|
+
facets: Any = None,
|
|
32
|
+
xlim: Optional[Sequence] = None,
|
|
33
|
+
ylim: Optional[Sequence] = None,
|
|
34
|
+
log: str = "",
|
|
35
|
+
main: Optional[str] = None,
|
|
36
|
+
xlab: Optional[str] = None,
|
|
37
|
+
ylab: Optional[str] = None,
|
|
38
|
+
asp: Optional[float] = None,
|
|
39
|
+
colour: Any = None,
|
|
40
|
+
color: Any = None,
|
|
41
|
+
fill: Any = None,
|
|
42
|
+
size: Any = None,
|
|
43
|
+
shape: Any = None,
|
|
44
|
+
alpha: Any = None,
|
|
45
|
+
**kwargs: Any,
|
|
46
|
+
) -> Any:
|
|
47
|
+
"""Create a quick plot (deprecated).
|
|
48
|
+
|
|
49
|
+
``qplot`` is a shorthand for ``ggplot() + geom_*()``. It is
|
|
50
|
+
deprecated; prefer the full ggplot pipeline.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
x, y : str or array-like, optional
|
|
55
|
+
Variables for the x and y axes. If strings, they are interpreted
|
|
56
|
+
as column names in *data*.
|
|
57
|
+
data : DataFrame, optional
|
|
58
|
+
Dataset.
|
|
59
|
+
geom : str or list of str, optional
|
|
60
|
+
Geom name(s) to use (e.g. ``"point"``, ``"histogram"``).
|
|
61
|
+
``"auto"`` guesses from the supplied aesthetics.
|
|
62
|
+
facets : str or None, optional
|
|
63
|
+
Faceting formula (stub).
|
|
64
|
+
xlim, ylim : sequence, optional
|
|
65
|
+
Axis limits.
|
|
66
|
+
log : str, optional
|
|
67
|
+
Which axes to log-transform (``"x"``, ``"y"``, or ``"xy"``).
|
|
68
|
+
main : str, optional
|
|
69
|
+
Plot title.
|
|
70
|
+
xlab, ylab : str, optional
|
|
71
|
+
Axis labels.
|
|
72
|
+
asp : float, optional
|
|
73
|
+
Aspect ratio (y/x).
|
|
74
|
+
colour, color, fill, size, shape, alpha : str or array-like, optional
|
|
75
|
+
Additional aesthetics.
|
|
76
|
+
**kwargs
|
|
77
|
+
Other parameters passed to the geom.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
GGPlot
|
|
82
|
+
A ggplot object.
|
|
83
|
+
|
|
84
|
+
Warnings
|
|
85
|
+
--------
|
|
86
|
+
``qplot()`` is deprecated since ggplot2 3.4.0. Use ``ggplot()``
|
|
87
|
+
instead.
|
|
88
|
+
"""
|
|
89
|
+
warnings.warn(
|
|
90
|
+
"qplot() is deprecated. Use ggplot() + geom_*() instead.",
|
|
91
|
+
FutureWarning,
|
|
92
|
+
stacklevel=2,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
from ggplot2_py.aes import aes
|
|
96
|
+
from ggplot2_py.plot import ggplot, GGPlot
|
|
97
|
+
from ggplot2_py.labels import labs
|
|
98
|
+
|
|
99
|
+
# Normalise colour/color
|
|
100
|
+
if color is not None and colour is None:
|
|
101
|
+
colour = color
|
|
102
|
+
|
|
103
|
+
# Build data if not provided
|
|
104
|
+
if data is None:
|
|
105
|
+
data_dict: dict = {}
|
|
106
|
+
if x is not None and not isinstance(x, str):
|
|
107
|
+
data_dict["x"] = np.asarray(x)
|
|
108
|
+
x = "x"
|
|
109
|
+
if y is not None and not isinstance(y, str):
|
|
110
|
+
data_dict["y"] = np.asarray(y)
|
|
111
|
+
y = "y"
|
|
112
|
+
if colour is not None and not isinstance(colour, str):
|
|
113
|
+
data_dict["colour"] = np.asarray(colour)
|
|
114
|
+
colour = "colour"
|
|
115
|
+
if fill is not None and not isinstance(fill, str):
|
|
116
|
+
data_dict["fill"] = np.asarray(fill)
|
|
117
|
+
fill = "fill"
|
|
118
|
+
if size is not None and not isinstance(size, str):
|
|
119
|
+
data_dict["size"] = np.asarray(size)
|
|
120
|
+
size = "size"
|
|
121
|
+
if shape is not None and not isinstance(shape, str):
|
|
122
|
+
data_dict["shape"] = np.asarray(shape)
|
|
123
|
+
shape = "shape"
|
|
124
|
+
if alpha is not None and not isinstance(alpha, str):
|
|
125
|
+
data_dict["alpha"] = np.asarray(alpha)
|
|
126
|
+
alpha = "alpha"
|
|
127
|
+
if data_dict:
|
|
128
|
+
data = pd.DataFrame(data_dict)
|
|
129
|
+
else:
|
|
130
|
+
data = pd.DataFrame()
|
|
131
|
+
|
|
132
|
+
# Build mapping
|
|
133
|
+
mapping_kwargs: dict = {}
|
|
134
|
+
if x is not None:
|
|
135
|
+
mapping_kwargs["x"] = x
|
|
136
|
+
if y is not None:
|
|
137
|
+
mapping_kwargs["y"] = y
|
|
138
|
+
if colour is not None:
|
|
139
|
+
mapping_kwargs["colour"] = colour
|
|
140
|
+
if fill is not None:
|
|
141
|
+
mapping_kwargs["fill"] = fill
|
|
142
|
+
if size is not None:
|
|
143
|
+
mapping_kwargs["size"] = size
|
|
144
|
+
if shape is not None:
|
|
145
|
+
mapping_kwargs["shape"] = shape
|
|
146
|
+
if alpha is not None:
|
|
147
|
+
mapping_kwargs["alpha"] = alpha
|
|
148
|
+
|
|
149
|
+
mapping = aes(**mapping_kwargs)
|
|
150
|
+
|
|
151
|
+
# Auto-detect geom
|
|
152
|
+
if isinstance(geom, str):
|
|
153
|
+
geoms = [geom]
|
|
154
|
+
else:
|
|
155
|
+
geoms = list(geom)
|
|
156
|
+
|
|
157
|
+
if "auto" in geoms:
|
|
158
|
+
if y is not None:
|
|
159
|
+
geoms = ["point" if g == "auto" else g for g in geoms]
|
|
160
|
+
elif x is not None:
|
|
161
|
+
# Check if x is discrete
|
|
162
|
+
if isinstance(data, pd.DataFrame) and x in data.columns:
|
|
163
|
+
col = data[x]
|
|
164
|
+
if col.dtype == object or hasattr(col, "cat"):
|
|
165
|
+
geoms = ["bar" if g == "auto" else g for g in geoms]
|
|
166
|
+
else:
|
|
167
|
+
geoms = ["histogram" if g == "auto" else g for g in geoms]
|
|
168
|
+
else:
|
|
169
|
+
geoms = ["histogram" if g == "auto" else g for g in geoms]
|
|
170
|
+
else:
|
|
171
|
+
geoms = ["point" if g == "auto" else g for g in geoms]
|
|
172
|
+
|
|
173
|
+
# Determine axis labels
|
|
174
|
+
if xlab is None:
|
|
175
|
+
xlab = str(x) if x is not None else ""
|
|
176
|
+
if ylab is None:
|
|
177
|
+
ylab = str(y) if y is not None else ""
|
|
178
|
+
|
|
179
|
+
# Build plot
|
|
180
|
+
p = ggplot(data, mapping)
|
|
181
|
+
|
|
182
|
+
# Add geoms
|
|
183
|
+
import ggplot2_py.geoms as _geoms_mod
|
|
184
|
+
|
|
185
|
+
for g in geoms:
|
|
186
|
+
geom_fn = getattr(_geoms_mod, f"geom_{g}", None)
|
|
187
|
+
if geom_fn is None:
|
|
188
|
+
cli_warn(f"Unknown geom: 'geom_{g}'.")
|
|
189
|
+
continue
|
|
190
|
+
p = p + geom_fn(**kwargs)
|
|
191
|
+
|
|
192
|
+
# Log transforms
|
|
193
|
+
if "x" in log:
|
|
194
|
+
try:
|
|
195
|
+
from ggplot2_py.scales import scale_x_log10
|
|
196
|
+
p = p + scale_x_log10()
|
|
197
|
+
except ImportError:
|
|
198
|
+
pass
|
|
199
|
+
if "y" in log:
|
|
200
|
+
try:
|
|
201
|
+
from ggplot2_py.scales import scale_y_log10
|
|
202
|
+
p = p + scale_y_log10()
|
|
203
|
+
except ImportError:
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
# Aspect ratio
|
|
207
|
+
if asp is not None:
|
|
208
|
+
from ggplot2_py.theme import theme
|
|
209
|
+
p = p + theme(aspect_ratio=asp)
|
|
210
|
+
|
|
211
|
+
# Labels
|
|
212
|
+
label_kwargs: dict = {}
|
|
213
|
+
if xlab:
|
|
214
|
+
label_kwargs["x"] = xlab
|
|
215
|
+
if ylab:
|
|
216
|
+
label_kwargs["y"] = ylab
|
|
217
|
+
if main:
|
|
218
|
+
label_kwargs["title"] = main
|
|
219
|
+
if label_kwargs:
|
|
220
|
+
p = p + labs(**label_kwargs)
|
|
221
|
+
|
|
222
|
+
# Axis limits
|
|
223
|
+
if xlim is not None:
|
|
224
|
+
from ggplot2_py.limits import xlim as _xlim
|
|
225
|
+
p = p + _xlim(*xlim)
|
|
226
|
+
if ylim is not None:
|
|
227
|
+
from ggplot2_py.limits import ylim as _ylim
|
|
228
|
+
p = p + _ylim(*ylim)
|
|
229
|
+
|
|
230
|
+
return p
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
quickplot = qplot
|