plotlet 0.2.0__py3-none-any.whl → 0.3.0__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.
plotlet/__init__.py CHANGED
@@ -1,29 +1,33 @@
1
1
  """plotlet — pure-Python SVG renderer, matplotlib-flavored.
2
2
 
3
- Tabular API (recommended):
4
-
5
3
  import plotlet as pt
6
4
  c = pt.chart(df, title="...", xlabel="x", ylabel="y", legend=True, grid=True)
7
5
  c.line(x="time", y="value", hue="series")
8
6
  c # auto-renders in Jupyter
9
7
 
10
- Chained API (legacy, still supported):
8
+ For non-tabular use, the chained form works directly on the same Chart:
11
9
 
12
- fig = pt.figure()
13
- fig.plot([1, 2, 3], [1, 4, 9], label="squares")
14
- fig.title("Hello").legend().grid(True)
15
- fig
10
+ c = pt.chart()
11
+ c.plot([1, 2, 3], [1, 4, 9], label="squares")
12
+ c.title("Hello").legend().grid(True)
13
+ c
16
14
  """
17
15
  from ._spec import SPEC
18
16
  from .colors import TAB10, colors
19
17
  from .colormaps import colormap, list_colormaps
20
- from .core import Figure, figure
21
18
  from .chart import Chart, chart
22
19
  from .layout import grid
23
20
  from .legend import legend
24
21
  from .registry import ArtistSpec, add_artist
22
+ from .layout_diagram import layout_diagram
25
23
 
26
- __all__ = ["chart", "Chart", "figure", "Figure", "SPEC", "TAB10", "colors",
24
+ __all__ = ["chart", "Chart", "SPEC", "TAB10", "colors",
27
25
  "colormap", "list_colormaps", "grid", "legend",
28
- "ArtistSpec", "add_artist"]
29
- __version__ = "0.2.0"
26
+ "ArtistSpec", "add_artist", "layout_diagram"]
27
+
28
+ # Single source of truth: pyproject.toml. importlib.metadata reads it at
29
+ # runtime from the installed package metadata (works for `pip install` and
30
+ # `pip install -e .` alike). Migrating to setuptools_scm later doesn't
31
+ # touch this code — it just changes how pyproject.toml's version is set.
32
+ from importlib.metadata import version as _pkg_version
33
+ __version__ = _pkg_version("plotlet")
@@ -79,6 +79,98 @@ def _refspan_legend_swatch(a, ctx, x0, y_mid):
79
79
  return _rect_swatch(a, x0, y_mid, ctx.defaults["refspan_alpha"])
80
80
 
81
81
 
82
+ # --- AI-readable structural attrs + payloads (0.3.0) ------------------------
83
+ # Each helper computes type-specific attrs from the recorded artist dict.
84
+ # The wrapper in core._wrap_artist supplies the common attrs (type, index,
85
+ # label, color); these add the per-artist fields. Returned dict keys map
86
+ # 1:1 to `data-plotlet-<key>` attribute names.
87
+
88
+ def _xy_minmax(xs, ys):
89
+ """Min/max for an x/y series, ignoring NaN. Returns dict ready to merge
90
+ into a data_attrs result."""
91
+ fxs = [x for x in xs if isinstance(x, (int, float)) and x == x]
92
+ fys = [y for y in ys if isinstance(y, (int, float)) and y == y]
93
+ out = {}
94
+ if fxs:
95
+ out["x-min"] = min(fxs)
96
+ out["x-max"] = max(fxs)
97
+ if fys:
98
+ out["y-min"] = min(fys)
99
+ out["y-max"] = max(fys)
100
+ return out
101
+
102
+
103
+ def _plot_data_attrs(a):
104
+ out = {"n": len(a["xs"])}
105
+ out.update(_xy_minmax(a["xs"], a["ys"]))
106
+ if a["opts"].get("linestyle"):
107
+ out["linestyle"] = a["opts"]["linestyle"]
108
+ if a["opts"].get("marker"):
109
+ out["marker"] = a["opts"]["marker"]
110
+ return out
111
+
112
+
113
+ def _scatter_data_attrs(a):
114
+ out = {"n": len(a["xs"])}
115
+ out.update(_xy_minmax(a["xs"], a["ys"]))
116
+ out["marker"] = a["opts"].get("marker", "o")
117
+ return out
118
+
119
+
120
+ def _bar_data_attrs(a):
121
+ fvals = [v for v in a["vals"] if isinstance(v, (int, float)) and v == v]
122
+ out = {"n": len(a["cats"])}
123
+ if fvals:
124
+ out["y-min"] = min(fvals)
125
+ out["y-max"] = max(fvals)
126
+ return out
127
+
128
+
129
+ def _hist_data_attrs(a):
130
+ raw = a["data"]
131
+ out = {"n": len(raw), "bins": len(a.get("_bins", [])) or a["opts"].get("bins", 10)}
132
+ bins = a.get("_bins") or []
133
+ if bins:
134
+ out["x-min"] = bins[0]["x0"]
135
+ out["x-max"] = bins[-1]["x1"]
136
+ out["count-max"] = max(b["count"] for b in bins)
137
+ return out
138
+
139
+
140
+ def _fill_between_data_attrs(a):
141
+ ys_all = list(a["y1"]) + list(a["y2"])
142
+ out = {"n": len(a["xs"])}
143
+ out.update(_xy_minmax(a["xs"], ys_all))
144
+ return out
145
+
146
+
147
+ def _axhline_data_attrs(a): return {"y": a["y"]}
148
+ def _axvline_data_attrs(a): return {"x": a["x"]}
149
+ def _axhspan_data_attrs(a): return {"ymin": a["ymin"], "ymax": a["ymax"]}
150
+ def _axvspan_data_attrs(a): return {"xmin": a["xmin"], "xmax": a["xmax"]}
151
+
152
+
153
+ def _imshow_data_attrs(a):
154
+ out = {
155
+ "rows": a["_nrows"],
156
+ "cols": a["_ncols"],
157
+ "vmin": a["_vmin"],
158
+ "vmax": a["_vmax"],
159
+ "cmap": a["opts"].get("cmap", _D["default_cmap"]),
160
+ # imshow is always raster (PNG-embedded above the rect threshold,
161
+ # individual <rect>s below). The flag is here so AI tools know
162
+ # which decoding strategy they're looking at.
163
+ "data-encoding": "png-embedded" if (a["_nrows"] * a["_ncols"]
164
+ > _D["imshow_max_rects"]) else "rects",
165
+ }
166
+ extent = a["opts"].get("extent")
167
+ if extent is not None:
168
+ out["extent"] = ",".join(repr(float(v)) for v in extent)
169
+ return out
170
+
171
+
172
+
173
+
82
174
  # --- plot (line) ------------------------------------------------------------
83
175
 
84
176
  add_artist(ArtistSpec(
@@ -89,6 +181,7 @@ add_artist(ArtistSpec(
89
181
  ydomain=_ys_of,
90
182
  draw=lambda a, ctx: _artist_plot(a, ctx.x_scale, ctx.y_scale, ctx.color),
91
183
  legend_swatch=_plot_legend_swatch,
184
+ data_attrs=_plot_data_attrs,
92
185
  ))
93
186
 
94
187
 
@@ -102,6 +195,7 @@ add_artist(ArtistSpec(
102
195
  ydomain=_ys_of,
103
196
  draw=lambda a, ctx: _artist_scatter(a, ctx.x_scale, ctx.y_scale, ctx.color),
104
197
  legend_swatch=_scatter_legend_swatch,
198
+ data_attrs=_scatter_data_attrs,
105
199
  ))
106
200
 
107
201
 
@@ -117,6 +211,7 @@ add_artist(ArtistSpec(
117
211
  ydomain=_vals_of,
118
212
  draw=lambda a, ctx: _artist_bar(a, ctx.x_scale, ctx.y_scale, ctx.color),
119
213
  legend_swatch=_bar_legend_swatch,
214
+ data_attrs=_bar_data_attrs,
120
215
  ))
121
216
 
122
217
 
@@ -129,6 +224,7 @@ add_artist(ArtistSpec(
129
224
  ydomain=_bin_ys,
130
225
  draw=lambda a, ctx: _artist_hist(a, ctx.x_scale, ctx.y_scale, ctx.ih, ctx.color),
131
226
  legend_swatch=_bar_legend_swatch,
227
+ data_attrs=_hist_data_attrs,
132
228
  ))
133
229
 
134
230
 
@@ -145,6 +241,7 @@ add_artist(ArtistSpec(
145
241
  ydomain=_y1y2_of,
146
242
  draw=lambda a, ctx: _artist_fill_between(a, ctx.x_scale, ctx.y_scale, ctx.color),
147
243
  legend_swatch=_plot_legend_swatch,
244
+ data_attrs=_fill_between_data_attrs,
148
245
  ))
149
246
 
150
247
 
@@ -160,6 +257,7 @@ add_artist(ArtistSpec(
160
257
  uses_color_cycle=False,
161
258
  default_color=_D["refline_color"],
162
259
  legend_swatch=_refline_legend_swatch,
260
+ data_attrs=_axhline_data_attrs,
163
261
  ))
164
262
 
165
263
  add_artist(ArtistSpec(
@@ -171,6 +269,7 @@ add_artist(ArtistSpec(
171
269
  uses_color_cycle=False,
172
270
  default_color=_D["refline_color"],
173
271
  legend_swatch=_refline_legend_swatch,
272
+ data_attrs=_axvline_data_attrs,
174
273
  ))
175
274
 
176
275
  add_artist(ArtistSpec(
@@ -182,6 +281,7 @@ add_artist(ArtistSpec(
182
281
  uses_color_cycle=False,
183
282
  default_color=_D["refspan_color"],
184
283
  legend_swatch=_refspan_legend_swatch,
284
+ data_attrs=_axhspan_data_attrs,
185
285
  ))
186
286
 
187
287
  add_artist(ArtistSpec(
@@ -193,6 +293,7 @@ add_artist(ArtistSpec(
193
293
  uses_color_cycle=False,
194
294
  default_color=_D["refspan_color"],
195
295
  legend_swatch=_refspan_legend_swatch,
296
+ data_attrs=_axvspan_data_attrs,
196
297
  ))
197
298
 
198
299
 
@@ -251,4 +352,5 @@ add_artist(ArtistSpec(
251
352
  draw=lambda a, ctx: _artist_imshow(a, ctx.x_scale, ctx.y_scale, None),
252
353
  legend_gradient=_imshow_legend_gradient,
253
354
  uses_color_cycle=False,
355
+ data_attrs=_imshow_data_attrs,
254
356
  ))