figrecipe 0.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.
@@ -0,0 +1,336 @@
1
+ Metadata-Version: 2.4
2
+ Name: figrecipe
3
+ Version: 0.5.0
4
+ Summary: Reproducible matplotlib wrapper with mm-precision layouts
5
+ Project-URL: Homepage, https://github.com/ywatanabe1989/figrecipe
6
+ Project-URL: Documentation, https://github.com/ywatanabe1989/figrecipe#readme
7
+ Project-URL: Repository, https://github.com/ywatanabe1989/figrecipe.git
8
+ Project-URL: Issues, https://github.com/ywatanabe1989/figrecipe/issues
9
+ Author-email: Yusuke Watanabe <ywatanabe@scitex.ai>
10
+ License-Expression: AGPL-3.0
11
+ License-File: LICENSE
12
+ Keywords: matplotlib,millimeter,plotting,publication,recipe,reproducibility,scientific,visualization,yaml
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Visualization
23
+ Requires-Python: >=3.9
24
+ Requires-Dist: matplotlib>=3.5.0
25
+ Requires-Dist: numpy>=1.20.0
26
+ Requires-Dist: ruamel-yaml>=0.17.0
27
+ Provides-Extra: all
28
+ Requires-Dist: pandas>=1.3.0; extra == 'all'
29
+ Requires-Dist: pillow>=9.0.0; extra == 'all'
30
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
31
+ Requires-Dist: pytest>=7.0.0; extra == 'all'
32
+ Requires-Dist: seaborn>=0.12.0; extra == 'all'
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
35
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
+ Provides-Extra: imaging
37
+ Requires-Dist: pillow>=9.0.0; extra == 'imaging'
38
+ Provides-Extra: seaborn
39
+ Requires-Dist: pandas>=1.3.0; extra == 'seaborn'
40
+ Requires-Dist: seaborn>=0.12.0; extra == 'seaborn'
41
+ Description-Content-Type: text/markdown
42
+
43
+ <!-- ---
44
+ !-- Timestamp: 2025-12-22 13:01:11
45
+ !-- Author: ywatanabe
46
+ !-- File: /home/ywatanabe/proj/figrecipe/README.md
47
+ !-- --- -->
48
+
49
+ <p align="center">
50
+ <img src="docs/figrecipe_logo.png" alt="figrecipe logo" width="200"/>
51
+ </p>
52
+
53
+ # FigRecipe
54
+
55
+ **Reproducible matplotlib figures with mm-precision layouts.**
56
+ FigRecipe is a lightweight recording & reproduction layer for matplotlib,
57
+ designed for scientific figures that must remain **editable, inspectable,
58
+ and reproducible**.
59
+
60
+ Part of **SciTeX™ – Research OS for reproducible science**
61
+ https://scitex.ai
62
+
63
+ [![PyPI version](https://badge.fury.io/py/figrecipe.svg)](https://badge.fury.io/py/figrecipe)
64
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
65
+
66
+ ---
67
+
68
+ ## Why FigRecipe?
69
+
70
+ In scientific workflows, figures are often:
71
+ - hard to reproduce once scripts change,
72
+ - resized manually in pixels or inches,
73
+ - impossible to partially reuse or inspect later.
74
+
75
+ **FigRecipe solves this by recording plotting calls as a structured “recipe”**,
76
+ allowing figures to be:
77
+ - faithfully reproduced,
78
+ - partially re-rendered,
79
+ - inspected for underlying data,
80
+ - laid out in **exact millimeters** for publication.
81
+
82
+ ---
83
+
84
+ ## Key Features
85
+
86
+ - ✅ Drop-in replacement for `matplotlib.pyplot` (use `fr.subplots()` to enable recording)
87
+ - ✅ Automatic recording of plotting calls
88
+ - ✅ Reproduce figures from a YAML recipe
89
+ - ✅ Extract plotted data programmatically
90
+ - ✅ Selective reproduction of specific plots
91
+ - ✅ Millimeter-based layout (journal-ready)
92
+ - ✅ Publication-quality style presets
93
+ - ✅ Dark theme support (data colors preserved)
94
+ - ✅ Seamless seaborn integration
95
+ - ✅ Crop figures to content with mm margins
96
+
97
+ ---
98
+
99
+ ## Installation
100
+
101
+ ```bash
102
+ pip install figrecipe
103
+
104
+ # Optional extras
105
+ pip install figrecipe[seaborn] # seaborn + pandas support
106
+ pip install figrecipe[imaging] # image cropping (Pillow)
107
+ pip install figrecipe[all] # all extras
108
+
109
+ # Optional: for PDF export from notebooks (SVG → PDF)
110
+ sudo apt install inkscape # Linux
111
+ brew install inkscape # macOS
112
+ ```
113
+
114
+ **Requirements:** Python >= 3.9
115
+
116
+ ## Basic Usage
117
+
118
+ ### Recording & Saving
119
+
120
+ ``` python
121
+ import figrecipe as fr
122
+ import numpy as np
123
+
124
+ x = np.linspace(0, 10, 100)
125
+ y = np.sin(x)
126
+
127
+ fig, ax = fr.subplots()
128
+ ax.plot(x, y, color='red', linewidth=2, id='sine_wave')
129
+ ax.set_xlabel('Time (s)')
130
+ ax.set_ylabel('Amplitude')
131
+
132
+ # Save image + recipe
133
+ img_path, yaml_path, result = fr.save(fig, 'figure.png')
134
+ # → creates: figure.png + figure.yaml
135
+ ```
136
+
137
+ ### Reproducing a Figure
138
+
139
+ ``` python
140
+ import figrecipe as fr
141
+
142
+ fig, ax = fr.reproduce('figure.yaml')
143
+ ```
144
+
145
+ ### Extracting Plotted Data
146
+
147
+ ``` python
148
+ import figrecipe as fr
149
+
150
+ data = fr.extract_data('figure.yaml')
151
+ # {'sine_wave': {'x': array([...]), 'y': array([...])}}
152
+ ```
153
+
154
+ ### Millimeter-Based Layout (Publication-Ready)
155
+
156
+ ``` python
157
+ fig, ax = fr.subplots(
158
+ axes_width_mm=60,
159
+ axes_height_mm=40,
160
+ margin_left_mm=15,
161
+ margin_bottom_mm=12,
162
+ )
163
+ ```
164
+ This guarantees consistent sizing across editors, exports, and journals.
165
+
166
+ ### Style Presets
167
+
168
+ ``` python
169
+ fr.list_presets()
170
+ # ['MATPLOTLIB', 'SCITEX']
171
+
172
+ # Publication-quality preset (applied globally)
173
+ fr.load_style('SCITEX')
174
+ fig, ax = fr.subplots()
175
+
176
+ # Dark theme (UI-only, data colors preserved)
177
+ fr.load_style('SCITEX_DARK')
178
+ # or: fr.load_style('SCITEX', dark=True)
179
+
180
+ # Custom style
181
+ fr.load_style('/path/to/my_style.yaml')
182
+ ```
183
+
184
+ See docs/EXAMPLE_RECIPE.yaml for a full style template.
185
+
186
+ ### Recipe Format (YAML)
187
+
188
+ ``` yaml
189
+ # Timestamp: "2025-12-22 11:53:14 (ywatanabe)"
190
+ # File: ./docs/EXAMPLE_RECIPE.yaml
191
+ # MATPLOTLIB Style Preset
192
+ # =======================
193
+ # Vanilla matplotlib defaults - minimal customization.
194
+ # Use this to reset to standard matplotlib behavior.
195
+
196
+ axes:
197
+ width_mm: null # Use matplotlib default (auto)
198
+ height_mm: null # Use matplotlib default (auto)
199
+ thickness_mm: null # Use matplotlib default
200
+
201
+ margins:
202
+ left_mm: null
203
+ right_mm: null
204
+ bottom_mm: null
205
+ top_mm: null
206
+
207
+ spacing:
208
+ horizontal_mm: null
209
+ vertical_mm: null
210
+
211
+ fonts:
212
+ family: null # matplotlib default (DejaVu Sans)
213
+ axis_label_pt: null
214
+ tick_label_pt: null
215
+ title_pt: null
216
+ suptitle_pt: null
217
+ legend_pt: null
218
+ annotation_pt: null
219
+
220
+ padding:
221
+ label_pt: null
222
+ tick_pt: null
223
+ title_pt: null
224
+
225
+ lines:
226
+ trace_mm: null
227
+ errorbar_mm: null
228
+ errorbar_cap_mm: null
229
+
230
+ ticks:
231
+ length_mm: null
232
+ thickness_mm: null
233
+ direction: null
234
+ n_ticks: null
235
+
236
+ markers:
237
+ size_mm: null
238
+ scatter_mm: null
239
+ edge_width_mm: null
240
+
241
+ legend:
242
+ frameon: null # matplotlib default (True)
243
+ bg: null # matplotlib default
244
+ edgecolor: null # matplotlib default
245
+ alpha: null # matplotlib default
246
+ loc: null # matplotlib default
247
+
248
+ output:
249
+ dpi: 300
250
+ transparent: false
251
+ format: "png"
252
+
253
+ behavior:
254
+ auto_scale_axes: false
255
+ hide_top_spine: false
256
+ hide_right_spine: false
257
+ grid: false
258
+
259
+ theme:
260
+ mode: "light"
261
+ dark:
262
+ figure_bg: "#1e1e1e"
263
+ axes_bg: "#1e1e1e"
264
+ legend_bg: "#1e1e1e"
265
+ text: "#d4d4d4"
266
+ spine: "#3c3c3c"
267
+ tick: "#d4d4d4"
268
+ grid: "#3a3a3a"
269
+ light:
270
+ figure_bg: "white"
271
+ axes_bg: "white"
272
+ legend_bg: "white"
273
+ text: "black"
274
+ spine: "black"
275
+ tick: "black"
276
+ grid: "#cccccc"
277
+
278
+ # Standard matplotlib color cycle (tab10)
279
+ colors:
280
+ palette:
281
+ - [31, 119, 180] # tab:blue
282
+ - [255, 127, 14] # tab:orange
283
+ - [44, 160, 44] # tab:green
284
+ - [214, 39, 40] # tab:red
285
+ - [148, 103, 189] # tab:purple
286
+ - [140, 86, 75] # tab:brown
287
+ - [227, 119, 194] # tab:pink
288
+ - [127, 127, 127] # tab:gray
289
+ - [188, 189, 34] # tab:olive
290
+ - [23, 190, 207] # tab:cyan
291
+
292
+ # EOF
293
+ ```
294
+
295
+ The recipe is human-readable, version-controllable, and inspectable.
296
+
297
+
298
+ ### API Overview
299
+
300
+ | Function | Description |
301
+ | ----------------------------- | --------------------------------- |
302
+ | `fr.subplots()` | Create a recording-enabled figure |
303
+ | `fr.save(fig, 'fig.png')` | Save image + recipe |
304
+ | `fr.reproduce('fig.yaml')` | Reproduce figure from recipe |
305
+ | `fr.extract_data('fig.yaml')` | Extract plotted data |
306
+ | `fr.info('fig.yaml')` | Inspect recipe metadata |
307
+ | `fr.load_style()` | Load style preset (global) |
308
+ | `fr.list_presets()` | List available presets |
309
+ | `fr.crop('fig.png')` | Crop to content with mm margin |
310
+
311
+
312
+ ### Examples
313
+ - 📓 Interactive demo notebook:
314
+ examples/figrecipe_demo.ipynb
315
+
316
+ - 🌐 View on nbviewer:
317
+ https://nbviewer.org/github/ywatanabe1989/figrecipe/blob/main/examples/figrecipe_demo.ipynb
318
+
319
+ The notebook includes side-by-side comparisons of original and reproduced figures.
320
+
321
+ ## Positioning
322
+
323
+ FigRecipe is intentionally minimal.
324
+ It focuses on recording, reproduction, and layout fidelity.
325
+
326
+ Higher-level workflows (figures, tables, statistics, GUIs) are handled in:
327
+
328
+ FTS (Figure-Table-Statistics Bundle) in SciTeX ecosystem (https://scitex.ai/vis/)
329
+
330
+
331
+ ## License
332
+
333
+ AGPL-3.0 See [LICENSE](LICENSE)
334
+ .
335
+
336
+ <!-- EOF -->
@@ -0,0 +1,26 @@
1
+ figrecipe/__init__.py,sha256=X9RnSndUi5ZC_JW6ReBjvYD84kjK8D4FNvB5QjekFg4,35296
2
+ figrecipe/_recorder.py,sha256=mPjhc6ZaUWrzW3lBxeB_epf-ESHLj05sKs_zeHkZ9_Y,14290
3
+ figrecipe/_reproducer.py,sha256=IQNYJ8OcvGRKNRLe561yqtmWgIJtzkx6okCes1xIHsk,9683
4
+ figrecipe/_seaborn.py,sha256=dRQgIbJG9Xeh1DYCDNrgaXgQe4MsnukEXFeEolWnfeo,8348
5
+ figrecipe/_serializer.py,sha256=OpWbCRSlhMuA2KInRXvze-g9V_d5ToLUIEmTj-jquYs,6267
6
+ figrecipe/_validator.py,sha256=dFZez0J4f8V9wUnrMaz_CV-TlndBDcHHbZO4mRDC6Po,5567
7
+ figrecipe/plt.py,sha256=GkURHdcupAVvpWKgTCC23jn3OjmKQmTY09A9wGMUdDQ,308
8
+ figrecipe/pyplot.py,sha256=xw-wFa6N7wJ-A3ThLbQvhafwySNIqD05u9UupksY7S4,5685
9
+ figrecipe/_signatures/__init__.py,sha256=twHKZ8o_9Ho4k0SD-cff72_aaWevK0noGlWav5fauHg,244
10
+ figrecipe/_signatures/_loader.py,sha256=HCrVzQNWqqt6qSr13G_A1461-v94g65usfIRJ4_zmJk,4744
11
+ figrecipe/_utils/__init__.py,sha256=usLkRQJ6oZJSUSzZWkb1x-lkAdHO9I1g7VinLf2kz24,815
12
+ figrecipe/_utils/_crop.py,sha256=YQgaYGI3gAFRF0zkQeUOlTRs9vsBmAK_24vooPPcPPc,8385
13
+ figrecipe/_utils/_diff.py,sha256=cjRXjMrfXFKz6uZQOZ-XYifc0mzmHZyRXn_LY13K1SY,2354
14
+ figrecipe/_utils/_image_diff.py,sha256=9648vx2f_K628YjCB-bhCOsRws4qqWuUk2l4uJlpdrc,5406
15
+ figrecipe/_utils/_numpy_io.py,sha256=leckngCnZKTvceM3RfUq1P9TA6z1SibfzWqlhKtOaxY,4533
16
+ figrecipe/_utils/_units.py,sha256=94e0MaJ27WkF7zDqNL-P7adbve3qWitPzWrCYOuDBe8,4628
17
+ figrecipe/_wrappers/__init__.py,sha256=CcBUID5G6Mo_bNGpCaz5vbfB8CG7XtF-9lOm7kShQPw,214
18
+ figrecipe/_wrappers/_axes.py,sha256=gLymbk5WYBdaJ8pVnSJH4X8SMs_foNJIDRN4pDeP6To,10659
19
+ figrecipe/_wrappers/_figure.py,sha256=ZSCH5jVgZbb9kgXyj_LumV52v5vspmRQ3N1KzY37CaQ,6491
20
+ figrecipe/styles/__init__.py,sha256=vGKtlJkUi06i0QC4qEw3ebUwpxTgablFUlyABSYr1Co,976
21
+ figrecipe/styles/_style_applier.py,sha256=f0iPzV5IF2yy94yirVYD9hd7op1EDYQqo8xcL2qBZVU,14238
22
+ figrecipe/styles/_style_loader.py,sha256=4LazXQzZRmRsWj3TvtDgCXP_Mp5nJca9bXmMH7LnsHw,13342
23
+ figrecipe-0.5.0.dist-info/METADATA,sha256=WbJp4fSSIse1uB_1c1ar2KL3ktYBVznKA_78fYFusFk,8924
24
+ figrecipe-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ figrecipe-0.5.0.dist-info/licenses/LICENSE,sha256=TfPDBt3ar0uv_f9cqCDMZ5rIzW3CY8anRRd4PkL6ejs,34522
26
+ figrecipe-0.5.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any