plot-io 0.12.0__py3-none-win_amd64.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-x86_64.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
@@ -0,0 +1,147 @@
1
+ """2-D kernel density contours (``kde(x, y)``, stat ``kde2d`` then ``contour``): seaborn's
2
+ ``kdeplot(x=, y=)``."""
3
+
4
+ import array
5
+ import math
6
+ from typing import Any
7
+
8
+ from .._methods import Kde2dMixin
9
+ from .. import columns
10
+ from ..density import _bandwidth
11
+ from ..layers import stats
12
+ from ..layers.base import Series
13
+ from ..layers.core import Call, Layer, Table
14
+ from ..layers.geoms import GEOMS
15
+ from ..layers.paint import base_color
16
+ from ..settings import Setting, number, table
17
+ from .contour import Contour
18
+
19
+ __all__ = ["Kde2d"]
20
+
21
+
22
+ class Kde2d(Kde2dMixin, Contour):
23
+ """Density contours of points ``(x, y)``: the 2-D Gaussian density on a grid over the
24
+ data plus ``cut`` bandwidths, drawn at levels enclosing equal shares of the mass.
25
+
26
+ Made by ``p.kde(x, y)`` (or ``plt.Kde(x, y)``), as seaborn's ``kdeplot(x=, y=)``. The
27
+ bandwidth is as `Density <docs/api.md#point-density>`_'s: scipy's covariance times Scott's
28
+ factor, or Silverman's, a number or a matrix, times ``adjust``; the grid is ``points``
29
+ × ``points`` in axis positions (log axes in log space). With a number n of ``levels``,
30
+ level k (0 … n − 1) encloses 1 − p of the mass, p = ``thresh`` + (1 − ``thresh``)·k/(n −
31
+ 1): the outermost 1 − ``thresh``, the last at the density's maximum; a list gives density
32
+ values. Unfilled lines take the plot's next color, unless ``color_map`` is set (a map,
33
+ or one color: as :class:`Contour`'s); ``fill=True`` colors the bands through
34
+ ``color_map``, the top band up to the maximum. Drawn by :class:`Contour`'s code (lines,
35
+ labels, colorbar).
36
+
37
+ Example::
38
+
39
+ rng = random.Random(1)
40
+ x = [rng.gauss(0, 1) for _ in range(300)]
41
+ p = plt.Plot(width=240, height=160)
42
+ p.kde(x, [v + rng.gauss(0, 0.6) for v in x], levels=6)
43
+ """
44
+
45
+ SETTINGS = table(
46
+ **{k: v for k, v in Contour.SETTINGS.items() if k != "levels"},
47
+ levels=Setting(lambda v: v if isinstance(v, list) else number(lo=1, integer=True)(v),
48
+ doc="A number n of iso-proportion levels: level k (0 … n − 1) encloses "
49
+ "1 − p of the mass, p = `thresh` + (1 − `thresh`)·k/(n − 1) (the "
50
+ "outermost 1 − `thresh`, the last at the density's maximum); or "
51
+ "density values."),
52
+ thresh=Setting(number(0, 1),
53
+ doc="Lowest iso-proportion: the outermost contour encloses 1 − "
54
+ "`thresh` of the mass."),
55
+ bandwidth=Setting(_bandwidth,
56
+ doc="`\"scott\"`, `\"silverman\"`, a number or a 2 × 2 matrix, as "
57
+ "`Density`."),
58
+ adjust=Setting(number(positive=True), doc="Factor of the bandwidth."),
59
+ weights=Setting(lambda v: columns.numbers(v, "weights"),
60
+ doc="A weight per point, counted as repeated points."),
61
+ cut=Setting(number(lo=0), doc="Grid extends this many bandwidths past the data."),
62
+ points=Setting(number(lo=16, hi=1024, integer=True),
63
+ doc="Grid points per side."),
64
+ )
65
+
66
+ DATA = {"x": "numbers", "y": "numbers"}
67
+
68
+ def __init__(self, x: Any, y: Any, plot: Any = None, **settings: Any) -> None:
69
+ self.h = self.w = 2
70
+ self.flat = array.array("d", [0.0] * 4)
71
+ self.xn = self.yn = array.array("d", [0.0, 1.0])
72
+ Series.__init__(self, plot=plot, **settings)
73
+
74
+ def _grid(self) -> dict[str, Any]:
75
+ sx, sy = self._scales()
76
+ return stats.compute(self, "kde2d", (sx, sy), kind="grid")
77
+
78
+ def _grid_data(self) -> tuple[Any, int, int, Any, Any]:
79
+ g = self._grid()
80
+ return g["flat"], g["w"], g["h"], g["fx"], g["fy"]
81
+
82
+ def level_values(self) -> list[float]:
83
+ lv = self.resolve("levels")
84
+ if isinstance(lv, list):
85
+ return sorted(float(v) for v in lv)
86
+ g = self._grid()
87
+ values = sorted((v for v in g["flat"] if v == v), reverse=True)
88
+ total = sum(values)
89
+ if not total:
90
+ return [0.0]
91
+ thresh = self.resolve("thresh")
92
+ props = [thresh + (1.0 - thresh) * i / (lv - 1) for i in range(lv)] if lv > 1 \
93
+ else [thresh]
94
+ cum, out, acc, j = [], [], 0.0, 0
95
+ for v in values:
96
+ acc += v
97
+ cum.append(acc / total)
98
+ for p in props: # density whose upper set holds 1 − p
99
+ target = 1.0 - p
100
+ while j < len(cum) - 1 and cum[j] < target:
101
+ j += 1
102
+ out.append(values[min(j, len(values) - 1)])
103
+ j = 0
104
+ return sorted(set(out))
105
+
106
+ def _bands(self, lv: list[float]) -> list[tuple[float, float, float]]:
107
+ flat = self._grid()["flat"]
108
+ out = []
109
+ for lo, hi in zip(lv, lv[1:] + [math.inf]):
110
+ top = hi if math.isfinite(hi) else max(flat) * 1.0001 + 1e-300
111
+ out.append((lo, hi if math.isfinite(hi) else top, top))
112
+ return out
113
+
114
+ def _level_color(self, ctx: Any, i: int, level: float) -> Any:
115
+ if not self._filled() and not self._mapped_given():
116
+ return base_color(self, ctx)
117
+ return super()._level_color(ctx, i, level)
118
+
119
+ def _mapped_given(self) -> bool:
120
+ """Whether a map is given (unfilled contours otherwise take the plot's color)."""
121
+ return self.is_set("color_map") or self.is_set("color_axis")
122
+
123
+ def _color_count(self) -> int:
124
+ uses = not self._filled() and not self._mapped_given()
125
+ return 1 if uses else 0
126
+
127
+ def _mapped_source(self) -> bool:
128
+ if not self._filled() and not self._mapped_given():
129
+ return False
130
+ return super()._mapped_source()
131
+
132
+ def _roles(self) -> dict[str, str]:
133
+ return {}
134
+
135
+ def _occupancy(self, call: Call) -> None:
136
+ # the density's points mark the cells for legend placement
137
+ for la in call.layers:
138
+ la.occupy = False
139
+ call.layers.append(Layer(GEOMS["points"], Table(x=self.cols["x"], y=self.cols["y"]),
140
+ paint=None,
141
+ key=False, bounds=False))
142
+
143
+ def _extent(self, call: Call) -> None:
144
+ sx, sy = self._scales()
145
+ g = self._grid()
146
+ call.extra = {"x": array.array("d", [sx.inverse(g["fx"][0]), sx.inverse(g["fx"][-1])]),
147
+ "y": array.array("d", [sy.inverse(g["fy"][0]), sy.inverse(g["fy"][-1])])}
@@ -0,0 +1,143 @@
1
+ """Line: a polyline through points, or several sharing x (``Path``), with optional markers
2
+ (``Points``) and error bars (``Segments``)."""
3
+
4
+ import array
5
+ from typing import TYPE_CHECKING, Any, Self, Unpack
6
+
7
+ from .. import groups
8
+ from ..color.values import color
9
+ from ..layers.base import common
10
+ from ..layers.core import Table
11
+ from ..layers.grammar import Lay, Spec
12
+ from ..layers.paint import xy_density_points
13
+ from ..settings import Setting, one_of, table
14
+ from ..transform import settings_both as coord_settings
15
+ from .curves import curve_settings
16
+ from .errors import Summarized, error_value
17
+
18
+ if TYPE_CHECKING:
19
+ from ..types import LineSettings
20
+
21
+ __all__ = ["Line"]
22
+
23
+
24
+ class Line(Summarized):
25
+ """A line through ``(x, y)``; ``y`` may hold several columns (one line each, sharing
26
+ ``x``: a 2-D buffer's columns, a data frame, a list of arrays), and
27
+ ``x`` may be omitted (``0, 1, 2, …``). ``orientation="horizontal"`` draws ``x`` on
28
+ the y axis (a profile along y). Numbers per point (or ``"density"``) in
29
+ ``marker_color``/``marker_edge_color`` map through the series' color axis.
30
+
31
+ Named line styles scale with the width. With replicates, ``estimate`` draws a line
32
+ through their estimates and ``interval`` a band (or error bars) around it
33
+ (`summaries <docs/api.md#summaries-estimate-interval>`_). Markers (``marker``, ``marker_size``, ``marker_color``, …) are drawn at
34
+ the points when ``marker`` or ``show_markers`` is set; numbers per point in
35
+ ``marker_color`` and ``marker_edge_color`` go through the series' `color axis <docs/api.md#6-color-and-size-axes>`_
36
+ (``p.add_colorbar(line)``), as ``color`` does on :class:`Scatter`; the line keeps
37
+ ``color``, and the legend's marker takes the gradient's middle color.
38
+
39
+ - ``interpolation``: ``linear``; ``step-pre``, ``step-post``, ``step-mid``; ``monotone`` (a
40
+ cubic through every point that never overshoots, Fritsch–Carlson; ``spline`` where x is
41
+ not monotonic); ``spline`` (centripetal Catmull–Rom, may overshoot). Each segment is
42
+ one exact Bézier, computed on the page after the axis scales. Steps and curves are not
43
+ decimated by ``simplify``.
44
+ - ``missing``: ``break`` ends a run at a missing value (NaN, ``None``, or outside the
45
+ axis scale's domain); runs are drawn on their own and a one-point run draws nothing.
46
+ ``skip`` connects the points on either side.
47
+
48
+ Example::
49
+
50
+ import math
51
+ x = [i / 10 for i in range(64)]
52
+ p = plt.Plot(width=240, height=160)
53
+ p.line(x, [math.sin(v) for v in x], name="sin")
54
+ p.line(x, [math.cos(v) for v in x], name="cos", interpolation="step-mid")
55
+ """
56
+
57
+ SETTINGS = table(
58
+ **coord_settings(),
59
+ color=Setting(color, doc="Line color; default: the plot's next color."),
60
+ **groups.Stroke.embed(only=("line_width", "line_style", "cap", "join"),
61
+ inherited=("line_width",),
62
+ docs={"line_style": "`solid`, `dashed`, `dotted`, `dashdot` or "
63
+ "a dash list; named styles scale with the "
64
+ "width."}),
65
+ **curve_settings(),
66
+ **groups.Marker.embed("marker_"),
67
+ **common("color_map"),
68
+ x_error=Setting(error_value, doc="Horizontal error bars at the points."),
69
+ y_error=Setting(error_value, doc="Vertical error bars at the points."),
70
+ show_markers=Setting(lambda v: bool(v),
71
+ doc="Draw markers at the points (also turned on by setting "
72
+ "`marker`)."),
73
+ orientation=Setting(one_of("vertical", "horizontal"),
74
+ doc="`vertical` (x along the x axis) or `horizontal` (x along "
75
+ "the y axis)."),
76
+ **common("estimate"),
77
+ interval_style=Setting(one_of("band", "bars"),
78
+ doc="The interval of `estimate`: a `band` (at 0.25 times "
79
+ "`opacity`) or error `bars`."),
80
+ **common("name", "opacity", "z", "rasterize", "simplify", "font_size", "font_family",
81
+ "text_color"),
82
+ )
83
+
84
+ DATA = {"x": "position", "y": "sets"}
85
+
86
+ def __init__(self, x: Any, y: Any = None, plot: Any = None, **settings: Any) -> None:
87
+ self._markers_on = "marker" in settings
88
+ super().__init__(plot=plot, **settings)
89
+
90
+ @property
91
+ def x(self) -> Any:
92
+ """x of the points (categories at their index among their own)."""
93
+ return self.cols["x"]
94
+
95
+ @property
96
+ def ys(self) -> list[array.array]:
97
+ """The lines' y: one column each."""
98
+ return self.cols.values
99
+
100
+ @property
101
+ def y(self) -> array.array:
102
+ return self.ys[0]
103
+
104
+ def set(self, **settings: "Unpack[LineSettings]") -> Self: # type: ignore[override]
105
+ if "marker" in settings:
106
+ self._markers_on = settings["marker"] is not None
107
+ super().set(**settings)
108
+ return self
109
+
110
+ def _markers(self) -> bool:
111
+ return self._markers_on or bool(self.resolve("show_markers"))
112
+
113
+ def density_points(self) -> tuple[Any, Any]:
114
+ """The markers' positions on the plot's axes (a density in ``marker_color``)."""
115
+ if len(self.ys) > 1:
116
+ raise ValueError("Line: a density in marker_color needs a single line (y has "
117
+ f"{len(self.ys)} rows)")
118
+ return xy_density_points(self, self.x, self.ys[0])
119
+
120
+ SPEC = Spec(
121
+ [Lay("errors", ("error_source", {})),
122
+ Lay("band", ("band", {"color": "faded", "opacity": 0.25}), table="interval",
123
+ key=False, occupy=False),
124
+ Lay("path", ("stroke", {"dash": True, "opacity": True,
125
+ "extra": ("cap", "join", "simplify", "interpolation",
126
+ "missing")})),
127
+ Lay("points", ("marker", {"prefix": "marker_", "n": lambda s: len(s.x)}),
128
+ table="markers", when="_markers()", occupy=False, key="first")],
129
+ tables={"data": lambda s, b: Table(x=s.x, y=s.ys if len(s.ys) > 1 else s.ys[0]),
130
+ "interval": lambda s, b: _bands(s),
131
+ "markers": lambda s, b: [Table(x=s.x, y=r) for r in s.ys]},
132
+ key={"fill": "base", "stroke": "base"},
133
+ zero=("y",), color_sources="_markers()")
134
+
135
+
136
+ def _bands(s: Line) -> list[Table] | None:
137
+ """The interval of ``estimate`` as a band per set (``interval_style="band"``)."""
138
+ st = s.stats
139
+ if st is None or s.resolve("interval") is None or s.resolve("interval_style") != "band":
140
+ return None
141
+ return [Table(x=s.x, y1=array.array("d", (m - d for m, d in zip(e, lo))),
142
+ y2=array.array("d", (m + d for m, d in zip(e, hi))))
143
+ for _, e, lo, hi in st["sets"]]