rgrid-python 4.5.3__tar.gz → 4.5.3.post1__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 (44) hide show
  1. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/PKG-INFO +3 -1
  2. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/README.md +2 -0
  3. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/__init__.py +3 -1
  4. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_draw.py +6 -0
  5. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_gpar.py +18 -2
  6. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_units.py +76 -10
  7. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/renderer.py +8 -6
  8. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/pyproject.toml +1 -1
  9. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/.gitattributes +0 -0
  10. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/.gitignore +0 -0
  11. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/LICENSE +0 -0
  12. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_arrow.py +0 -0
  13. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_clippath.py +0 -0
  14. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_colour.py +0 -0
  15. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_coords.py +0 -0
  16. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_curve.py +0 -0
  17. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_display_list.py +0 -0
  18. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_edit.py +0 -0
  19. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_font_metrics.py +0 -0
  20. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_grab.py +0 -0
  21. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_grob.py +0 -0
  22. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_group.py +0 -0
  23. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_highlevel.py +0 -0
  24. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_just.py +0 -0
  25. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_layout.py +0 -0
  26. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_ls.py +0 -0
  27. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_mask.py +0 -0
  28. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_path.py +0 -0
  29. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_patterns.py +0 -0
  30. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_primitives.py +0 -0
  31. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_renderer_base.py +0 -0
  32. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_scene_graph.py +0 -0
  33. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_size.py +0 -0
  34. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_state.py +0 -0
  35. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_transforms.py +0 -0
  36. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_typeset.py +0 -0
  37. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_utils.py +0 -0
  38. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_viewport.py +0 -0
  39. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/_vp_calc.py +0 -0
  40. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/py.typed +0 -0
  41. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/renderer_web.py +0 -0
  42. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/resources/d3.v7.min.js +0 -0
  43. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/resources/gridpy.css +0 -0
  44. {rgrid_python-4.5.3 → rgrid_python-4.5.3.post1}/grid_py/resources/gridpy.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rgrid-python
3
- Version: 4.5.3
3
+ Version: 4.5.3.post1
4
4
  Summary: Python port of the R grid package (tracks R grid 4.5.3)
5
5
  Project-URL: Homepage, https://github.com/Bio-Babel/grid_py
6
6
  Project-URL: Repository, https://github.com/Bio-Babel/grid_py
@@ -41,6 +41,8 @@ Description-Content-Type: text/markdown
41
41
 
42
42
  # grid_py
43
43
 
44
+ [![PyPI](https://img.shields.io/pypi/v/rgrid-python)](https://pypi.org/project/rgrid-python/)
45
+
44
46
  Python port of the R **grid** package.
45
47
 
46
48
  ## Installation
@@ -1,5 +1,7 @@
1
1
  # grid_py
2
2
 
3
+ [![PyPI](https://img.shields.io/pypi/v/rgrid-python)](https://pypi.org/project/rgrid-python/)
4
+
3
5
  Python port of the R **grid** package.
4
6
 
5
7
  ## Installation
@@ -6,7 +6,7 @@ units, viewports, grobs (graphical objects), layouts, and rendering via
6
6
  Cairo (pycairo).
7
7
  """
8
8
 
9
- __version__ = "4.5.3"
9
+ __version__ = "4.5.3.post1"
10
10
 
11
11
  # --- Utilities ---
12
12
  from grid_py._utils import depth, explode, grid_pretty, n2mfrow
@@ -18,6 +18,7 @@ from grid_py._just import valid_just, resolve_hjust, resolve_vjust, resolve_rast
18
18
  from grid_py._units import (
19
19
  Unit, is_unit, unit_type, unit_c, unit_length,
20
20
  unit_pmax, unit_pmin, unit_psum, unit_rep,
21
+ unit_summary_sum, unit_summary_min, unit_summary_max,
21
22
  string_width, string_height, string_ascent, string_descent,
22
23
  absolute_size,
23
24
  convert_unit, convert_x, convert_y, convert_width, convert_height,
@@ -226,6 +227,7 @@ __all__ = [
226
227
  # Units
227
228
  "Unit", "is_unit", "unit_type", "unit_c", "unit_length",
228
229
  "unit_pmax", "unit_pmin", "unit_psum", "unit_rep",
230
+ "unit_summary_sum", "unit_summary_min", "unit_summary_max",
229
231
  "string_width", "string_height", "string_ascent", "string_descent",
230
232
  "absolute_size",
231
233
  "convert_unit", "convert_x", "convert_y", "convert_width", "convert_height",
@@ -109,6 +109,12 @@ def _subset_gpar(gp: Optional[Gpar], i: int) -> Optional[Gpar]:
109
109
  picked = val[i % len(val)]
110
110
  elif isinstance(val, (list, tuple)) and len(val) > 1:
111
111
  picked = val[i % len(val)]
112
+ elif isinstance(val, (list, tuple)) and len(val) == 1 \
113
+ and val[0] is None and key in ("col", "fill"):
114
+ # Length-1 [None] NA sentinel from Gpar(col=None)/Gpar(fill=None).
115
+ # Preserve the NA intent across subset — emit "transparent" so
116
+ # the renderer's scalar-colour path parses to (0,0,0,0).
117
+ picked = "transparent"
112
118
  else:
113
119
  picked = val
114
120
 
@@ -199,6 +199,14 @@ class Gpar:
199
199
  # -- process remaining parameters ----------------------------------
200
200
  for name, value in kwargs.items():
201
201
  if value is None:
202
+ # Colour parameters: preserve explicit None as a one-element
203
+ # NA sentinel so the renderer can tell "col absent (inherit,
204
+ # default black)" apart from "col explicitly NA (transparent)".
205
+ # Mirrors R's ``gpar(col=NA)`` / ``gpar(fill=NA)`` semantics
206
+ # (see R grid src/gpar.c gpCol(): isNull(col) → R_TRANWHITE).
207
+ # Other parameters have no NA semantic; drop silently.
208
+ if name in ("col", "fill"):
209
+ params[name] = [None]
202
210
  continue
203
211
 
204
212
  vals = _as_list(value)
@@ -283,8 +291,16 @@ class Gpar:
283
291
  # backend, matching R's behaviour).
284
292
  pass
285
293
 
286
- # Store single-element lists as scalars for cleaner repr.
287
- params[name] = vals[0] if len(vals) == 1 else vals
294
+ # Store single-element lists as scalars for cleaner repr,
295
+ # except for the colour NA sentinel [None] which must stay a
296
+ # sequence so the renderer treats it as R's gpar(col=NA).
297
+ if len(vals) == 1:
298
+ if name in ("col", "fill") and vals[0] is None:
299
+ params[name] = [None]
300
+ else:
301
+ params[name] = vals[0]
302
+ else:
303
+ params[name] = vals
288
304
 
289
305
  self._params = params
290
306
 
@@ -1574,6 +1574,56 @@ def convert_unit(
1574
1574
  )
1575
1575
  if resolved is not None:
1576
1576
  result_vals[i] = resolved
1577
+ elif src_unit in ("sum", "min", "max"):
1578
+ # R ``grid/src/unit.c: L_convert`` dispatches ``sum.unit`` /
1579
+ # ``min.unit`` / ``max.unit`` via ``L_sumUnits`` /
1580
+ # ``L_minUnits`` / ``L_maxUnits``, each of which calls
1581
+ # ``convertUnit`` recursively on every child in the
1582
+ # compound's list and combines the resulting absolute
1583
+ # lengths. Without this branch the fallback at the end of
1584
+ # this loop returns the outer scalar (1.0) unchanged —
1585
+ # which is why ``convertWidth(unit(1,'grobwidth',g) +
1586
+ # unit(0.05,'inches'),'cm')`` returned 1.0 regardless of
1587
+ # the text's actual rendered width.
1588
+ child = x._data[i]
1589
+ if (
1590
+ child is not None
1591
+ and isinstance(child, Unit)
1592
+ and len(child) > 0
1593
+ ):
1594
+ child_inches: List[float] = []
1595
+ for j in range(len(child)):
1596
+ sub = Unit.__new__(Unit)
1597
+ sub._values = np.array(
1598
+ [child._values[j]], dtype=np.float64,
1599
+ )
1600
+ sub._units = [child._units[j]]
1601
+ sub._data = [child._data[j]]
1602
+ sub._is_absolute = (
1603
+ child._units[j] in _ABSOLUTE_UNIT_TYPES
1604
+ )
1605
+ inches_arr = convert_unit(
1606
+ sub, "inches",
1607
+ axisFrom=axisFrom, typeFrom=typeFrom,
1608
+ axisTo=axisTo, typeTo=typeTo,
1609
+ valueOnly=True,
1610
+ )
1611
+ child_inches.append(float(inches_arr[0]))
1612
+ if src_unit == "sum":
1613
+ combined = float(np.sum(child_inches))
1614
+ elif src_unit == "min":
1615
+ combined = float(np.min(child_inches))
1616
+ else:
1617
+ combined = float(np.max(child_inches))
1618
+ combined *= float(x._values[i])
1619
+ if target in _ABSOLUTE_UNIT_TYPES:
1620
+ result_vals[i] = combined / _INCHES_PER[target]
1621
+ else:
1622
+ result_vals[i] = combined
1623
+ converted = False
1624
+ else:
1625
+ result_vals[i] = x._values[i]
1626
+ converted = False
1577
1627
  elif src_unit in _STR_METRIC_TYPES:
1578
1628
  # Fallback without renderer: string metric → inches → target
1579
1629
  inches_val = _eval_str_metric(src_unit, x._data[i], x._values[i])
@@ -1583,18 +1633,34 @@ def convert_unit(
1583
1633
  result_vals[i] = inches_val
1584
1634
  converted = False
1585
1635
  elif src_unit in _GROB_METRIC_TYPES:
1586
- # Fallback: grob metric → inches → target
1636
+ # Fallback: grob metric → inches → target.
1637
+ # Mirrors R ``grid/src/unit.c``:
1638
+ # evaluateGrobUnit(..., evalType=2)
1639
+ # unitx <- widthDetails(grob)
1640
+ # result = transformWidthtoINCHES(unitx, 0, ...)
1641
+ # R takes *only index 0* of ``widthDetails``'s return,
1642
+ # relying on its methods (e.g. ``widthDetails.titleGrob``
1643
+ # ``<- sum(x$widths)``) to wrap multi-element units as
1644
+ # a single sum.unit. The recursive ``transformWidthtoINCHES``
1645
+ # then unwraps L_SUM via the compound branch above.
1587
1646
  metric_unit = _eval_grob_metric(src_unit, x._data[i])
1588
- if (
1589
- metric_unit is not None
1590
- and len(metric_unit) > 0
1591
- and metric_unit._units[0] in _ABSOLUTE_UNIT_TYPES
1592
- ):
1593
- src_inches = (
1594
- metric_unit._values[0]
1595
- * _INCHES_PER[metric_unit._units[0]]
1647
+ if metric_unit is not None and len(metric_unit) > 0:
1648
+ head = Unit.__new__(Unit)
1649
+ head._values = np.array(
1650
+ [metric_unit._values[0]], dtype=np.float64,
1651
+ )
1652
+ head._units = [metric_unit._units[0]]
1653
+ head._data = [metric_unit._data[0]]
1654
+ head._is_absolute = (
1655
+ metric_unit._units[0] in _ABSOLUTE_UNIT_TYPES
1656
+ )
1657
+ inches_arr = convert_unit(
1658
+ head, "inches",
1659
+ axisFrom=axisFrom, typeFrom=typeFrom,
1660
+ axisTo=axisTo, typeTo=typeTo,
1661
+ valueOnly=True,
1596
1662
  )
1597
- src_inches *= x._values[i]
1663
+ src_inches = float(inches_arr[0]) * float(x._values[i])
1598
1664
  if target in _ABSOLUTE_UNIT_TYPES:
1599
1665
  result_vals[i] = src_inches / _INCHES_PER[target]
1600
1666
  else:
@@ -336,12 +336,14 @@ class CairoRenderer(GridRenderer):
336
336
 
337
337
  col = gp.get("col", None)
338
338
  # R semantics:
339
- # * col=NULL (unset) → inherit parent, default "black"
340
- # * col=NA (explicit) no stroke (transparent)
341
- # In Python Gpar, None-scalar is dropped at construction, so
342
- # ``gp.get("col") is None`` NULL. A sequence whose entries
343
- # are None (coming from ggplot2 ``colour=NA`` data) must be
344
- # treated as NA, matching R's ``gpar(col=NA)``.
339
+ # * col absent from gp → inherit parent, default "black"
340
+ # * Gpar(col=None) stored as [None] (NA sentinel)
341
+ # transparent (≡ R gpar(col=NA))
342
+ # * sequence with first=None transparent (ggplot2 colour=NA)
343
+ # * scalar string "NA"/"none"/ → transparent (resolved by
344
+ # "transparent" _parse_colour)
345
+ # The [None] sentinel is produced by Gpar(col=None) — see
346
+ # _gpar.py Gpar.__init__.
345
347
  _is_seq = hasattr(col, "__len__") and not isinstance(col, str)
346
348
  if _is_seq:
347
349
  col_val = col[0]
@@ -12,7 +12,7 @@ name = "rgrid-python"
12
12
  # a corresponding R update, bump a PEP 440 post-release suffix:
13
13
  # "4.5.3" → "4.5.3.post1" → "4.5.3.post2" → ...
14
14
  # When R grid itself ships a new upstream version, move to e.g. "4.5.4".
15
- version = "4.5.3"
15
+ version = "4.5.3.post1"
16
16
  description = "Python port of the R grid package (tracks R grid 4.5.3)"
17
17
  readme = "README.md"
18
18
  requires-python = ">=3.10"
File without changes