figrecipe 0.7.4__py3-none-any.whl → 0.9.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 +74 -76
- figrecipe/__main__.py +12 -0
- figrecipe/_api/_panel.py +67 -0
- figrecipe/_api/_save.py +100 -4
- figrecipe/_cli/__init__.py +7 -0
- figrecipe/_cli/_compose.py +87 -0
- figrecipe/_cli/_convert.py +117 -0
- figrecipe/_cli/_crop.py +82 -0
- figrecipe/_cli/_edit.py +70 -0
- figrecipe/_cli/_extract.py +128 -0
- figrecipe/_cli/_fonts.py +47 -0
- figrecipe/_cli/_info.py +67 -0
- figrecipe/_cli/_main.py +58 -0
- figrecipe/_cli/_reproduce.py +79 -0
- figrecipe/_cli/_style.py +77 -0
- figrecipe/_cli/_validate.py +66 -0
- figrecipe/_cli/_version.py +50 -0
- figrecipe/_composition/__init__.py +32 -0
- figrecipe/_composition/_alignment.py +452 -0
- figrecipe/_composition/_compose.py +179 -0
- figrecipe/_composition/_import_axes.py +127 -0
- figrecipe/_composition/_visibility.py +125 -0
- figrecipe/_dev/__init__.py +2 -0
- figrecipe/_dev/browser/__init__.py +69 -0
- figrecipe/_dev/browser/_audio.py +240 -0
- figrecipe/_dev/browser/_caption.py +356 -0
- figrecipe/_dev/browser/_click_effect.py +146 -0
- figrecipe/_dev/browser/_cursor.py +196 -0
- figrecipe/_dev/browser/_highlight.py +105 -0
- figrecipe/_dev/browser/_narration.py +237 -0
- figrecipe/_dev/browser/_recorder.py +446 -0
- figrecipe/_dev/browser/_utils.py +178 -0
- figrecipe/_dev/browser/_video_trim/__init__.py +152 -0
- figrecipe/_dev/browser/_video_trim/_detection.py +223 -0
- figrecipe/_dev/browser/_video_trim/_markers.py +140 -0
- figrecipe/_editor/__init__.py +36 -36
- figrecipe/_editor/_bbox/_extract.py +155 -9
- figrecipe/_editor/_bbox/_extract_text.py +124 -0
- figrecipe/_editor/_call_overrides.py +183 -0
- figrecipe/_editor/_datatable_plot_handlers.py +249 -0
- figrecipe/_editor/_figure_layout.py +211 -0
- figrecipe/_editor/_flask_app.py +157 -16
- figrecipe/_editor/_helpers.py +17 -8
- figrecipe/_editor/_hitmap/_detect.py +89 -32
- figrecipe/_editor/_hitmap_main.py +4 -4
- figrecipe/_editor/_overrides.py +4 -1
- figrecipe/_editor/_plot_types_registry.py +190 -0
- figrecipe/_editor/_render_overrides.py +38 -11
- figrecipe/_editor/_renderer.py +46 -1
- figrecipe/_editor/_routes_annotation.py +114 -0
- figrecipe/_editor/_routes_axis.py +35 -6
- figrecipe/_editor/_routes_captions.py +130 -0
- figrecipe/_editor/_routes_composition.py +270 -0
- figrecipe/_editor/_routes_core.py +15 -173
- figrecipe/_editor/_routes_datatable.py +364 -0
- figrecipe/_editor/_routes_element.py +37 -19
- figrecipe/_editor/_routes_files.py +443 -0
- figrecipe/_editor/_routes_image.py +200 -0
- figrecipe/_editor/_routes_snapshot.py +94 -0
- figrecipe/_editor/_routes_style.py +28 -8
- figrecipe/_editor/_templates/__init__.py +40 -2
- figrecipe/_editor/_templates/_html.py +97 -103
- figrecipe/_editor/_templates/_html_components/__init__.py +13 -0
- figrecipe/_editor/_templates/_html_components/_composition_toolbar.py +79 -0
- figrecipe/_editor/_templates/_html_components/_file_browser.py +41 -0
- figrecipe/_editor/_templates/_html_datatable.py +92 -0
- figrecipe/_editor/_templates/_scripts/__init__.py +58 -0
- figrecipe/_editor/_templates/_scripts/_accordion.py +328 -0
- figrecipe/_editor/_templates/_scripts/_annotation_drag.py +504 -0
- figrecipe/_editor/_templates/_scripts/_api.py +1 -1
- figrecipe/_editor/_templates/_scripts/_canvas_context_menu.py +182 -0
- figrecipe/_editor/_templates/_scripts/_captions.py +231 -0
- figrecipe/_editor/_templates/_scripts/_composition.py +283 -0
- figrecipe/_editor/_templates/_scripts/_core.py +94 -37
- figrecipe/_editor/_templates/_scripts/_datatable/__init__.py +59 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_cell_edit.py +97 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_clipboard.py +164 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_context_menu.py +221 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_core.py +150 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_editable.py +511 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_import.py +161 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_plot.py +261 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_selection.py +438 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_table.py +256 -0
- figrecipe/_editor/_templates/_scripts/_datatable/_tabs.py +354 -0
- figrecipe/_editor/_templates/_scripts/_element_editor.py +17 -2
- figrecipe/_editor/_templates/_scripts/_files.py +274 -40
- figrecipe/_editor/_templates/_scripts/_files_context_menu.py +240 -0
- figrecipe/_editor/_templates/_scripts/_hitmap.py +87 -84
- figrecipe/_editor/_templates/_scripts/_image_drop.py +428 -0
- figrecipe/_editor/_templates/_scripts/_legend_drag.py +5 -0
- figrecipe/_editor/_templates/_scripts/_multi_select.py +198 -0
- figrecipe/_editor/_templates/_scripts/_panel_drag.py +219 -48
- figrecipe/_editor/_templates/_scripts/_panel_drag_snapshot.py +33 -0
- figrecipe/_editor/_templates/_scripts/_panel_position.py +238 -54
- figrecipe/_editor/_templates/_scripts/_panel_resize.py +230 -0
- figrecipe/_editor/_templates/_scripts/_panel_snap.py +307 -0
- figrecipe/_editor/_templates/_scripts/_region_select.py +255 -0
- figrecipe/_editor/_templates/_scripts/_selection.py +8 -1
- figrecipe/_editor/_templates/_scripts/_sync.py +242 -0
- figrecipe/_editor/_templates/_scripts/_undo_redo.py +348 -0
- figrecipe/_editor/_templates/_scripts/_zoom.py +52 -19
- figrecipe/_editor/_templates/_styles/__init__.py +9 -0
- figrecipe/_editor/_templates/_styles/_base.py +47 -0
- figrecipe/_editor/_templates/_styles/_buttons.py +127 -6
- figrecipe/_editor/_templates/_styles/_composition.py +87 -0
- figrecipe/_editor/_templates/_styles/_controls.py +168 -3
- figrecipe/_editor/_templates/_styles/_datatable/__init__.py +40 -0
- figrecipe/_editor/_templates/_styles/_datatable/_editable.py +203 -0
- figrecipe/_editor/_templates/_styles/_datatable/_panel.py +268 -0
- figrecipe/_editor/_templates/_styles/_datatable/_table.py +479 -0
- figrecipe/_editor/_templates/_styles/_datatable/_toolbar.py +384 -0
- figrecipe/_editor/_templates/_styles/_datatable/_vars.py +123 -0
- figrecipe/_editor/_templates/_styles/_dynamic_props.py +5 -5
- figrecipe/_editor/_templates/_styles/_file_browser.py +466 -0
- figrecipe/_editor/_templates/_styles/_forms.py +98 -0
- figrecipe/_editor/_templates/_styles/_hitmap.py +7 -0
- figrecipe/_editor/_templates/_styles/_modals.py +29 -0
- figrecipe/_editor/_templates/_styles/_overlays.py +5 -5
- figrecipe/_editor/_templates/_styles/_preview.py +213 -8
- figrecipe/_editor/_templates/_styles/_spinner.py +117 -0
- figrecipe/_editor/static/audio/click.mp3 +0 -0
- figrecipe/_editor/static/click.mp3 +0 -0
- figrecipe/_editor/static/icons/favicon.ico +0 -0
- figrecipe/_integrations/__init__.py +17 -0
- figrecipe/_integrations/_scitex_stats.py +298 -0
- figrecipe/_params/_DECORATION_METHODS.py +2 -0
- figrecipe/_recorder.py +28 -3
- figrecipe/_reproducer/_core.py +60 -49
- figrecipe/_utils/__init__.py +3 -0
- figrecipe/_utils/_bundle.py +205 -0
- figrecipe/_wrappers/_axes.py +150 -2
- figrecipe/_wrappers/_caption_generator.py +218 -0
- figrecipe/_wrappers/_figure.py +26 -1
- figrecipe/_wrappers/_stat_annotation.py +274 -0
- figrecipe/styles/_style_applier.py +10 -2
- figrecipe/styles/presets/SCITEX.yaml +11 -4
- {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/METADATA +144 -146
- figrecipe-0.9.0.dist-info/RECORD +277 -0
- figrecipe-0.9.0.dist-info/entry_points.txt +2 -0
- figrecipe-0.7.4.dist-info/RECORD +0 -188
- {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/WHEEL +0 -0
- {figrecipe-0.7.4.dist-info → figrecipe-0.9.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: figrecipe
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Reproducible matplotlib wrapper with mm-precision layouts
|
|
5
5
|
Project-URL: Homepage, https://github.com/ywatanabe1989/figrecipe
|
|
6
6
|
Project-URL: Documentation, https://github.com/ywatanabe1989/figrecipe#readme
|
|
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
23
|
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: click>=8.0.0
|
|
24
25
|
Requires-Dist: matplotlib>=3.5.0
|
|
25
26
|
Requires-Dist: numpy>=1.20.0
|
|
26
27
|
Requires-Dist: ruamel-yaml>=0.17.0
|
|
@@ -29,12 +30,26 @@ Provides-Extra: all
|
|
|
29
30
|
Requires-Dist: flask>=2.0.0; extra == 'all'
|
|
30
31
|
Requires-Dist: pandas>=1.3.0; extra == 'all'
|
|
31
32
|
Requires-Dist: pillow>=9.0.0; extra == 'all'
|
|
33
|
+
Requires-Dist: playwright>=1.40.0; extra == 'all'
|
|
34
|
+
Requires-Dist: pytesseract>=0.3.0; extra == 'all'
|
|
32
35
|
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
|
|
33
36
|
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
37
|
+
Requires-Dist: pywebview>=4.0.0; extra == 'all'
|
|
34
38
|
Requires-Dist: seaborn>=0.12.0; extra == 'all'
|
|
39
|
+
Provides-Extra: demo
|
|
40
|
+
Requires-Dist: playwright>=1.40.0; extra == 'demo'
|
|
41
|
+
Requires-Dist: pytesseract>=0.3.0; extra == 'demo'
|
|
42
|
+
Provides-Extra: desktop
|
|
43
|
+
Requires-Dist: flask>=2.0.0; extra == 'desktop'
|
|
44
|
+
Requires-Dist: pillow>=9.0.0; extra == 'desktop'
|
|
45
|
+
Requires-Dist: pyqt6-webengine>=6.0.0; extra == 'desktop'
|
|
46
|
+
Requires-Dist: pyqt6>=6.0.0; extra == 'desktop'
|
|
47
|
+
Requires-Dist: pywebview>=4.0.0; extra == 'desktop'
|
|
48
|
+
Requires-Dist: qtpy>=2.0.0; extra == 'desktop'
|
|
35
49
|
Provides-Extra: dev
|
|
36
50
|
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
|
|
37
51
|
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest-xdist>=3.0.0; extra == 'dev'
|
|
38
53
|
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
39
54
|
Provides-Extra: editor
|
|
40
55
|
Requires-Dist: flask>=2.0.0; extra == 'editor'
|
|
@@ -47,7 +62,7 @@ Requires-Dist: seaborn>=0.12.0; extra == 'seaborn'
|
|
|
47
62
|
Description-Content-Type: text/markdown
|
|
48
63
|
|
|
49
64
|
<!-- ---
|
|
50
|
-
!-- Timestamp: 2025-12-
|
|
65
|
+
!-- Timestamp: 2025-12-27 02:15:07
|
|
51
66
|
!-- Author: ywatanabe
|
|
52
67
|
!-- File: /home/ywatanabe/proj/figrecipe/README.md
|
|
53
68
|
!-- --- -->
|
|
@@ -58,51 +73,29 @@ Description-Content-Type: text/markdown
|
|
|
58
73
|
</a>
|
|
59
74
|
</p>
|
|
60
75
|
|
|
61
|
-
# FigRecipe
|
|
76
|
+
# FigRecipe — **Reproducible matplotlib figures with mm-precision layouts.**
|
|
62
77
|
|
|
63
|
-
**
|
|
64
|
-
FigRecipe is a lightweight recording & reproduction layer for matplotlib,
|
|
65
|
-
designed for scientific figures that must remain **editable, inspectable,
|
|
66
|
-
and reproducible**.
|
|
78
|
+
FigRecipe separates **what** is plotted (data) from **how** it is styled, storing both in a structured format. This enables reproducible figures with GUI editing while preserving scientific integrity, and allows AI integration in a scientifically rigorous manner. Ultimately, FigRecipe will bundle: (1) reproducible, style-editable figures, and (2) metadata such as statistical values—creating atomic, portable, and traceable scientific figure objects essential for automated research in the AI era.
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
https://scitex.ai
|
|
80
|
+
FigRecipe is part of [**SciTeX™ (pending) – Research OS for reproducible science**](https://scitex.ai)
|
|
70
81
|
|
|
71
82
|
[](https://badge.fury.io/py/figrecipe)
|
|
72
83
|
[](https://github.com/ywatanabe1989/figrecipe/actions/workflows/test.yml)
|
|
73
84
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
74
85
|
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Why FigRecipe?
|
|
78
|
-
|
|
79
|
-
In scientific workflows, figures are often:
|
|
80
|
-
- hard to reproduce once scripts change,
|
|
81
|
-
- resized manually in pixels or inches,
|
|
82
|
-
- impossible to partially reuse or inspect later.
|
|
83
|
-
|
|
84
|
-
**FigRecipe solves this by recording plotting calls as a structured “recipe”**,
|
|
85
|
-
allowing figures to be:
|
|
86
|
-
- faithfully reproduced,
|
|
87
|
-
- partially re-rendered,
|
|
88
|
-
- inspected for underlying data,
|
|
89
|
-
- laid out in **exact millimeters** for publication.
|
|
90
86
|
|
|
91
87
|
---
|
|
92
88
|
|
|
93
89
|
## Key Features
|
|
94
90
|
|
|
95
|
-
- ✅ Drop-in replacement for `matplotlib.pyplot
|
|
96
|
-
- ✅
|
|
97
|
-
- ✅
|
|
98
|
-
- ✅
|
|
99
|
-
- ✅ Selective reproduction of specific plots
|
|
100
|
-
- ✅ Millimeter-based layout (journal-ready)
|
|
91
|
+
- ✅ Drop-in replacement for `matplotlib.pyplot`—minimal migration and learning cost
|
|
92
|
+
- ✅ All intermediate files use familiar formats (PNG/SVG/PDF/YAML/JSON)
|
|
93
|
+
- ✅ Import/Export to integrate with your existing workflow
|
|
94
|
+
- ✅ Millimeter-based layout (journal-ready)—difficult to achieve manually with matplotlib
|
|
101
95
|
- ✅ Publication-quality style presets
|
|
102
|
-
- ✅ Dark theme support (data colors preserved)
|
|
103
|
-
- ✅
|
|
104
|
-
- ✅
|
|
105
|
-
- ✅ **Interactive GUI editor** with live preview
|
|
96
|
+
- ✅ Dark theme support (data colors preserved), with light theme export for journal compliance
|
|
97
|
+
- ✅ Research-focused features: automatic cropping, axis alignment, panel labels, and caption embedding
|
|
98
|
+
- ✅ Interactive GUI editor for manual adjustments
|
|
106
99
|
|
|
107
100
|
---
|
|
108
101
|
|
|
@@ -110,20 +103,29 @@ allowing figures to be:
|
|
|
110
103
|
|
|
111
104
|
📓 **[View Demo Notebook on nbviewer](https://nbviewer.org/github/ywatanabe1989/figrecipe/blob/main/examples/figrecipe_demo.ipynb)** (recommended)
|
|
112
105
|
|
|
113
|
-
|
|
106
|
+
<details>
|
|
107
|
+
<summary><b>Demo Videos</b> — GUI Editor in action</summary>
|
|
114
108
|
|
|
115
|
-
|
|
109
|
+
| Dark Mode | Change Color | Drag Panel |
|
|
110
|
+
|:---:|:---:|:---:|
|
|
111
|
+
|  |  |  |
|
|
116
112
|
|
|
117
|
-
|
|
113
|
+
| Move Legend | Undo/Redo | Toggle Theme |
|
|
114
|
+
|:---:|:---:|:---:|
|
|
115
|
+
|  |  |  |
|
|
118
116
|
|
|
119
|
-
|
|
117
|
+
| Hover Feedback | Edit Labels | Zoom Controls |
|
|
118
|
+
|:---:|:---:|:---:|
|
|
119
|
+
|  |  |  |
|
|
120
|
+
|
|
121
|
+
</details>
|
|
120
122
|
|
|
121
123
|
<details>
|
|
122
|
-
<summary><b>
|
|
124
|
+
<summary><b>Supported Plot Types</b> — 46 matplotlib plot types in 9 categories</summary>
|
|
125
|
+
|
|
123
126
|
<p align="center">
|
|
124
127
|
<img src="docs/images/plot_types/all_plot_types.png" alt="All Plot Types" width="100%"/>
|
|
125
128
|
</p>
|
|
126
|
-
</details>
|
|
127
129
|
|
|
128
130
|
| Line & Curve | Scatter | Distribution |
|
|
129
131
|
|:---:|:---:|:---:|
|
|
@@ -138,6 +140,7 @@ FigRecipe supports 46 matplotlib plot types, organized into 9 categories:
|
|
|
138
140
|
|  |  |  |
|
|
139
141
|
|
|
140
142
|
Generate all plots: `python examples/demo_plot_all.py`
|
|
143
|
+
</details>
|
|
141
144
|
|
|
142
145
|
## Installation
|
|
143
146
|
|
|
@@ -178,12 +181,53 @@ img_path, yaml_path, result = fr.save(fig, 'figure.png')
|
|
|
178
181
|
# → creates: figure.png + figure.yaml
|
|
179
182
|
```
|
|
180
183
|
|
|
184
|
+
<details>
|
|
185
|
+
<summary><b>Supported I/O Formats</b> — Save and load are fully symmetric</summary>
|
|
186
|
+
|
|
187
|
+
**Save** creates both image and recipe. **Load** finds recipe from any format:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
# Save examples
|
|
191
|
+
fr.save(fig, 'figure.png') # → figure.png + figure.yaml
|
|
192
|
+
fr.save(fig, 'figure.yaml') # → figure.yaml + figure.png
|
|
193
|
+
fr.save(fig, 'figure_bundle/') # → directory with recipe.yaml + figure.png
|
|
194
|
+
fr.save(fig, 'figure.zip') # → ZIP containing recipe.yaml + figure.png
|
|
195
|
+
|
|
196
|
+
# Load examples (symmetric with save)
|
|
197
|
+
fig, ax = fr.load('figure.png') # ← finds figure.yaml
|
|
198
|
+
fig, ax = fr.load('figure.yaml') # ← direct
|
|
199
|
+
fig, ax = fr.load('figure_bundle/') # ← finds recipe.yaml inside
|
|
200
|
+
fig, ax = fr.load('figure.zip') # ← extracts recipe.yaml
|
|
201
|
+
|
|
202
|
+
# Edit also supports all formats
|
|
203
|
+
fr.edit('figure.png') # Opens editor, finds figure.yaml
|
|
204
|
+
|
|
205
|
+
# Note: fr.reproduce() is an alias for fr.load()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Format | Save | Load | Notes |
|
|
209
|
+
|--------|:----:|:----:|-------|
|
|
210
|
+
| `.png` / `.jpg` / `.jpeg` | ✓ | ✓ | Creates/finds `.yaml` alongside |
|
|
211
|
+
| `.pdf` / `.svg` | ✓ | ✓ | Creates/finds `.yaml` alongside |
|
|
212
|
+
| `.tif` / `.tiff` | ✓ | ✓ | Creates/finds `.yaml` alongside |
|
|
213
|
+
| `.yaml` / `.yml` | ✓ | ✓ | Creates/finds image alongside |
|
|
214
|
+
| Directory (`path/`) | ✓ | ✓ | Bundle with `recipe.yaml` + image |
|
|
215
|
+
| `.zip` | ✓ | ✓ | ZIP bundle with `recipe.yaml` + image |
|
|
216
|
+
|
|
217
|
+
**Alternative save method:**
|
|
218
|
+
```python
|
|
219
|
+
fig.savefig('figure.png') # Same as fr.save()
|
|
220
|
+
fig.savefig('figure.png', save_recipe=False) # Image only, no recipe
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
</details>
|
|
224
|
+
|
|
181
225
|
### Reproducing a Figure
|
|
182
226
|
|
|
183
227
|
``` python
|
|
184
228
|
import figrecipe as fr
|
|
185
229
|
|
|
186
|
-
fig, ax = fr.reproduce('figure.yaml')
|
|
230
|
+
fig, ax = fr.reproduce('figure.yaml') # Or .png, .pdf, directory/, .zip
|
|
187
231
|
```
|
|
188
232
|
|
|
189
233
|
### Extracting Plotted Data
|
|
@@ -195,18 +239,6 @@ data = fr.extract_data('figure.yaml')
|
|
|
195
239
|
# {'sine_wave': {'x': array([...]), 'y': array([...])}}
|
|
196
240
|
```
|
|
197
241
|
|
|
198
|
-
### Millimeter-Based Layout (Publication-Ready)
|
|
199
|
-
|
|
200
|
-
``` python
|
|
201
|
-
fig, ax = fr.subplots(
|
|
202
|
-
axes_width_mm=60,
|
|
203
|
-
axes_height_mm=40,
|
|
204
|
-
margin_left_mm=15,
|
|
205
|
-
margin_bottom_mm=12,
|
|
206
|
-
)
|
|
207
|
-
```
|
|
208
|
-
This guarantees consistent sizing across editors, exports, and journals.
|
|
209
|
-
|
|
210
242
|
### Style Presets
|
|
211
243
|
|
|
212
244
|
``` python
|
|
@@ -227,6 +259,47 @@ fr.load_style('/path/to/my_style.yaml')
|
|
|
227
259
|
|
|
228
260
|
See [src/figrecipe/styles/presets/](src/figrecipe/styles/presets/) for full examples.
|
|
229
261
|
|
|
262
|
+
### Millimeter-Based Layout (Publication-Ready)
|
|
263
|
+
|
|
264
|
+
``` python
|
|
265
|
+
fig, ax = fr.subplots(
|
|
266
|
+
axes_width_mm=60,
|
|
267
|
+
axes_height_mm=40,
|
|
268
|
+
margin_left_mm=15,
|
|
269
|
+
margin_bottom_mm=12,
|
|
270
|
+
)
|
|
271
|
+
```
|
|
272
|
+
This guarantees consistent sizing across editors, exports, and journals.
|
|
273
|
+
|
|
274
|
+
### Figure Legends (Scientific Captions)
|
|
275
|
+
|
|
276
|
+
Store publication-ready figure legends as metadata (not rendered on the figure):
|
|
277
|
+
|
|
278
|
+
``` python
|
|
279
|
+
fig, axes = fr.subplots(1, 2)
|
|
280
|
+
|
|
281
|
+
# Figure legend (main description)
|
|
282
|
+
fig.set_caption(
|
|
283
|
+
"Comparison of treatment effects on neural activity. "
|
|
284
|
+
"Data represent mean ± SEM."
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Panel legends (A, B, C, ...)
|
|
288
|
+
axes[0].set_caption("Representative traces from control condition")
|
|
289
|
+
axes[1].set_caption("Quantification across subjects (n=12)")
|
|
290
|
+
|
|
291
|
+
# Access captions
|
|
292
|
+
print(fig.caption) # Figure legend
|
|
293
|
+
print(axes[0].caption) # Panel A legend
|
|
294
|
+
|
|
295
|
+
# Auto-generate with statistics
|
|
296
|
+
fig.set_stats({"comparisons": [{"name": "A vs B", "p_value": 0.003}]})
|
|
297
|
+
full_legend = fig.generate_caption(style="publication")
|
|
298
|
+
# → "Comparison of... (A) Representative traces... (B) Quantification... A vs B (p=0.003)."
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Captions are saved in the recipe YAML and displayed in the GUI editor's caption pane below the canvas—ready for copy-paste into manuscripts.
|
|
302
|
+
|
|
230
303
|
### Interactive GUI Editor
|
|
231
304
|
|
|
232
305
|
``` python
|
|
@@ -259,16 +332,11 @@ The editor provides:
|
|
|
259
332
|
|:---:|:---:|:---:|
|
|
260
333
|
|  |  |  |
|
|
261
334
|
|
|
262
|
-
|
|
335
|
+
<details>
|
|
336
|
+
<summary><b>Style Format (YAML)</b> — Full preset example</summary>
|
|
263
337
|
|
|
264
338
|
``` yaml
|
|
265
|
-
#
|
|
266
|
-
# File: ./src/figrecipe/styles/presets/SCITEX.yaml
|
|
267
|
-
# FIGRECIPE Style Preset
|
|
268
|
-
# ======================
|
|
269
|
-
# Publication-quality settings for scientific figures.
|
|
270
|
-
# Optimized for scientific journals with Arial font.
|
|
271
|
-
|
|
339
|
+
# FIGRECIPE Style Preset (SCITEX)
|
|
272
340
|
axes:
|
|
273
341
|
width_mm: 40
|
|
274
342
|
height_mm: 28
|
|
@@ -280,113 +348,46 @@ margins:
|
|
|
280
348
|
bottom_mm: 1
|
|
281
349
|
top_mm: 1
|
|
282
350
|
|
|
283
|
-
spacing:
|
|
284
|
-
horizontal_mm: 8
|
|
285
|
-
vertical_mm: 10
|
|
286
|
-
|
|
287
351
|
fonts:
|
|
288
352
|
family: "Arial"
|
|
289
353
|
axis_label_pt: 7
|
|
290
354
|
tick_label_pt: 7
|
|
291
355
|
title_pt: 8
|
|
292
|
-
suptitle_pt: 8
|
|
293
|
-
legend_pt: 6
|
|
294
|
-
annotation_pt: 6
|
|
295
|
-
|
|
296
|
-
padding:
|
|
297
|
-
label_pt: 2.0
|
|
298
|
-
tick_pt: 2.0
|
|
299
|
-
title_pt: 4.0
|
|
300
356
|
|
|
301
357
|
lines:
|
|
302
358
|
trace_mm: 0.2
|
|
303
359
|
errorbar_mm: 0.2
|
|
304
|
-
errorbar_cap_mm: 0.8
|
|
305
360
|
|
|
306
361
|
ticks:
|
|
307
362
|
length_mm: 0.8
|
|
308
363
|
thickness_mm: 0.2
|
|
309
364
|
direction: "out"
|
|
310
|
-
n_ticks: 4
|
|
311
|
-
|
|
312
|
-
markers:
|
|
313
|
-
size_mm: 0.8
|
|
314
|
-
scatter_mm: 0.8
|
|
315
|
-
edge_width_mm: null # None = no border (cleaner than 0)
|
|
316
|
-
|
|
317
|
-
legend:
|
|
318
|
-
frameon: false # No frame for clean look
|
|
319
|
-
bg: null # Background (null = use theme.legend_bg)
|
|
320
|
-
edgecolor: null # Frame edge color
|
|
321
|
-
alpha: 1.0 # Transparency
|
|
322
|
-
loc: "best"
|
|
323
365
|
|
|
324
366
|
output:
|
|
325
367
|
dpi: 300
|
|
326
368
|
transparent: true
|
|
327
369
|
format: "pdf"
|
|
328
370
|
|
|
329
|
-
behavior:
|
|
330
|
-
auto_scale_axes: true
|
|
331
|
-
hide_top_spine: true
|
|
332
|
-
hide_right_spine: true
|
|
333
|
-
grid: false
|
|
334
|
-
|
|
335
371
|
theme:
|
|
336
372
|
mode: "light"
|
|
337
373
|
dark:
|
|
338
|
-
figure_bg: "transparent"
|
|
339
|
-
axes_bg: "transparent"
|
|
340
|
-
legend_bg: "transparent"
|
|
341
374
|
text: "#d4d4d4"
|
|
342
375
|
spine: "#d4d4d4"
|
|
343
|
-
tick: "#d4d4d4"
|
|
344
|
-
grid: "#3a3a3a"
|
|
345
376
|
light:
|
|
346
|
-
figure_bg: "transparent"
|
|
347
|
-
axes_bg: "transparent"
|
|
348
|
-
legend_bg: "transparent"
|
|
349
377
|
text: "black"
|
|
350
378
|
spine: "black"
|
|
351
|
-
tick: "black"
|
|
352
|
-
grid: "#cccccc"
|
|
353
379
|
|
|
354
|
-
# SciTeX Color Palette (RGB format)
|
|
355
380
|
colors:
|
|
356
381
|
palette:
|
|
357
382
|
- [0, 128, 192] # blue
|
|
358
383
|
- [255, 70, 50] # red
|
|
359
384
|
- [20, 180, 20] # green
|
|
360
|
-
- [230, 160, 20] # yellow
|
|
361
|
-
- [200, 50, 255] # purple
|
|
362
|
-
- [20, 200, 200] # lightblue
|
|
363
|
-
- [228, 94, 50] # orange
|
|
364
|
-
- [255, 150, 200] # pink
|
|
365
|
-
|
|
366
|
-
# Named colors
|
|
367
|
-
white: [255, 255, 255]
|
|
368
|
-
black: [0, 0, 0]
|
|
369
|
-
blue: [0, 128, 192]
|
|
370
|
-
red: [255, 70, 50]
|
|
371
|
-
pink: [255, 150, 200]
|
|
372
|
-
green: [20, 180, 20]
|
|
373
|
-
yellow: [230, 160, 20]
|
|
374
|
-
gray: [128, 128, 128]
|
|
375
|
-
grey: [128, 128, 128]
|
|
376
|
-
purple: [200, 50, 255]
|
|
377
|
-
lightblue: [20, 200, 200]
|
|
378
|
-
brown: [128, 0, 0]
|
|
379
|
-
navy: [0, 0, 100]
|
|
380
|
-
orange: [228, 94, 50]
|
|
381
|
-
|
|
382
|
-
# Semantic
|
|
383
|
-
primary: [0, 128, 192]
|
|
384
|
-
secondary: [255, 70, 50]
|
|
385
|
-
accent: [20, 180, 20]
|
|
386
|
-
|
|
387
385
|
# EOF
|
|
388
386
|
```
|
|
389
387
|
|
|
388
|
+
See [src/figrecipe/styles/presets/](src/figrecipe/styles/presets/) for complete examples.
|
|
389
|
+
</details>
|
|
390
|
+
|
|
390
391
|
|
|
391
392
|
### API Overview
|
|
392
393
|
|
|
@@ -394,7 +395,7 @@ colors:
|
|
|
394
395
|
|----------------------------------|---------------------------------------------------|
|
|
395
396
|
| `import figrecipe.pyplot as plt` | Drop-in replacement of `matplotlib.pyplot as plt` |
|
|
396
397
|
| `import figrecipe as fr` | Import figrecipe package |
|
|
397
|
-
|
|
398
|
+
|
|
398
399
|
| Function | |
|
|
399
400
|
|----------------------------------|---------------------------------------------------|
|
|
400
401
|
| `fr.subplots()` | Create a recording-enabled figure |
|
|
@@ -406,24 +407,21 @@ colors:
|
|
|
406
407
|
| `fr.load_style()` | Load style preset (global) |
|
|
407
408
|
| `fr.list_presets()` | List available presets |
|
|
408
409
|
| `fr.crop('fig.png')` | Crop to content with mm margin |
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
FigRecipe focuses on *how* figures are constructed, not *what* they represent.
|
|
413
|
-
|
|
414
|
-
FigRecipe provides recording, reproduction, layout fidelity, and interactive editing.
|
|
415
|
-
|
|
416
|
-
Higher-level workflows (figures–tables–statistics bundle, integration with manuscript writing) are handled in:
|
|
417
|
-
|
|
418
|
-
FTS (Figure-Table-Statistics Bundle) in SciTeX Ecosystem:
|
|
419
|
-
https://github.com/ywatanabe1989/scitex-code
|
|
420
|
-
https://scitex.ai/vis/
|
|
421
|
-
https://scitex.ai/writer/
|
|
410
|
+
| `fig.set_caption(text)` | Set figure legend (metadata) |
|
|
411
|
+
| `ax.set_caption(text)` | Set panel legend (metadata) |
|
|
422
412
|
|
|
423
413
|
|
|
424
414
|
## License
|
|
425
415
|
|
|
426
416
|
AGPL-3.0 See [LICENSE](LICENSE)
|
|
427
|
-
|
|
417
|
+
|
|
418
|
+
## Contact
|
|
419
|
+
Yusuke Watanabe (ywatanabe@scitex.ai)
|
|
420
|
+
|
|
421
|
+
<p align="center">
|
|
422
|
+
<a href="https://scitex.ai" target="_blank">
|
|
423
|
+
<img src="docs/scitex-icon-navy-inverted.png" alt="SciTeX" width="80"/>
|
|
424
|
+
</a>
|
|
425
|
+
</p>
|
|
428
426
|
|
|
429
427
|
<!-- EOF -->
|