scitex 2.15.3__py3-none-any.whl → 2.15.5__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.
- scitex/_mcp_resources/__init__.py +2 -0
- scitex/_mcp_resources/_scholar.py +148 -0
- scitex/_mcp_tools/canvas.py +49 -15
- scitex/_mcp_tools/scholar.py +50 -99
- scitex/canvas/__init__.py +169 -287
- scitex/canvas/_legacy.py +171 -0
- scitex/canvas/mcp_server.py +16 -3
- scitex/capture/mcp_server.py +16 -2
- scitex/cli/scholar/__init__.py +55 -28
- scitex/cli/scholar/_crossref_scitex.py +25 -266
- scitex/cli/scholar/_openalex_scitex.py +55 -0
- scitex/scholar/__init__.py +14 -9
- scitex/scholar/_mcp/crossref_tool_schemas.py +133 -0
- scitex/scholar/_mcp/openalex_handlers.py +212 -0
- scitex/scholar/_mcp/openalex_tool_schemas.py +96 -0
- scitex/scholar/_mcp/tool_schemas.py +16 -1
- scitex/scholar/local_dbs/__init__.py +31 -0
- scitex/scholar/local_dbs/crossref_scitex.py +30 -0
- scitex/scholar/local_dbs/openalex_scitex.py +30 -0
- scitex/scholar/mcp_server.py +59 -4
- scitex/stats/mcp_server.py +16 -3
- scitex/template/mcp_server.py +16 -3
- scitex/ui/mcp_server.py +16 -3
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/METADATA +1 -1
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/RECORD +28 -20
- scitex/scholar/crossref_scitex.py +0 -367
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/WHEEL +0 -0
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/entry_points.txt +0 -0
- {scitex-2.15.3.dist-info → scitex-2.15.5.dist-info}/licenses/LICENSE +0 -0
scitex/canvas/__init__.py
CHANGED
|
@@ -1,338 +1,220 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp:
|
|
3
|
-
# File:
|
|
2
|
+
# Timestamp: 2026-01-29
|
|
3
|
+
# File: src/scitex/canvas/__init__.py
|
|
4
4
|
"""
|
|
5
|
-
SciTeX
|
|
5
|
+
SciTeX Canvas Module (DEPRECATED)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
.. deprecated:: 2.16.0
|
|
8
|
+
This module is deprecated. Use figrecipe instead:
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- Figure: Reserved for matplotlib's fig object (see scitex.plt)
|
|
10
|
+
- Interactive editor: ``figrecipe.edit()`` (browser GUI at port 5050)
|
|
11
|
+
- Multi-panel composition: ``figrecipe.compose()``
|
|
12
|
+
- Save/reproduce: ``figrecipe.save()`` / ``figrecipe.reproduce()``
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
-----------
|
|
16
|
-
>>> import scitex as stx
|
|
17
|
-
>>>
|
|
18
|
-
>>> # Create canvas and add panels
|
|
19
|
-
>>> stx.vis.create_canvas("/output", "fig1")
|
|
20
|
-
>>> stx.vis.add_panel("/output", "fig1", "panel_a", source="plot.png",
|
|
21
|
-
... xy_mm=(10, 10), size_mm=(80, 60), label="A")
|
|
22
|
-
>>>
|
|
23
|
-
>>> # Save with stx.io (auto-exports PNG/PDF/SVG)
|
|
24
|
-
>>> canvas = stx.io.load("/output/fig1.canvas")
|
|
25
|
-
>>> stx.io.save(canvas, "/output/fig1_copy.canvas")
|
|
14
|
+
Install: ``pip install figrecipe``
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
-------------------
|
|
29
|
-
{parent_dir}/{canvas_name}.canvas/
|
|
30
|
-
├── canvas.json # Layout, panels, composition
|
|
31
|
-
├── panels/ # Panel directories
|
|
32
|
-
└── exports/ # canvas.png, canvas.pdf, canvas.svg
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
# Submodules for advanced use
|
|
36
|
-
from . import backend, editor, io, model, utils
|
|
16
|
+
Migration examples::
|
|
37
17
|
|
|
38
|
-
#
|
|
39
|
-
from .canvas import
|
|
18
|
+
# Old (scitex.canvas)
|
|
19
|
+
from scitex.canvas import edit
|
|
20
|
+
edit(fig)
|
|
40
21
|
|
|
41
|
-
#
|
|
42
|
-
|
|
22
|
+
# New (figrecipe)
|
|
23
|
+
import figrecipe as fr
|
|
24
|
+
fr.edit(fig)
|
|
43
25
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# Primary API (minimal, reusable, flexible)
|
|
48
|
-
# =============================================================================
|
|
49
|
-
# Canvas operations
|
|
50
|
-
# Panel operations
|
|
51
|
-
from .io import add_panel_from_image, add_panel_from_scitex
|
|
52
|
-
from .io import canvas_directory_exists as canvas_exists
|
|
53
|
-
from .io import delete_canvas_directory as delete_canvas
|
|
54
|
-
from .io import ensure_canvas_directory as create_canvas
|
|
55
|
-
from .io import export_canvas_to_file as export_canvas
|
|
56
|
-
from .io import get_canvas_directory_path as get_canvas_path
|
|
57
|
-
from .io import list_canvas_directories as list_canvases
|
|
58
|
-
from .io import list_panels, remove_panel, update_panel
|
|
59
|
-
from .io import verify_all_data_hashes as verify_data
|
|
26
|
+
# Old (scitex.canvas multi-panel)
|
|
27
|
+
stx.canvas.create_canvas(...)
|
|
28
|
+
stx.canvas.add_panel(...)
|
|
60
29
|
|
|
30
|
+
# New (figrecipe.compose)
|
|
31
|
+
fig, axes = fr.compose(
|
|
32
|
+
sources={
|
|
33
|
+
"panel_a.png": {"xy_mm": (10, 10), "size_mm": (80, 60)},
|
|
34
|
+
"panel_b.png": {"xy_mm": (100, 10), "size_mm": (80, 60)},
|
|
35
|
+
},
|
|
36
|
+
canvas_size_mm=(190, 80),
|
|
37
|
+
panel_labels=True,
|
|
38
|
+
)
|
|
39
|
+
"""
|
|
61
40
|
|
|
62
|
-
|
|
63
|
-
# Convenience wrapper for add_panel
|
|
64
|
-
# =============================================================================
|
|
65
|
-
def add_panel(
|
|
66
|
-
parent_dir,
|
|
67
|
-
canvas_name,
|
|
68
|
-
panel_name,
|
|
69
|
-
source,
|
|
70
|
-
xy_mm=(0, 0),
|
|
71
|
-
size_mm=(50, 50),
|
|
72
|
-
label="",
|
|
73
|
-
bundle=False,
|
|
74
|
-
**kwargs,
|
|
75
|
-
):
|
|
76
|
-
"""
|
|
77
|
-
Add a panel to canvas (auto-detects scitex vs image type).
|
|
41
|
+
from __future__ import annotations
|
|
78
42
|
|
|
79
|
-
|
|
80
|
-
----------
|
|
81
|
-
parent_dir : str or Path
|
|
82
|
-
Parent directory containing canvas
|
|
83
|
-
canvas_name : str
|
|
84
|
-
Canvas name
|
|
85
|
-
panel_name : str
|
|
86
|
-
Name for the panel
|
|
87
|
-
source : str or Path
|
|
88
|
-
Source file (PNG, JPG, SVG)
|
|
89
|
-
xy_mm : tuple
|
|
90
|
-
(x_mm, y_mm) position on canvas in millimeters
|
|
91
|
-
size_mm : tuple
|
|
92
|
-
(width_mm, height_mm) panel size in millimeters
|
|
93
|
-
label : str
|
|
94
|
-
Panel label (A, B, C...)
|
|
95
|
-
bundle : bool
|
|
96
|
-
If True, copy files. If False (default), use symlinks.
|
|
97
|
-
**kwargs
|
|
98
|
-
Additional panel properties (rotation_deg, opacity, flip_h, etc.)
|
|
99
|
-
"""
|
|
100
|
-
from pathlib import Path
|
|
43
|
+
import warnings
|
|
101
44
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# Check if scitex output (has .json/.csv siblings)
|
|
112
|
-
json_sibling = source.parent / f"{source.stem}.json"
|
|
113
|
-
if json_sibling.exists():
|
|
114
|
-
return add_panel_from_scitex(
|
|
115
|
-
project_dir=parent_dir,
|
|
116
|
-
canvas_name=canvas_name,
|
|
117
|
-
panel_name=panel_name,
|
|
118
|
-
source_png=source,
|
|
119
|
-
panel_properties=panel_properties,
|
|
120
|
-
bundle=bundle,
|
|
121
|
-
)
|
|
122
|
-
else:
|
|
123
|
-
return add_panel_from_image(
|
|
124
|
-
project_dir=parent_dir,
|
|
125
|
-
canvas_name=canvas_name,
|
|
126
|
-
panel_name=panel_name,
|
|
127
|
-
source_image=source,
|
|
128
|
-
panel_properties=panel_properties,
|
|
129
|
-
bundle=bundle,
|
|
130
|
-
)
|
|
45
|
+
# Issue deprecation warning on import
|
|
46
|
+
warnings.warn(
|
|
47
|
+
"scitex.canvas is deprecated. Use figrecipe instead:\n"
|
|
48
|
+
" - fr.edit() for interactive GUI editor (port 5050)\n"
|
|
49
|
+
" - fr.compose() for multi-panel composition\n"
|
|
50
|
+
" - pip install figrecipe",
|
|
51
|
+
DeprecationWarning,
|
|
52
|
+
stacklevel=2,
|
|
53
|
+
)
|
|
131
54
|
|
|
132
55
|
|
|
133
56
|
# =============================================================================
|
|
134
|
-
#
|
|
57
|
+
# Delegate to figrecipe (preferred)
|
|
135
58
|
# =============================================================================
|
|
59
|
+
def edit(*args, **kwargs):
|
|
60
|
+
"""Launch interactive GUI editor.
|
|
136
61
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
panels,
|
|
140
|
-
path,
|
|
141
|
-
spec=None,
|
|
142
|
-
as_zip=None,
|
|
143
|
-
):
|
|
144
|
-
"""
|
|
145
|
-
Save panels as a .figure publication figure bundle.
|
|
146
|
-
|
|
147
|
-
Parameters
|
|
148
|
-
----------
|
|
149
|
-
panels : dict
|
|
150
|
-
Dictionary mapping panel IDs to .plot bundle paths or data.
|
|
151
|
-
Example: {"A": "timecourse.plot", "B": "barplot.plot"}
|
|
152
|
-
path : str or Path
|
|
153
|
-
Output path (e.g., "Figure1.figure.zip" or "Figure1.figure").
|
|
154
|
-
- Path ending with ".zip" creates ZIP archive
|
|
155
|
-
- Path ending with ".figure" creates directory bundle
|
|
156
|
-
spec : dict, optional
|
|
157
|
-
Figure specification. Auto-generated if None.
|
|
158
|
-
as_zip : bool, optional
|
|
159
|
-
If True, save as ZIP archive. If False, save as directory.
|
|
160
|
-
Default: auto-detect from path.
|
|
161
|
-
|
|
162
|
-
Returns
|
|
163
|
-
-------
|
|
164
|
-
Path
|
|
165
|
-
Path to saved bundle.
|
|
166
|
-
|
|
167
|
-
Examples
|
|
168
|
-
--------
|
|
169
|
-
>>> import scitex.canvas as sfig
|
|
170
|
-
>>> panels = {
|
|
171
|
-
... "A": "timecourse.plot",
|
|
172
|
-
... "B": "barplot.plot"
|
|
173
|
-
... }
|
|
174
|
-
>>> sfig.save_figure(panels, "Figure1.figure.zip") # Creates ZIP
|
|
175
|
-
>>> sfig.save_figure(panels, "Figure1.figure") # Creates directory
|
|
176
|
-
"""
|
|
177
|
-
import shutil
|
|
178
|
-
from pathlib import Path
|
|
179
|
-
|
|
180
|
-
from scitex.io.bundle import BundleType, save
|
|
181
|
-
|
|
182
|
-
p = Path(path)
|
|
183
|
-
spath = str(path)
|
|
184
|
-
|
|
185
|
-
# Auto-detect as_zip from path suffix if not specified
|
|
186
|
-
if as_zip is None:
|
|
187
|
-
as_zip = spath.endswith(".zip")
|
|
188
|
-
|
|
189
|
-
# Auto-generate spec if not provided
|
|
190
|
-
if spec is None:
|
|
191
|
-
spec = _generate_figure_spec(panels)
|
|
192
|
-
|
|
193
|
-
# Build bundle data - pass source paths directly for file copying
|
|
194
|
-
bundle_data = {
|
|
195
|
-
"spec": spec,
|
|
196
|
-
"plots": {},
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
# Pass source paths directly (not loaded data) to preserve all files
|
|
200
|
-
for panel_id, plot_source in panels.items():
|
|
201
|
-
plot_path = Path(plot_source)
|
|
202
|
-
if plot_path.exists():
|
|
203
|
-
# Store source path for direct copying
|
|
204
|
-
bundle_data["plots"][panel_id] = str(plot_path)
|
|
205
|
-
|
|
206
|
-
return save(bundle_data, p, bundle_type=BundleType.FIGURE, as_zip=as_zip)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def load_figure(path):
|
|
62
|
+
.. deprecated:: 2.16.0
|
|
63
|
+
Use ``figrecipe.edit()`` instead.
|
|
210
64
|
"""
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
65
|
+
warnings.warn(
|
|
66
|
+
"scitex.canvas.edit() is deprecated. Use figrecipe.edit() instead.",
|
|
67
|
+
DeprecationWarning,
|
|
68
|
+
stacklevel=2,
|
|
69
|
+
)
|
|
70
|
+
try:
|
|
71
|
+
import figrecipe as fr
|
|
72
|
+
|
|
73
|
+
return fr.edit(*args, **kwargs)
|
|
74
|
+
except ImportError as e:
|
|
75
|
+
raise ImportError(
|
|
76
|
+
"figrecipe is required for the editor. Install with: pip install figrecipe"
|
|
77
|
+
) from e
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def compose(*args, **kwargs):
|
|
81
|
+
"""Compose multi-panel figures.
|
|
82
|
+
|
|
83
|
+
.. deprecated:: 2.16.0
|
|
84
|
+
Use ``figrecipe.compose()`` instead.
|
|
231
85
|
"""
|
|
232
|
-
|
|
86
|
+
warnings.warn(
|
|
87
|
+
"scitex.canvas.compose() is deprecated. Use figrecipe.compose() instead.",
|
|
88
|
+
DeprecationWarning,
|
|
89
|
+
stacklevel=2,
|
|
90
|
+
)
|
|
91
|
+
try:
|
|
92
|
+
import figrecipe as fr
|
|
233
93
|
|
|
234
|
-
|
|
94
|
+
return fr.compose(*args, **kwargs)
|
|
95
|
+
except ImportError as e:
|
|
96
|
+
raise ImportError(
|
|
97
|
+
"figrecipe is required for composition. Install with: pip install figrecipe"
|
|
98
|
+
) from e
|
|
235
99
|
|
|
236
|
-
if bundle["type"] != "figure":
|
|
237
|
-
raise ValueError(f"Not a .figure bundle: {path}")
|
|
238
100
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
"
|
|
260
|
-
"
|
|
261
|
-
|
|
262
|
-
"title": "",
|
|
263
|
-
"caption": "",
|
|
264
|
-
"styles": {
|
|
265
|
-
"size": {"width_mm": 180, "height_mm": 120},
|
|
266
|
-
"background": "#ffffff",
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
"panels": [],
|
|
101
|
+
# =============================================================================
|
|
102
|
+
# Legacy imports (deprecated, for backward compatibility)
|
|
103
|
+
# =============================================================================
|
|
104
|
+
def __getattr__(name):
|
|
105
|
+
"""Lazy import legacy submodules with deprecation warnings."""
|
|
106
|
+
_legacy_submodules = {"backend", "editor", "io", "model", "utils"}
|
|
107
|
+
_legacy_functions = {
|
|
108
|
+
"Canvas",
|
|
109
|
+
"create_canvas",
|
|
110
|
+
"get_canvas_path",
|
|
111
|
+
"canvas_exists",
|
|
112
|
+
"list_canvases",
|
|
113
|
+
"delete_canvas",
|
|
114
|
+
"add_panel",
|
|
115
|
+
"update_panel",
|
|
116
|
+
"remove_panel",
|
|
117
|
+
"list_panels",
|
|
118
|
+
"export_canvas",
|
|
119
|
+
"verify_data",
|
|
120
|
+
"save_figure",
|
|
121
|
+
"load_figure",
|
|
122
|
+
"add_panel_from_image",
|
|
123
|
+
"add_panel_from_scitex",
|
|
270
124
|
}
|
|
271
125
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
126
|
+
if name in _legacy_submodules:
|
|
127
|
+
warnings.warn(
|
|
128
|
+
f"scitex.canvas.{name} is deprecated. Use figrecipe instead.",
|
|
129
|
+
DeprecationWarning,
|
|
130
|
+
stacklevel=2,
|
|
131
|
+
)
|
|
132
|
+
if name == "backend":
|
|
133
|
+
from . import backend as mod
|
|
134
|
+
elif name == "editor":
|
|
135
|
+
from . import editor as mod
|
|
136
|
+
elif name == "io":
|
|
137
|
+
from . import io as mod
|
|
138
|
+
elif name == "model":
|
|
139
|
+
from . import model as mod
|
|
140
|
+
elif name == "utils":
|
|
141
|
+
from . import utils as mod
|
|
142
|
+
return mod
|
|
143
|
+
|
|
144
|
+
if name in _legacy_functions:
|
|
145
|
+
warnings.warn(
|
|
146
|
+
f"scitex.canvas.{name} is deprecated. Use figrecipe.compose() instead.",
|
|
147
|
+
DeprecationWarning,
|
|
148
|
+
stacklevel=2,
|
|
149
|
+
)
|
|
150
|
+
# Import from legacy locations
|
|
151
|
+
if name == "Canvas":
|
|
152
|
+
from .canvas import Canvas
|
|
153
|
+
|
|
154
|
+
return Canvas
|
|
155
|
+
elif name in {
|
|
156
|
+
"create_canvas",
|
|
157
|
+
"get_canvas_path",
|
|
158
|
+
"canvas_exists",
|
|
159
|
+
"list_canvases",
|
|
160
|
+
"delete_canvas",
|
|
161
|
+
"add_panel_from_image",
|
|
162
|
+
"add_panel_from_scitex",
|
|
163
|
+
"list_panels",
|
|
164
|
+
"remove_panel",
|
|
165
|
+
"update_panel",
|
|
166
|
+
"export_canvas",
|
|
167
|
+
"verify_data",
|
|
168
|
+
}:
|
|
169
|
+
from . import io as _io
|
|
170
|
+
|
|
171
|
+
_name_map = {
|
|
172
|
+
"create_canvas": "ensure_canvas_directory",
|
|
173
|
+
"get_canvas_path": "get_canvas_directory_path",
|
|
174
|
+
"canvas_exists": "canvas_directory_exists",
|
|
175
|
+
"list_canvases": "list_canvas_directories",
|
|
176
|
+
"delete_canvas": "delete_canvas_directory",
|
|
177
|
+
"export_canvas": "export_canvas_to_file",
|
|
178
|
+
"verify_data": "verify_all_data_hashes",
|
|
179
|
+
}
|
|
180
|
+
actual_name = _name_map.get(name, name)
|
|
181
|
+
return getattr(_io, actual_name)
|
|
182
|
+
elif name == "add_panel":
|
|
183
|
+
from ._legacy import add_panel
|
|
290
184
|
|
|
291
|
-
|
|
292
|
-
|
|
185
|
+
return add_panel
|
|
186
|
+
elif name in {"save_figure", "load_figure"}:
|
|
187
|
+
from ._legacy import load_figure, save_figure
|
|
293
188
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
"id": panel_id,
|
|
298
|
-
"label": panel_id,
|
|
299
|
-
"caption": "",
|
|
300
|
-
"plot": f"{panel_id}.plot",
|
|
301
|
-
"position": {"x_mm": x, "y_mm": y},
|
|
302
|
-
"size": {"width_mm": panel_w, "height_mm": panel_h},
|
|
303
|
-
}
|
|
304
|
-
)
|
|
189
|
+
if name == "save_figure":
|
|
190
|
+
return save_figure
|
|
191
|
+
return load_figure
|
|
305
192
|
|
|
306
|
-
|
|
193
|
+
raise AttributeError(f"module 'scitex.canvas' has no attribute '{name}'")
|
|
307
194
|
|
|
308
195
|
|
|
309
196
|
__all__ = [
|
|
310
|
-
#
|
|
197
|
+
# Recommended (delegates to figrecipe)
|
|
198
|
+
"edit",
|
|
199
|
+
"compose",
|
|
200
|
+
# Legacy (deprecated)
|
|
311
201
|
"Canvas",
|
|
312
|
-
# Submodules (advanced)
|
|
313
202
|
"io",
|
|
314
203
|
"model",
|
|
315
204
|
"backend",
|
|
316
205
|
"utils",
|
|
317
206
|
"editor",
|
|
318
|
-
# Canvas operations
|
|
319
207
|
"create_canvas",
|
|
320
208
|
"get_canvas_path",
|
|
321
209
|
"canvas_exists",
|
|
322
210
|
"list_canvases",
|
|
323
211
|
"delete_canvas",
|
|
324
|
-
# Panel operations
|
|
325
212
|
"add_panel",
|
|
326
213
|
"update_panel",
|
|
327
214
|
"remove_panel",
|
|
328
215
|
"list_panels",
|
|
329
|
-
# Export
|
|
330
216
|
"export_canvas",
|
|
331
|
-
# Data integrity
|
|
332
217
|
"verify_data",
|
|
333
|
-
# Editor
|
|
334
|
-
"edit",
|
|
335
|
-
# .figure bundle
|
|
336
218
|
"save_figure",
|
|
337
219
|
"load_figure",
|
|
338
220
|
]
|
scitex/canvas/_legacy.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-29
|
|
3
|
+
# File: src/scitex/canvas/_legacy.py
|
|
4
|
+
"""Legacy functions for backward compatibility.
|
|
5
|
+
|
|
6
|
+
All functions here are deprecated. Use figrecipe instead.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def add_panel(
|
|
16
|
+
parent_dir,
|
|
17
|
+
canvas_name,
|
|
18
|
+
panel_name,
|
|
19
|
+
source,
|
|
20
|
+
xy_mm=(0, 0),
|
|
21
|
+
size_mm=(50, 50),
|
|
22
|
+
label="",
|
|
23
|
+
bundle=False,
|
|
24
|
+
**kwargs,
|
|
25
|
+
):
|
|
26
|
+
"""Add a panel to canvas (DEPRECATED).
|
|
27
|
+
|
|
28
|
+
Use figrecipe.compose() instead.
|
|
29
|
+
"""
|
|
30
|
+
from .io import add_panel_from_image, add_panel_from_scitex
|
|
31
|
+
|
|
32
|
+
source = Path(source)
|
|
33
|
+
panel_properties = {
|
|
34
|
+
"position": {"x_mm": xy_mm[0], "y_mm": xy_mm[1]},
|
|
35
|
+
"size": {"width_mm": size_mm[0], "height_mm": size_mm[1]},
|
|
36
|
+
**kwargs,
|
|
37
|
+
}
|
|
38
|
+
if label:
|
|
39
|
+
panel_properties["label"] = {"text": label, "position": "top-left"}
|
|
40
|
+
|
|
41
|
+
json_sibling = source.parent / f"{source.stem}.json"
|
|
42
|
+
if json_sibling.exists():
|
|
43
|
+
return add_panel_from_scitex(
|
|
44
|
+
project_dir=parent_dir,
|
|
45
|
+
canvas_name=canvas_name,
|
|
46
|
+
panel_name=panel_name,
|
|
47
|
+
source_png=source,
|
|
48
|
+
panel_properties=panel_properties,
|
|
49
|
+
bundle=bundle,
|
|
50
|
+
)
|
|
51
|
+
else:
|
|
52
|
+
return add_panel_from_image(
|
|
53
|
+
project_dir=parent_dir,
|
|
54
|
+
canvas_name=canvas_name,
|
|
55
|
+
panel_name=panel_name,
|
|
56
|
+
source_image=source,
|
|
57
|
+
panel_properties=panel_properties,
|
|
58
|
+
bundle=bundle,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def save_figure(
|
|
63
|
+
panels,
|
|
64
|
+
path,
|
|
65
|
+
spec=None,
|
|
66
|
+
as_zip=None,
|
|
67
|
+
):
|
|
68
|
+
"""Save panels as a .figure bundle (DEPRECATED).
|
|
69
|
+
|
|
70
|
+
Use figrecipe.compose() and figrecipe.save() instead.
|
|
71
|
+
"""
|
|
72
|
+
from scitex.io.bundle import BundleType, save
|
|
73
|
+
|
|
74
|
+
p = Path(path)
|
|
75
|
+
spath = str(path)
|
|
76
|
+
|
|
77
|
+
if as_zip is None:
|
|
78
|
+
as_zip = spath.endswith(".zip")
|
|
79
|
+
|
|
80
|
+
if spec is None:
|
|
81
|
+
spec = _generate_figure_spec(panels)
|
|
82
|
+
|
|
83
|
+
bundle_data = {
|
|
84
|
+
"spec": spec,
|
|
85
|
+
"plots": {},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for panel_id, plot_source in panels.items():
|
|
89
|
+
plot_path = Path(plot_source)
|
|
90
|
+
if plot_path.exists():
|
|
91
|
+
bundle_data["plots"][panel_id] = str(plot_path)
|
|
92
|
+
|
|
93
|
+
return save(bundle_data, p, bundle_type=BundleType.FIGURE, as_zip=as_zip)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def load_figure(path):
|
|
97
|
+
"""Load a .figure bundle (DEPRECATED).
|
|
98
|
+
|
|
99
|
+
Use figrecipe.load() instead.
|
|
100
|
+
"""
|
|
101
|
+
from scitex.io.bundle import load
|
|
102
|
+
|
|
103
|
+
bundle = load(path)
|
|
104
|
+
|
|
105
|
+
if bundle["type"] != "figure":
|
|
106
|
+
raise ValueError(f"Not a .figure bundle: {path}")
|
|
107
|
+
|
|
108
|
+
result = {
|
|
109
|
+
"spec": bundle.get("spec", {}),
|
|
110
|
+
"panels": {},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for panel_id, plot_bundle in bundle.get("plots", {}).items():
|
|
114
|
+
result["panels"][panel_id] = {
|
|
115
|
+
"spec": plot_bundle.get("spec", {}),
|
|
116
|
+
"data": plot_bundle.get("data"),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _generate_figure_spec(panels) -> dict[str, Any]:
|
|
123
|
+
"""Generate figure.json spec from panels."""
|
|
124
|
+
spec: dict[str, Any] = {
|
|
125
|
+
"schema": {"name": "scitex.canvas.figure", "version": "1.0.0"},
|
|
126
|
+
"figure": {
|
|
127
|
+
"id": "figure",
|
|
128
|
+
"title": "",
|
|
129
|
+
"caption": "",
|
|
130
|
+
"styles": {
|
|
131
|
+
"size": {"width_mm": 180, "height_mm": 120},
|
|
132
|
+
"background": "#ffffff",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
"panels": [],
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
panel_ids = sorted(panels.keys())
|
|
139
|
+
n_panels = len(panel_ids)
|
|
140
|
+
|
|
141
|
+
if n_panels == 0:
|
|
142
|
+
return spec
|
|
143
|
+
|
|
144
|
+
cols = min(n_panels, 2)
|
|
145
|
+
|
|
146
|
+
panel_w = 80
|
|
147
|
+
panel_h = 50
|
|
148
|
+
margin = 5
|
|
149
|
+
|
|
150
|
+
for i, panel_id in enumerate(panel_ids):
|
|
151
|
+
row = i // cols
|
|
152
|
+
col = i % cols
|
|
153
|
+
|
|
154
|
+
x = margin + col * (panel_w + margin)
|
|
155
|
+
y = margin + row * (panel_h + margin)
|
|
156
|
+
|
|
157
|
+
spec["panels"].append(
|
|
158
|
+
{
|
|
159
|
+
"id": panel_id,
|
|
160
|
+
"label": panel_id,
|
|
161
|
+
"caption": "",
|
|
162
|
+
"plot": f"{panel_id}.plot",
|
|
163
|
+
"position": {"x_mm": x, "y_mm": y},
|
|
164
|
+
"size": {"width_mm": panel_w, "height_mm": panel_h},
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return spec
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# EOF
|