figrecipe 0.5.0__py3-none-any.whl → 0.6.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.
- figrecipe/__init__.py +361 -93
- figrecipe/_dev/__init__.py +120 -0
- figrecipe/_dev/demo_plotters/__init__.py +195 -0
- figrecipe/_dev/demo_plotters/plot_acorr.py +24 -0
- figrecipe/_dev/demo_plotters/plot_angle_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/plot_bar.py +25 -0
- figrecipe/_dev/demo_plotters/plot_barbs.py +30 -0
- figrecipe/_dev/demo_plotters/plot_barh.py +25 -0
- figrecipe/_dev/demo_plotters/plot_boxplot.py +24 -0
- figrecipe/_dev/demo_plotters/plot_cohere.py +29 -0
- figrecipe/_dev/demo_plotters/plot_contour.py +30 -0
- figrecipe/_dev/demo_plotters/plot_contourf.py +29 -0
- figrecipe/_dev/demo_plotters/plot_csd.py +29 -0
- figrecipe/_dev/demo_plotters/plot_ecdf.py +24 -0
- figrecipe/_dev/demo_plotters/plot_errorbar.py +28 -0
- figrecipe/_dev/demo_plotters/plot_eventplot.py +25 -0
- figrecipe/_dev/demo_plotters/plot_fill.py +29 -0
- figrecipe/_dev/demo_plotters/plot_fill_between.py +30 -0
- figrecipe/_dev/demo_plotters/plot_fill_betweenx.py +28 -0
- figrecipe/_dev/demo_plotters/plot_hexbin.py +25 -0
- figrecipe/_dev/demo_plotters/plot_hist.py +24 -0
- figrecipe/_dev/demo_plotters/plot_hist2d.py +25 -0
- figrecipe/_dev/demo_plotters/plot_imshow.py +23 -0
- figrecipe/_dev/demo_plotters/plot_loglog.py +27 -0
- figrecipe/_dev/demo_plotters/plot_magnitude_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/plot_matshow.py +23 -0
- figrecipe/_dev/demo_plotters/plot_pcolor.py +29 -0
- figrecipe/_dev/demo_plotters/plot_pcolormesh.py +29 -0
- figrecipe/_dev/demo_plotters/plot_phase_spectrum.py +28 -0
- figrecipe/_dev/demo_plotters/plot_pie.py +23 -0
- figrecipe/_dev/demo_plotters/plot_plot.py +27 -0
- figrecipe/_dev/demo_plotters/plot_psd.py +29 -0
- figrecipe/_dev/demo_plotters/plot_quiver.py +30 -0
- figrecipe/_dev/demo_plotters/plot_scatter.py +24 -0
- figrecipe/_dev/demo_plotters/plot_semilogx.py +27 -0
- figrecipe/_dev/demo_plotters/plot_semilogy.py +27 -0
- figrecipe/_dev/demo_plotters/plot_specgram.py +30 -0
- figrecipe/_dev/demo_plotters/plot_spy.py +29 -0
- figrecipe/_dev/demo_plotters/plot_stackplot.py +29 -0
- figrecipe/_dev/demo_plotters/plot_stairs.py +27 -0
- figrecipe/_dev/demo_plotters/plot_stem.py +27 -0
- figrecipe/_dev/demo_plotters/plot_step.py +27 -0
- figrecipe/_dev/demo_plotters/plot_streamplot.py +30 -0
- figrecipe/_dev/demo_plotters/plot_tricontour.py +28 -0
- figrecipe/_dev/demo_plotters/plot_tricontourf.py +28 -0
- figrecipe/_dev/demo_plotters/plot_tripcolor.py +29 -0
- figrecipe/_dev/demo_plotters/plot_triplot.py +25 -0
- figrecipe/_dev/demo_plotters/plot_violinplot.py +25 -0
- figrecipe/_dev/demo_plotters/plot_xcorr.py +25 -0
- figrecipe/_editor/__init__.py +230 -0
- figrecipe/_editor/_bbox.py +978 -0
- figrecipe/_editor/_flask_app.py +1229 -0
- figrecipe/_editor/_hitmap.py +937 -0
- figrecipe/_editor/_overrides.py +318 -0
- figrecipe/_editor/_renderer.py +349 -0
- figrecipe/_editor/_templates/__init__.py +75 -0
- figrecipe/_editor/_templates/_html.py +406 -0
- figrecipe/_editor/_templates/_scripts.py +2778 -0
- figrecipe/_editor/_templates/_styles.py +1326 -0
- figrecipe/_params/_DECORATION_METHODS.py +27 -0
- figrecipe/_params/_PLOTTING_METHODS.py +58 -0
- figrecipe/_params/__init__.py +9 -0
- figrecipe/_recorder.py +126 -73
- figrecipe/_reproducer.py +658 -41
- figrecipe/_seaborn.py +14 -9
- figrecipe/_serializer.py +2 -2
- figrecipe/_signatures/README.md +68 -0
- figrecipe/_signatures/__init__.py +12 -2
- figrecipe/_signatures/_loader.py +515 -56
- figrecipe/_utils/__init__.py +6 -4
- figrecipe/_utils/_crop.py +10 -4
- figrecipe/_utils/_image_diff.py +37 -33
- figrecipe/_utils/_numpy_io.py +0 -1
- figrecipe/_utils/_units.py +11 -3
- figrecipe/_validator.py +12 -3
- figrecipe/_wrappers/_axes.py +860 -46
- figrecipe/_wrappers/_figure.py +115 -18
- figrecipe/plt.py +0 -1
- figrecipe/pyplot.py +2 -1
- figrecipe/styles/__init__.py +9 -10
- figrecipe/styles/_style_applier.py +332 -28
- figrecipe/styles/_style_loader.py +172 -44
- figrecipe/styles/presets/MATPLOTLIB.yaml +94 -0
- figrecipe/styles/presets/SCITEX.yaml +176 -0
- figrecipe-0.6.0.dist-info/METADATA +394 -0
- figrecipe-0.6.0.dist-info/RECORD +90 -0
- figrecipe-0.5.0.dist-info/METADATA +0 -336
- figrecipe-0.5.0.dist-info/RECORD +0 -26
- {figrecipe-0.5.0.dist-info → figrecipe-0.6.0.dist-info}/WHEEL +0 -0
- {figrecipe-0.5.0.dist-info → figrecipe-0.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-23 09:55:04 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/figrecipe/src/figrecipe/DECORATION_METHODS.py
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
"""Top-level docstring here"""
|
|
8
|
+
|
|
9
|
+
DECORATION_METHODS = {
|
|
10
|
+
"set_xlabel",
|
|
11
|
+
"set_ylabel",
|
|
12
|
+
"set_title",
|
|
13
|
+
"set_xlim",
|
|
14
|
+
"set_ylim",
|
|
15
|
+
"set_aspect",
|
|
16
|
+
"legend",
|
|
17
|
+
"grid",
|
|
18
|
+
"axhline",
|
|
19
|
+
"axvline",
|
|
20
|
+
"axhspan",
|
|
21
|
+
"axvspan",
|
|
22
|
+
"text",
|
|
23
|
+
"annotate",
|
|
24
|
+
"clabel",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# EOF
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-23 09:55:10 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/figrecipe/src/figrecipe/PLOTTING_METHODS.py
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
"""Top-level docstring here"""
|
|
8
|
+
|
|
9
|
+
PLOTTING_METHODS = {
|
|
10
|
+
"plot",
|
|
11
|
+
"scatter",
|
|
12
|
+
"bar",
|
|
13
|
+
"barh",
|
|
14
|
+
"hist",
|
|
15
|
+
"hist2d",
|
|
16
|
+
"boxplot",
|
|
17
|
+
"violinplot",
|
|
18
|
+
"pie",
|
|
19
|
+
"errorbar",
|
|
20
|
+
"fill",
|
|
21
|
+
"fill_between",
|
|
22
|
+
"fill_betweenx",
|
|
23
|
+
"stackplot",
|
|
24
|
+
"stem",
|
|
25
|
+
"step",
|
|
26
|
+
"imshow",
|
|
27
|
+
"pcolor",
|
|
28
|
+
"pcolormesh",
|
|
29
|
+
"contour",
|
|
30
|
+
"contourf",
|
|
31
|
+
"quiver",
|
|
32
|
+
"barbs",
|
|
33
|
+
"streamplot",
|
|
34
|
+
"hexbin",
|
|
35
|
+
"tripcolor",
|
|
36
|
+
"triplot",
|
|
37
|
+
"tricontour",
|
|
38
|
+
"tricontourf",
|
|
39
|
+
"eventplot",
|
|
40
|
+
"stairs",
|
|
41
|
+
"ecdf",
|
|
42
|
+
"matshow",
|
|
43
|
+
"spy",
|
|
44
|
+
"loglog",
|
|
45
|
+
"semilogx",
|
|
46
|
+
"semilogy",
|
|
47
|
+
"acorr",
|
|
48
|
+
"xcorr",
|
|
49
|
+
"specgram",
|
|
50
|
+
"psd",
|
|
51
|
+
"csd",
|
|
52
|
+
"cohere",
|
|
53
|
+
"angle_spectrum",
|
|
54
|
+
"magnitude_spectrum",
|
|
55
|
+
"phase_spectrum",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# EOF
|
figrecipe/_recorder.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-23 09:57:28 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/figrecipe/src/figrecipe/_recorder.py
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
"""Core recording functionality for figrecipe."""
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
import uuid
|
|
6
10
|
from dataclasses import dataclass, field
|
|
7
11
|
from datetime import datetime
|
|
8
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
9
|
-
import uuid
|
|
10
13
|
|
|
11
14
|
import matplotlib
|
|
12
15
|
import numpy as np
|
|
@@ -34,7 +37,9 @@ class CallRecord:
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
@classmethod
|
|
37
|
-
def from_dict(
|
|
40
|
+
def from_dict(
|
|
41
|
+
cls, data: Dict[str, Any], ax_position: Tuple[int, int] = (0, 0)
|
|
42
|
+
) -> "CallRecord":
|
|
38
43
|
"""Create from dictionary."""
|
|
39
44
|
return cls(
|
|
40
45
|
id=data["id"],
|
|
@@ -86,6 +91,10 @@ class FigureRecord:
|
|
|
86
91
|
style: Optional[Dict[str, Any]] = None
|
|
87
92
|
# Constrained layout flag
|
|
88
93
|
constrained_layout: bool = False
|
|
94
|
+
# Figure-level decorations (suptitle, supxlabel, supylabel)
|
|
95
|
+
suptitle: Optional[Dict[str, Any]] = None
|
|
96
|
+
supxlabel: Optional[Dict[str, Any]] = None
|
|
97
|
+
supylabel: Optional[Dict[str, Any]] = None
|
|
89
98
|
|
|
90
99
|
def get_axes_key(self, row: int, col: int) -> str:
|
|
91
100
|
"""Get dictionary key for axes at position."""
|
|
@@ -120,6 +129,15 @@ class FigureRecord:
|
|
|
120
129
|
# Add constrained_layout if True
|
|
121
130
|
if self.constrained_layout:
|
|
122
131
|
result["figure"]["constrained_layout"] = True
|
|
132
|
+
# Add suptitle if set
|
|
133
|
+
if self.suptitle is not None:
|
|
134
|
+
result["figure"]["suptitle"] = self.suptitle
|
|
135
|
+
# Add supxlabel if set
|
|
136
|
+
if self.supxlabel is not None:
|
|
137
|
+
result["figure"]["supxlabel"] = self.supxlabel
|
|
138
|
+
# Add supylabel if set
|
|
139
|
+
if self.supylabel is not None:
|
|
140
|
+
result["figure"]["supylabel"] = self.supylabel
|
|
123
141
|
return result
|
|
124
142
|
|
|
125
143
|
@classmethod
|
|
@@ -135,6 +153,9 @@ class FigureRecord:
|
|
|
135
153
|
layout=fig_data.get("layout"),
|
|
136
154
|
style=fig_data.get("style"),
|
|
137
155
|
constrained_layout=fig_data.get("constrained_layout", False),
|
|
156
|
+
suptitle=fig_data.get("suptitle"),
|
|
157
|
+
supxlabel=fig_data.get("supxlabel"),
|
|
158
|
+
supylabel=fig_data.get("supylabel"),
|
|
138
159
|
)
|
|
139
160
|
|
|
140
161
|
# Reconstruct axes
|
|
@@ -160,26 +181,7 @@ class FigureRecord:
|
|
|
160
181
|
class Recorder:
|
|
161
182
|
"""Central recorder for tracking matplotlib calls."""
|
|
162
183
|
|
|
163
|
-
|
|
164
|
-
PLOTTING_METHODS = {
|
|
165
|
-
"plot", "scatter", "bar", "barh", "hist", "hist2d",
|
|
166
|
-
"boxplot", "violinplot", "pie", "errorbar", "fill",
|
|
167
|
-
"fill_between", "fill_betweenx", "stackplot", "stem",
|
|
168
|
-
"step", "imshow", "pcolor", "pcolormesh", "contour",
|
|
169
|
-
"contourf", "quiver", "barbs", "streamplot", "hexbin",
|
|
170
|
-
"tripcolor", "triplot", "tricontour", "tricontourf",
|
|
171
|
-
"eventplot", "stairs", "ecdf", "matshow", "spy",
|
|
172
|
-
"loglog", "semilogx", "semilogy", "acorr", "xcorr",
|
|
173
|
-
"specgram", "psd", "csd", "cohere", "angle_spectrum",
|
|
174
|
-
"magnitude_spectrum", "phase_spectrum",
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
# Decoration methods
|
|
178
|
-
DECORATION_METHODS = {
|
|
179
|
-
"set_xlabel", "set_ylabel", "set_title", "set_xlim",
|
|
180
|
-
"set_ylim", "legend", "grid", "axhline", "axvline",
|
|
181
|
-
"axhspan", "axvspan", "text", "annotate",
|
|
182
|
-
}
|
|
184
|
+
from ._params import DECORATION_METHODS, PLOTTING_METHODS
|
|
183
185
|
|
|
184
186
|
def __init__(self):
|
|
185
187
|
self._figure_record: Optional[FigureRecord] = None
|
|
@@ -291,53 +293,93 @@ class Recorder:
|
|
|
291
293
|
arg_names = self._get_arg_names(method_name, len(args))
|
|
292
294
|
|
|
293
295
|
for i, (name, value) in enumerate(zip(arg_names, args)):
|
|
296
|
+
# Handle result references (e.g., ContourSet for clabel)
|
|
297
|
+
if isinstance(value, dict) and "__ref__" in value:
|
|
298
|
+
processed.append(
|
|
299
|
+
{
|
|
300
|
+
"name": name,
|
|
301
|
+
"data": {"__ref__": value["__ref__"]},
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
continue
|
|
305
|
+
|
|
294
306
|
if isinstance(value, np.ndarray):
|
|
295
307
|
if should_store_inline(value):
|
|
296
|
-
processed.append(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
308
|
+
processed.append(
|
|
309
|
+
{
|
|
310
|
+
"name": name,
|
|
311
|
+
"data": to_serializable(value),
|
|
312
|
+
"dtype": str(value.dtype),
|
|
313
|
+
}
|
|
314
|
+
)
|
|
301
315
|
else:
|
|
302
316
|
# Mark for file storage (will be handled by serializer)
|
|
303
|
-
processed.append(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
processed.append(
|
|
318
|
+
{
|
|
319
|
+
"name": name,
|
|
320
|
+
"data": "__FILE__",
|
|
321
|
+
"dtype": str(value.dtype),
|
|
322
|
+
"_array": value, # Temporary, removed during serialization
|
|
323
|
+
}
|
|
324
|
+
)
|
|
309
325
|
elif hasattr(value, "values"): # pandas
|
|
310
326
|
arr = np.asarray(value)
|
|
311
327
|
if should_store_inline(arr):
|
|
312
|
-
processed.append(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
328
|
+
processed.append(
|
|
329
|
+
{
|
|
330
|
+
"name": name,
|
|
331
|
+
"data": to_serializable(arr),
|
|
332
|
+
"dtype": str(arr.dtype),
|
|
333
|
+
}
|
|
334
|
+
)
|
|
317
335
|
else:
|
|
318
|
-
processed.append(
|
|
336
|
+
processed.append(
|
|
337
|
+
{
|
|
338
|
+
"name": name,
|
|
339
|
+
"data": "__FILE__",
|
|
340
|
+
"dtype": str(arr.dtype),
|
|
341
|
+
"_array": arr,
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
elif (
|
|
345
|
+
isinstance(value, (list, tuple))
|
|
346
|
+
and len(value) > 0
|
|
347
|
+
and isinstance(value[0], np.ndarray)
|
|
348
|
+
):
|
|
349
|
+
# List of arrays (e.g., boxplot, violinplot data)
|
|
350
|
+
arrays_data = [to_serializable(arr) for arr in value]
|
|
351
|
+
dtypes = [str(arr.dtype) for arr in value]
|
|
352
|
+
processed.append(
|
|
353
|
+
{
|
|
319
354
|
"name": name,
|
|
320
|
-
"data":
|
|
321
|
-
"dtype":
|
|
322
|
-
"
|
|
323
|
-
}
|
|
355
|
+
"data": arrays_data,
|
|
356
|
+
"dtype": (dtypes[0] if len(set(dtypes)) == 1 else dtypes),
|
|
357
|
+
"_is_array_list": True,
|
|
358
|
+
}
|
|
359
|
+
)
|
|
324
360
|
else:
|
|
325
361
|
# Scalar or other serializable value
|
|
326
362
|
try:
|
|
327
|
-
processed.append(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
363
|
+
processed.append(
|
|
364
|
+
{
|
|
365
|
+
"name": name,
|
|
366
|
+
"data": (
|
|
367
|
+
value if self._is_serializable(value) else str(value)
|
|
368
|
+
),
|
|
369
|
+
}
|
|
370
|
+
)
|
|
331
371
|
except (TypeError, ValueError):
|
|
332
|
-
processed.append(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
372
|
+
processed.append(
|
|
373
|
+
{
|
|
374
|
+
"name": name,
|
|
375
|
+
"data": str(value),
|
|
376
|
+
}
|
|
377
|
+
)
|
|
336
378
|
|
|
337
379
|
return processed
|
|
338
380
|
|
|
339
381
|
def _get_arg_names(self, method_name: str, n_args: int) -> List[str]:
|
|
340
|
-
"""Get argument names for a method.
|
|
382
|
+
"""Get argument names for a method from signatures.
|
|
341
383
|
|
|
342
384
|
Parameters
|
|
343
385
|
----------
|
|
@@ -351,31 +393,18 @@ class Recorder:
|
|
|
351
393
|
list
|
|
352
394
|
List of argument names.
|
|
353
395
|
"""
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
"plot": ["x", "y", "fmt"],
|
|
357
|
-
"scatter": ["x", "y", "s", "c"],
|
|
358
|
-
"bar": ["x", "height", "width", "bottom"],
|
|
359
|
-
"barh": ["y", "width", "height", "left"],
|
|
360
|
-
"hist": ["x", "bins"],
|
|
361
|
-
"imshow": ["X"],
|
|
362
|
-
"contour": ["X", "Y", "Z", "levels"],
|
|
363
|
-
"contourf": ["X", "Y", "Z", "levels"],
|
|
364
|
-
"fill_between": ["x", "y1", "y2"],
|
|
365
|
-
"errorbar": ["x", "y", "yerr", "xerr"],
|
|
366
|
-
"text": ["x", "y", "s"],
|
|
367
|
-
"annotate": ["text", "xy", "xytext"],
|
|
368
|
-
}
|
|
396
|
+
try:
|
|
397
|
+
from ._signatures import get_signature
|
|
369
398
|
|
|
370
|
-
|
|
371
|
-
names =
|
|
399
|
+
sig = get_signature(method_name)
|
|
400
|
+
names = [arg["name"] for arg in sig["args"][:n_args]]
|
|
372
401
|
# Pad with generic names if needed
|
|
373
402
|
while len(names) < n_args:
|
|
374
403
|
names.append(f"arg{len(names)}")
|
|
375
404
|
return names
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
405
|
+
except Exception:
|
|
406
|
+
# Fallback to generic names
|
|
407
|
+
return [f"arg{i}" for i in range(n_args)]
|
|
379
408
|
|
|
380
409
|
def _process_kwargs(
|
|
381
410
|
self,
|
|
@@ -384,6 +413,8 @@ class Recorder:
|
|
|
384
413
|
) -> Dict[str, Any]:
|
|
385
414
|
"""Process keyword arguments for storage.
|
|
386
415
|
|
|
416
|
+
Only stores non-default kwargs to keep recipes minimal.
|
|
417
|
+
|
|
387
418
|
Parameters
|
|
388
419
|
----------
|
|
389
420
|
kwargs : dict
|
|
@@ -396,6 +427,15 @@ class Recorder:
|
|
|
396
427
|
dict
|
|
397
428
|
Processed kwargs (non-default only).
|
|
398
429
|
"""
|
|
430
|
+
# Get defaults from signature
|
|
431
|
+
defaults = {}
|
|
432
|
+
try:
|
|
433
|
+
from ._signatures import get_defaults
|
|
434
|
+
|
|
435
|
+
defaults = get_defaults(method_name)
|
|
436
|
+
except Exception:
|
|
437
|
+
pass
|
|
438
|
+
|
|
399
439
|
# Remove internal keys
|
|
400
440
|
skip_keys = {"id", "track", "_array"}
|
|
401
441
|
processed = {}
|
|
@@ -404,6 +444,16 @@ class Recorder:
|
|
|
404
444
|
if key in skip_keys:
|
|
405
445
|
continue
|
|
406
446
|
|
|
447
|
+
# Skip if value matches default
|
|
448
|
+
if key in defaults:
|
|
449
|
+
default_val = defaults[key]
|
|
450
|
+
# Compare values (handle None specially)
|
|
451
|
+
if default_val is not None and value == default_val:
|
|
452
|
+
continue
|
|
453
|
+
# Also skip if both are None
|
|
454
|
+
if default_val is None and value is None:
|
|
455
|
+
continue
|
|
456
|
+
|
|
407
457
|
if self._is_serializable(value):
|
|
408
458
|
processed[key] = value
|
|
409
459
|
elif isinstance(value, np.ndarray):
|
|
@@ -433,3 +483,6 @@ class Recorder:
|
|
|
433
483
|
for k, v in value.items()
|
|
434
484
|
)
|
|
435
485
|
return False
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
# EOF
|