ggh4x-python 0.3.1.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.
- ggh4x/__init__.py +140 -0
- ggh4x/_aimed_text_grob.py +432 -0
- ggh4x/_borrowed_ggplot2.py +273 -0
- ggh4x/_cli.py +84 -0
- ggh4x/_datasets.py +106 -0
- ggh4x/_download.py +111 -0
- ggh4x/_facet_helpers.py +313 -0
- ggh4x/_facet_utils.py +649 -0
- ggh4x/_gap_grobs.py +606 -0
- ggh4x/_registry.py +10 -0
- ggh4x/_rlang.py +93 -0
- ggh4x/_utils.py +150 -0
- ggh4x/_vctrs.py +233 -0
- ggh4x/conveniences.py +601 -0
- ggh4x/coord_axes_inside.py +380 -0
- ggh4x/element_part_rect.py +545 -0
- ggh4x/facet_grid2.py +1018 -0
- ggh4x/facet_manual.py +901 -0
- ggh4x/facet_nested.py +776 -0
- ggh4x/facet_nested_wrap.py +193 -0
- ggh4x/facet_wrap2.py +896 -0
- ggh4x/geom_box.py +536 -0
- ggh4x/geom_outline_point.py +444 -0
- ggh4x/geom_pointpath.py +259 -0
- ggh4x/geom_polygonraster.py +252 -0
- ggh4x/geom_rectrug.py +489 -0
- ggh4x/geom_text_aimed.py +279 -0
- ggh4x/guide_stringlegend.py +354 -0
- ggh4x/help_secondary.py +549 -0
- ggh4x/multiscale/__init__.py +51 -0
- ggh4x/multiscale/_multiscale_add.py +207 -0
- ggh4x/multiscale/scale_listed.py +167 -0
- ggh4x/multiscale/scale_manual.py +478 -0
- ggh4x/multiscale/scale_multi.py +393 -0
- ggh4x/panel_scales/__init__.py +58 -0
- ggh4x/panel_scales/at_panel.py +115 -0
- ggh4x/panel_scales/facetted_pos_scales.py +647 -0
- ggh4x/panel_scales/force_panelsize.py +411 -0
- ggh4x/panel_scales/scale_facet.py +222 -0
- ggh4x/position_disjoint_ranges.py +229 -0
- ggh4x/position_lineartrans.py +242 -0
- ggh4x/py.typed +0 -0
- ggh4x/resources/faithful.csv +273 -0
- ggh4x/resources/iris.csv +151 -0
- ggh4x/resources/mtcars.csv +33 -0
- ggh4x/resources/pressure.csv +20 -0
- ggh4x/resources/volcano.csv +87 -0
- ggh4x/save.py +255 -0
- ggh4x/stat_difference.py +388 -0
- ggh4x/stat_funxy.py +436 -0
- ggh4x/stat_rle.py +290 -0
- ggh4x/stat_rollingkernel.py +369 -0
- ggh4x/stat_theodensity.py +681 -0
- ggh4x/strip_nested.py +448 -0
- ggh4x/strip_split.py +687 -0
- ggh4x/strip_tag.py +636 -0
- ggh4x/strip_themed.py +232 -0
- ggh4x/strip_vanilla.py +1464 -0
- ggh4x/themes.py +31 -0
- ggh4x/themes_ggh4x.py +67 -0
- ggh4x_python-0.3.1.9000.dist-info/METADATA +40 -0
- ggh4x_python-0.3.1.9000.dist-info/RECORD +64 -0
- ggh4x_python-0.3.1.9000.dist-info/WHEEL +4 -0
- ggh4x_python-0.3.1.9000.dist-info/licenses/LICENSE +3 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Polygon parameterisation for rasters (port of ggh4x ``geom_polygonraster.R``).
|
|
2
|
+
|
|
3
|
+
``geom_polygonraster()`` takes equally-sized raster pixels and re-parametrises
|
|
4
|
+
each as a four-vertex polygon. This is less efficient than a true raster but
|
|
5
|
+
lets the pixels be transformed by non-linear ``coord``-functions (e.g.
|
|
6
|
+
:func:`ggplot2_py.coord_polar`) or ``position``-functions such as
|
|
7
|
+
:func:`ggh4x.position_lineartrans`.
|
|
8
|
+
|
|
9
|
+
R source: ``ggh4x/R/geom_polygonraster.R``.
|
|
10
|
+
|
|
11
|
+
Notes
|
|
12
|
+
-----
|
|
13
|
+
* :meth:`GeomPolygonRaster.setup_data` completely overrides
|
|
14
|
+
:class:`ggplot2_py.GeomRaster`'s setup (which uses a diff-of-unique pixel
|
|
15
|
+
size); it uses :func:`ggplot2_py._utils.resolution` (``zero=True``) and a
|
|
16
|
+
*specific* four-vertex corner winding (``geom_polygonraster.R:92-99``).
|
|
17
|
+
* :meth:`GeomPolygonRaster.draw_panel` overwrites ``group`` with the pixel
|
|
18
|
+
``id`` before ``coord_munch`` so each pixel is its own polygon, and forces an
|
|
19
|
+
invisible border (``col=0, lwd=0, lty=0``).
|
|
20
|
+
* The default position is :func:`ggh4x.position_lineartrans` (lazily imported
|
|
21
|
+
to avoid an import cycle).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any, Optional
|
|
27
|
+
|
|
28
|
+
import numpy as np
|
|
29
|
+
import pandas as pd
|
|
30
|
+
|
|
31
|
+
from ggplot2_py.geom import (
|
|
32
|
+
GeomRaster,
|
|
33
|
+
Gpar,
|
|
34
|
+
Mapping,
|
|
35
|
+
_coord_transform,
|
|
36
|
+
_ggname,
|
|
37
|
+
polygon_grob,
|
|
38
|
+
null_grob,
|
|
39
|
+
scales_alpha,
|
|
40
|
+
)
|
|
41
|
+
from ggplot2_py.coord import coord_munch
|
|
42
|
+
from ggplot2_py._utils import resolution
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"geom_polygonraster",
|
|
46
|
+
"GeomPolygonRaster",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class GeomPolygonRaster(GeomRaster):
|
|
51
|
+
"""Raster geom that draws each pixel as a four-vertex polygon.
|
|
52
|
+
|
|
53
|
+
Subclass of :class:`ggplot2_py.GeomRaster` ported from R
|
|
54
|
+
``GeomPolygonRaster`` (``geom_polygonraster.R:82-130``).
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def setup_data(self, data: pd.DataFrame, params: dict) -> pd.DataFrame:
|
|
58
|
+
"""Reparametrise each pixel into four corner vertices.
|
|
59
|
+
|
|
60
|
+
Port of R ``GeomPolygonRaster$setup_data``
|
|
61
|
+
(``geom_polygonraster.R:84-107``). Each pixel row is replicated four
|
|
62
|
+
times and assigned the four corner coordinates with the exact R corner
|
|
63
|
+
winding, then sorted by pixel ``id``.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
data : pandas.DataFrame
|
|
68
|
+
Layer data with ``x``/``y`` pixel centres.
|
|
69
|
+
params : dict
|
|
70
|
+
Layer parameters (``hjust``/``vjust``).
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
pandas.DataFrame
|
|
75
|
+
Data with four vertex rows per pixel and an ``id`` column.
|
|
76
|
+
"""
|
|
77
|
+
data = data.copy().reset_index(drop=True)
|
|
78
|
+
x = data["x"].to_numpy(dtype="float64")
|
|
79
|
+
y = data["y"].to_numpy(dtype="float64")
|
|
80
|
+
w = resolution(x)
|
|
81
|
+
h = resolution(y)
|
|
82
|
+
hjust = params.get("hjust", 0.5)
|
|
83
|
+
if hjust is None:
|
|
84
|
+
hjust = 0.5
|
|
85
|
+
vjust = params.get("vjust", 0.5)
|
|
86
|
+
if vjust is None:
|
|
87
|
+
vjust = 0.5
|
|
88
|
+
|
|
89
|
+
n = len(data)
|
|
90
|
+
data["id"] = np.arange(1, n + 1)
|
|
91
|
+
|
|
92
|
+
# R corner matrix (ncol = 2), built from these concatenations:
|
|
93
|
+
# xs = [x-w*(1-hjust) (×2), x+w*hjust (×2)]
|
|
94
|
+
# ys = [y-h*(1-vjust), y+h*vjust (×2), y-h*(1-vjust)]
|
|
95
|
+
x_lo = x - w * (1 - hjust)
|
|
96
|
+
x_hi = x + w * hjust
|
|
97
|
+
y_lo = y - h * (1 - vjust)
|
|
98
|
+
y_hi = y + h * vjust
|
|
99
|
+
xs = np.concatenate([x_lo, x_lo, x_hi, x_hi])
|
|
100
|
+
ys = np.concatenate([y_lo, y_hi, y_hi, y_lo])
|
|
101
|
+
|
|
102
|
+
# rbind(data, data, data, data): copy block k holds vertex k.
|
|
103
|
+
rep = pd.concat([data] * 4, ignore_index=True)
|
|
104
|
+
rep["x"] = xs
|
|
105
|
+
rep["y"] = ys
|
|
106
|
+
# order(id) groups the four vertices of each pixel together.
|
|
107
|
+
rep = rep.sort_values("id", kind="stable").reset_index(drop=True)
|
|
108
|
+
return rep
|
|
109
|
+
|
|
110
|
+
def draw_panel(
|
|
111
|
+
self,
|
|
112
|
+
data: pd.DataFrame,
|
|
113
|
+
panel_params: Any,
|
|
114
|
+
coord: Any,
|
|
115
|
+
hjust: float = 0.5,
|
|
116
|
+
vjust: float = 0.5,
|
|
117
|
+
**params: Any,
|
|
118
|
+
) -> Any:
|
|
119
|
+
"""Draw one polygon per pixel.
|
|
120
|
+
|
|
121
|
+
Port of R ``GeomPolygonRaster$draw_panel``
|
|
122
|
+
(``geom_polygonraster.R:108-129``).
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
data : pandas.DataFrame
|
|
127
|
+
Layer data (four vertex rows per pixel).
|
|
128
|
+
panel_params : Any
|
|
129
|
+
Panel scales / ranges.
|
|
130
|
+
coord : Any
|
|
131
|
+
Active coordinate system.
|
|
132
|
+
hjust, vjust : float, default ``0.5``
|
|
133
|
+
Pixel anchor justifications (accepted for parameter parity).
|
|
134
|
+
**params : Any
|
|
135
|
+
Ignored extra parameters.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
grid_py.Grob
|
|
140
|
+
A single :func:`grid_py.polygon_grob` (or
|
|
141
|
+
:func:`grid_py.null_grob` when there is a single row).
|
|
142
|
+
"""
|
|
143
|
+
if len(data) == 1:
|
|
144
|
+
return null_grob()
|
|
145
|
+
|
|
146
|
+
data = data.copy()
|
|
147
|
+
data["group"] = data["id"]
|
|
148
|
+
coords = coord_munch(coord, data, panel_params)
|
|
149
|
+
coords = coords.reset_index(drop=True)
|
|
150
|
+
|
|
151
|
+
# first <- coords[!duplicated(data$id), ]
|
|
152
|
+
id_arr = coords["id"].to_numpy()
|
|
153
|
+
_, first_idx = np.unique(id_arr, return_index=True)
|
|
154
|
+
first = coords.iloc[np.sort(first_idx)]
|
|
155
|
+
|
|
156
|
+
fill = (
|
|
157
|
+
scales_alpha(
|
|
158
|
+
first["fill"].to_numpy() if "fill" in first.columns else "grey35",
|
|
159
|
+
first["alpha"].to_numpy() if "alpha" in first.columns else None,
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return _ggname(
|
|
164
|
+
"geom_polygon",
|
|
165
|
+
polygon_grob(
|
|
166
|
+
x=coords["x"].to_numpy(dtype="float64"),
|
|
167
|
+
y=coords["y"].to_numpy(dtype="float64"),
|
|
168
|
+
default_units="native",
|
|
169
|
+
id=coords["id"].to_numpy(),
|
|
170
|
+
gp=Gpar(col=0, fill=fill, lwd=0, lty=0),
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def geom_polygonraster(
|
|
176
|
+
mapping: Optional[Mapping] = None,
|
|
177
|
+
data: Any = None,
|
|
178
|
+
stat: str = "identity",
|
|
179
|
+
position: Any = None,
|
|
180
|
+
hjust: float = 0.5,
|
|
181
|
+
vjust: float = 0.5,
|
|
182
|
+
na_rm: bool = False,
|
|
183
|
+
show_legend: Any = None,
|
|
184
|
+
inherit_aes: bool = True,
|
|
185
|
+
**kwargs: Any,
|
|
186
|
+
) -> Any:
|
|
187
|
+
"""Create a polygon-raster layer.
|
|
188
|
+
|
|
189
|
+
Port of R ``geom_polygonraster()`` (``geom_polygonraster.R:51-74``). Each
|
|
190
|
+
raster pixel becomes a four-vertex polygon, enabling non-linear coord and
|
|
191
|
+
position transformations.
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
mapping : Mapping, optional
|
|
196
|
+
Aesthetic mapping created by :func:`ggplot2_py.aes`.
|
|
197
|
+
data : Any, optional
|
|
198
|
+
Layer data.
|
|
199
|
+
stat : str, default ``"identity"``
|
|
200
|
+
Statistical transformation.
|
|
201
|
+
position : Position, optional
|
|
202
|
+
Position adjustment. Defaults to :func:`ggh4x.position_lineartrans`
|
|
203
|
+
(R's default).
|
|
204
|
+
hjust, vjust : float, default ``0.5``
|
|
205
|
+
Pixel anchor justifications. Must be a length-1 numeric.
|
|
206
|
+
na_rm : bool, default ``False``
|
|
207
|
+
If ``True``, silently remove missing values.
|
|
208
|
+
show_legend : bool or None, default ``None``
|
|
209
|
+
Whether to show a legend for this layer.
|
|
210
|
+
inherit_aes : bool, default ``True``
|
|
211
|
+
Whether to inherit the plot's default aesthetics.
|
|
212
|
+
**kwargs : Any
|
|
213
|
+
Additional aesthetic parameters passed to the layer.
|
|
214
|
+
|
|
215
|
+
Returns
|
|
216
|
+
-------
|
|
217
|
+
ggplot2_py.Layer
|
|
218
|
+
A layer object that can be added to a plot.
|
|
219
|
+
|
|
220
|
+
Raises
|
|
221
|
+
------
|
|
222
|
+
TypeError
|
|
223
|
+
If ``hjust``/``vjust`` are not length-1 numerics.
|
|
224
|
+
"""
|
|
225
|
+
from ggplot2_py.layer import layer
|
|
226
|
+
|
|
227
|
+
if not isinstance(hjust, (int, float)):
|
|
228
|
+
raise TypeError("`hjust` must be a length-1 numeric.")
|
|
229
|
+
if not isinstance(vjust, (int, float)):
|
|
230
|
+
raise TypeError("`vjust` must be a length-1 numeric.")
|
|
231
|
+
|
|
232
|
+
if position is None:
|
|
233
|
+
# Lazy import to avoid a cross-subsystem import cycle.
|
|
234
|
+
from ggh4x.position_lineartrans import position_lineartrans
|
|
235
|
+
|
|
236
|
+
position = position_lineartrans()
|
|
237
|
+
|
|
238
|
+
return layer(
|
|
239
|
+
data=data,
|
|
240
|
+
mapping=mapping,
|
|
241
|
+
stat=stat,
|
|
242
|
+
geom=GeomPolygonRaster,
|
|
243
|
+
position=position,
|
|
244
|
+
show_legend=show_legend,
|
|
245
|
+
inherit_aes=inherit_aes,
|
|
246
|
+
params={
|
|
247
|
+
"hjust": hjust,
|
|
248
|
+
"vjust": vjust,
|
|
249
|
+
"na_rm": na_rm,
|
|
250
|
+
**kwargs,
|
|
251
|
+
},
|
|
252
|
+
)
|