scitex 2.7.0__py3-none-any.whl → 2.8.1__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 (355) hide show
  1. scitex/__init__.py +6 -2
  2. scitex/__version__.py +1 -1
  3. scitex/audio/README.md +52 -0
  4. scitex/audio/__init__.py +384 -0
  5. scitex/audio/__main__.py +129 -0
  6. scitex/audio/_tts.py +334 -0
  7. scitex/audio/engines/__init__.py +44 -0
  8. scitex/audio/engines/base.py +275 -0
  9. scitex/audio/engines/elevenlabs_engine.py +143 -0
  10. scitex/audio/engines/gtts_engine.py +162 -0
  11. scitex/audio/engines/pyttsx3_engine.py +131 -0
  12. scitex/audio/mcp_server.py +757 -0
  13. scitex/bridge/_helpers.py +1 -1
  14. scitex/bridge/_plt_vis.py +1 -1
  15. scitex/bridge/_stats_vis.py +1 -1
  16. scitex/dev/plt/__init__.py +272 -0
  17. scitex/dev/plt/plot_mpl_axhline.py +28 -0
  18. scitex/dev/plt/plot_mpl_axhspan.py +28 -0
  19. scitex/dev/plt/plot_mpl_axvline.py +28 -0
  20. scitex/dev/plt/plot_mpl_axvspan.py +28 -0
  21. scitex/dev/plt/plot_mpl_bar.py +29 -0
  22. scitex/dev/plt/plot_mpl_barh.py +29 -0
  23. scitex/dev/plt/plot_mpl_boxplot.py +28 -0
  24. scitex/dev/plt/plot_mpl_contour.py +31 -0
  25. scitex/dev/plt/plot_mpl_contourf.py +31 -0
  26. scitex/dev/plt/plot_mpl_errorbar.py +30 -0
  27. scitex/dev/plt/plot_mpl_eventplot.py +28 -0
  28. scitex/dev/plt/plot_mpl_fill.py +30 -0
  29. scitex/dev/plt/plot_mpl_fill_between.py +31 -0
  30. scitex/dev/plt/plot_mpl_hexbin.py +28 -0
  31. scitex/dev/plt/plot_mpl_hist.py +28 -0
  32. scitex/dev/plt/plot_mpl_hist2d.py +28 -0
  33. scitex/dev/plt/plot_mpl_imshow.py +29 -0
  34. scitex/dev/plt/plot_mpl_pcolormesh.py +31 -0
  35. scitex/dev/plt/plot_mpl_pie.py +29 -0
  36. scitex/dev/plt/plot_mpl_plot.py +29 -0
  37. scitex/dev/plt/plot_mpl_quiver.py +31 -0
  38. scitex/dev/plt/plot_mpl_scatter.py +28 -0
  39. scitex/dev/plt/plot_mpl_stackplot.py +31 -0
  40. scitex/dev/plt/plot_mpl_stem.py +29 -0
  41. scitex/dev/plt/plot_mpl_step.py +29 -0
  42. scitex/dev/plt/plot_mpl_violinplot.py +28 -0
  43. scitex/dev/plt/plot_sns_barplot.py +29 -0
  44. scitex/dev/plt/plot_sns_boxplot.py +29 -0
  45. scitex/dev/plt/plot_sns_heatmap.py +28 -0
  46. scitex/dev/plt/plot_sns_histplot.py +29 -0
  47. scitex/dev/plt/plot_sns_kdeplot.py +29 -0
  48. scitex/dev/plt/plot_sns_lineplot.py +31 -0
  49. scitex/dev/plt/plot_sns_scatterplot.py +29 -0
  50. scitex/dev/plt/plot_sns_stripplot.py +29 -0
  51. scitex/dev/plt/plot_sns_swarmplot.py +29 -0
  52. scitex/dev/plt/plot_sns_violinplot.py +29 -0
  53. scitex/dev/plt/plot_stx_bar.py +29 -0
  54. scitex/dev/plt/plot_stx_barh.py +29 -0
  55. scitex/dev/plt/plot_stx_box.py +28 -0
  56. scitex/dev/plt/plot_stx_boxplot.py +28 -0
  57. scitex/dev/plt/plot_stx_conf_mat.py +28 -0
  58. scitex/dev/plt/plot_stx_contour.py +31 -0
  59. scitex/dev/plt/plot_stx_ecdf.py +28 -0
  60. scitex/dev/plt/plot_stx_errorbar.py +30 -0
  61. scitex/dev/plt/plot_stx_fill_between.py +31 -0
  62. scitex/dev/plt/plot_stx_fillv.py +28 -0
  63. scitex/dev/plt/plot_stx_heatmap.py +28 -0
  64. scitex/dev/plt/plot_stx_image.py +28 -0
  65. scitex/dev/plt/plot_stx_imshow.py +28 -0
  66. scitex/dev/plt/plot_stx_joyplot.py +28 -0
  67. scitex/dev/plt/plot_stx_kde.py +28 -0
  68. scitex/dev/plt/plot_stx_line.py +28 -0
  69. scitex/dev/plt/plot_stx_mean_ci.py +28 -0
  70. scitex/dev/plt/plot_stx_mean_std.py +28 -0
  71. scitex/dev/plt/plot_stx_median_iqr.py +28 -0
  72. scitex/dev/plt/plot_stx_raster.py +28 -0
  73. scitex/dev/plt/plot_stx_rectangle.py +28 -0
  74. scitex/dev/plt/plot_stx_scatter.py +29 -0
  75. scitex/dev/plt/plot_stx_shaded_line.py +29 -0
  76. scitex/dev/plt/plot_stx_violin.py +28 -0
  77. scitex/dev/plt/plot_stx_violinplot.py +28 -0
  78. scitex/diagram/README.md +197 -0
  79. scitex/diagram/__init__.py +48 -0
  80. scitex/diagram/_compile.py +312 -0
  81. scitex/diagram/_diagram.py +355 -0
  82. scitex/diagram/_presets.py +173 -0
  83. scitex/diagram/_schema.py +182 -0
  84. scitex/diagram/_split.py +278 -0
  85. scitex/fig/__init__.py +352 -0
  86. scitex/{vis → fig}/backend/_parser.py +1 -1
  87. scitex/{vis → fig}/canvas.py +1 -1
  88. scitex/{vis → fig}/editor/__init__.py +5 -2
  89. scitex/{vis → fig}/editor/_dearpygui_editor.py +1 -1
  90. scitex/{vis → fig}/editor/_defaults.py +70 -5
  91. scitex/{vis → fig}/editor/_mpl_editor.py +1 -1
  92. scitex/{vis → fig}/editor/_qt_editor.py +182 -2
  93. scitex/{vis → fig}/editor/_tkinter_editor.py +1 -1
  94. scitex/fig/editor/edit/__init__.py +50 -0
  95. scitex/fig/editor/edit/backend_detector.py +109 -0
  96. scitex/fig/editor/edit/bundle_resolver.py +240 -0
  97. scitex/fig/editor/edit/editor_launcher.py +239 -0
  98. scitex/fig/editor/edit/manual_handler.py +53 -0
  99. scitex/fig/editor/edit/panel_loader.py +232 -0
  100. scitex/fig/editor/edit/path_resolver.py +67 -0
  101. scitex/fig/editor/flask_editor/_bbox.py +1299 -0
  102. scitex/fig/editor/flask_editor/_core.py +1429 -0
  103. scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
  104. scitex/fig/editor/flask_editor/_renderer.py +813 -0
  105. scitex/fig/editor/flask_editor/static/css/base/reset.css +41 -0
  106. scitex/fig/editor/flask_editor/static/css/base/typography.css +16 -0
  107. scitex/fig/editor/flask_editor/static/css/base/variables.css +85 -0
  108. scitex/fig/editor/flask_editor/static/css/components/buttons.css +217 -0
  109. scitex/fig/editor/flask_editor/static/css/components/context-menu.css +93 -0
  110. scitex/fig/editor/flask_editor/static/css/components/dropdown.css +57 -0
  111. scitex/fig/editor/flask_editor/static/css/components/forms.css +112 -0
  112. scitex/fig/editor/flask_editor/static/css/components/modal.css +59 -0
  113. scitex/fig/editor/flask_editor/static/css/components/sections.css +212 -0
  114. scitex/fig/editor/flask_editor/static/css/features/canvas.css +176 -0
  115. scitex/fig/editor/flask_editor/static/css/features/element-inspector.css +190 -0
  116. scitex/fig/editor/flask_editor/static/css/features/loading.css +59 -0
  117. scitex/fig/editor/flask_editor/static/css/features/overlay.css +45 -0
  118. scitex/fig/editor/flask_editor/static/css/features/panel-grid.css +95 -0
  119. scitex/fig/editor/flask_editor/static/css/features/selection.css +101 -0
  120. scitex/fig/editor/flask_editor/static/css/features/statistics.css +138 -0
  121. scitex/fig/editor/flask_editor/static/css/index.css +31 -0
  122. scitex/fig/editor/flask_editor/static/css/layout/container.css +7 -0
  123. scitex/fig/editor/flask_editor/static/css/layout/controls.css +56 -0
  124. scitex/fig/editor/flask_editor/static/css/layout/preview.css +78 -0
  125. scitex/fig/editor/flask_editor/static/js/alignment/axis.js +314 -0
  126. scitex/fig/editor/flask_editor/static/js/alignment/basic.js +107 -0
  127. scitex/fig/editor/flask_editor/static/js/alignment/distribute.js +54 -0
  128. scitex/fig/editor/flask_editor/static/js/canvas/canvas.js +172 -0
  129. scitex/fig/editor/flask_editor/static/js/canvas/dragging.js +258 -0
  130. scitex/fig/editor/flask_editor/static/js/canvas/resize.js +48 -0
  131. scitex/fig/editor/flask_editor/static/js/canvas/selection.js +71 -0
  132. scitex/fig/editor/flask_editor/static/js/core/api.js +288 -0
  133. scitex/fig/editor/flask_editor/static/js/core/state.js +143 -0
  134. scitex/fig/editor/flask_editor/static/js/core/utils.js +245 -0
  135. scitex/fig/editor/flask_editor/static/js/dev/element-inspector.js +992 -0
  136. scitex/fig/editor/flask_editor/static/js/editor/bbox.js +339 -0
  137. scitex/fig/editor/flask_editor/static/js/editor/element-drag.js +286 -0
  138. scitex/fig/editor/flask_editor/static/js/editor/overlay.js +371 -0
  139. scitex/fig/editor/flask_editor/static/js/editor/preview.js +293 -0
  140. scitex/fig/editor/flask_editor/static/js/main.js +426 -0
  141. scitex/fig/editor/flask_editor/static/js/shortcuts/context-menu.js +152 -0
  142. scitex/fig/editor/flask_editor/static/js/shortcuts/keyboard.js +265 -0
  143. scitex/fig/editor/flask_editor/static/js/ui/controls.js +184 -0
  144. scitex/fig/editor/flask_editor/static/js/ui/download.js +57 -0
  145. scitex/fig/editor/flask_editor/static/js/ui/help.js +100 -0
  146. scitex/fig/editor/flask_editor/static/js/ui/theme.js +34 -0
  147. scitex/fig/editor/flask_editor/templates/__init__.py +123 -0
  148. scitex/fig/editor/flask_editor/templates/_html.py +852 -0
  149. scitex/fig/editor/flask_editor/templates/_scripts.py +4933 -0
  150. scitex/fig/editor/flask_editor/templates/_styles.py +1658 -0
  151. scitex/{vis → fig}/io/__init__.py +13 -1
  152. scitex/fig/io/_bundle.py +1058 -0
  153. scitex/{vis → fig}/io/_canvas.py +1 -1
  154. scitex/{vis → fig}/io/_data.py +1 -1
  155. scitex/{vis → fig}/io/_export.py +1 -1
  156. scitex/{vis → fig}/io/_load.py +1 -1
  157. scitex/{vis → fig}/io/_panel.py +1 -1
  158. scitex/{vis → fig}/io/_save.py +1 -1
  159. scitex/{vis → fig}/model/__init__.py +1 -1
  160. scitex/{vis → fig}/model/_annotations.py +1 -1
  161. scitex/{vis → fig}/model/_axes.py +1 -1
  162. scitex/{vis → fig}/model/_figure.py +1 -1
  163. scitex/{vis → fig}/model/_guides.py +1 -1
  164. scitex/{vis → fig}/model/_plot.py +1 -1
  165. scitex/{vis → fig}/model/_styles.py +1 -1
  166. scitex/{vis → fig}/utils/__init__.py +1 -1
  167. scitex/io/__init__.py +22 -26
  168. scitex/io/_bundle.py +493 -0
  169. scitex/io/_flush.py +5 -2
  170. scitex/io/_load.py +98 -0
  171. scitex/io/_load_modules/_H5Explorer.py +5 -2
  172. scitex/io/_load_modules/_canvas.py +2 -2
  173. scitex/io/_load_modules/_image.py +3 -4
  174. scitex/io/_load_modules/_txt.py +4 -2
  175. scitex/io/_metadata.py +34 -324
  176. scitex/io/_metadata_modules/__init__.py +46 -0
  177. scitex/io/_metadata_modules/_embed.py +70 -0
  178. scitex/io/_metadata_modules/_read.py +64 -0
  179. scitex/io/_metadata_modules/_utils.py +79 -0
  180. scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
  181. scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
  182. scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
  183. scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
  184. scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
  185. scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
  186. scitex/io/_metadata_modules/read_metadata_png.py +39 -0
  187. scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
  188. scitex/io/_qr_utils.py +5 -3
  189. scitex/io/_save.py +548 -30
  190. scitex/io/_save_modules/_canvas.py +3 -3
  191. scitex/io/_save_modules/_image.py +5 -9
  192. scitex/io/_save_modules/_tex.py +7 -4
  193. scitex/io/_zip_bundle.py +439 -0
  194. scitex/io/utils/h5_to_zarr.py +11 -9
  195. scitex/msword/__init__.py +255 -0
  196. scitex/msword/profiles.py +357 -0
  197. scitex/msword/reader.py +753 -0
  198. scitex/msword/utils.py +289 -0
  199. scitex/msword/writer.py +362 -0
  200. scitex/plt/__init__.py +5 -2
  201. scitex/plt/_subplots/_AxesWrapper.py +6 -6
  202. scitex/plt/_subplots/_AxisWrapper.py +15 -9
  203. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
  204. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
  205. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
  206. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
  207. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
  208. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
  209. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
  210. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
  211. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
  212. scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
  213. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
  214. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
  215. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
  216. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
  217. scitex/plt/_subplots/_FigWrapper.py +6 -6
  218. scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
  219. scitex/plt/_subplots/_export_as_csv.py +35 -5
  220. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
  221. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
  222. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
  223. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
  224. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
  225. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
  226. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
  227. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
  228. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
  229. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
  230. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
  231. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
  232. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
  233. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
  234. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
  235. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
  236. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
  237. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
  238. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
  239. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
  240. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
  241. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
  242. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
  243. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
  244. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
  245. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
  246. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
  247. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
  248. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
  249. scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
  250. scitex/plt/gallery/_generate.py +421 -14
  251. scitex/plt/io/__init__.py +53 -0
  252. scitex/plt/io/_bundle.py +490 -0
  253. scitex/plt/io/_layered_bundle.py +1343 -0
  254. scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
  255. scitex/plt/styles/__init__.py +14 -0
  256. scitex/plt/styles/presets.py +78 -0
  257. scitex/plt/utils/__init__.py +13 -1
  258. scitex/plt/utils/_collect_figure_metadata.py +10 -14
  259. scitex/plt/utils/_configure_mpl.py +6 -18
  260. scitex/plt/utils/_crop.py +32 -14
  261. scitex/plt/utils/_csv_column_naming.py +54 -0
  262. scitex/plt/utils/_figure_mm.py +116 -1
  263. scitex/plt/utils/_hitmap.py +1643 -0
  264. scitex/plt/utils/metadata/__init__.py +25 -0
  265. scitex/plt/utils/metadata/_core.py +9 -10
  266. scitex/plt/utils/metadata/_dimensions.py +6 -3
  267. scitex/plt/utils/metadata/_editable_export.py +405 -0
  268. scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
  269. scitex/schema/__init__.py +109 -16
  270. scitex/schema/_canvas.py +1 -1
  271. scitex/schema/_plot.py +1015 -0
  272. scitex/schema/_stats.py +2 -2
  273. scitex/stats/__init__.py +117 -0
  274. scitex/stats/io/__init__.py +29 -0
  275. scitex/stats/io/_bundle.py +156 -0
  276. scitex/tex/__init__.py +4 -0
  277. scitex/tex/_export.py +890 -0
  278. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/METADATA +11 -1
  279. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/RECORD +294 -170
  280. scitex/io/memo.md +0 -2827
  281. scitex/plt/REQUESTS.md +0 -191
  282. scitex/plt/_subplots/TODO.md +0 -53
  283. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
  284. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
  285. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
  286. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
  287. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
  288. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
  289. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
  290. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
  291. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
  292. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
  293. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
  294. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
  295. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
  296. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
  297. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
  298. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
  299. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
  300. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
  301. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
  302. scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
  303. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
  304. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
  305. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
  306. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
  307. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
  308. scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
  309. scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
  310. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
  311. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
  312. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
  313. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
  314. scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
  315. scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
  316. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
  317. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
  318. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
  319. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
  320. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
  321. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
  322. scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
  323. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
  324. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
  325. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
  326. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
  327. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
  328. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
  329. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
  330. scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
  331. scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
  332. scitex/vis/__init__.py +0 -177
  333. scitex/vis/editor/_edit.py +0 -390
  334. scitex/vis/editor/flask_editor/_bbox.py +0 -529
  335. scitex/vis/editor/flask_editor/_core.py +0 -168
  336. scitex/vis/editor/flask_editor/_renderer.py +0 -393
  337. scitex/vis/editor/flask_editor/templates/__init__.py +0 -33
  338. scitex/vis/editor/flask_editor/templates/_html.py +0 -513
  339. scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
  340. scitex/vis/editor/flask_editor/templates/_styles.py +0 -739
  341. /scitex/{vis → fig}/README.md +0 -0
  342. /scitex/{vis → fig}/backend/__init__.py +0 -0
  343. /scitex/{vis → fig}/backend/_export.py +0 -0
  344. /scitex/{vis → fig}/backend/_render.py +0 -0
  345. /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
  346. /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
  347. /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
  348. /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
  349. /scitex/{vis → fig}/io/_directory.py +0 -0
  350. /scitex/{vis → fig}/model/_plot_types.py +0 -0
  351. /scitex/{vis → fig}/utils/_defaults.py +0 -0
  352. /scitex/{vis → fig}/utils/_validate.py +0 -0
  353. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/WHEEL +0 -0
  354. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/entry_points.txt +0 -0
  355. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/licenses/LICENSE +0 -0
@@ -5,9 +5,12 @@
5
5
 
6
6
  """Gallery generation functionality."""
7
7
 
8
+ import json
8
9
  import os
9
10
  from pathlib import Path
10
11
 
12
+ import numpy as np
13
+
11
14
  from ._plots import PLOT_FUNCTIONS
12
15
  from ._registry import CATEGORIES
13
16
 
@@ -20,9 +23,11 @@ def generate(
20
23
  dpi=150,
21
24
  save_csv=True,
22
25
  save_png=True,
26
+ save_svg=True,
27
+ save_pltz=True,
23
28
  verbose=True,
24
29
  ):
25
- """Generate gallery plots with CSVs.
30
+ """Generate gallery plots with CSVs and optional .pltz bundles.
26
31
 
27
32
  Parameters
28
33
  ----------
@@ -42,6 +47,10 @@ def generate(
42
47
  Whether to save CSV data files.
43
48
  save_png : bool
44
49
  Whether to save PNG image files.
50
+ save_svg : bool
51
+ Whether to save SVG image files for element selection.
52
+ save_pltz : bool
53
+ Whether to save .pltz bundles (reproducible plot packages).
45
54
  verbose : bool
46
55
  Print progress messages.
47
56
 
@@ -69,7 +78,7 @@ def generate(
69
78
  if verbose:
70
79
  print(f"Generating {len(plots_to_generate)} plots to {output_dir}")
71
80
 
72
- results = {"png": [], "csv": [], "errors": []}
81
+ results = {"png": [], "svg": [], "csv": [], "pltz": [], "errors": []}
73
82
 
74
83
  for plot_name in plots_to_generate:
75
84
  if plot_name not in PLOT_FUNCTIONS:
@@ -93,20 +102,70 @@ def generate(
93
102
  # Generate plot
94
103
  fig, ax = plot_func(fig, ax, stx)
95
104
 
96
- # Save PNG (this also generates JSON and CSV automatically)
105
+ # Save as .pltz bundle - this is the single source of truth
106
+ # All other formats (PNG, SVG, CSV, hitmap) are extracted from the bundle
107
+ pltz_path = cat_dir / f"{plot_name}.pltz.d"
108
+ stx.io.save(fig, pltz_path, dpi=dpi)
109
+
110
+ if verbose:
111
+ print(f" [PLTZ] {pltz_path}")
112
+
113
+ # Extract files from bundle to gallery directory
114
+ # The pltz bundle contains: plot.png, plot.svg, plot.pdf, plot.csv, plot.json, plot_hitmap.png
115
+ import shutil
116
+
97
117
  if save_png:
98
- png_path = cat_dir / f"{plot_name}.png"
99
- stx.io.save(fig, png_path, dpi=dpi)
100
- results["png"].append(str(png_path))
101
- if verbose:
102
- print(f" [PNG] {png_path}")
118
+ bundle_png = pltz_path / "plot.png"
119
+ gallery_png = cat_dir / f"{plot_name}.png"
120
+ if bundle_png.exists():
121
+ shutil.copy(bundle_png, gallery_png)
122
+ results["png"].append(str(gallery_png))
123
+ if verbose:
124
+ from PIL import Image
125
+ with Image.open(gallery_png) as img:
126
+ print(f" [PNG] {gallery_png} ({img.size[0]}x{img.size[1]})")
127
+
128
+ if save_csv:
129
+ bundle_csv = pltz_path / "plot.csv"
130
+ gallery_csv = cat_dir / f"{plot_name}.csv"
131
+ if bundle_csv.exists():
132
+ shutil.copy(bundle_csv, gallery_csv)
133
+ results["csv"].append(str(gallery_csv))
134
+ if verbose:
135
+ print(f" [CSV] {gallery_csv}")
103
136
 
104
- # CSV is auto-generated alongside PNG by stx.io.save
105
- csv_path = cat_dir / f"{plot_name}.csv"
106
- if csv_path.exists():
107
- results["csv"].append(str(csv_path))
137
+ if save_svg:
138
+ bundle_svg = pltz_path / "plot.svg"
139
+ gallery_svg = cat_dir / f"{plot_name}.svg"
140
+ if bundle_svg.exists():
141
+ shutil.copy(bundle_svg, gallery_svg)
142
+ results["svg"].append(str(gallery_svg))
108
143
  if verbose:
109
- print(f" [CSV] {csv_path}")
144
+ print(f" [SVG] {gallery_svg}")
145
+
146
+ # Copy hitmap from bundle
147
+ bundle_hitmap = pltz_path / "plot_hitmap.png"
148
+ gallery_hitmap = cat_dir / f"{plot_name}_hitmap.png"
149
+ if bundle_hitmap.exists():
150
+ shutil.copy(bundle_hitmap, gallery_hitmap)
151
+ if verbose:
152
+ from PIL import Image
153
+ with Image.open(gallery_hitmap) as img:
154
+ print(f" [HITMAP] {gallery_hitmap} ({img.size[0]}x{img.size[1]})")
155
+
156
+ # Copy and update JSON from bundle
157
+ bundle_json = pltz_path / "plot.json"
158
+ gallery_json = cat_dir / f"{plot_name}.json"
159
+ if bundle_json.exists():
160
+ shutil.copy(bundle_json, gallery_json)
161
+ # Add element_bboxes to the copied JSON
162
+ _add_element_bboxes_to_json(fig, ax, dpi, gallery_json, verbose)
163
+
164
+ if save_pltz:
165
+ results["pltz"].append(str(pltz_path))
166
+ else:
167
+ # Remove bundle if not requested
168
+ shutil.rmtree(pltz_path)
110
169
 
111
170
  stx.plt.close(fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig)
112
171
 
@@ -116,7 +175,7 @@ def generate(
116
175
  print(f" [ERROR] {plot_name}: {e}")
117
176
 
118
177
  if verbose:
119
- print(f"\nGenerated: {len(results['png'])} PNG, {len(results['csv'])} CSV")
178
+ print(f"\nGenerated: {len(results['png'])} PNG, {len(results['svg'])} SVG, {len(results['csv'])} CSV, {len(results['pltz'])} PLTZ")
120
179
  if results["errors"]:
121
180
  print(f"Errors: {len(results['errors'])}")
122
181
 
@@ -150,4 +209,352 @@ def _get_category_for_plot(plot_name):
150
209
  return "uncategorized"
151
210
 
152
211
 
212
+ def _add_element_bboxes_to_json(fig, ax, dpi, json_path, verbose=True):
213
+ """Add element_bboxes to an existing JSON metadata file.
214
+
215
+ Extracts bounding boxes and path_simplified for all figure elements
216
+ to enable interactive element selection in web editors.
217
+
218
+ Parameters
219
+ ----------
220
+ fig : FigureWrapper or matplotlib.figure.Figure
221
+ The figure object
222
+ ax : AxisWrapper or matplotlib.axes.Axes
223
+ The axes object
224
+ dpi : int
225
+ DPI used for saving
226
+ json_path : Path
227
+ Path to the JSON file to update
228
+ verbose : bool
229
+ Print progress messages
230
+ """
231
+ from PIL import Image
232
+ from scitex.plt.utils.metadata._geometry_extraction import (
233
+ extract_axes_bbox_px,
234
+ extract_line_geometry,
235
+ extract_scatter_geometry,
236
+ extract_polygon_geometry,
237
+ )
238
+
239
+ try:
240
+ # Get matplotlib objects
241
+ mpl_fig = fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig
242
+ mpl_ax = ax._ax_mpl if hasattr(ax, "_ax_mpl") else ax
243
+
244
+ # Get renderer
245
+ try:
246
+ renderer = mpl_fig.canvas.get_renderer()
247
+ except Exception:
248
+ mpl_fig.canvas.draw()
249
+ renderer = mpl_fig.canvas.get_renderer()
250
+
251
+ # Get saved image dimensions (needed for coordinate transformation)
252
+ png_path = json_path.with_suffix('.png')
253
+ if png_path.exists():
254
+ with Image.open(png_path) as img:
255
+ img_width, img_height = img.size
256
+ else:
257
+ # Fallback to figure dimensions
258
+ img_width = int(mpl_fig.get_figwidth() * dpi)
259
+ img_height = int(mpl_fig.get_figheight() * dpi)
260
+
261
+ # Extract element bboxes using the same logic as vis_app
262
+ element_bboxes = _extract_element_bboxes_for_gallery(
263
+ mpl_fig, mpl_ax, renderer, img_width, img_height
264
+ )
265
+
266
+ if not element_bboxes:
267
+ return
268
+
269
+ # Load existing JSON
270
+ with open(json_path, 'r') as f:
271
+ metadata = json.load(f)
272
+
273
+ # Add element_bboxes
274
+ metadata['element_bboxes'] = element_bboxes
275
+
276
+ # Also ensure figure_size_px is present
277
+ if 'dimensions' not in metadata:
278
+ metadata['dimensions'] = {}
279
+ metadata['dimensions']['figure_size_px'] = {
280
+ 'width': img_width,
281
+ 'height': img_height
282
+ }
283
+
284
+ # Save updated JSON
285
+ with open(json_path, 'w') as f:
286
+ json.dump(metadata, f, indent=4)
287
+
288
+ if verbose:
289
+ print(f" [BBOXES] Added {len(element_bboxes)} element bboxes to {json_path.name}")
290
+
291
+ except Exception as e:
292
+ if verbose:
293
+ print(f" [WARN] Could not add element_bboxes: {e}")
294
+
295
+
296
+ def _extract_element_bboxes_for_gallery(fig, ax, renderer, img_width, img_height):
297
+ """Extract element bounding boxes for gallery figures.
298
+
299
+ Similar to vis_app's extract_element_bboxes but simplified for gallery use.
300
+ """
301
+ import numpy as np
302
+ from matplotlib.transforms import Bbox
303
+
304
+ # Get figure tight bbox in inches
305
+ fig_bbox = fig.get_tightbbox(renderer)
306
+ tight_x0 = fig_bbox.x0
307
+ tight_y0 = fig_bbox.y0
308
+ tight_width = fig_bbox.width
309
+ tight_height = fig_bbox.height
310
+
311
+ # bbox_inches='tight' adds pad_inches around the tight bbox
312
+ pad_inches = 0.1
313
+ saved_width_inches = tight_width + 2 * pad_inches
314
+ saved_height_inches = tight_height + 2 * pad_inches
315
+
316
+ # Scale factors for converting inches to pixels
317
+ scale_x = img_width / saved_width_inches
318
+ scale_y = img_height / saved_height_inches
319
+
320
+ bboxes = {}
321
+
322
+ def get_element_bbox(element, name):
323
+ """Get element bbox in image pixel coordinates."""
324
+ try:
325
+ bbox = element.get_window_extent(renderer)
326
+ if not (np.isfinite(bbox.x0) and np.isfinite(bbox.x1) and
327
+ np.isfinite(bbox.y0) and np.isfinite(bbox.y1)):
328
+ return
329
+
330
+ elem_x0_inches = bbox.x0 / fig.dpi
331
+ elem_x1_inches = bbox.x1 / fig.dpi
332
+ elem_y0_inches = bbox.y0 / fig.dpi
333
+ elem_y1_inches = bbox.y1 / fig.dpi
334
+
335
+ x0_rel = elem_x0_inches - tight_x0 + pad_inches
336
+ x1_rel = elem_x1_inches - tight_x0 + pad_inches
337
+ y0_rel = saved_height_inches - (elem_y1_inches - tight_y0 + pad_inches)
338
+ y1_rel = saved_height_inches - (elem_y0_inches - tight_y0 + pad_inches)
339
+
340
+ bboxes[name] = {
341
+ "x0": max(0, int(x0_rel * scale_x)),
342
+ "y0": max(0, int(y0_rel * scale_y)),
343
+ "x1": min(img_width, int(x1_rel * scale_x)),
344
+ "y1": min(img_height, int(y1_rel * scale_y)),
345
+ "label": name.replace("_", " ").title(),
346
+ }
347
+ except Exception:
348
+ pass
349
+
350
+ def coords_to_img_points(data_coords):
351
+ """Convert data coordinates to image pixel coordinates."""
352
+ if len(data_coords) == 0:
353
+ return []
354
+ transform = ax.transData
355
+ points_display = transform.transform(data_coords)
356
+ points_img = []
357
+ for px, py in points_display:
358
+ if not np.isfinite(px) or not np.isfinite(py):
359
+ continue
360
+ px_inches = px / fig.dpi
361
+ py_inches = py / fig.dpi
362
+ x_rel = px_inches - tight_x0 + pad_inches
363
+ y_rel = saved_height_inches - (py_inches - tight_y0 + pad_inches)
364
+ x_img = max(-10000, min(10000, int(x_rel * scale_x)))
365
+ y_img = max(-10000, min(10000, int(y_rel * scale_y)))
366
+ points_img.append([x_img, y_img])
367
+ # Downsample if too many points
368
+ if len(points_img) > 100:
369
+ step = len(points_img) // 100
370
+ points_img = points_img[::step]
371
+ return points_img
372
+
373
+ # Extract lines
374
+ line_idx = 0
375
+ for line in ax.get_lines():
376
+ try:
377
+ label = line.get_label()
378
+ if label.startswith("_"):
379
+ continue
380
+
381
+ trace_name = f"trace_{line_idx}"
382
+ get_element_bbox(line, trace_name)
383
+
384
+ if trace_name in bboxes:
385
+ bboxes[trace_name]["label"] = label or f"Line {line_idx}"
386
+ bboxes[trace_name]["trace_idx"] = line_idx
387
+ bboxes[trace_name]["element_type"] = "line"
388
+
389
+ xdata, ydata = line.get_xdata(), line.get_ydata()
390
+ if len(xdata) > 0:
391
+ # Use path_simplified for hit detection
392
+ bboxes[trace_name]["path_simplified"] = coords_to_img_points(
393
+ list(zip(xdata, ydata))
394
+ )
395
+ line_idx += 1
396
+ except Exception:
397
+ pass
398
+
399
+ # Extract scatter collections
400
+ scatter_idx = 0
401
+ for coll in ax.collections:
402
+ try:
403
+ coll_type = type(coll).__name__
404
+ if coll_type == "PathCollection":
405
+ label = coll.get_label()
406
+ if label and label.startswith("_"):
407
+ label = None
408
+
409
+ element_name = f"scatter_{scatter_idx}"
410
+ offsets = coll.get_offsets()
411
+
412
+ if len(offsets) > 0:
413
+ points_img = coords_to_img_points(offsets)
414
+ if points_img:
415
+ xs = [p[0] for p in points_img]
416
+ ys = [p[1] for p in points_img]
417
+ padding = 10
418
+ bboxes[element_name] = {
419
+ "x0": max(0, min(xs) - padding),
420
+ "y0": max(0, min(ys) - padding),
421
+ "x1": min(img_width, max(xs) + padding),
422
+ "y1": min(img_height, max(ys) + padding),
423
+ "label": label or f"Scatter {scatter_idx}",
424
+ "element_type": "scatter",
425
+ "points": points_img,
426
+ }
427
+ scatter_idx += 1
428
+ except Exception:
429
+ pass
430
+
431
+ # Extract bars
432
+ bar_idx = 0
433
+ for patch in ax.patches:
434
+ try:
435
+ patch_type = type(patch).__name__
436
+ if patch_type == "Rectangle":
437
+ label = patch.get_label()
438
+ element_name = f"bar_{bar_idx}"
439
+ get_element_bbox(patch, element_name)
440
+ if element_name in bboxes:
441
+ bboxes[element_name]["label"] = label or f"Bar {bar_idx}"
442
+ bboxes[element_name]["element_type"] = "bar"
443
+ bar_idx += 1
444
+ except Exception:
445
+ pass
446
+
447
+ return bboxes
448
+
449
+
450
+ def _generate_and_save_hitmap(fig, dpi, hitmap_path, json_path, verbose=True, crop_box=None):
451
+ """Generate hitmap PNG and add color_map to JSON.
452
+
453
+ The hitmap is generated at the same size as the PNG by:
454
+ 1. Rendering the full figure with ID colors (same as PNG before crop)
455
+ 2. Applying the exact same crop coordinates as the PNG
456
+
457
+ Parameters
458
+ ----------
459
+ fig : FigureWrapper or matplotlib.figure.Figure
460
+ The figure object (before closing)
461
+ dpi : int
462
+ DPI for hitmap rendering
463
+ hitmap_path : Path
464
+ Output path for hitmap PNG
465
+ json_path : Path
466
+ Path to JSON file to update with hitmap_color_map
467
+ verbose : bool
468
+ Print progress messages
469
+ crop_box : tuple, optional
470
+ Explicit crop coordinates (left, upper, right, lower) from PNG cropping.
471
+ If provided, applies the same crop to hitmap for exact size matching.
472
+ """
473
+ from PIL import Image
474
+ from scitex.plt.utils._hitmap import generate_hitmap_id_colors
475
+
476
+ try:
477
+ # Get matplotlib figure
478
+ mpl_fig = fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig
479
+
480
+ # Generate hitmap at original figure size (same as PNG before cropping)
481
+ hitmap_array, color_map = generate_hitmap_id_colors(mpl_fig, dpi=dpi)
482
+
483
+ if not color_map:
484
+ if verbose:
485
+ print(f" [HITMAP] No elements found to map - generating empty hitmap")
486
+ # Still generate hitmap (all zeros/black) for consistency
487
+ # This ensures hitmap always exists with correct size
488
+
489
+ # Convert hitmap array to RGB PNG
490
+ h, w = hitmap_array.shape
491
+ rgb = np.zeros((h, w, 3), dtype=np.uint8)
492
+ rgb[:, :, 0] = (hitmap_array >> 16) & 0xFF
493
+ rgb[:, :, 1] = (hitmap_array >> 8) & 0xFF
494
+ rgb[:, :, 2] = hitmap_array & 0xFF
495
+ hitmap_full = Image.fromarray(rgb, mode='RGB')
496
+
497
+ # Save full hitmap first (before cropping)
498
+ hitmap_full.save(hitmap_path, format='PNG')
499
+
500
+ if verbose:
501
+ print(f" [HITMAP] Full size: {w}x{h}")
502
+
503
+ # Apply same crop as PNG if crop_box provided
504
+ if crop_box is not None:
505
+ from scitex.plt.utils._crop import crop
506
+ crop(
507
+ str(hitmap_path),
508
+ output_path=str(hitmap_path),
509
+ overwrite=True,
510
+ crop_box=crop_box,
511
+ verbose=False,
512
+ )
513
+ if verbose:
514
+ with Image.open(hitmap_path) as cropped:
515
+ print(f" [HITMAP] Cropped to: {cropped.size[0]}x{cropped.size[1]}")
516
+
517
+ # Validate sizes match
518
+ png_path = hitmap_path.parent / hitmap_path.name.replace('_hitmap.png', '.png')
519
+ if png_path.exists():
520
+ with Image.open(png_path) as png_img, Image.open(hitmap_path) as hitmap_img:
521
+ png_size = png_img.size
522
+ hitmap_size = hitmap_img.size
523
+ if png_size != hitmap_size:
524
+ print(f" [ERROR] Size mismatch! PNG={png_size}, Hitmap={hitmap_size}")
525
+ raise ValueError(f"Hitmap size {hitmap_size} doesn't match PNG size {png_size}")
526
+ elif verbose:
527
+ print(f" [HITMAP] Size validated: {hitmap_size[0]}x{hitmap_size[1]} (matches PNG)")
528
+
529
+ if verbose:
530
+ print(f" [HITMAP] {hitmap_path.name} ({len(color_map)} elements)")
531
+
532
+ # Add hitmap_color_map to JSON
533
+ if json_path.exists():
534
+ with open(json_path, 'r') as f:
535
+ metadata = json.load(f)
536
+
537
+ # Store color_map with string keys for JSON compatibility
538
+ metadata['hitmap_color_map'] = {str(k): v for k, v in color_map.items()}
539
+ metadata['hitmap_file'] = hitmap_path.name
540
+
541
+ # Store crop_box in metadata for reference
542
+ if crop_box is not None:
543
+ metadata['hitmap_crop_box'] = {
544
+ 'left': int(crop_box[0]),
545
+ 'upper': int(crop_box[1]),
546
+ 'right': int(crop_box[2]),
547
+ 'lower': int(crop_box[3]),
548
+ }
549
+
550
+ with open(json_path, 'w') as f:
551
+ json.dump(metadata, f, indent=4)
552
+
553
+ except Exception as e:
554
+ if verbose:
555
+ print(f" [WARN] Could not generate hitmap: {e}")
556
+ import traceback
557
+ traceback.print_exc()
558
+
559
+
153
560
  # EOF
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-13 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/io/__init__.py
5
+
6
+ """
7
+ I/O operations for scitex.plt - Plot bundles (.pltz).
8
+
9
+ This module handles:
10
+ - .pltz bundle load/save operations (legacy and layered formats)
11
+ - CSV data export/import
12
+ - Hitmap generation and storage
13
+ - Bundle overview generation
14
+
15
+ Layered Format (v2.0):
16
+ plot.pltz.d/
17
+ spec.json # Semantic: WHAT to plot
18
+ style.json # Appearance: HOW it looks
19
+ data.csv # Raw data
20
+ exports/ # Preview images
21
+ cache/ # Regenerable geometry data
22
+ """
23
+
24
+ from ._bundle import (
25
+ validate_pltz_spec,
26
+ load_pltz_bundle,
27
+ save_pltz_bundle,
28
+ generate_bundle_overview,
29
+ PLTZ_SCHEMA_SPEC,
30
+ )
31
+
32
+ from ._layered_bundle import (
33
+ save_layered_pltz_bundle,
34
+ load_layered_pltz_bundle,
35
+ merge_layered_bundle,
36
+ is_layered_bundle,
37
+ )
38
+
39
+ __all__ = [
40
+ # Legacy bundle operations
41
+ "validate_pltz_spec",
42
+ "load_pltz_bundle",
43
+ "save_pltz_bundle",
44
+ "generate_bundle_overview",
45
+ "PLTZ_SCHEMA_SPEC",
46
+ # Layered bundle operations (v2.0)
47
+ "save_layered_pltz_bundle",
48
+ "load_layered_pltz_bundle",
49
+ "merge_layered_bundle",
50
+ "is_layered_bundle",
51
+ ]
52
+
53
+ # EOF