scitex 2.10.3__py3-none-any.whl → 2.13.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 (504) hide show
  1. scitex/__init__.py +1 -4
  2. scitex/__main__.py +24 -5
  3. scitex/__version__.py +1 -1
  4. scitex/_install_guide.py +14 -2
  5. scitex/_optional_deps.py +33 -0
  6. scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
  7. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
  8. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
  9. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
  10. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
  11. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
  12. scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
  13. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
  14. scitex/ai/plt/_plot_feature_importance.py +1 -1
  15. scitex/ai/plt/_plot_learning_curve.py +1 -1
  16. scitex/ai/plt/_plot_optuna_study.py +1 -1
  17. scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
  18. scitex/ai/plt/_plot_roc_curve.py +1 -1
  19. scitex/ai/plt/_stx_conf_mat.py +1 -1
  20. scitex/ai/training/_LearningCurveLogger.py +1 -1
  21. scitex/audio/mcp_server.py +38 -8
  22. scitex/bridge/_figrecipe.py +1 -1
  23. scitex/bridge/_helpers.py +1 -1
  24. scitex/bridge/_plt_vis.py +1 -1
  25. scitex/bridge/_stats_plt.py +1 -1
  26. scitex/bridge/_stats_vis.py +2 -2
  27. scitex/browser/automation/CookieHandler.py +1 -1
  28. scitex/browser/core/BrowserMixin.py +1 -1
  29. scitex/browser/core/ChromeProfileManager.py +1 -1
  30. scitex/browser/debugging/_browser_logger.py +1 -1
  31. scitex/browser/debugging/_highlight_element.py +1 -1
  32. scitex/browser/debugging/_show_grid.py +1 -1
  33. scitex/browser/interaction/click_center.py +1 -1
  34. scitex/browser/interaction/click_with_fallbacks.py +1 -1
  35. scitex/browser/interaction/close_popups.py +1 -1
  36. scitex/browser/interaction/fill_with_fallbacks.py +1 -1
  37. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
  38. scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
  39. scitex/browser/stealth/HumanBehavior.py +1 -1
  40. scitex/browser/stealth/StealthManager.py +1 -1
  41. scitex/{fig → canvas}/__init__.py +84 -96
  42. scitex/canvas/_mcp_handlers.py +372 -0
  43. scitex/canvas/_mcp_tool_schemas.py +219 -0
  44. scitex/{fig → canvas}/backend/_parser.py +1 -1
  45. scitex/{fig → canvas}/canvas.py +13 -14
  46. scitex/{fts/_fig/_editor → canvas/editor}/_defaults.py +2 -2
  47. scitex/{fig → canvas}/editor/edit/__init__.py +11 -14
  48. scitex/{fig → canvas}/editor/edit/bundle_resolver.py +56 -48
  49. scitex/{fig → canvas}/editor/edit/editor_launcher.py +79 -26
  50. scitex/{fts/_fig/_editor/_cui/_panel_loader.py → canvas/editor/edit/panel_loader.py} +8 -8
  51. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_bbox.py +2 -1
  52. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_core.py +84 -84
  53. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_renderer.py +7 -6
  54. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/static/css/features/canvas.css +2 -2
  55. scitex/{fig → canvas}/editor/flask_editor/static/css/features/panel-grid.css +1 -1
  56. scitex/{fig → canvas}/editor/flask_editor/static/js/core/api.js +3 -4
  57. scitex/{fig → canvas}/editor/flask_editor/static/js/editor/preview.js +5 -5
  58. scitex/{fig → canvas}/editor/flask_editor/templates/_html.py +3 -3
  59. scitex/{fig → canvas}/editor/flask_editor/templates/_scripts.py +10 -10
  60. scitex/{fig → canvas}/editor/flask_editor/templates/_styles.py +3 -3
  61. scitex/{fig → canvas}/io/__init__.py +32 -38
  62. scitex/{fig → canvas}/io/_bundle.py +217 -154
  63. scitex/{fig → canvas}/io/_canvas.py +1 -1
  64. scitex/{fig → canvas}/io/_data.py +1 -1
  65. scitex/{fig → canvas}/io/_export.py +1 -1
  66. scitex/{fig → canvas}/io/_load.py +1 -1
  67. scitex/{fig → canvas}/io/_panel.py +1 -1
  68. scitex/{fig → canvas}/io/_save.py +1 -1
  69. scitex/canvas/mcp_server.py +151 -0
  70. scitex/{fig → canvas}/model/__init__.py +1 -1
  71. scitex/{fig → canvas}/model/_annotations.py +1 -1
  72. scitex/{fig → canvas}/model/_axes.py +1 -1
  73. scitex/{fig → canvas}/model/_figure.py +1 -1
  74. scitex/{fig → canvas}/model/_guides.py +1 -1
  75. scitex/{fig → canvas}/model/_plot.py +1 -1
  76. scitex/{fig → canvas}/model/_styles.py +1 -1
  77. scitex/{fig → canvas}/utils/__init__.py +1 -1
  78. scitex/capture/mcp_server.py +41 -12
  79. scitex/cli/audio.py +233 -0
  80. scitex/cli/capture.py +307 -0
  81. scitex/cli/convert.py +10 -6
  82. scitex/cli/main.py +27 -4
  83. scitex/cli/repro.py +233 -0
  84. scitex/cli/resource.py +240 -0
  85. scitex/cli/stats.py +325 -0
  86. scitex/cli/template.py +236 -0
  87. scitex/cli/tex.py +286 -0
  88. scitex/cli/web.py +11 -12
  89. scitex/dev/__init__.py +3 -0
  90. scitex/dev/_pyproject.py +405 -0
  91. scitex/dev/plt/__init__.py +2 -2
  92. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  93. scitex/dev/plt/mpl/get_signatures.py +1 -1
  94. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  95. scitex/diagram/README.md +7 -7
  96. scitex/diagram/_mcp_handlers.py +400 -0
  97. scitex/diagram/_mcp_tool_schemas.py +157 -0
  98. scitex/diagram/mcp_server.py +151 -0
  99. scitex/dsp/_demo_sig.py +51 -5
  100. scitex/dsp/_mne.py +13 -2
  101. scitex/dsp/_modulation_index.py +15 -3
  102. scitex/dsp/_pac.py +23 -5
  103. scitex/dsp/_psd.py +16 -4
  104. scitex/dsp/_resample.py +24 -4
  105. scitex/dsp/_transform.py +16 -3
  106. scitex/dsp/add_noise.py +15 -1
  107. scitex/dsp/norm.py +17 -2
  108. scitex/dsp/reference.py +17 -1
  109. scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
  110. scitex/dsp/utils/_zero_pad.py +18 -4
  111. scitex/dt/_normalize_timestamp.py +1 -1
  112. scitex/git/_session.py +1 -1
  113. scitex/io/__init__.py +7 -19
  114. scitex/io/_load.py +15 -19
  115. scitex/io/_load_modules/_canvas.py +2 -2
  116. scitex/io/_load_modules/_con.py +17 -6
  117. scitex/io/_load_modules/_eeg.py +28 -13
  118. scitex/io/_load_modules/_optuna.py +21 -63
  119. scitex/io/_load_modules/_torch.py +11 -3
  120. scitex/io/_save.py +11 -16
  121. scitex/io/_save_modules/__init__.py +6 -10
  122. scitex/io/_save_modules/_canvas.py +3 -3
  123. scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
  124. scitex/io/_save_modules/_plot_bundle.py +112 -0
  125. scitex/io/_save_modules/{_pltz_stx.py → _plot_scitex.py} +7 -7
  126. scitex/io/_save_modules/_stx_bundle.py +16 -16
  127. scitex/io/_save_modules/_torch.py +11 -3
  128. scitex/io/bundle/README.md +89 -80
  129. scitex/{fts/_bundle/_FTS.py → io/bundle/_Bundle.py} +197 -95
  130. scitex/io/bundle/__init__.py +67 -35
  131. scitex/{fts/_bundle → io/bundle}/_children.py +32 -40
  132. scitex/io/bundle/_core.py +184 -97
  133. scitex/{fts/_bundle/_dataclasses/_Node.py → io/bundle/_dataclasses/_Spec.py} +29 -23
  134. scitex/{fts/_bundle/_dataclasses/_NodeRefs.py → io/bundle/_dataclasses/_SpecRefs.py} +6 -6
  135. scitex/{fts/_bundle → io/bundle}/_dataclasses/__init__.py +4 -4
  136. scitex/{fts/_bundle → io/bundle}/_loader.py +19 -19
  137. scitex/io/bundle/_manifest.py +99 -0
  138. scitex/{fts/_bundle → io/bundle}/_mpl_helpers.py +119 -28
  139. scitex/io/bundle/_nested.py +113 -100
  140. scitex/{fts/_bundle → io/bundle}/_saver.py +13 -14
  141. scitex/{fts/_bundle → io/bundle}/_storage.py +3 -3
  142. scitex/io/bundle/_types.py +41 -16
  143. scitex/{fts/_bundle → io/bundle}/_validation.py +20 -18
  144. scitex/io/bundle/_zip.py +21 -31
  145. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_backend/_parser.py +1 -1
  146. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Annotations.py +1 -1
  147. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Axes.py +1 -1
  148. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Figure.py +1 -1
  149. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Guides.py +1 -1
  150. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Plot.py +1 -1
  151. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Styles.py +1 -1
  152. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_utils/_plot_layout.py +1 -1
  153. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/__init__.py +1 -1
  154. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/_app.py +1 -1
  155. scitex/{fts/_tables → io/bundle/kinds/_table}/_latex/_export.py +1 -1
  156. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_figure_exporter.py +1 -1
  157. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_table_exporter.py +1 -1
  158. scitex/io/bundle/schemas/__init__.py +30 -0
  159. scitex/mcp_server.py +159 -0
  160. scitex/parallel/_run.py +5 -4
  161. scitex/path/_find.py +60 -83
  162. scitex/path/_get_module_path.py +23 -21
  163. scitex/path/_get_spath.py +6 -27
  164. scitex/path/_getsize.py +23 -9
  165. scitex/path/_increment_version.py +31 -38
  166. scitex/path/_mk_spath.py +26 -29
  167. scitex/path/_path.py +5 -12
  168. scitex/path/_split.py +27 -15
  169. scitex/path/_this_path.py +23 -9
  170. scitex/plt/_mcp_handlers.py +361 -0
  171. scitex/plt/_mcp_tool_schemas.py +169 -0
  172. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +2 -1
  173. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +2 -2
  174. scitex/plt/gallery/_generate.py +76 -50
  175. scitex/plt/io/__init__.py +17 -19
  176. scitex/plt/io/_bundle.py +99 -52
  177. scitex/plt/io/_layered_bundle.py +303 -168
  178. scitex/plt/mcp_server.py +205 -0
  179. scitex/plt/utils/_csv_column_naming.py +250 -118
  180. scitex/repro/README_RandomStateManager.md +3 -3
  181. scitex/repro/_RandomStateManager.py +14 -14
  182. scitex/repro/_gen_ID.py +1 -1
  183. scitex/repro/_gen_timestamp.py +1 -1
  184. scitex/repro/_hash_array.py +4 -4
  185. scitex/schema/__init__.py +69 -73
  186. scitex/schema/_canvas.py +1 -1
  187. scitex/schema/_stats.py +2 -2
  188. scitex/scholar/__main__.py +24 -2
  189. scitex/scholar/_mcp_handlers.py +685 -0
  190. scitex/scholar/_mcp_tool_schemas.py +339 -0
  191. scitex/scholar/docs/template.py +1 -1
  192. scitex/scholar/examples/07_storage_integration.py +1 -1
  193. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
  194. scitex/scholar/impact_factor/jcr/build_database.py +1 -1
  195. scitex/scholar/mcp_server.py +315 -0
  196. scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
  197. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
  198. scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
  199. scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
  200. scitex/scholar/storage/PaperIO.py +1 -1
  201. scitex/session/README.md +4 -4
  202. scitex/session/__init__.py +1 -1
  203. scitex/session/_decorator.py +9 -9
  204. scitex/session/_lifecycle.py +5 -5
  205. scitex/session/template.py +1 -1
  206. scitex/stats/__init__.py +30 -33
  207. scitex/stats/__main__.py +281 -0
  208. scitex/stats/_mcp_handlers.py +1191 -0
  209. scitex/stats/_mcp_tool_schemas.py +384 -0
  210. scitex/stats/_schema.py +1 -1
  211. scitex/stats/correct/_correct_bonferroni.py +1 -1
  212. scitex/stats/correct/_correct_fdr.py +1 -1
  213. scitex/stats/correct/_correct_fdr_.py +1 -1
  214. scitex/stats/correct/_correct_holm.py +1 -1
  215. scitex/stats/correct/_correct_sidak.py +1 -1
  216. scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
  217. scitex/stats/effect_sizes/_cohens_d.py +1 -1
  218. scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
  219. scitex/stats/effect_sizes/_eta_squared.py +1 -1
  220. scitex/stats/effect_sizes/_prob_superiority.py +1 -1
  221. scitex/stats/io/__init__.py +10 -11
  222. scitex/stats/io/_bundle.py +16 -16
  223. scitex/stats/mcp_server.py +405 -0
  224. scitex/stats/posthoc/_dunnett.py +1 -1
  225. scitex/stats/posthoc/_games_howell.py +1 -1
  226. scitex/stats/posthoc/_tukey_hsd.py +1 -1
  227. scitex/stats/power/_power.py +1 -1
  228. scitex/stats/utils/_effect_size.py +1 -1
  229. scitex/stats/utils/_formatters.py +1 -1
  230. scitex/stats/utils/_power.py +1 -1
  231. scitex/template/_mcp_handlers.py +259 -0
  232. scitex/template/_mcp_tool_schemas.py +112 -0
  233. scitex/template/mcp_server.py +186 -0
  234. scitex/utils/_verify_scitex_format.py +2 -2
  235. scitex/utils/template.py +1 -1
  236. scitex/web/__init__.py +12 -11
  237. scitex/web/_scraping.py +26 -265
  238. scitex/web/download_images.py +316 -0
  239. scitex/writer/Writer.py +1 -1
  240. scitex/writer/_clone_writer_project.py +1 -1
  241. scitex/writer/_validate_tree_structures.py +1 -1
  242. scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
  243. scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
  244. scitex/writer/dataclasses/core/_Document.py +1 -1
  245. scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
  246. scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
  247. scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
  248. scitex/writer/utils/.legacy_git_retry.py +7 -5
  249. scitex/writer/utils/_parse_latex_logs.py +1 -1
  250. scitex-2.13.0.dist-info/METADATA +1231 -0
  251. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/RECORD +376 -470
  252. scitex-2.13.0.dist-info/entry_points.txt +11 -0
  253. scitex/fig/editor/_defaults.py +0 -300
  254. scitex/fig/editor/edit/panel_loader.py +0 -232
  255. scitex/fig/editor/flask_editor/_bbox.py +0 -1299
  256. scitex/fig/editor/flask_editor/_core.py +0 -1429
  257. scitex/fig/editor/flask_editor/_renderer.py +0 -813
  258. scitex/fig/editor/flask_editor/static/css/features/canvas.css +0 -176
  259. scitex/fts/README.md +0 -262
  260. scitex/fts/TODO.md +0 -66
  261. scitex/fts/__init__.py +0 -90
  262. scitex/fts/_bundle/README_IN_BUNDLE.md +0 -102
  263. scitex/fts/_bundle/__init__.py +0 -38
  264. scitex/fts/_bundle/_utils/__init__.py +0 -55
  265. scitex/fts/_bundle/_utils/_const.py +0 -26
  266. scitex/fts/_bundle/_utils/_errors.py +0 -73
  267. scitex/fts/_bundle/_utils/_generate.py +0 -21
  268. scitex/fts/_bundle/_utils/_types.py +0 -76
  269. scitex/fts/_bundle/_zipbundle.py +0 -165
  270. scitex/fts/_fig/__init__.py +0 -22
  271. scitex/fts/_fig/_backend/_parser.py +0 -188
  272. scitex/fts/_fig/_editor/__init__.py +0 -14
  273. scitex/fts/_fig/_editor/_cui/__init__.py +0 -33
  274. scitex/fts/_fig/_editor/_cui/_backend_detector.py +0 -39
  275. scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +0 -366
  276. scitex/fts/_fig/_editor/_cui/_editor_launcher.py +0 -175
  277. scitex/fts/_fig/_editor/_cui/_manual_handler.py +0 -52
  278. scitex/fts/_fig/_editor/_cui/_path_resolver.py +0 -66
  279. scitex/fts/_fig/_editor/_gui/__init__.py +0 -11
  280. scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +0 -20
  281. scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +0 -664
  282. scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +0 -79
  283. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +0 -41
  284. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +0 -16
  285. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +0 -85
  286. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +0 -217
  287. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +0 -93
  288. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +0 -57
  289. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +0 -112
  290. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +0 -59
  291. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +0 -212
  292. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +0 -190
  293. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +0 -59
  294. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +0 -45
  295. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +0 -95
  296. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +0 -101
  297. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +0 -138
  298. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +0 -31
  299. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +0 -7
  300. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +0 -56
  301. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +0 -78
  302. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +0 -314
  303. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +0 -107
  304. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +0 -54
  305. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +0 -172
  306. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +0 -258
  307. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +0 -48
  308. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +0 -71
  309. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +0 -288
  310. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +0 -143
  311. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +0 -245
  312. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +0 -992
  313. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +0 -339
  314. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +0 -286
  315. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +0 -371
  316. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +0 -293
  317. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +0 -426
  318. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +0 -152
  319. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +0 -265
  320. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +0 -184
  321. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +0 -57
  322. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +0 -100
  323. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +0 -34
  324. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +0 -124
  325. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +0 -851
  326. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +0 -4932
  327. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +0 -1657
  328. scitex/fts/_fig/_editor/_gui/_flask_editor.py +0 -36
  329. scitex/fts/_fig/_models/_Annotations.py +0 -115
  330. scitex/fts/_fig/_models/_Axes.py +0 -152
  331. scitex/fts/_fig/_models/_Figure.py +0 -138
  332. scitex/fts/_fig/_models/_Plot.py +0 -123
  333. scitex/fts/_fig/_utils/_plot_layout.py +0 -397
  334. scitex/fts/_kinds/_figure/_composite.py +0 -345
  335. scitex/fts/_kinds/_plot/_backend/__init__.py +0 -53
  336. scitex/fts/_kinds/_plot/_backend/_export.py +0 -165
  337. scitex/fts/_kinds/_plot/_backend/_render.py +0 -538
  338. scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +0 -46
  339. scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +0 -82
  340. scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +0 -441
  341. scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +0 -52
  342. scitex/fts/_kinds/_plot/_dataclasses/__init__.py +0 -47
  343. scitex/fts/_kinds/_plot/_models/_Guides.py +0 -104
  344. scitex/fts/_kinds/_plot/_models/_Styles.py +0 -245
  345. scitex/fts/_kinds/_plot/_models/__init__.py +0 -80
  346. scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +0 -156
  347. scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +0 -43
  348. scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +0 -38
  349. scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +0 -36
  350. scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +0 -60
  351. scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +0 -30
  352. scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +0 -61
  353. scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +0 -57
  354. scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +0 -30
  355. scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +0 -121
  356. scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +0 -36
  357. scitex/fts/_kinds/_plot/_utils/__init__.py +0 -129
  358. scitex/fts/_kinds/_plot/_utils/_auto_layout.py +0 -127
  359. scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +0 -111
  360. scitex/fts/_kinds/_plot/_utils/_const_sizes.py +0 -48
  361. scitex/fts/_kinds/_plot/_utils/_convert_coords.py +0 -77
  362. scitex/fts/_kinds/_plot/_utils/_get_template.py +0 -178
  363. scitex/fts/_kinds/_plot/_utils/_normalize.py +0 -73
  364. scitex/fts/_kinds/_plot/_utils/_validate.py +0 -197
  365. scitex/fts/_kinds/_table/_latex/_export.py +0 -279
  366. scitex/fts/_stats/__init__.py +0 -48
  367. scitex/fts/_stats/_dataclasses/_Stats.py +0 -423
  368. scitex/fts/_stats/_dataclasses/__init__.py +0 -48
  369. scitex/fts/_tables/__init__.py +0 -65
  370. scitex/fts/_tables/_latex/__init__.py +0 -93
  371. scitex/fts/_tables/_latex/_editor/__init__.py +0 -11
  372. scitex/fts/_tables/_latex/_editor/_app.py +0 -725
  373. scitex/fts/_tables/_latex/_figure_exporter.py +0 -153
  374. scitex/fts/_tables/_latex/_stats_formatter.py +0 -274
  375. scitex/fts/_tables/_latex/_table_exporter.py +0 -362
  376. scitex/fts/_tables/_latex/_utils.py +0 -369
  377. scitex/fts/_tables/_latex/_validator.py +0 -445
  378. scitex/io/_save_modules/_pltz_bundle.py +0 -356
  379. scitex-2.10.3.dist-info/METADATA +0 -952
  380. scitex-2.10.3.dist-info/entry_points.txt +0 -2
  381. /scitex/{fig → canvas}/README.md +0 -0
  382. /scitex/{fig → canvas}/backend/__init__.py +0 -0
  383. /scitex/{fig → canvas}/backend/_export.py +0 -0
  384. /scitex/{fig → canvas}/backend/_render.py +0 -0
  385. /scitex/{fig → canvas}/docs/CANVAS_ARCHITECTURE.md +0 -0
  386. /scitex/{fig → canvas}/editor/__init__.py +0 -0
  387. /scitex/{fig → canvas}/editor/_dearpygui_editor.py +0 -0
  388. /scitex/{fig → canvas}/editor/_flask_editor.py +0 -0
  389. /scitex/{fig → canvas}/editor/_mpl_editor.py +0 -0
  390. /scitex/{fig → canvas}/editor/_qt_editor.py +0 -0
  391. /scitex/{fig → canvas}/editor/_tkinter_editor.py +0 -0
  392. /scitex/{fig → canvas}/editor/edit/backend_detector.py +0 -0
  393. /scitex/{fig → canvas}/editor/edit/manual_handler.py +0 -0
  394. /scitex/{fig → canvas}/editor/edit/path_resolver.py +0 -0
  395. /scitex/{fig → canvas}/editor/flask_editor/__init__.py +0 -0
  396. /scitex/{fig → canvas}/editor/flask_editor/_plotter.py +0 -0
  397. /scitex/{fig → canvas}/editor/flask_editor/_utils.py +0 -0
  398. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/reset.css +0 -0
  399. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/typography.css +0 -0
  400. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/variables.css +0 -0
  401. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/buttons.css +0 -0
  402. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/context-menu.css +0 -0
  403. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/dropdown.css +0 -0
  404. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/forms.css +0 -0
  405. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/modal.css +0 -0
  406. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/sections.css +0 -0
  407. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/element-inspector.css +0 -0
  408. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/loading.css +0 -0
  409. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/overlay.css +0 -0
  410. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/selection.css +0 -0
  411. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/statistics.css +0 -0
  412. /scitex/{fig → canvas}/editor/flask_editor/static/css/index.css +0 -0
  413. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/container.css +0 -0
  414. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/controls.css +0 -0
  415. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/preview.css +0 -0
  416. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/axis.js +0 -0
  417. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/basic.js +0 -0
  418. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/distribute.js +0 -0
  419. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/canvas.js +0 -0
  420. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/dragging.js +0 -0
  421. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/resize.js +0 -0
  422. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/selection.js +0 -0
  423. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/state.js +0 -0
  424. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/utils.js +0 -0
  425. /scitex/{fig → canvas}/editor/flask_editor/static/js/dev/element-inspector.js +0 -0
  426. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/bbox.js +0 -0
  427. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/element-drag.js +0 -0
  428. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/overlay.js +0 -0
  429. /scitex/{fig → canvas}/editor/flask_editor/static/js/main.js +0 -0
  430. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/context-menu.js +0 -0
  431. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/keyboard.js +0 -0
  432. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/controls.js +0 -0
  433. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/download.js +0 -0
  434. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/help.js +0 -0
  435. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/theme.js +0 -0
  436. /scitex/{fig → canvas}/editor/flask_editor/templates/__init__.py +0 -0
  437. /scitex/{fig → canvas}/io/_directory.py +0 -0
  438. /scitex/{fig → canvas}/model/_plot_types.py +0 -0
  439. /scitex/{fig → canvas}/utils/_defaults.py +0 -0
  440. /scitex/{fig → canvas}/utils/_validate.py +0 -0
  441. /scitex/{fts/_bundle → io/bundle}/_conversion/__init__.py +0 -0
  442. /scitex/{fts/_bundle → io/bundle}/_conversion/_bundle2dict.py +0 -0
  443. /scitex/{fts/_bundle → io/bundle}/_conversion/_dict2bundle.py +0 -0
  444. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_Axes.py +0 -0
  445. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_BBox.py +0 -0
  446. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_ColumnDef.py +0 -0
  447. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataFormat.py +0 -0
  448. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataInfo.py +0 -0
  449. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataSource.py +0 -0
  450. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_SizeMM.py +0 -0
  451. /scitex/{fts/_bundle → io/bundle}/_extractors/__init__.py +0 -0
  452. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_bar.py +0 -0
  453. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_line.py +0 -0
  454. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_scatter.py +0 -0
  455. /scitex/{fts/_kinds → io/bundle/kinds}/__init__.py +0 -0
  456. /scitex/{fts/_kinds → io/bundle/kinds}/_figure/__init__.py +0 -0
  457. /scitex/{fts/_fig → io/bundle/kinds/_figure}/_composite.py +0 -0
  458. /scitex/{fts/_kinds → io/bundle/kinds}/_plot/__init__.py +0 -0
  459. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/__init__.py +0 -0
  460. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_export.py +0 -0
  461. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_render.py +0 -0
  462. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_ChannelEncoding.py +0 -0
  463. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Encoding.py +0 -0
  464. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Theme.py +0 -0
  465. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_TraceEncoding.py +0 -0
  466. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/__init__.py +0 -0
  467. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/__init__.py +0 -0
  468. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/__init__.py +0 -0
  469. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_bar.py +0 -0
  470. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_box.py +0 -0
  471. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_distribution.py +0 -0
  472. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_errorbar.py +0 -0
  473. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_histogram.py +0 -0
  474. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_image.py +0 -0
  475. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_line.py +0 -0
  476. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_scatter.py +0 -0
  477. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_seaborn.py +0 -0
  478. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_violin.py +0 -0
  479. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/__init__.py +0 -0
  480. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_auto_layout.py +0 -0
  481. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_calc_bounds.py +0 -0
  482. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_const_sizes.py +0 -0
  483. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_convert_coords.py +0 -0
  484. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_get_template.py +0 -0
  485. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_normalize.py +0 -0
  486. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_validate.py +0 -0
  487. /scitex/{fts/_kinds → io/bundle/kinds}/_shape/__init__.py +0 -0
  488. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/__init__.py +0 -0
  489. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/_Stats.py +0 -0
  490. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/__init__.py +0 -0
  491. /scitex/{fts/_kinds → io/bundle/kinds}/_table/__init__.py +0 -0
  492. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/__init__.py +0 -0
  493. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_stats_formatter.py +0 -0
  494. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_utils.py +0 -0
  495. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_validator.py +0 -0
  496. /scitex/{fts/_kinds → io/bundle/kinds}/_text/__init__.py +0 -0
  497. /scitex/{fts/_schemas → io/bundle/schemas}/data_info.schema.json +0 -0
  498. /scitex/{fts/_schemas → io/bundle/schemas}/encoding.schema.json +0 -0
  499. /scitex/{fts/_schemas → io/bundle/schemas}/node.schema.json +0 -0
  500. /scitex/{fts/_schemas → io/bundle/schemas}/render_manifest.schema.json +0 -0
  501. /scitex/{fts/_schemas → io/bundle/schemas}/stats.schema.json +0 -0
  502. /scitex/{fts/_schemas → io/bundle/schemas}/theme.schema.json +0 -0
  503. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
  504. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # Timestamp: "2025-12-14 (ywatanabe)"
4
3
  # File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/io/_layered_bundle.py
5
4
 
6
5
  """
7
- Layered .pltz Bundle I/O - New schema with spec/style/geometry separation.
6
+ Layered .plot Bundle I/O - New schema with spec/style/geometry separation.
8
7
 
9
8
  Bundle structure:
10
- plot.pltz.d/
9
+ plot.plot/
11
10
  spec.json # Semantic: WHAT to plot (canonical)
12
11
  style.json # Appearance: HOW it looks (canonical)
13
12
  data.csv # Raw data (immutable)
@@ -25,31 +24,43 @@ Design Principles:
25
24
  - Canonical units: ratio (0-1) for axes bbox, mm for panel size
26
25
  """
27
26
 
28
- import json
29
27
  import hashlib
30
- from pathlib import Path
31
- from typing import Any, Dict, List, Optional, Tuple
28
+ import json
32
29
  from dataclasses import asdict
30
+ from pathlib import Path
31
+ from typing import Any, Dict, List, Optional
33
32
 
34
33
  from scitex import logging
35
34
  from scitex.plt.styles import get_default_dpi, get_preview_dpi
36
35
  from scitex.schema import (
37
- # Spec classes
38
- PltzSpec, PltzTraceSpec, PltzAxesItem, PltzAxesLimits, PltzAxesLabels,
39
- PltzDataSource, BboxRatio, BboxPx,
40
- # Style classes
41
- PltzStyle, PltzTheme, PltzFont, PltzSize, PltzTraceStyle, PltzLegendSpec,
42
- # Geometry classes
43
- PltzGeometry, PltzRenderedAxes, PltzRenderedArtist, PltzRenderManifest,
44
- # Version constants
45
- PLOT_SPEC_VERSION, PLOT_STYLE_VERSION, PLOT_GEOMETRY_VERSION,
36
+ PLOT_GEOMETRY_VERSION,
37
+ PLOT_SPEC_VERSION,
38
+ PLOT_STYLE_VERSION,
39
+ AxesLabels,
40
+ AxesLimits,
41
+ AxesSpecItem,
42
+ BboxPx,
43
+ BboxRatio,
44
+ DataSourceSpec,
45
+ FontSpec,
46
+ LegendSpec,
47
+ PlotGeometry,
48
+ PlotSpec,
49
+ PlotStyle,
50
+ RenderedArtist,
51
+ RenderedAxes,
52
+ RenderManifest,
53
+ SizeSpec,
54
+ ThemeSpec,
55
+ TraceSpec,
56
+ TraceStyleSpec,
46
57
  )
47
58
 
48
59
  logger = logging.getLogger()
49
60
 
50
61
  __all__ = [
51
- "save_layered_pltz_bundle",
52
- "load_layered_pltz_bundle",
62
+ "save_layered_plot_bundle",
63
+ "load_layered_plot_bundle",
53
64
  "merge_layered_bundle",
54
65
  "is_layered_bundle",
55
66
  ]
@@ -60,7 +71,7 @@ def is_layered_bundle(bundle_dir: Path) -> bool:
60
71
  return (bundle_dir / "spec.json").exists()
61
72
 
62
73
 
63
- def save_layered_pltz_bundle(
74
+ def save_layered_plot_bundle(
64
75
  fig,
65
76
  bundle_dir: Path,
66
77
  basename: str = "plot",
@@ -68,14 +79,14 @@ def save_layered_pltz_bundle(
68
79
  csv_df=None,
69
80
  ) -> None:
70
81
  """
71
- Save matplotlib figure as layered .pltz bundle.
82
+ Save matplotlib figure as layered .plot bundle.
72
83
 
73
84
  Parameters
74
85
  ----------
75
86
  fig : matplotlib.figure.Figure
76
87
  The figure to save.
77
88
  bundle_dir : Path
78
- Output directory (e.g., plot.pltz.d).
89
+ Output directory (e.g., plot.plot).
79
90
  basename : str
80
91
  Base filename for exports.
81
92
  dpi : int, optional
@@ -86,9 +97,10 @@ def save_layered_pltz_bundle(
86
97
  # Resolve DPI from config if not specified
87
98
  if dpi is None:
88
99
  dpi = get_default_dpi()
89
- import numpy as np
90
100
  import tempfile
91
101
  import warnings
102
+
103
+ import numpy as np
92
104
  from PIL import Image as PILImage
93
105
 
94
106
  bundle_dir = Path(bundle_dir)
@@ -103,7 +115,7 @@ def save_layered_pltz_bundle(
103
115
  # Extract figure dimensions
104
116
  fig_width_inch, fig_height_inch = fig.get_size_inches()
105
117
 
106
- # === Build PltzSpec (semantic) ===
118
+ # === Build PlotSpec (semantic) ===
107
119
  axes_items = []
108
120
  traces = []
109
121
  extracted_data = {}
@@ -113,7 +125,7 @@ def save_layered_pltz_bundle(
113
125
  ax_id = f"ax{ax_idx}"
114
126
 
115
127
  # Create axes item
116
- ax_item = PltzAxesItem(
128
+ ax_item = AxesSpecItem(
117
129
  id=ax_id,
118
130
  bbox=BboxRatio(
119
131
  x0=round(bbox.x0, 4),
@@ -122,11 +134,11 @@ def save_layered_pltz_bundle(
122
134
  height=round(bbox.height, 4),
123
135
  space="panel",
124
136
  ),
125
- limits=PltzAxesLimits(
137
+ limits=AxesLimits(
126
138
  x=list(ax.get_xlim()),
127
139
  y=list(ax.get_ylim()),
128
140
  ),
129
- labels=PltzAxesLabels(
141
+ labels=AxesLabels(
130
142
  xlabel=ax.get_xlabel() or None,
131
143
  ylabel=ax.get_ylabel() or None,
132
144
  title=ax.get_title() or None,
@@ -137,8 +149,8 @@ def save_layered_pltz_bundle(
137
149
  # Extract traces from lines
138
150
  for line_idx, line in enumerate(ax.get_lines()):
139
151
  label = line.get_label()
140
- if label is None or label.startswith('_'):
141
- label = f'series_{line_idx}'
152
+ if label is None or label.startswith("_"):
153
+ label = f"series_{line_idx}"
142
154
 
143
155
  trace_id = f"{ax_id}-line-{line_idx}"
144
156
  xdata, ydata = line.get_data()
@@ -149,7 +161,7 @@ def save_layered_pltz_bundle(
149
161
  extracted_data[x_col] = np.array(xdata)
150
162
  extracted_data[y_col] = np.array(ydata)
151
163
 
152
- trace = PltzTraceSpec(
164
+ trace = TraceSpec(
153
165
  id=trace_id,
154
166
  type="line",
155
167
  axes_index=ax_idx,
@@ -165,13 +177,16 @@ def save_layered_pltz_bundle(
165
177
  if extracted_data:
166
178
  # Use extracted data from matplotlib artists (captures axhline, etc.)
167
179
  import pandas as pd
180
+
168
181
  max_len = max(len(v) for v in extracted_data.values())
169
182
  padded = {}
170
183
  for k, v in extracted_data.items():
171
184
  # Convert to float for NaN padding compatibility
172
185
  v_float = np.array(v, dtype=float)
173
186
  if len(v_float) < max_len:
174
- padded[k] = np.pad(v_float, (0, max_len - len(v_float)), constant_values=np.nan)
187
+ padded[k] = np.pad(
188
+ v_float, (0, max_len - len(v_float)), constant_values=np.nan
189
+ )
175
190
  else:
176
191
  padded[k] = v_float
177
192
  csv_df = pd.DataFrame(padded)
@@ -185,9 +200,9 @@ def save_layered_pltz_bundle(
185
200
  csv_hash = f"sha256:{hashlib.sha256(csv_str.encode()).hexdigest()[:16]}"
186
201
 
187
202
  # Create spec
188
- spec = PltzSpec(
203
+ spec = PlotSpec(
189
204
  plot_id=basename,
190
- data=PltzDataSource(
205
+ data=DataSourceSpec(
191
206
  csv=f"{basename}.csv",
192
207
  format="wide",
193
208
  hash=csv_hash,
@@ -196,33 +211,36 @@ def save_layered_pltz_bundle(
196
211
  traces=traces,
197
212
  )
198
213
 
199
- # === Build PltzStyle (appearance) ===
214
+ # === Build PlotStyle (appearance) ===
200
215
  # Detect theme from figure
201
216
  theme_mode = "light"
202
- if hasattr(fig, '_scitex_theme'):
217
+ if hasattr(fig, "_scitex_theme"):
203
218
  theme_mode = fig._scitex_theme
204
219
 
205
220
  trace_styles = []
206
221
  for ax_idx, ax in enumerate(fig.axes):
207
222
  for line_idx, line in enumerate(ax.get_lines()):
208
223
  label = line.get_label()
209
- if label and not label.startswith('_'):
224
+ if label and not label.startswith("_"):
210
225
  # Get line color
211
226
  import matplotlib.colors as mcolors
227
+
212
228
  color = line.get_color()
213
229
  if isinstance(color, (list, tuple)):
214
230
  color = mcolors.to_hex(color)
215
231
 
216
232
  trace_id = f"ax{ax_idx}-line-{line_idx}"
217
- trace_styles.append(PltzTraceStyle(
218
- trace_id=trace_id,
219
- color=color,
220
- linewidth=line.get_linewidth(),
221
- alpha=line.get_alpha(),
222
- ))
233
+ trace_styles.append(
234
+ TraceStyleSpec(
235
+ trace_id=trace_id,
236
+ color=color,
237
+ linewidth=line.get_linewidth(),
238
+ alpha=line.get_alpha(),
239
+ )
240
+ )
223
241
 
224
242
  # Extract legend configuration from first axes with legend
225
- legend_spec = PltzLegendSpec(visible=True, location="best")
243
+ legend_spec = LegendSpec(visible=True, location="best")
226
244
  for ax in fig.axes:
227
245
  legend = ax.get_legend()
228
246
  if legend is not None:
@@ -230,9 +248,17 @@ def save_layered_pltz_bundle(
230
248
  # matplotlib legend._loc can be int or string
231
249
  loc = legend._loc
232
250
  loc_map = {
233
- 0: "best", 1: "upper right", 2: "upper left", 3: "lower left",
234
- 4: "lower right", 5: "right", 6: "center left", 7: "center right",
235
- 8: "lower center", 9: "upper center", 10: "center",
251
+ 0: "best",
252
+ 1: "upper right",
253
+ 2: "upper left",
254
+ 3: "lower left",
255
+ 4: "lower right",
256
+ 5: "right",
257
+ 6: "center left",
258
+ 7: "center right",
259
+ 8: "lower center",
260
+ 9: "upper center",
261
+ 10: "center",
236
262
  }
237
263
  if isinstance(loc, int):
238
264
  location = loc_map.get(loc, "best")
@@ -269,18 +295,18 @@ def save_layered_pltz_bundle(
269
295
  pass # Keep "best" if we can't determine
270
296
 
271
297
  # Extract other legend properties
272
- legend_spec = PltzLegendSpec(
298
+ legend_spec = LegendSpec(
273
299
  visible=legend.get_visible(),
274
300
  location=location,
275
301
  frameon=legend.get_frame_on(),
276
- fontsize=legend._fontsize if hasattr(legend, '_fontsize') else None,
277
- ncols=legend._ncols if hasattr(legend, '_ncols') else 1,
302
+ fontsize=legend._fontsize if hasattr(legend, "_fontsize") else None,
303
+ ncols=legend._ncols if hasattr(legend, "_ncols") else 1,
278
304
  title=legend.get_title().get_text() if legend.get_title() else None,
279
305
  )
280
306
  break # Use first legend found
281
307
 
282
- style = PltzStyle(
283
- theme=PltzTheme(
308
+ style = PlotStyle(
309
+ theme=ThemeSpec(
284
310
  mode=theme_mode,
285
311
  colors={
286
312
  "background": "transparent",
@@ -290,11 +316,11 @@ def save_layered_pltz_bundle(
290
316
  "tick": "black" if theme_mode == "light" else "#e8e8e8",
291
317
  },
292
318
  ),
293
- size=PltzSize(
319
+ size=SizeSpec(
294
320
  width_mm=round(fig_width_inch * 25.4, 1),
295
321
  height_mm=round(fig_height_inch * 25.4, 1),
296
322
  ),
297
- font=PltzFont(family="sans-serif", size_pt=8.0),
323
+ font=FontSpec(family="sans-serif", size_pt=8.0),
298
324
  traces=trace_styles,
299
325
  legend=legend_spec,
300
326
  )
@@ -353,22 +379,25 @@ def save_layered_pltz_bundle(
353
379
  tmp_path = Path(tmp_dir)
354
380
 
355
381
  with warnings.catch_warnings():
356
- warnings.filterwarnings('ignore', message='.*tight_layout.*')
382
+ warnings.filterwarnings("ignore", message=".*tight_layout.*")
357
383
 
358
384
  # Save PNG at full figure size (crop function will handle tight cropping)
359
385
  # This ensures coordinate transformations are accurate
360
386
  png_path = exports_dir / f"{basename}.png"
361
- fig.savefig(png_path, dpi=dpi, format='png', transparent=True)
387
+ fig.savefig(png_path, dpi=dpi, format="png", transparent=True)
362
388
 
363
389
  # Save SVG with tight bbox (separate concern, no coord issues)
364
390
  svg_path = exports_dir / f"{basename}.svg"
365
- fig.savefig(svg_path, bbox_inches='tight', format='svg')
391
+ fig.savefig(svg_path, bbox_inches="tight", format="svg")
366
392
 
367
393
  # Generate hitmap
368
394
  from scitex.plt.utils._hitmap import (
369
- apply_hitmap_colors, restore_original_colors,
370
- extract_path_data, extract_selectable_regions,
371
- HITMAP_BACKGROUND_COLOR, HITMAP_AXES_COLOR
395
+ HITMAP_AXES_COLOR,
396
+ HITMAP_BACKGROUND_COLOR,
397
+ apply_hitmap_colors,
398
+ extract_path_data,
399
+ extract_selectable_regions,
400
+ restore_original_colors,
372
401
  )
373
402
 
374
403
  original_props, color_map, groups = apply_hitmap_colors(fig)
@@ -386,8 +415,9 @@ def save_layered_pltz_bundle(
386
415
 
387
416
  # Save hitmap at full figure size (will crop with same box as main PNG)
388
417
  hitmap_path = exports_dir / f"{basename}_hitmap.png"
389
- fig.savefig(hitmap_path, dpi=dpi, format='png',
390
- facecolor=HITMAP_BACKGROUND_COLOR)
418
+ fig.savefig(
419
+ hitmap_path, dpi=dpi, format="png", facecolor=HITMAP_BACKGROUND_COLOR
420
+ )
391
421
 
392
422
  # Restore colors
393
423
  restore_original_colors(original_props)
@@ -401,17 +431,26 @@ def save_layered_pltz_bundle(
401
431
  from scitex.plt.utils._crop import crop
402
432
 
403
433
  _, margin_crop_box = crop(
404
- str(png_path), output_path=str(png_path),
405
- overwrite=True, margin=12, verbose=False, return_offset=True,
434
+ str(png_path),
435
+ output_path=str(png_path),
436
+ overwrite=True,
437
+ margin=12,
438
+ verbose=False,
439
+ return_offset=True,
406
440
  )
407
441
 
408
- crop(str(hitmap_path), output_path=str(hitmap_path),
409
- overwrite=True, crop_box=(
410
- margin_crop_box['left'],
411
- margin_crop_box['upper'],
412
- margin_crop_box['right'],
413
- margin_crop_box['lower'],
414
- ), verbose=False)
442
+ crop(
443
+ str(hitmap_path),
444
+ output_path=str(hitmap_path),
445
+ overwrite=True,
446
+ crop_box=(
447
+ margin_crop_box["left"],
448
+ margin_crop_box["upper"],
449
+ margin_crop_box["right"],
450
+ margin_crop_box["lower"],
451
+ ),
452
+ verbose=False,
453
+ )
415
454
  except Exception as e:
416
455
  logger.debug(f"Crop failed: {e}")
417
456
 
@@ -432,7 +471,7 @@ def save_layered_pltz_bundle(
432
471
  total_offset_left = margin_crop_box["left"] if margin_crop_box else 0
433
472
  total_offset_upper = margin_crop_box["upper"] if margin_crop_box else 0
434
473
 
435
- # === Build PltzGeometry (cache) ===
474
+ # === Build PlotGeometry (cache) ===
436
475
  # Extract at export DPI so coords are in full figure space (matches saved PNG before crop)
437
476
  path_data = extract_path_data(fig)
438
477
  selectable_regions = extract_selectable_regions(fig)
@@ -456,35 +495,51 @@ def save_layered_pltz_bundle(
456
495
  rendered_axes = []
457
496
  for ax_idx, ax_data in enumerate(path_data.get("axes", [])):
458
497
  bbox_data = ax_data.get("bbox_px", {})
459
- rendered_axes.append(PltzRenderedAxes(
460
- id=f"ax{ax_idx}",
461
- xlim=ax_data.get("xlim", [0, 1]),
462
- ylim=ax_data.get("ylim", [0, 1]),
463
- bbox_px=BboxPx(
464
- x0=bbox_data.get("x0", 0),
465
- y0=bbox_data.get("y0", 0),
466
- width=bbox_data.get("width", bbox_data.get("x1", 0) - bbox_data.get("x0", 0)),
467
- height=bbox_data.get("height", bbox_data.get("y1", 0) - bbox_data.get("y0", 0)),
468
- ),
469
- ))
498
+ rendered_axes.append(
499
+ RenderedAxes(
500
+ id=f"ax{ax_idx}",
501
+ xlim=ax_data.get("xlim", [0, 1]),
502
+ ylim=ax_data.get("ylim", [0, 1]),
503
+ bbox_px=BboxPx(
504
+ x0=bbox_data.get("x0", 0),
505
+ y0=bbox_data.get("y0", 0),
506
+ width=bbox_data.get(
507
+ "width", bbox_data.get("x1", 0) - bbox_data.get("x0", 0)
508
+ ),
509
+ height=bbox_data.get(
510
+ "height", bbox_data.get("y1", 0) - bbox_data.get("y0", 0)
511
+ ),
512
+ ),
513
+ )
514
+ )
470
515
 
471
516
  rendered_artists = []
472
517
  for artist in path_data.get("artists", []):
473
518
  bbox_data = artist.get("bbox_px", {})
474
- rendered_artists.append(PltzRenderedArtist(
475
- id=str(artist.get("id", "")),
476
- type=artist.get("type", "unknown"),
477
- axes_index=artist.get("axes_index", 0),
478
- bbox_px=BboxPx(
479
- x0=bbox_data.get("x0", 0),
480
- y0=bbox_data.get("y0", 0),
481
- width=bbox_data.get("width", bbox_data.get("x1", 0) - bbox_data.get("x0", 0)),
482
- height=bbox_data.get("height", bbox_data.get("y1", 0) - bbox_data.get("y0", 0)),
483
- ) if bbox_data else None,
484
- path_px=artist.get("path_px"),
485
- ))
486
-
487
- geometry = PltzGeometry(
519
+ rendered_artists.append(
520
+ RenderedArtist(
521
+ id=str(artist.get("id", "")),
522
+ type=artist.get("type", "unknown"),
523
+ axes_index=artist.get("axes_index", 0),
524
+ bbox_px=(
525
+ BboxPx(
526
+ x0=bbox_data.get("x0", 0),
527
+ y0=bbox_data.get("y0", 0),
528
+ width=bbox_data.get(
529
+ "width", bbox_data.get("x1", 0) - bbox_data.get("x0", 0)
530
+ ),
531
+ height=bbox_data.get(
532
+ "height", bbox_data.get("y1", 0) - bbox_data.get("y0", 0)
533
+ ),
534
+ )
535
+ if bbox_data
536
+ else None
537
+ ),
538
+ path_px=artist.get("path_px"),
539
+ )
540
+ )
541
+
542
+ geometry = PlotGeometry(
488
543
  source_hash=csv_hash or "",
489
544
  figure_px=final_image_size_px, # Final cropped image size
490
545
  dpi=dpi, # Export DPI (stored for consumers)
@@ -497,7 +552,7 @@ def save_layered_pltz_bundle(
497
552
  "groups": groups,
498
553
  # Store DPI info for consumers that need to retrieve from data
499
554
  "fig_dpi": fig_dpi, # Original matplotlib fig.dpi
500
- "export_dpi": dpi, # Export DPI used for PNG
555
+ "export_dpi": dpi, # Export DPI used for PNG
501
556
  "dpi_scale": dpi_scale, # export_dpi / fig_dpi
502
557
  },
503
558
  selectable_regions=selectable_regions,
@@ -510,34 +565,55 @@ def save_layered_pltz_bundle(
510
565
  # spec.json
511
566
  spec_path = bundle_dir / "spec.json"
512
567
  with open(spec_path, "w") as f:
513
- json.dump({
514
- "schema": {"name": "scitex.plt.spec", "version": PLOT_SPEC_VERSION},
515
- **asdict(spec),
516
- }, f, indent=2, default=str)
568
+ json.dump(
569
+ {
570
+ "schema": {"name": "scitex.plt.spec", "version": PLOT_SPEC_VERSION},
571
+ **asdict(spec),
572
+ },
573
+ f,
574
+ indent=2,
575
+ default=str,
576
+ )
517
577
 
518
578
  # style.json
519
579
  style_path = bundle_dir / "style.json"
520
580
  with open(style_path, "w") as f:
521
- json.dump({
522
- "schema": {"name": "scitex.plt.style", "version": PLOT_STYLE_VERSION},
523
- **asdict(style),
524
- }, f, indent=2, default=str)
581
+ json.dump(
582
+ {
583
+ "schema": {"name": "scitex.plt.style", "version": PLOT_STYLE_VERSION},
584
+ **asdict(style),
585
+ },
586
+ f,
587
+ indent=2,
588
+ default=str,
589
+ )
525
590
 
526
591
  # cache/geometry_px.json
527
592
  geometry_path = cache_dir / "geometry_px.json"
528
593
  with open(geometry_path, "w") as f:
529
- json.dump({
530
- "schema": {"name": "scitex.plt.geometry", "version": PLOT_GEOMETRY_VERSION},
531
- "_comment": "CACHE - can be deleted and regenerated from spec + style",
532
- **asdict(geometry),
533
- }, f, indent=2, default=str)
594
+ json.dump(
595
+ {
596
+ "schema": {
597
+ "name": "scitex.plt.geometry",
598
+ "version": PLOT_GEOMETRY_VERSION,
599
+ },
600
+ "_comment": "CACHE - can be deleted and regenerated from spec + style",
601
+ **asdict(geometry),
602
+ },
603
+ f,
604
+ indent=2,
605
+ default=str,
606
+ )
534
607
 
535
608
  # cache/render_manifest.json
536
609
  spec_hash = hashlib.sha256(open(spec_path, "rb").read()).hexdigest()[:16]
537
610
  style_hash = hashlib.sha256(open(style_path, "rb").read()).hexdigest()[:16]
538
- manifest = PltzRenderManifest(
611
+ manifest = RenderManifest(
539
612
  source_hash=f"{spec_hash}:{style_hash}",
540
- panel_size_mm=[round(fig_width_inch * 25.4, 1), round(fig_height_inch * 25.4, 1)],
613
+ panel_size_mm=[
614
+ round(fig_width_inch * 25.4, 1),
615
+ round(fig_height_inch * 25.4, 1),
616
+ ],
541
617
  dpi=dpi,
542
618
  render_px=final_image_size_px,
543
619
  overview_png=f"exports/{basename}.png",
@@ -546,10 +622,18 @@ def save_layered_pltz_bundle(
546
622
  )
547
623
  manifest_path = cache_dir / "render_manifest.json"
548
624
  with open(manifest_path, "w") as f:
549
- json.dump({
550
- "schema": {"name": "scitex.plt.render_manifest", "version": PLOT_GEOMETRY_VERSION},
551
- **asdict(manifest),
552
- }, f, indent=2, default=str)
625
+ json.dump(
626
+ {
627
+ "schema": {
628
+ "name": "scitex.plt.render_manifest",
629
+ "version": PLOT_GEOMETRY_VERSION,
630
+ },
631
+ **asdict(manifest),
632
+ },
633
+ f,
634
+ indent=2,
635
+ default=str,
636
+ )
553
637
 
554
638
  # Save CSV
555
639
  if csv_df is not None:
@@ -557,26 +641,26 @@ def save_layered_pltz_bundle(
557
641
  csv_df.to_csv(csv_path, index=False)
558
642
 
559
643
  # Generate overview showing main image and hitmap side by side
560
- _generate_pltz_overview(exports_dir, basename)
644
+ _generate_plot_overview(exports_dir, basename)
561
645
 
562
646
  # Generate dynamic README.md
563
- _generate_pltz_readme(bundle_dir, basename, spec, style, geometry, manifest)
647
+ _generate_plot_readme(bundle_dir, basename, spec, style, geometry, manifest)
564
648
 
565
- logger.debug(f"Saved layered pltz bundle: {bundle_dir}")
649
+ logger.debug(f"Saved layered plot bundle: {bundle_dir}")
566
650
 
567
651
 
568
- def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
652
+ def _generate_plot_overview(exports_dir: Path, basename: str) -> None:
569
653
  """Generate comprehensive overview with plot, hitmap, overlay, bboxes, and JSON info.
570
654
 
571
655
  Args:
572
656
  exports_dir: Path to exports directory.
573
657
  basename: Base filename for the bundle.
574
658
  """
575
- import matplotlib.pyplot as plt
576
- import matplotlib.patches as patches
577
- from PIL import Image
578
659
  import warnings
660
+
661
+ import matplotlib.pyplot as plt
579
662
  import numpy as np
663
+ from PIL import Image
580
664
 
581
665
  bundle_dir = exports_dir.parent
582
666
  png_path = exports_dir / f"{basename}.png"
@@ -602,16 +686,16 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
602
686
  manifest_path = bundle_dir / "cache" / "render_manifest.json"
603
687
 
604
688
  if spec_path.exists():
605
- with open(spec_path, "r") as f:
689
+ with open(spec_path) as f:
606
690
  spec_data = json.load(f)
607
691
  if style_path.exists():
608
- with open(style_path, "r") as f:
692
+ with open(style_path) as f:
609
693
  style_data = json.load(f)
610
694
  if geometry_path.exists():
611
- with open(geometry_path, "r") as f:
695
+ with open(geometry_path) as f:
612
696
  geometry_data = json.load(f)
613
697
  if manifest_path.exists():
614
- with open(manifest_path, "r") as f:
698
+ with open(manifest_path) as f:
615
699
  manifest_data = json.load(f)
616
700
 
617
701
  # Get DPI and panel size for mm scaler
@@ -659,12 +743,28 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
659
743
  if color_map_id in color_map:
660
744
  label = color_map[color_map_id].get("label", label)
661
745
 
662
- ax_hitmap.text(cx, cy, label, fontsize=8, ha="center", va="center",
663
- color="white", fontweight="bold",
664
- bbox=dict(boxstyle="round,pad=0.2", facecolor="black", alpha=0.7))
746
+ ax_hitmap.text(
747
+ cx,
748
+ cy,
749
+ label,
750
+ fontsize=8,
751
+ ha="center",
752
+ va="center",
753
+ color="white",
754
+ fontweight="bold",
755
+ bbox=dict(
756
+ boxstyle="round,pad=0.2", facecolor="black", alpha=0.7
757
+ ),
758
+ )
665
759
  else:
666
- ax_hitmap.text(0.5, 0.5, "No hitmap", ha="center", va="center",
667
- transform=ax_hitmap.transAxes)
760
+ ax_hitmap.text(
761
+ 0.5,
762
+ 0.5,
763
+ "No hitmap",
764
+ ha="center",
765
+ va="center",
766
+ transform=ax_hitmap.transAxes,
767
+ )
668
768
  ax_hitmap.axis("off")
669
769
 
670
770
  # 3. Overlay (plot + hitmap with transparency)
@@ -686,7 +786,7 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
686
786
  ax_bboxes.imshow(main_img)
687
787
 
688
788
  # Note: bbox_px coordinates are already in final image space
689
- # (adjusted during save_layered_pltz_bundle), so no offset needed
789
+ # (adjusted during save_layered_plot_bundle), so no offset needed
690
790
 
691
791
  # Draw bboxes from geometry
692
792
  colors = ["red", "blue", "green", "orange", "purple", "cyan"]
@@ -740,12 +840,18 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
740
840
 
741
841
  # Format JSON summary with limited depth
742
842
  json_text = _format_json_summary(
743
- {"spec": spec_data, "style": style_data},
744
- max_depth=2
843
+ {"spec": spec_data, "style": style_data}, max_depth=2
844
+ )
845
+ ax_json.text(
846
+ 0.02,
847
+ 0.98,
848
+ json_text,
849
+ transform=ax_json.transAxes,
850
+ fontsize=7,
851
+ fontfamily="monospace",
852
+ verticalalignment="top",
853
+ bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.5),
745
854
  )
746
- ax_json.text(0.02, 0.98, json_text, transform=ax_json.transAxes,
747
- fontsize=7, fontfamily="monospace", verticalalignment="top",
748
- bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.5))
749
855
 
750
856
  # 6. mm Scaler
751
857
  ax_scale = fig.add_subplot(gs[1, 2])
@@ -756,11 +862,11 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
756
862
 
757
863
  # Add grid lines every 10mm
758
864
  for x in range(0, int(panel_size_mm[0]) + 1, 10):
759
- ax_scale.axvline(x, color='gray', linewidth=0.5, alpha=0.5)
865
+ ax_scale.axvline(x, color="gray", linewidth=0.5, alpha=0.5)
760
866
  if x > 0:
761
867
  ax_scale.text(x, -1, f"{x}", ha="center", fontsize=7)
762
868
  for y in range(0, int(panel_size_mm[1]) + 1, 10):
763
- ax_scale.axhline(y, color='gray', linewidth=0.5, alpha=0.5)
869
+ ax_scale.axhline(y, color="gray", linewidth=0.5, alpha=0.5)
764
870
  if y > 0:
765
871
  ax_scale.text(-1, y, f"{y}", ha="right", va="center", fontsize=7)
766
872
 
@@ -771,31 +877,43 @@ def _generate_pltz_overview(exports_dir: Path, basename: str) -> None:
771
877
 
772
878
  # Add size text
773
879
  size_text = f"Panel: {panel_size_mm[0]:.1f} × {panel_size_mm[1]:.1f} mm\nDPI: {dpi}\nPixels: {img_width} × {img_height}"
774
- ax_scale.text(panel_size_mm[0] * 0.95, panel_size_mm[1] * 0.95, size_text,
775
- ha="right", va="bottom", fontsize=8,
776
- bbox=dict(boxstyle="round", facecolor="white", alpha=0.8))
880
+ ax_scale.text(
881
+ panel_size_mm[0] * 0.95,
882
+ panel_size_mm[1] * 0.95,
883
+ size_text,
884
+ ha="right",
885
+ va="bottom",
886
+ fontsize=8,
887
+ bbox=dict(boxstyle="round", facecolor="white", alpha=0.8),
888
+ )
777
889
 
778
890
  fig.suptitle(f"Overview: {basename}", fontsize=14, fontweight="bold", y=0.98)
779
891
 
780
892
  overview_path = exports_dir / f"{basename}_overview.png"
781
893
  with warnings.catch_warnings():
782
894
  warnings.filterwarnings("ignore", message=".*tight_layout.*")
783
- fig.savefig(overview_path, dpi=get_preview_dpi(), bbox_inches="tight", facecolor="white")
895
+ fig.savefig(
896
+ overview_path,
897
+ dpi=get_preview_dpi(),
898
+ bbox_inches="tight",
899
+ facecolor="white",
900
+ )
784
901
  plt.close(fig)
785
902
 
786
903
  except Exception as e:
787
- logger.debug(f"Could not generate pltz overview: {e}")
904
+ logger.debug(f"Could not generate plot overview: {e}")
788
905
  import traceback
906
+
789
907
  logger.debug(traceback.format_exc())
790
908
 
791
909
 
792
- def _generate_pltz_readme(
910
+ def _generate_plot_readme(
793
911
  bundle_dir: Path,
794
912
  basename: str,
795
- spec: "PltzSpec",
796
- style: "PltzStyle",
797
- geometry: "PltzGeometry",
798
- manifest: "PltzRenderManifest",
913
+ spec: "PlotSpec",
914
+ style: "PlotStyle",
915
+ geometry: "PlotGeometry",
916
+ manifest: "RenderManifest",
799
917
  ) -> None:
800
918
  """Generate a dynamic README.md describing the bundle.
801
919
 
@@ -805,13 +923,13 @@ def _generate_pltz_readme(
805
923
  Path to the bundle directory.
806
924
  basename : str
807
925
  Base filename for the bundle.
808
- spec : PltzSpec
926
+ spec : PlotSpec
809
927
  The plot specification.
810
- style : PltzStyle
928
+ style : PlotStyle
811
929
  The plot style.
812
- geometry : PltzGeometry
930
+ geometry : PlotGeometry
813
931
  The rendered geometry.
814
- manifest : PltzRenderManifest
932
+ manifest : RenderManifest
815
933
  The render manifest.
816
934
  """
817
935
  from datetime import datetime
@@ -826,7 +944,7 @@ def _generate_pltz_readme(
826
944
  dpi = manifest.dpi
827
945
  render_px = manifest.render_px
828
946
 
829
- readme_content = f"""# {basename}.pltz.d
947
+ readme_content = f"""# {basename}.plot
830
948
 
831
949
  > SciTeX Layered Plot Bundle - Auto-generated README
832
950
 
@@ -837,7 +955,7 @@ def _generate_pltz_readme(
837
955
  ## Bundle Structure
838
956
 
839
957
  ```
840
- {basename}.pltz.d/
958
+ {basename}.plot/
841
959
  ├── spec.json # WHAT to plot (semantic, editable)
842
960
  ├── style.json # HOW it looks (appearance, editable)
843
961
  ├── {basename}.csv # Raw data (immutable)
@@ -862,7 +980,7 @@ def _generate_pltz_readme(
862
980
  | Size | {width_mm:.1f} × {height_mm:.1f} mm |
863
981
  | DPI | {dpi} |
864
982
  | Pixels | {render_px[0]} × {render_px[1]} |
865
- | Theme | {style.theme.mode if style.theme else 'light'} |
983
+ | Theme | {style.theme.mode if style.theme else "light"} |
866
984
 
867
985
  ## Coordinate System
868
986
 
@@ -893,7 +1011,7 @@ Original Figure (at export DPI)
893
1011
  import scitex as stx
894
1012
 
895
1013
  # Load the bundle
896
- bundle = stx.plt.io.load_layered_pltz_bundle("{bundle_dir}")
1014
+ bundle = stx.plt.io.load_layered_plot_bundle("{bundle_dir}")
897
1015
 
898
1016
  # Access components
899
1017
  spec = bundle["spec"] # What to plot
@@ -920,7 +1038,7 @@ stx.plt.io.regenerate_cache("{bundle_dir}")
920
1038
 
921
1039
  ---
922
1040
 
923
- *Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
1041
+ *Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}*
924
1042
  *Schema: scitex.plt v{PLOT_SPEC_VERSION}*
925
1043
  """
926
1044
 
@@ -953,6 +1071,7 @@ def _adjust_coords_for_offset(
953
1071
  selectable_regions with adjusted coordinates.
954
1072
  """
955
1073
  import copy
1074
+
956
1075
  result = copy.deepcopy(selectable_regions)
957
1076
 
958
1077
  def adjust_bbox(bbox: List[float]) -> List[float]:
@@ -1030,6 +1149,7 @@ def _adjust_path_data_for_offset(
1030
1149
  path_data with adjusted coordinates.
1031
1150
  """
1032
1151
  import copy
1152
+
1033
1153
  result = copy.deepcopy(path_data)
1034
1154
 
1035
1155
  # Adjust axes bbox_px
@@ -1089,6 +1209,7 @@ def _adjust_path_data_for_crop(
1089
1209
  path_data with adjusted coordinates.
1090
1210
  """
1091
1211
  import copy
1212
+
1092
1213
  result = copy.deepcopy(path_data)
1093
1214
 
1094
1215
  # Adjust axes bbox_px
@@ -1134,12 +1255,22 @@ def _draw_bbox(ax, bbox: List, color: str, label: str, lw: float = 2) -> None:
1134
1255
  x0, y0, x1, y1 = bbox
1135
1256
  width = x1 - x0
1136
1257
  height = y1 - y0
1137
- rect = patches.Rectangle((x0, y0), width, height,
1138
- linewidth=lw, edgecolor=color, facecolor='none')
1258
+ rect = patches.Rectangle(
1259
+ (x0, y0), width, height, linewidth=lw, edgecolor=color, facecolor="none"
1260
+ )
1139
1261
  ax.add_patch(rect)
1140
1262
  # Place label at top-left corner inside the box with background
1141
- ax.text(x0 + 2, y0 + 2, label, fontsize=6, color="white", va='top', ha='left',
1142
- fontweight='bold', bbox=dict(boxstyle="round,pad=0.1", facecolor=color, alpha=0.8))
1263
+ ax.text(
1264
+ x0 + 2,
1265
+ y0 + 2,
1266
+ label,
1267
+ fontsize=6,
1268
+ color="white",
1269
+ va="top",
1270
+ ha="left",
1271
+ fontweight="bold",
1272
+ bbox=dict(boxstyle="round,pad=0.1", facecolor=color, alpha=0.8),
1273
+ )
1143
1274
 
1144
1275
 
1145
1276
  def _format_json_summary(data: Dict, max_depth: int = 2, current_depth: int = 0) -> str:
@@ -1184,14 +1315,14 @@ def _format_json_summary(data: Dict, max_depth: int = 2, current_depth: int = 0)
1184
1315
  return "\n".join(lines[:40]) # Limit total lines
1185
1316
 
1186
1317
 
1187
- def load_layered_pltz_bundle(bundle_dir: Path) -> Dict[str, Any]:
1318
+ def load_layered_plot_bundle(bundle_dir: Path) -> Dict[str, Any]:
1188
1319
  """
1189
- Load layered .pltz bundle and return merged spec for editor.
1320
+ Load layered .plot bundle and return merged spec for editor.
1190
1321
 
1191
1322
  Parameters
1192
1323
  ----------
1193
1324
  bundle_dir : Path
1194
- Path to .pltz.d bundle.
1325
+ Path to .plot bundle.
1195
1326
 
1196
1327
  Returns
1197
1328
  -------
@@ -1211,20 +1342,20 @@ def load_layered_pltz_bundle(bundle_dir: Path) -> Dict[str, Any]:
1211
1342
  # Load spec.json
1212
1343
  spec_path = bundle_dir / "spec.json"
1213
1344
  if spec_path.exists():
1214
- with open(spec_path, "r") as f:
1345
+ with open(spec_path) as f:
1215
1346
  result["spec"] = json.load(f)
1216
1347
  result["basename"] = result["spec"].get("plot_id", "plot")
1217
1348
 
1218
1349
  # Load style.json
1219
1350
  style_path = bundle_dir / "style.json"
1220
1351
  if style_path.exists():
1221
- with open(style_path, "r") as f:
1352
+ with open(style_path) as f:
1222
1353
  result["style"] = json.load(f)
1223
1354
 
1224
1355
  # Load geometry from cache
1225
1356
  geometry_path = bundle_dir / "cache" / "geometry_px.json"
1226
1357
  if geometry_path.exists():
1227
- with open(geometry_path, "r") as f:
1358
+ with open(geometry_path) as f:
1228
1359
  result["geometry"] = json.load(f)
1229
1360
 
1230
1361
  # Create merged view for backward compatibility with editor
@@ -1266,7 +1397,11 @@ def merge_layered_bundle(
1266
1397
  merged["size"] = {
1267
1398
  "width_mm": style["size"].get("width_mm", 80),
1268
1399
  "height_mm": style["size"].get("height_mm", 68),
1269
- "dpi": geometry.get("dpi", get_default_dpi()) if geometry else get_default_dpi(),
1400
+ "dpi": (
1401
+ geometry.get("dpi", get_default_dpi())
1402
+ if geometry
1403
+ else get_default_dpi()
1404
+ ),
1270
1405
  }
1271
1406
 
1272
1407
  # Merge axes from spec + style + geometry