plot-io 0.12.0__py3-none-win_arm64.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 (130) hide show
  1. plot_io/__init__.py +73 -0
  2. plot_io/_methods.py +1691 -0
  3. plot_io/_native/__init__.py +199 -0
  4. plot_io/_native/__main__.py +197 -0
  5. plot_io/_native/_api.py +457 -0
  6. plot_io/_native/bin/windows-arm64.dll +0 -0
  7. plot_io/_native/kernels.py +335 -0
  8. plot_io/_native/manifest.json +49 -0
  9. plot_io/axis.py +1347 -0
  10. plot_io/boxes.py +1156 -0
  11. plot_io/canvas.py +389 -0
  12. plot_io/color/__init__.py +3 -0
  13. plot_io/color/data.py +1646 -0
  14. plot_io/color/maps.py +922 -0
  15. plot_io/color/values.py +295 -0
  16. plot_io/color/variants.py +1246 -0
  17. plot_io/colorbar.py +1426 -0
  18. plot_io/columns.py +614 -0
  19. plot_io/decorations.py +920 -0
  20. plot_io/defaults.py +809 -0
  21. plot_io/density.py +113 -0
  22. plot_io/ext.py +68 -0
  23. plot_io/facets.py +240 -0
  24. plot_io/figure.py +788 -0
  25. plot_io/formatters.py +97 -0
  26. plot_io/genome/__init__.py +17 -0
  27. plot_io/genome/adapters.py +356 -0
  28. plot_io/genome/combine.py +123 -0
  29. plot_io/genome/contacts.py +508 -0
  30. plot_io/genome/intervals.py +750 -0
  31. plot_io/genome/lanes.py +191 -0
  32. plot_io/genome/layout.py +184 -0
  33. plot_io/genome/links.py +364 -0
  34. plot_io/genome/pack.py +27 -0
  35. plot_io/genome/readers.py +145 -0
  36. plot_io/genome/regions.py +228 -0
  37. plot_io/genome/scale.py +349 -0
  38. plot_io/genome/series.py +344 -0
  39. plot_io/genome/signal.py +621 -0
  40. plot_io/genome/sites.py +782 -0
  41. plot_io/genome/sources.py +459 -0
  42. plot_io/genome/testing.py +161 -0
  43. plot_io/geometry.py +289 -0
  44. plot_io/groups.py +308 -0
  45. plot_io/guides.py +503 -0
  46. plot_io/helpers/__init__.py +17 -0
  47. plot_io/helpers/clustermap.py +202 -0
  48. plot_io/helpers/dendrogram.py +172 -0
  49. plot_io/helpers/grids.py +304 -0
  50. plot_io/helpers/qq.py +334 -0
  51. plot_io/helpers/raincloud.py +249 -0
  52. plot_io/helpers/tree.py +214 -0
  53. plot_io/helpers/volcano.py +505 -0
  54. plot_io/hints.py +125 -0
  55. plot_io/kernels.py +740 -0
  56. plot_io/labels.py +566 -0
  57. plot_io/layers/__init__.py +100 -0
  58. plot_io/layers/base.py +630 -0
  59. plot_io/layers/context.py +87 -0
  60. plot_io/layers/core.py +446 -0
  61. plot_io/layers/geoms.py +1362 -0
  62. plot_io/layers/grammar.py +586 -0
  63. plot_io/layers/paint.py +614 -0
  64. plot_io/layers/pipeline.py +170 -0
  65. plot_io/layers/positions.py +431 -0
  66. plot_io/layers/stats.py +1088 -0
  67. plot_io/layout.py +1381 -0
  68. plot_io/legend.py +605 -0
  69. plot_io/levels.py +509 -0
  70. plot_io/limits.py +124 -0
  71. plot_io/lines.py +42 -0
  72. plot_io/mapped.py +522 -0
  73. plot_io/markers.py +110 -0
  74. plot_io/markup.py +128 -0
  75. plot_io/numbers.py +354 -0
  76. plot_io/occupancy.py +295 -0
  77. plot_io/plot.py +597 -0
  78. plot_io/presets/__init__.py +51 -0
  79. plot_io/presets/_util.py +153 -0
  80. plot_io/presets/area.py +145 -0
  81. plot_io/presets/bar.py +261 -0
  82. plot_io/presets/box.py +400 -0
  83. plot_io/presets/catpoints.py +177 -0
  84. plot_io/presets/contour.py +353 -0
  85. plot_io/presets/curves.py +30 -0
  86. plot_io/presets/dots.py +355 -0
  87. plot_io/presets/ecdf.py +97 -0
  88. plot_io/presets/errorbar.py +106 -0
  89. plot_io/presets/errors.py +296 -0
  90. plot_io/presets/fill.py +74 -0
  91. plot_io/presets/heatmap.py +322 -0
  92. plot_io/presets/hexbin.py +198 -0
  93. plot_io/presets/hist.py +391 -0
  94. plot_io/presets/hist2d.py +87 -0
  95. plot_io/presets/kde.py +162 -0
  96. plot_io/presets/kde2d.py +147 -0
  97. plot_io/presets/line.py +143 -0
  98. plot_io/presets/pie.py +502 -0
  99. plot_io/presets/regression.py +115 -0
  100. plot_io/presets/scatter.py +194 -0
  101. plot_io/presets/stem.py +100 -0
  102. plot_io/presets/violin.py +323 -0
  103. plot_io/py.typed +0 -0
  104. plot_io/registry.py +82 -0
  105. plot_io/render.py +480 -0
  106. plot_io/rows.py +491 -0
  107. plot_io/scales.py +103 -0
  108. plot_io/seams.py +138 -0
  109. plot_io/settings.py +807 -0
  110. plot_io/shapes.py +66 -0
  111. plot_io/sharing.py +232 -0
  112. plot_io/sizemaps.py +97 -0
  113. plot_io/spec.py +240 -0
  114. plot_io/states.py +216 -0
  115. plot_io/styles/__init__.py +307 -0
  116. plot_io/styles/library.py +397 -0
  117. plot_io/tables.py +138 -0
  118. plot_io/text.py +412 -0
  119. plot_io/ticks.py +400 -0
  120. plot_io/times.py +287 -0
  121. plot_io/titles.py +225 -0
  122. plot_io/transform.py +114 -0
  123. plot_io/types.py +13604 -0
  124. plot_io/units.py +768 -0
  125. plot_io/validators.py +1029 -0
  126. plot_io/values.py +190 -0
  127. plot_io-0.12.0.dist-info/METADATA +215 -0
  128. plot_io-0.12.0.dist-info/RECORD +130 -0
  129. plot_io-0.12.0.dist-info/WHEEL +4 -0
  130. plot_io-0.12.0.dist-info/licenses/LICENSE +28 -0
plot_io/seams.py ADDED
@@ -0,0 +1,138 @@
1
+ """Seams: where outlined shapes touch (stacked, dodged or adjacent bars, pie wedges), the
2
+ shared edge is redrawn in one color (white by default), so neighbours stay apart instead of
3
+ showing two overlapping outlines. The outlines under a seam are left out of the shapes'
4
+ geometry (not painted over), so none shows through the seam's anti-aliased edges."""
5
+
6
+ from typing import Any
7
+ from .canvas import Canvas
8
+
9
+ __all__ = ["rect_contacts", "rect_seams", "seam_box", "outline_pieces", "draw_seams"]
10
+
11
+ Rect = tuple[float, float, float, float, float] # x0, y0, x1, y1 (page units), width
12
+ _EPS = 0.01 # page units: edges this close touch
13
+ #: (at most: closer for rectangles smaller than 1 px, see :func:`rect_contacts`)
14
+
15
+
16
+ def rect_seams(new: list[Rect], old: list[Rect]) -> list[tuple[float, ...]]:
17
+ """Segments ``(x0, y0, x1, y1, width)`` where a rectangle of ``new`` touches another of
18
+ ``new`` or one of ``old`` (edges at the same place, overlapping along it); the width is
19
+ the wider outline of the two."""
20
+ return list(dict.fromkeys(s for s, _ in rect_contacts(new, old)))
21
+
22
+
23
+ def rect_contacts(new: list[Rect], old: list[Rect]) -> list[tuple[tuple[float, ...], int]]:
24
+ """As :func:`rect_seams`, each segment with the index of the other rectangle of the
25
+ pair in ``old + new`` (an earlier one when it is in ``old``)."""
26
+ import bisect
27
+ out: list[tuple[tuple[float, ...], int]] = []
28
+ every = old + new
29
+ # per side (left, right, top, bottom: the coordinate's index in a rectangle), the
30
+ # rectangles by the position of that edge in steps of _EPS; each bucket sorted by the
31
+ # start along the edge (y0 for left and right, x0 for top and bottom), with the
32
+ # starts and the longest edge for bisection
33
+ index: list[dict[int, Any]] = [{}, {}, {}, {}]
34
+ for i, r in enumerate(every):
35
+ for c in range(4):
36
+ index[c].setdefault(round(r[c] / _EPS), []).append(i)
37
+ for c in range(4):
38
+ a = 1 if c in (0, 2) else 0
39
+ for k, js in index[c].items():
40
+ js.sort(key=lambda j: every[j][a])
41
+ longest = max(0.0, *(every[j][a + 2] - every[j][a] for j in js))
42
+ index[c][k] = (js, [every[j][a] for j in js], longest)
43
+ first_new = len(old)
44
+ size = [min(r[2] - r[0], r[3] - r[1]) for r in every]
45
+ # right and bottom edges against every other rectangle; left and top ones against the
46
+ # earlier rectangles only (pairs of new ones are found from one side)
47
+ sides = ((2, 0, True), (3, 1, True), (0, 2, False), (1, 3, False))
48
+ for i in range(first_new, len(every)):
49
+ r = every[i]
50
+ x0, y0, x1, y1, w = r
51
+ for mine, other, both in sides:
52
+ v = r[mine]
53
+ k = round(v / _EPS)
54
+ found = index[other]
55
+ lo_e, hi_e = (y0, y1) if mine in (0, 2) else (x0, x1)
56
+ near: list[int] = []
57
+ for kk in (k - 1, k, k + 1):
58
+ bucket = found.get(kk)
59
+ if bucket is None:
60
+ continue
61
+ js, starts, longest = bucket
62
+ first = bisect.bisect_left(starts, lo_e - longest)
63
+ last = bisect.bisect_right(starts, hi_e)
64
+ near.extend(sorted(js[first:last]))
65
+ for j in near:
66
+ if j == i or (not both and j >= first_new):
67
+ continue
68
+ b = every[j]
69
+ # edges this close touch: _EPS, or 1 % of the smaller rectangle (gaps
70
+ # between rectangles narrower than a px are not contacts)
71
+ if abs(b[other] - v) > min(_EPS, 0.01 * min(size[i], size[j])):
72
+ continue
73
+ width = max(w, b[4])
74
+ if mine in (0, 2):
75
+ lo, hi = max(y0, b[1]), min(y1, b[3])
76
+ if hi - lo > _EPS:
77
+ out.append(((v, lo, v, hi, width), j))
78
+ else:
79
+ lo, hi = max(x0, b[0]), min(x1, b[2])
80
+ if hi - lo > _EPS:
81
+ out.append(((lo, v, hi, v, width), j))
82
+ return out
83
+
84
+
85
+ Box = tuple[float, float, float, float] # x0, y0, x1, y1
86
+
87
+
88
+ def seam_box(segment: tuple[float, ...], square: bool = False) -> Box:
89
+ """The area an axis-aligned segment ``(x0, y0, x1, y1, width)`` covers when stroked
90
+ with butt caps, or square caps (``square``)."""
91
+ x0, y0, x1, y1, w = segment[:5]
92
+ h = w / 2
93
+ e = h if square else 0.0
94
+ if abs(x1 - x0) <= _EPS:
95
+ return (x0 - h, min(y0, y1) - e, x0 + h, max(y0, y1) + e)
96
+ return (min(x0, x1) - e, y0 - h, max(x0, x1) + e, y0 + h)
97
+
98
+
99
+ def _minus(a: Box, b: Box) -> list[Box]:
100
+ ax0, ay0, ax1, ay1 = a
101
+ bx0, by0, bx1, by1 = b
102
+ if bx0 >= ax1 or bx1 <= ax0 or by0 >= ay1 or by1 <= ay0:
103
+ return [a]
104
+ out = []
105
+ if by0 > ay0:
106
+ out.append((ax0, ay0, ax1, by0))
107
+ if by1 < ay1:
108
+ out.append((ax0, by1, ax1, ay1))
109
+ my0, my1 = max(ay0, by0), min(ay1, by1)
110
+ if bx0 > ax0:
111
+ out.append((ax0, my0, bx0, my1))
112
+ if bx1 < ax1:
113
+ out.append((bx1, my0, ax1, my1))
114
+ return [r for r in out if r[2] - r[0] > 1e-9 and r[3] - r[1] > 1e-9]
115
+
116
+
117
+ def outline_pieces(rect: Box, width: float, cuts: list[Box]) -> list[Box]:
118
+ """The area of a rectangle's outline (``width``, centred on the edges, square corners)
119
+ without the ``cuts``, as disjoint rectangles."""
120
+ x0, y0, x1, y1 = rect
121
+ h = width / 2
122
+ if y1 - y0 <= width or x1 - x0 <= width:
123
+ pieces = [(x0 - h, y0 - h, x1 + h, y1 + h)]
124
+ else:
125
+ pieces = [(x0 - h, y0 - h, x1 + h, y0 + h), (x0 - h, y1 - h, x1 + h, y1 + h),
126
+ (x0 - h, y0 + h, x0 + h, y1 - h), (x1 - h, y0 + h, x1 + h, y1 - h)]
127
+ for c in cuts:
128
+ pieces = [q for p in pieces for q in _minus(p, c)]
129
+ return pieces
130
+
131
+
132
+ def draw_seams(canvas: Canvas, segments: list[tuple[float, ...]], color: Any) -> None:
133
+ """Draw seams (butt caps, so outlines across their ends stay whole)."""
134
+ if not segments or color is None:
135
+ return
136
+ canvas.draw_segments([s[0] for s in segments], [s[1] for s in segments],
137
+ [s[2] for s in segments], [s[3] for s in segments], stroke=color,
138
+ stroke_width=[s[4] for s in segments], stroke_linecap="butt")