scitex 2.4.2__py3-none-any.whl → 2.5.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.
Files changed (64) hide show
  1. scitex/__version__.py +1 -1
  2. scitex/browser/__init__.py +53 -0
  3. scitex/browser/debugging/__init__.py +56 -0
  4. scitex/browser/debugging/_failure_capture.py +372 -0
  5. scitex/browser/debugging/_sync_session.py +259 -0
  6. scitex/browser/debugging/_test_monitor.py +284 -0
  7. scitex/browser/debugging/_visual_cursor.py +432 -0
  8. scitex/io/_load.py +5 -0
  9. scitex/io/_load_modules/_canvas.py +171 -0
  10. scitex/io/_save.py +8 -0
  11. scitex/io/_save_modules/_canvas.py +356 -0
  12. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +77 -22
  13. scitex/plt/docs/FIGURE_ARCHITECTURE.md +257 -0
  14. scitex/plt/utils/__init__.py +10 -0
  15. scitex/plt/utils/_collect_figure_metadata.py +14 -12
  16. scitex/plt/utils/_csv_column_naming.py +237 -0
  17. scitex/scholar/citation_graph/database.py +9 -2
  18. scitex/scholar/config/ScholarConfig.py +23 -3
  19. scitex/scholar/config/default.yaml +55 -0
  20. scitex/scholar/core/Paper.py +102 -0
  21. scitex/scholar/core/__init__.py +44 -0
  22. scitex/scholar/core/journal_normalizer.py +524 -0
  23. scitex/scholar/core/oa_cache.py +285 -0
  24. scitex/scholar/core/open_access.py +457 -0
  25. scitex/scholar/pdf_download/ScholarPDFDownloader.py +137 -0
  26. scitex/scholar/pdf_download/strategies/__init__.py +6 -0
  27. scitex/scholar/pdf_download/strategies/open_access_download.py +186 -0
  28. scitex/scholar/pipelines/ScholarPipelineSearchParallel.py +18 -3
  29. scitex/scholar/pipelines/ScholarPipelineSearchSingle.py +15 -2
  30. scitex/session/_decorator.py +13 -1
  31. scitex/vis/README.md +246 -615
  32. scitex/vis/__init__.py +138 -78
  33. scitex/vis/canvas.py +423 -0
  34. scitex/vis/docs/CANVAS_ARCHITECTURE.md +307 -0
  35. scitex/vis/editor/__init__.py +1 -1
  36. scitex/vis/editor/_dearpygui_editor.py +1830 -0
  37. scitex/vis/editor/_defaults.py +40 -1
  38. scitex/vis/editor/_edit.py +54 -18
  39. scitex/vis/editor/_flask_editor.py +37 -0
  40. scitex/vis/editor/_qt_editor.py +865 -0
  41. scitex/vis/editor/flask_editor/__init__.py +21 -0
  42. scitex/vis/editor/flask_editor/bbox.py +216 -0
  43. scitex/vis/editor/flask_editor/core.py +152 -0
  44. scitex/vis/editor/flask_editor/plotter.py +130 -0
  45. scitex/vis/editor/flask_editor/renderer.py +184 -0
  46. scitex/vis/editor/flask_editor/templates/__init__.py +33 -0
  47. scitex/vis/editor/flask_editor/templates/html.py +295 -0
  48. scitex/vis/editor/flask_editor/templates/scripts.py +614 -0
  49. scitex/vis/editor/flask_editor/templates/styles.py +549 -0
  50. scitex/vis/editor/flask_editor/utils.py +81 -0
  51. scitex/vis/io/__init__.py +84 -21
  52. scitex/vis/io/canvas.py +226 -0
  53. scitex/vis/io/data.py +204 -0
  54. scitex/vis/io/directory.py +202 -0
  55. scitex/vis/io/export.py +460 -0
  56. scitex/vis/io/panel.py +424 -0
  57. {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/METADATA +9 -2
  58. {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/RECORD +61 -32
  59. scitex/vis/DJANGO_INTEGRATION.md +0 -677
  60. scitex/vis/editor/_web_editor.py +0 -1440
  61. scitex/vis/tmp.txt +0 -239
  62. {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/WHEEL +0 -0
  63. {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/entry_points.txt +0 -0
  64. {scitex-2.4.2.dist-info → scitex-2.5.0.dist-info}/licenses/LICENSE +0 -0
scitex/vis/README.md CHANGED
@@ -1,18 +1,28 @@
1
1
  <!-- ---
2
- !-- Timestamp: 2025-11-22 10:37:48
2
+ !-- Timestamp: 2025-12-08
3
3
  !-- Author: ywatanabe
4
4
  !-- File: /home/ywatanabe/proj/scitex-code/src/scitex/vis/README.md
5
5
  !-- --- -->
6
6
 
7
- # scitex.vis - Structured Visualization for Publication Figures
7
+ # scitex.vis - Canvas-Based Figure Composition
8
8
 
9
- **JSON-based figure specifications for reproducible, publication-quality visualizations**
9
+ **Compose publication-quality figures from multiple panels**
10
+
11
+ Schema Version: 2.0.0
10
12
 
11
13
  ---
12
14
 
13
15
  ## Overview
14
16
 
15
- `scitex.vis` is the visualization pillar of the SciTeX ecosystem, providing a structured approach to creating publication-quality figures through JSON specifications. It bridges the gap between data and final figures by treating visualization as structured data.
17
+ `scitex.vis` provides canvas-based composition of publication figures. A **canvas** represents a complete paper figure (e.g., "Figure 1") that can contain multiple **panels** (A, B, C...).
18
+
19
+ ### Terminology
20
+
21
+ | Term | Meaning | Example |
22
+ |------|---------|---------|
23
+ | **Canvas** | Paper figure workspace | "Figure 1" in a publication |
24
+ | **Panel** | Single component on canvas | Panel A, B, C... |
25
+ | **Figure** | Reserved for matplotlib's `fig` object | `stx.plt` output |
16
26
 
17
27
  ### The SciTeX Ecosystem
18
28
 
@@ -20,736 +30,357 @@
20
30
  scitex/
21
31
  ├── scholar/ → Literature & metadata management
22
32
  ├── writer/ → Document generation (LaTeX/manuscripts)
23
- └── vis/ → Visualization & figures (this module)
33
+ ├── plt/ → Plotting (matplotlib wrapper, outputs PNG+JSON+CSV)
34
+ └── vis/ → Canvas composition (this module)
24
35
  ```
25
36
 
26
- ### Why scitex.vis?
27
-
28
- Traditional plotting workflows have several pain points:
29
- - **Not version-controllable**: Figures are binary blobs
30
- - **Not reproducible**: Code scattered across notebooks, hard to recreate exact output
31
- - **Not collaborative**: Hard to edit someone else's plotting code
32
- - **Not structured**: No standard way to represent figure specifications
33
-
34
- `scitex.vis` solves these by:
35
- - ✅ **JSON-based**: Figures as structured, version-controllable text
36
- - ✅ **Reproducible**: One JSON → One figure, guaranteed
37
- - ✅ **Collaborative**: Easy to edit, review, and share specifications
38
- - ✅ **Structured**: Standard schema for all figure types
39
- - ✅ **Publication-ready**: Built-in templates for Nature, Science, etc.
40
-
41
37
  ---
42
38
 
43
39
  ## Quick Start
44
40
 
45
- ### Basic Usage
41
+ ### Create and Compose a Canvas
46
42
 
47
43
  ```python
48
44
  import scitex as stx
49
- import numpy as np
50
-
51
- # 1. Create figure using publication template
52
- fig_json = stx.vis.get_template("nature_single", height_mm=100)
53
-
54
- # 2. Define your plot
55
- x = np.linspace(0, 2*np.pi, 100)
56
- y = np.sin(x)
57
-
58
- fig_json["axes"] = [{
59
- "row": 0,
60
- "col": 0,
61
- "xlabel": "Time (s)",
62
- "ylabel": "Amplitude",
63
- "title": "Sine Wave",
64
- "plots": [{
65
- "plot_type": "line",
66
- "data": {"x": x.tolist(), "y": y.tolist()},
67
- "color": "blue",
68
- "linewidth": 2,
69
- "label": "sin(x)"
70
- }],
71
- "grid": True,
72
- "legend": True
73
- }]
74
-
75
- # 3. Save the specification
76
- stx.vis.save_figure_json(fig_json, "figure.json")
77
-
78
- # 4. Render to matplotlib
79
- fig, axes = stx.vis.build_figure_from_json(fig_json)
80
-
81
- # 5. Export to image
82
- stx.vis.export_figure(fig_json, "figure.png", dpi=300)
83
- ```
84
-
85
- ### Project-Based Workflow
86
45
 
87
- ```python
88
- # Save to project structure: project/scitex/vis/figs/fig-001.json
89
- stx.vis.save_figure_json_to_project(
46
+ # 1. Create a canvas
47
+ stx.vis.ensure_canvas_directory(
90
48
  project_dir="/path/to/project",
91
- figure_id="fig-001",
92
- fig_json=fig_json
49
+ canvas_name="fig1_results"
93
50
  )
94
51
 
95
- # Load from project
96
- fig_json = stx.vis.load_figure_json_from_project(
52
+ # 2. Add panels from stx.plt outputs
53
+ stx.vis.add_panel_from_scitex(
97
54
  project_dir="/path/to/project",
98
- figure_id="fig-001"
55
+ canvas_name="fig1_results",
56
+ panel_name="panel_a",
57
+ source_png="./output/timeseries.png",
58
+ panel_properties={
59
+ "position": {"x_mm": 10, "y_mm": 10},
60
+ "size": {"width_mm": 80, "height_mm": 60},
61
+ "label": {"text": "A"}
62
+ }
99
63
  )
100
64
 
101
- # Export directly
102
- stx.vis.export_figure(fig_json, "output/fig-001.png", dpi=300)
103
- ```
104
-
105
- ---
106
-
107
- ## Architecture
65
+ # 3. Add an image panel
66
+ stx.vis.add_panel_from_image(
67
+ project_dir="/path/to/project",
68
+ canvas_name="fig1_results",
69
+ panel_name="panel_b",
70
+ source_image="./external/diagram.png",
71
+ panel_properties={
72
+ "position": {"x_mm": 100, "y_mm": 10},
73
+ "size": {"width_mm": 70, "height_mm": 60},
74
+ "label": {"text": "B"}
75
+ }
76
+ )
108
77
 
109
- ```
110
- scitex.vis/
111
- ├── model/ # JSON data models
112
- │ ├── FigureModel # Top-level figure specification
113
- │ ├── AxesModel # Subplot configuration
114
- │ ├── PlotModel # Individual plot (line, scatter, etc.)
115
- │ ├── GuideModel # Reference lines, spans
116
- │ └── AnnotationModel # Text, arrows, shapes
117
-
118
- ├── backend/ # Rendering engine
119
- │ ├── parser.py # JSON → Python objects
120
- │ ├── render.py # Objects → matplotlib figures
121
- │ └── export.py # Export to PNG/PDF/SVG
122
-
123
- ├── io/ # Load/save operations
124
- │ ├── load.py # Load figure JSONs
125
- │ └── save.py # Save figure JSONs
126
-
127
- └── utils/ # Utilities
128
- ├── validate.py # JSON validation
129
- └── defaults.py # Publication templates
78
+ # 4. Export composed canvas
79
+ stx.vis.export_canvas_to_file(
80
+ project_dir="/path/to/project",
81
+ canvas_name="fig1_results",
82
+ output_format="png"
83
+ )
130
84
  ```
131
85
 
132
86
  ---
133
87
 
134
- ## Publication Templates
135
-
136
- ### Available Templates
137
-
138
- ```python
139
- # List all templates
140
- templates = stx.vis.list_templates()
141
- # ['nature_single', 'nature_double', 'science_single', 'a4', 'square', 'presentation']
142
-
143
- # Get template dimensions
144
- for name in templates:
145
- template = stx.vis.get_template(name)
146
- print(f"{name}: {template['width_mm']} × {template['height_mm']} mm")
147
- ```
148
-
149
- ### Template Dimensions
150
-
151
- | Template | Width (mm) | Use Case |
152
- |----------|------------|----------|
153
- | `nature_single` | 89 | Nature single column |
154
- | `nature_double` | 183 | Nature double column |
155
- | `science_single` | 84 | Science single column |
156
- | `a4` | 180 | A4 document figures |
157
- | `square` | 120 | Square aspect ratio |
158
- | `presentation` | 254 | Presentation slides (16:9) |
159
-
160
- ### Creating Custom Templates
161
-
162
- ```python
163
- # Start with a template
164
- fig_json = stx.vis.get_template("nature_single")
88
+ ## Directory Structure
165
89
 
166
- # Customize dimensions
167
- fig_json["height_mm"] = 120
168
- fig_json["nrows"] = 2
169
- fig_json["ncols"] = 1
90
+ Canvas directories use `.canvas` extension for portability and distinguishability:
170
91
 
171
- # Or create from scratch
172
- fig_json = {
173
- "width_mm": 180,
174
- "height_mm": 120,
175
- "nrows": 1,
176
- "ncols": 1,
177
- "dpi": 300,
178
- "axes": []
179
- }
180
92
  ```
181
-
182
- ---
183
-
184
- ## Figure JSON Schema
185
-
186
- ### Minimal Example
187
-
188
- ```json
189
- {
190
- "width_mm": 89,
191
- "height_mm": 100,
192
- "nrows": 1,
193
- "ncols": 1,
194
- "axes": [
195
- {
196
- "row": 0,
197
- "col": 0,
198
- "xlabel": "X",
199
- "ylabel": "Y",
200
- "plots": [
201
- {
202
- "plot_type": "line",
203
- "data": {"x": [0, 1, 2], "y": [0, 1, 4]},
204
- "color": "blue"
205
- }
206
- ]
207
- }
208
- ]
209
- }
93
+ project/scitex/vis/canvases/
94
+ └── fig1_results.canvas/ # .canvas extension for bundle
95
+ ├── canvas.json # Layout, panels, composition
96
+ ├── panels/
97
+ │ ├── panel_a/ # type: scitex (full stx.plt output)
98
+ │ │ ├── panel.json
99
+ │ │ ├── panel.csv
100
+ │ │ └── panel.png
101
+ │ └── panel_b/ # type: image (static)
102
+ │ └── panel.png
103
+ └── exports/
104
+ ├── canvas.png # Final composed output
105
+ ├── canvas.pdf
106
+ └── canvas.svg
210
107
  ```
211
108
 
212
- ### Complete Example
213
-
214
- ```json
215
- {
216
- "width_mm": 183,
217
- "height_mm": 120,
218
- "nrows": 1,
219
- "ncols": 2,
220
- "dpi": 300,
221
- "facecolor": "white",
222
- "suptitle": "Figure 1: Example Results",
223
- "suptitle_fontsize": 12,
224
- "axes": [
225
- {
226
- "row": 0,
227
- "col": 0,
228
- "xlabel": "Time (s)",
229
- "ylabel": "Amplitude",
230
- "title": "Experimental Data",
231
- "xlim": [0, 10],
232
- "ylim": [-1, 1],
233
- "grid": true,
234
- "legend": true,
235
- "plots": [
236
- {
237
- "plot_type": "line",
238
- "data": {"x": [...], "y": [...]},
239
- "color": "blue",
240
- "linewidth": 2,
241
- "label": "Measurement"
242
- },
243
- {
244
- "plot_type": "scatter",
245
- "data": {"x": [...], "y": [...]},
246
- "color": "red",
247
- "alpha": 0.6,
248
- "label": "Control"
249
- }
250
- ],
251
- "guides": [
252
- {
253
- "guide_type": "axhline",
254
- "y": 0,
255
- "color": "gray",
256
- "linestyle": "--"
257
- }
258
- ],
259
- "annotations": [
260
- {
261
- "annotation_type": "text",
262
- "text": "Peak",
263
- "x": 5,
264
- "y": 0.8,
265
- "fontsize": 10
266
- }
267
- ]
268
- }
269
- ]
270
- }
271
- ```
109
+ The `.canvas` extension makes directories self-documenting, portable, and detectable by `scitex.io`.
272
110
 
273
111
  ---
274
112
 
275
- ## Plot Types
276
-
277
- ### Supported Plot Types
278
-
279
- | Plot Type | Description | Required Data Fields |
280
- |-----------|-------------|---------------------|
281
- | `line` | Line plot | `x`, `y` |
282
- | `scatter` | Scatter plot | `x`, `y` |
283
- | `errorbar` | Error bars | `x`, `y`, optional `xerr`, `yerr` |
284
- | `bar` | Bar chart | `x`, `height` (or `y`) |
285
- | `barh` | Horizontal bar chart | `y`, `width` (or `x`) |
286
- | `hist` | Histogram | `x`, optional `bins` |
287
- | `fill_between` | Filled area | `x`, `y1`, `y2` |
288
- | `heatmap` | Heatmap | `z` (or `img`) |
289
- | `imshow` | Image display | `img` (or `z`) |
290
- | `contour` | Contour lines | `x`, `y`, `z` |
291
- | `contourf` | Filled contours | `x`, `y`, `z` |
113
+ ## Panel Types
292
114
 
293
- ### Examples
115
+ | Type | Contents | Editable | Re-renderable |
116
+ |------|----------|----------|---------------|
117
+ | `scitex` | PNG + JSON + CSV | Full (data, style) | Yes |
118
+ | `image` | PNG/JPG/SVG only | Position/size/transform | No |
294
119
 
295
- #### Line Plot
120
+ ### Panel Properties
296
121
 
297
122
  ```python
298
- {
299
- "plot_type": "line",
300
- "data": {"x": [0, 1, 2, 3], "y": [0, 1, 4, 9]},
301
- "color": "blue",
302
- "linewidth": 2,
303
- "linestyle": "-",
304
- "marker": "o",
305
- "label": "Quadratic"
306
- }
307
- ```
123
+ panel_properties = {
124
+ # Position and size (required)
125
+ "position": {"x_mm": 10, "y_mm": 10},
126
+ "size": {"width_mm": 70, "height_mm": 50},
127
+
128
+ # Transform
129
+ "z_index": 0, # Stacking order
130
+ "rotation_deg": 0, # Rotation (clockwise)
131
+ "opacity": 1.0, # 0.0 - 1.0
132
+ "flip_h": False, # Horizontal flip
133
+ "flip_v": False, # Vertical flip
134
+ "visible": True,
135
+
136
+ # Clip (crop)
137
+ "clip": {
138
+ "enabled": False,
139
+ "x_mm": 0, "y_mm": 0,
140
+ "width_mm": None, "height_mm": None
141
+ },
308
142
 
309
- #### Scatter Plot
143
+ # Label (A, B, C...)
144
+ "label": {
145
+ "text": "A",
146
+ "position": "top-left",
147
+ "fontsize": 12,
148
+ "fontweight": "bold"
149
+ },
310
150
 
311
- ```python
312
- {
313
- "plot_type": "scatter",
314
- "data": {"x": [...], "y": [...]},
315
- "color": "red",
316
- "alpha": 0.6,
317
- "markersize": 50,
318
- "label": "Data points"
151
+ # Border
152
+ "border": {
153
+ "visible": False,
154
+ "color": "#000000",
155
+ "width_mm": 0.2
156
+ }
319
157
  }
320
158
  ```
321
159
 
322
- #### Error Bar Plot
323
-
324
- ```python
325
- {
326
- "plot_type": "errorbar",
327
- "data": {"x": [...], "y": [...]},
328
- "yerr": [...], # Can be scalar or array
329
- "capsize": 5,
330
- "color": "green",
331
- "label": "Mean ± SD"
332
- }
333
- ```
160
+ ---
334
161
 
335
- #### Heatmap
162
+ ## canvas.json Schema
336
163
 
337
- ```python
164
+ ```json
338
165
  {
339
- "plot_type": "heatmap",
340
- "data": {"z": [[...], [...], [...]]}, # 2D array
341
- "cmap": "viridis",
342
- "vmin": 0,
343
- "vmax": 1
344
- }
345
- ```
346
-
347
- ---
166
+ "schema_version": "2.0.0",
167
+ "canvas_name": "fig1_results",
348
168
 
349
- ## Multi-Subplot Figures
169
+ "size": {
170
+ "width_mm": 180,
171
+ "height_mm": 240
172
+ },
350
173
 
351
- ### Creating Subplots
174
+ "background": {
175
+ "color": "#ffffff",
176
+ "grid": false
177
+ },
352
178
 
353
- ```python
354
- # 2×2 subplot layout
355
- fig_json = stx.vis.get_template("nature_double", height_mm=160)
356
- fig_json["nrows"] = 2
357
- fig_json["ncols"] = 2
358
-
359
- # Define each subplot
360
- fig_json["axes"] = [
361
- # Top-left (row=0, col=0)
362
- {
363
- "row": 0,
364
- "col": 0,
365
- "title": "Plot A",
366
- "plots": [...]
367
- },
368
- # Top-right (row=0, col=1)
179
+ "panels": [
369
180
  {
370
- "row": 0,
371
- "col": 1,
372
- "title": "Plot B",
373
- "plots": [...]
181
+ "name": "panel_a",
182
+ "type": "scitex",
183
+ "position": {"x_mm": 10, "y_mm": 10},
184
+ "size": {"width_mm": 80, "height_mm": 60},
185
+ "z_index": 0,
186
+ "label": {"text": "A", "position": "top-left"}
374
187
  },
375
- # Bottom-left (row=1, col=0)
376
188
  {
377
- "row": 1,
378
- "col": 0,
379
- "title": "Plot C",
380
- "plots": [...]
381
- },
382
- # Bottom-right (row=1, col=1)
383
- {
384
- "row": 1,
385
- "col": 1,
386
- "title": "Plot D",
387
- "plots": [...]
189
+ "name": "panel_b",
190
+ "type": "image",
191
+ "source": "panel.png",
192
+ "position": {"x_mm": 100, "y_mm": 10},
193
+ "size": {"width_mm": 70, "height_mm": 60},
194
+ "label": {"text": "B"}
388
195
  }
389
- ]
390
- ```
391
-
392
- ---
196
+ ],
393
197
 
394
- ## Guides and Annotations
395
-
396
- ### Reference Lines and Spans
397
-
398
- ```python
399
- # Horizontal line
400
- {
401
- "guide_type": "axhline",
402
- "y": 0,
403
- "color": "gray",
404
- "linestyle": "--",
405
- "linewidth": 1
406
- }
198
+ "annotations": [
199
+ {"type": "text", "content": "p < 0.05", "position": {"x_mm": 50, "y_mm": 80}}
200
+ ],
407
201
 
408
- # Vertical line
409
- {
410
- "guide_type": "axvline",
411
- "x": 5,
412
- "color": "red",
413
- "alpha": 0.5
414
- }
415
-
416
- # Horizontal span (shaded region)
417
- {
418
- "guide_type": "axhspan",
419
- "ymin": -0.5,
420
- "ymax": 0.5,
421
- "color": "yellow",
422
- "alpha": 0.3
423
- }
424
-
425
- # Vertical span
426
- {
427
- "guide_type": "axvspan",
428
- "xmin": 2,
429
- "xmax": 4,
430
- "color": "blue",
431
- "alpha": 0.2
432
- }
433
- ```
202
+ "data_files": [
203
+ {"path": "panels/panel_a/panel.csv", "hash": "sha256:abc123..."}
204
+ ],
434
205
 
435
- ### Text Annotations
436
-
437
- ```python
438
- # Simple text
439
- {
440
- "annotation_type": "text",
441
- "text": "Important point",
442
- "x": 5,
443
- "y": 10,
444
- "fontsize": 12,
445
- "color": "red",
446
- "ha": "center", # horizontal alignment
447
- "va": "bottom" # vertical alignment
448
- }
449
-
450
- # Annotate with arrow
451
- {
452
- "annotation_type": "annotate",
453
- "text": "Peak value",
454
- "x": 5, # Point to annotate
455
- "y": 10,
456
- "xytext": [6, 12], # Text position
457
- "arrowprops": {
458
- "arrowstyle": "->",
459
- "color": "black",
460
- "lw": 1.5
206
+ "metadata": {
207
+ "created_at": "2025-12-08T12:00:00Z",
208
+ "updated_at": "2025-12-08T15:30:00Z"
461
209
  }
462
210
  }
463
211
  ```
464
212
 
465
213
  ---
466
214
 
467
- ## Advanced Usage
215
+ ## API Reference
468
216
 
469
- ### Using Models Directly
217
+ ### Directory Operations
470
218
 
471
219
  ```python
472
- from scitex.vis.model import FigureModel, AxesModel, PlotModel
473
-
474
- # Create models programmatically
475
- fig_model = FigureModel(
476
- width_mm=stx.vis.NATURE_SINGLE_COLUMN_MM,
477
- height_mm=100,
478
- nrows=1,
479
- ncols=1
480
- )
481
-
482
- axes_model = AxesModel(
483
- row=0,
484
- col=0,
485
- xlabel="Time",
486
- ylabel="Signal"
487
- )
220
+ # Create canvas directory structure
221
+ canvas_dir = stx.vis.ensure_canvas_directory(project_dir, canvas_name)
488
222
 
489
- plot_model = PlotModel(
490
- plot_type="line",
491
- data={"x": [0, 1, 2], "y": [0, 1, 4]},
492
- color="blue"
493
- )
223
+ # Get canvas path
224
+ path = stx.vis.get_canvas_directory_path(project_dir, canvas_name)
494
225
 
495
- # Build hierarchy
496
- axes_model.add_plot(plot_model.to_dict())
497
- fig_model.add_axes(axes_model.to_dict())
226
+ # List all canvases
227
+ canvases = stx.vis.list_canvas_directories(project_dir)
498
228
 
499
- # Validate
500
- fig_model.validate()
229
+ # Check existence
230
+ exists = stx.vis.canvas_directory_exists(project_dir, canvas_name)
501
231
 
502
- # Convert to JSON and render
503
- fig_json = fig_model.to_dict()
504
- fig, axes = stx.vis.build_figure_from_json(fig_json)
232
+ # Delete canvas
233
+ deleted = stx.vis.delete_canvas_directory(project_dir, canvas_name)
505
234
  ```
506
235
 
507
- ### Validation
236
+ ### Canvas Operations
508
237
 
509
238
  ```python
510
- from scitex.vis.backend import validate_figure_json
239
+ # Save canvas.json
240
+ stx.vis.save_canvas_json(project_dir, canvas_name, canvas_json)
511
241
 
512
- try:
513
- validate_figure_json(fig_json)
514
- print("✓ Valid figure JSON")
515
- except ValueError as e:
516
- print(f"✗ Invalid: {e}")
517
- ```
242
+ # Load canvas.json (with hash verification)
243
+ canvas_json = stx.vis.load_canvas_json(project_dir, canvas_name)
518
244
 
519
- ### Export Multiple Formats
245
+ # Partial update
246
+ stx.vis.update_canvas_json(project_dir, canvas_name, {"size": {"width_mm": 200}})
520
247
 
521
- ```python
522
- # Export to PNG, PDF, and SVG simultaneously
523
- paths = stx.vis.backend.export_multiple_formats(
524
- fig_json=fig_json,
525
- output_dir="output",
526
- base_name="figure-01",
527
- formats=["png", "pdf", "svg"],
528
- dpi=300,
529
- auto_crop=True
530
- )
531
-
532
- # Returns: {'png': Path(...), 'pdf': Path(...), 'svg': Path(...)}
248
+ # Get schema version
249
+ version = stx.vis.get_canvas_schema_version(project_dir, canvas_name)
533
250
  ```
534
251
 
535
- ---
536
-
537
- ## Integration with scitex.plt
538
-
539
- `scitex.vis` uses `scitex.plt` as its rendering backend, which means:
540
-
541
- 1. **All figures maintain mm-exact dimensions**
542
- 2. **Automatic metadata embedding** (creation time, dimensions, etc.)
543
- 3. **Consistent styling** across all figures
544
- 4. **High-quality output** optimized for publications
252
+ ### Panel Operations
545
253
 
546
254
  ```python
547
- # This renders through scitex.plt
548
- fig, axes = stx.vis.build_figure_from_json(fig_json)
255
+ # Add panel from stx.plt output
256
+ stx.vis.add_panel_from_scitex(
257
+ project_dir, canvas_name, panel_name,
258
+ source_png="plot.png",
259
+ panel_properties={...}
260
+ )
549
261
 
550
- # You get a FigWrapper with all scitex.plt features
551
- print(type(fig)) # <class 'scitex.plt._subplots._FigWrapper.FigWrapper'>
262
+ # Add panel from image
263
+ stx.vis.add_panel_from_image(
264
+ project_dir, canvas_name, panel_name,
265
+ source_image="image.png",
266
+ panel_properties={...}
267
+ )
552
268
 
553
- # Axes are AxisWrapper objects
554
- print(type(axes[0])) # <class 'scitex.plt._subplots._AxesWrapper.AxisWrapper'>
555
- ```
269
+ # Update panel properties
270
+ stx.vis.update_panel(project_dir, canvas_name, panel_name, {"opacity": 0.8})
556
271
 
557
- ---
272
+ # Remove panel
273
+ stx.vis.remove_panel(project_dir, canvas_name, panel_name)
558
274
 
559
- ## API Reference
275
+ # List panels
276
+ panels = stx.vis.list_panels(project_dir, canvas_name)
560
277
 
561
- ### Top-Level Functions
278
+ # Get single panel
279
+ panel = stx.vis.get_panel(project_dir, canvas_name, panel_name)
562
280
 
563
- ```python
564
- # Templates
565
- stx.vis.get_template(name, **kwargs) -> Dict
566
- stx.vis.list_templates() -> List[str]
567
-
568
- # Build & Export
569
- stx.vis.build_figure_from_json(fig_json) -> (fig, axes)
570
- stx.vis.export_figure(fig_json, output_path, fmt=None, dpi=300, **kwargs) -> Path
571
- stx.vis.export_figure_from_file(json_path, output_path, **kwargs) -> Path
572
-
573
- # I/O
574
- stx.vis.load_figure_json(path, validate=True) -> Dict
575
- stx.vis.save_figure_json(fig_json, path) -> Path
576
- stx.vis.load_figure_json_from_project(project_dir, figure_id) -> Dict
577
- stx.vis.save_figure_json_to_project(project_dir, figure_id, fig_json) -> Path
578
-
579
- # Models
580
- stx.vis.FigureModel
581
- stx.vis.AxesModel
582
- stx.vis.PlotModel
583
- stx.vis.GuideModel
584
- stx.vis.AnnotationModel
585
-
586
- # Constants
587
- stx.vis.NATURE_SINGLE_COLUMN_MM # 89
588
- stx.vis.NATURE_DOUBLE_COLUMN_MM # 183
281
+ # Reorder panels (z-index)
282
+ stx.vis.reorder_panels(project_dir, canvas_name, ["panel_b", "panel_a"])
589
283
  ```
590
284
 
591
- ### Backend Module
285
+ ### Data Operations (Hash Verification)
592
286
 
593
287
  ```python
594
- from scitex.vis import backend
288
+ # Compute file hash
289
+ hash_str = stx.vis.compute_file_hash(filepath) # "sha256:abc123..."
595
290
 
596
- # Parsing
597
- backend.parse_figure_json(fig_json) -> FigureModel
598
- backend.validate_figure_json(fig_json) -> bool
291
+ # Verify hash
292
+ is_valid = stx.vis.verify_data_hash(filepath, expected_hash)
599
293
 
600
- # Rendering
601
- backend.render_figure(fig_model) -> (fig, axes)
602
- backend.build_figure_from_json(fig_json) -> (fig, axes)
603
-
604
- # Export
605
- backend.export_figure(fig_json, output_path, **kwargs) -> Path
606
- backend.export_multiple_formats(fig_json, output_dir, base_name, formats) -> Dict
294
+ # Verify all data files in canvas
295
+ results = stx.vis.verify_all_data_hashes(project_dir, canvas_name)
296
+ # {"panels/panel_a/panel.csv": True, ...}
607
297
  ```
608
298
 
609
- ### IO Module
299
+ ### Export Operations
610
300
 
611
301
  ```python
612
- from scitex.vis import io
613
-
614
- # Load
615
- io.load_figure_json(path) -> Dict
616
- io.load_figure_json_from_project(project_dir, figure_id) -> Dict
617
- io.load_figure_model(path) -> FigureModel
618
- io.list_figures_in_project(project_dir) -> List[str]
619
-
620
- # Save
621
- io.save_figure_json(fig_json, path) -> Path
622
- io.save_figure_json_to_project(project_dir, figure_id, fig_json) -> Path
623
- io.save_figure_model(fig_model, path) -> Path
624
- ```
302
+ # Export to single format
303
+ export_path = stx.vis.export_canvas_to_file(
304
+ project_dir, canvas_name,
305
+ output_format="png", # png, pdf, svg
306
+ dpi=300
307
+ )
625
308
 
626
- ### Utils Module
309
+ # Export to multiple formats
310
+ paths = stx.vis.export_canvas_to_multiple_formats(
311
+ project_dir, canvas_name,
312
+ formats=["png", "pdf", "svg"]
313
+ )
627
314
 
628
- ```python
629
- from scitex.vis import utils
630
-
631
- # Templates
632
- utils.get_nature_single_column(height_mm=89, nrows=1, ncols=1) -> Dict
633
- utils.get_nature_double_column(height_mm=120, nrows=1, ncols=1) -> Dict
634
- utils.get_science_single_column(height_mm=84, nrows=1, ncols=1) -> Dict
635
- utils.get_a4_figure(width_mm=180, height_mm=120) -> Dict
636
- utils.get_square_figure(size_mm=120) -> Dict
637
- utils.get_presentation_slide(aspect_ratio="16:9") -> Dict
638
-
639
- # Validation
640
- utils.validate_json_structure(fig_json) -> bool
641
- utils.validate_plot_data(plot_data) -> bool
642
- utils.check_schema_version(fig_json) -> str
643
-
644
- # Constants
645
- utils.NATURE_SINGLE_COLUMN_MM
646
- utils.NATURE_DOUBLE_COLUMN_MM
647
- utils.SCIENCE_SINGLE_COLUMN_MM
648
- utils.A4_WIDTH_MM
649
- utils.A4_HEIGHT_MM
315
+ # List existing exports
316
+ exports = stx.vis.list_canvas_exports(project_dir, canvas_name)
650
317
  ```
651
318
 
652
319
  ---
653
320
 
654
- ## Project Structure
321
+ ## Integration with stx.plt
655
322
 
656
- When using project-based workflows, figures are organized as:
323
+ `stx.plt` outputs (PNG + JSON + CSV) can be directly added as panels:
657
324
 
325
+ ```python
326
+ # 1. Create figures with stx.plt
327
+ fig, ax = stx.plt.subplots()
328
+ ax.plot(x, y)
329
+ stx.io.save(fig, "./output/timeseries.png")
330
+ # Creates: timeseries.png, timeseries.json, timeseries.csv
331
+
332
+ # 2. Add to canvas as panel
333
+ stx.vis.add_panel_from_scitex(
334
+ project_dir, canvas_name, "panel_a",
335
+ source_png="./output/timeseries.png" # Auto-finds .json and .csv
336
+ )
658
337
  ```
659
- project/
660
- └── scitex/
661
- └── vis/
662
- ├── figs/ # Figure JSON specifications
663
- │ ├── fig-001.json
664
- │ ├── fig-002.json
665
- │ └── ...
666
- └── export/ # Exported images (optional)
667
- ├── fig-001.png
668
- ├── fig-002.pdf
669
- └── ...
670
- ```
671
-
672
- This structure:
673
- - ✅ **Version controllable**: JSON files track with your code
674
- - ✅ **Organized**: Clear separation of specs and outputs
675
- - ✅ **Collaborative**: Easy to review and edit
676
- - ✅ **Reproducible**: One JSON → One figure
677
-
678
- ---
679
-
680
- ## Comparison with Other Tools
681
-
682
- | Feature | scitex.vis | Matplotlib | Plotly | Seaborn |
683
- |---------|-----------|-----------|--------|---------|
684
- | JSON-based specs | ✅ | ❌ | ✅ | ❌ |
685
- | Version controllable | ✅ | ❌ | Partial | ❌ |
686
- | Publication templates | ✅ | ❌ | ❌ | ❌ |
687
- | mm-exact dimensions | ✅ | ❌ | ❌ | ❌ |
688
- | Metadata embedding | ✅ | ❌ | ❌ | ❌ |
689
- | Project structure | ✅ | ❌ | ❌ | ❌ |
690
- | Backend flexibility | ✅ | N/A | ❌ | Depends on mpl |
691
338
 
692
339
  ---
693
340
 
694
- ## Future Enhancements
695
-
696
- Planned features for future versions:
697
-
698
- - [ ] **Interactive editing**: Web UI for figure JSON editing
699
- - [ ] **AI figure generation**: LLM-based figure creation from descriptions
700
- - [ ] **Figure diff/merge**: Git-friendly figure comparison
701
- - [ ] **Style inheritance**: Template inheritance and composition
702
- - [ ] **Figure collections**: Multi-figure documents
703
- - [ ] **Backend plugins**: Support for alternative renderers
704
- - [ ] **Automatic layouts**: Smart subplot arrangement
705
- - [ ] **3D plots**: Support for 3D visualizations
706
-
707
- ---
708
-
709
- ## Contributing
710
-
711
- When contributing to `scitex.vis`:
712
-
713
- 1. **Models**: Extend models in `model/` for new features
714
- 2. **Renderers**: Add plot types in `backend/render.py`
715
- 3. **Templates**: Add publication formats in `utils/defaults.py`
716
- 4. **Validation**: Update validators in `utils/validate.py`
717
-
718
- ---
341
+ ## Examples
719
342
 
720
- ## License
343
+ See `examples/vis/` for complete examples:
721
344
 
722
- Part of the SciTeX project. See main LICENSE file.
345
+ - `demo_canvas.py` - Canvas composition workflow
346
+ - `demo_vis_editor.py` - Interactive editor usage
347
+ - `demo_vis_module.py` - Legacy JSON-based workflow
723
348
 
724
349
  ---
725
350
 
726
351
  ## Related Documentation
727
352
 
353
+ - [CANVAS_ARCHITECTURE.md](./docs/CANVAS_ARCHITECTURE.md) - Full architecture details
728
354
  - [scitex.plt](../plt/README.md) - Plotting backend
729
- - [scitex.io](../io/README.md) - I/O operations
730
- - [scitex.scholar](../scholar/README.md) - Literature management
731
- - [scitex.writer](../writer/README.md) - Document generation
355
+ - [FIGURE_ARCHITECTURE.md](../plt/docs/FIGURE_ARCHITECTURE.md) - Figure output format
732
356
 
733
357
  ---
734
358
 
735
- ## Examples
359
+ ## Integration with stx.io
736
360
 
737
- See `examples/demo_vis_module.py` for comprehensive examples including:
738
- - Basic figure creation
739
- - Multi-subplot layouts
740
- - Project workflows
741
- - Model validation
742
- - Template usage
361
+ Canvas directories (`.canvas`) are first-class citizens in the scitex I/O system:
743
362
 
744
- Run the demo:
745
- ```bash
746
- python examples/demo_vis_module.py
363
+ ```python
364
+ # Save canvas to a portable directory
365
+ stx.io.save(canvas_dict, "/path/to/fig1_results.canvas")
366
+
367
+ # Load canvas from directory
368
+ canvas = stx.io.load("/path/to/fig1_results.canvas")
369
+
370
+ # Access canvas properties
371
+ print(canvas["canvas_name"])
372
+ print(canvas["panels"])
747
373
  ```
748
374
 
749
375
  ---
750
376
 
751
- **Made with ❤️ by the SciTeX team**
377
+ ## Constants
752
378
 
753
- *Completing the SciTeX ecosystem: scholar → writer → vis*
379
+ ```python
380
+ stx.vis.SCHEMA_VERSION # "2.0.0"
381
+ stx.vis.CANVAS_EXTENSION # ".canvas"
382
+ stx.vis.NATURE_SINGLE_COLUMN_MM # 89
383
+ stx.vis.NATURE_DOUBLE_COLUMN_MM # 183
384
+ ```
754
385
 
755
- <!-- EOF -->
386
+ <!-- EOF -->