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.
Files changed (64) hide show
  1. ggh4x/__init__.py +140 -0
  2. ggh4x/_aimed_text_grob.py +432 -0
  3. ggh4x/_borrowed_ggplot2.py +273 -0
  4. ggh4x/_cli.py +84 -0
  5. ggh4x/_datasets.py +106 -0
  6. ggh4x/_download.py +111 -0
  7. ggh4x/_facet_helpers.py +313 -0
  8. ggh4x/_facet_utils.py +649 -0
  9. ggh4x/_gap_grobs.py +606 -0
  10. ggh4x/_registry.py +10 -0
  11. ggh4x/_rlang.py +93 -0
  12. ggh4x/_utils.py +150 -0
  13. ggh4x/_vctrs.py +233 -0
  14. ggh4x/conveniences.py +601 -0
  15. ggh4x/coord_axes_inside.py +380 -0
  16. ggh4x/element_part_rect.py +545 -0
  17. ggh4x/facet_grid2.py +1018 -0
  18. ggh4x/facet_manual.py +901 -0
  19. ggh4x/facet_nested.py +776 -0
  20. ggh4x/facet_nested_wrap.py +193 -0
  21. ggh4x/facet_wrap2.py +896 -0
  22. ggh4x/geom_box.py +536 -0
  23. ggh4x/geom_outline_point.py +444 -0
  24. ggh4x/geom_pointpath.py +259 -0
  25. ggh4x/geom_polygonraster.py +252 -0
  26. ggh4x/geom_rectrug.py +489 -0
  27. ggh4x/geom_text_aimed.py +279 -0
  28. ggh4x/guide_stringlegend.py +354 -0
  29. ggh4x/help_secondary.py +549 -0
  30. ggh4x/multiscale/__init__.py +51 -0
  31. ggh4x/multiscale/_multiscale_add.py +207 -0
  32. ggh4x/multiscale/scale_listed.py +167 -0
  33. ggh4x/multiscale/scale_manual.py +478 -0
  34. ggh4x/multiscale/scale_multi.py +393 -0
  35. ggh4x/panel_scales/__init__.py +58 -0
  36. ggh4x/panel_scales/at_panel.py +115 -0
  37. ggh4x/panel_scales/facetted_pos_scales.py +647 -0
  38. ggh4x/panel_scales/force_panelsize.py +411 -0
  39. ggh4x/panel_scales/scale_facet.py +222 -0
  40. ggh4x/position_disjoint_ranges.py +229 -0
  41. ggh4x/position_lineartrans.py +242 -0
  42. ggh4x/py.typed +0 -0
  43. ggh4x/resources/faithful.csv +273 -0
  44. ggh4x/resources/iris.csv +151 -0
  45. ggh4x/resources/mtcars.csv +33 -0
  46. ggh4x/resources/pressure.csv +20 -0
  47. ggh4x/resources/volcano.csv +87 -0
  48. ggh4x/save.py +255 -0
  49. ggh4x/stat_difference.py +388 -0
  50. ggh4x/stat_funxy.py +436 -0
  51. ggh4x/stat_rle.py +290 -0
  52. ggh4x/stat_rollingkernel.py +369 -0
  53. ggh4x/stat_theodensity.py +681 -0
  54. ggh4x/strip_nested.py +448 -0
  55. ggh4x/strip_split.py +687 -0
  56. ggh4x/strip_tag.py +636 -0
  57. ggh4x/strip_themed.py +232 -0
  58. ggh4x/strip_vanilla.py +1464 -0
  59. ggh4x/themes.py +31 -0
  60. ggh4x/themes_ggh4x.py +67 -0
  61. ggh4x_python-0.3.1.9000.dist-info/METADATA +40 -0
  62. ggh4x_python-0.3.1.9000.dist-info/RECORD +64 -0
  63. ggh4x_python-0.3.1.9000.dist-info/WHEEL +4 -0
  64. 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
+ )