scitex 2.7.3__py3-none-any.whl → 2.10.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 (563) hide show
  1. scitex/__init__.py +15 -7
  2. scitex/__version__.py +1 -2
  3. scitex/_install_guide.py +250 -0
  4. scitex/_optional_deps.py +206 -39
  5. scitex/ai/_gen_ai/_Groq.py +2 -4
  6. scitex/ai/_gen_ai/_OpenAI.py +5 -2
  7. scitex/ai/_gen_ai/_Perplexity.py +20 -6
  8. scitex/audio/__init__.py +24 -15
  9. scitex/audio/_cross_process_lock.py +139 -0
  10. scitex/audio/_mcp_handlers.py +256 -0
  11. scitex/audio/_mcp_tool_schemas.py +203 -0
  12. scitex/audio/engines/elevenlabs_engine.py +5 -2
  13. scitex/audio/mcp_server.py +98 -457
  14. scitex/bridge/__init__.py +30 -19
  15. scitex/bridge/_figrecipe.py +245 -0
  16. scitex/bridge/_helpers.py +2 -1
  17. scitex/bridge/_plt_vis.py +23 -10
  18. scitex/bridge/_stats_plt.py +18 -5
  19. scitex/bridge/_stats_vis.py +16 -2
  20. scitex/browser/__init__.py +84 -44
  21. scitex/browser/automation/__init__.py +5 -1
  22. scitex/browser/core/BrowserMixin.py +17 -4
  23. scitex/browser/core/__init__.py +11 -2
  24. scitex/browser/remote/CaptchaHandler.py +1 -1
  25. scitex/browser/remote/ZenRowsAPIClient.py +1 -1
  26. scitex/capture/grid.py +487 -0
  27. scitex/capture/mcp_handlers.py +401 -0
  28. scitex/capture/mcp_tool_defs.py +192 -0
  29. scitex/capture/mcp_tools.py +241 -0
  30. scitex/capture/mcp_utils.py +30 -0
  31. scitex/cli/convert.py +421 -0
  32. scitex/cli/main.py +6 -4
  33. scitex/datetime/__init__.py +46 -0
  34. scitex/datetime/_linspace.py +100 -0
  35. scitex/datetime/_normalize_timestamp.py +306 -0
  36. scitex/db/_delete_duplicates.py +4 -4
  37. scitex/db/_sqlite3/_delete_duplicates.py +11 -2
  38. scitex/dev/plt/__init__.py +61 -62
  39. scitex/dev/plt/demo_plotters/__init__.py +0 -0
  40. scitex/dev/plt/demo_plotters/plot_mpl_axhline.py +28 -0
  41. scitex/dev/plt/demo_plotters/plot_mpl_axhspan.py +28 -0
  42. scitex/dev/plt/demo_plotters/plot_mpl_axvline.py +28 -0
  43. scitex/dev/plt/demo_plotters/plot_mpl_axvspan.py +28 -0
  44. scitex/dev/plt/demo_plotters/plot_mpl_bar.py +29 -0
  45. scitex/dev/plt/demo_plotters/plot_mpl_barh.py +29 -0
  46. scitex/dev/plt/demo_plotters/plot_mpl_boxplot.py +28 -0
  47. scitex/dev/plt/demo_plotters/plot_mpl_contour.py +31 -0
  48. scitex/dev/plt/demo_plotters/plot_mpl_contourf.py +31 -0
  49. scitex/dev/plt/demo_plotters/plot_mpl_errorbar.py +30 -0
  50. scitex/dev/plt/demo_plotters/plot_mpl_eventplot.py +28 -0
  51. scitex/dev/plt/demo_plotters/plot_mpl_fill.py +30 -0
  52. scitex/dev/plt/demo_plotters/plot_mpl_fill_between.py +31 -0
  53. scitex/dev/plt/demo_plotters/plot_mpl_hexbin.py +28 -0
  54. scitex/dev/plt/demo_plotters/plot_mpl_hist.py +28 -0
  55. scitex/dev/plt/demo_plotters/plot_mpl_hist2d.py +28 -0
  56. scitex/dev/plt/demo_plotters/plot_mpl_imshow.py +29 -0
  57. scitex/dev/plt/demo_plotters/plot_mpl_pcolormesh.py +31 -0
  58. scitex/dev/plt/demo_plotters/plot_mpl_pie.py +29 -0
  59. scitex/dev/plt/demo_plotters/plot_mpl_plot.py +29 -0
  60. scitex/dev/plt/demo_plotters/plot_mpl_quiver.py +31 -0
  61. scitex/dev/plt/demo_plotters/plot_mpl_scatter.py +28 -0
  62. scitex/dev/plt/demo_plotters/plot_mpl_stackplot.py +31 -0
  63. scitex/dev/plt/demo_plotters/plot_mpl_stem.py +29 -0
  64. scitex/dev/plt/demo_plotters/plot_mpl_step.py +29 -0
  65. scitex/dev/plt/demo_plotters/plot_mpl_violinplot.py +28 -0
  66. scitex/dev/plt/demo_plotters/plot_sns_barplot.py +29 -0
  67. scitex/dev/plt/demo_plotters/plot_sns_boxplot.py +29 -0
  68. scitex/dev/plt/demo_plotters/plot_sns_heatmap.py +28 -0
  69. scitex/dev/plt/demo_plotters/plot_sns_histplot.py +29 -0
  70. scitex/dev/plt/demo_plotters/plot_sns_kdeplot.py +29 -0
  71. scitex/dev/plt/demo_plotters/plot_sns_lineplot.py +31 -0
  72. scitex/dev/plt/demo_plotters/plot_sns_scatterplot.py +29 -0
  73. scitex/dev/plt/demo_plotters/plot_sns_stripplot.py +29 -0
  74. scitex/dev/plt/demo_plotters/plot_sns_swarmplot.py +29 -0
  75. scitex/dev/plt/demo_plotters/plot_sns_violinplot.py +29 -0
  76. scitex/dev/plt/demo_plotters/plot_stx_bar.py +29 -0
  77. scitex/dev/plt/demo_plotters/plot_stx_barh.py +29 -0
  78. scitex/dev/plt/demo_plotters/plot_stx_box.py +28 -0
  79. scitex/dev/plt/demo_plotters/plot_stx_boxplot.py +28 -0
  80. scitex/dev/plt/demo_plotters/plot_stx_conf_mat.py +28 -0
  81. scitex/dev/plt/demo_plotters/plot_stx_contour.py +31 -0
  82. scitex/dev/plt/demo_plotters/plot_stx_ecdf.py +28 -0
  83. scitex/dev/plt/demo_plotters/plot_stx_errorbar.py +30 -0
  84. scitex/dev/plt/demo_plotters/plot_stx_fill_between.py +31 -0
  85. scitex/dev/plt/demo_plotters/plot_stx_fillv.py +28 -0
  86. scitex/dev/plt/demo_plotters/plot_stx_heatmap.py +28 -0
  87. scitex/dev/plt/demo_plotters/plot_stx_image.py +28 -0
  88. scitex/dev/plt/demo_plotters/plot_stx_imshow.py +28 -0
  89. scitex/dev/plt/demo_plotters/plot_stx_joyplot.py +28 -0
  90. scitex/dev/plt/demo_plotters/plot_stx_kde.py +28 -0
  91. scitex/dev/plt/demo_plotters/plot_stx_line.py +28 -0
  92. scitex/dev/plt/demo_plotters/plot_stx_mean_ci.py +28 -0
  93. scitex/dev/plt/demo_plotters/plot_stx_mean_std.py +28 -0
  94. scitex/dev/plt/demo_plotters/plot_stx_median_iqr.py +28 -0
  95. scitex/dev/plt/demo_plotters/plot_stx_raster.py +28 -0
  96. scitex/dev/plt/demo_plotters/plot_stx_rectangle.py +28 -0
  97. scitex/dev/plt/demo_plotters/plot_stx_scatter.py +29 -0
  98. scitex/dev/plt/demo_plotters/plot_stx_shaded_line.py +29 -0
  99. scitex/dev/plt/demo_plotters/plot_stx_violin.py +28 -0
  100. scitex/dev/plt/demo_plotters/plot_stx_violinplot.py +28 -0
  101. scitex/dev/plt/mpl/get_dir_ax.py +46 -0
  102. scitex/dev/plt/mpl/get_signatures.py +176 -0
  103. scitex/dev/plt/mpl/get_signatures_details.py +522 -0
  104. scitex/dev/plt/plot_mpl_axhline.py +0 -0
  105. scitex/dev/plt/plot_mpl_axhspan.py +0 -0
  106. scitex/dev/plt/plot_mpl_axvline.py +0 -0
  107. scitex/dev/plt/plot_mpl_axvspan.py +0 -0
  108. scitex/dev/plt/plot_mpl_bar.py +0 -0
  109. scitex/dev/plt/plot_mpl_barh.py +0 -0
  110. scitex/dev/plt/plot_mpl_boxplot.py +0 -0
  111. scitex/dev/plt/plot_mpl_contour.py +0 -0
  112. scitex/dev/plt/plot_mpl_contourf.py +0 -0
  113. scitex/dev/plt/plot_mpl_errorbar.py +0 -0
  114. scitex/dev/plt/plot_mpl_eventplot.py +0 -0
  115. scitex/dev/plt/plot_mpl_fill.py +0 -0
  116. scitex/dev/plt/plot_mpl_fill_between.py +0 -0
  117. scitex/dev/plt/plot_mpl_hexbin.py +0 -0
  118. scitex/dev/plt/plot_mpl_hist.py +0 -0
  119. scitex/dev/plt/plot_mpl_hist2d.py +0 -0
  120. scitex/dev/plt/plot_mpl_imshow.py +0 -0
  121. scitex/dev/plt/plot_mpl_pcolormesh.py +0 -0
  122. scitex/dev/plt/plot_mpl_pie.py +0 -0
  123. scitex/dev/plt/plot_mpl_plot.py +0 -0
  124. scitex/dev/plt/plot_mpl_quiver.py +0 -0
  125. scitex/dev/plt/plot_mpl_scatter.py +0 -0
  126. scitex/dev/plt/plot_mpl_stackplot.py +0 -0
  127. scitex/dev/plt/plot_mpl_stem.py +0 -0
  128. scitex/dev/plt/plot_mpl_step.py +0 -0
  129. scitex/dev/plt/plot_mpl_violinplot.py +0 -0
  130. scitex/dev/plt/plot_sns_barplot.py +0 -0
  131. scitex/dev/plt/plot_sns_boxplot.py +0 -0
  132. scitex/dev/plt/plot_sns_heatmap.py +0 -0
  133. scitex/dev/plt/plot_sns_histplot.py +0 -0
  134. scitex/dev/plt/plot_sns_kdeplot.py +0 -0
  135. scitex/dev/plt/plot_sns_lineplot.py +0 -0
  136. scitex/dev/plt/plot_sns_scatterplot.py +0 -0
  137. scitex/dev/plt/plot_sns_stripplot.py +0 -0
  138. scitex/dev/plt/plot_sns_swarmplot.py +0 -0
  139. scitex/dev/plt/plot_sns_violinplot.py +0 -0
  140. scitex/dev/plt/plot_stx_bar.py +0 -0
  141. scitex/dev/plt/plot_stx_barh.py +0 -0
  142. scitex/dev/plt/plot_stx_box.py +0 -0
  143. scitex/dev/plt/plot_stx_boxplot.py +0 -0
  144. scitex/dev/plt/plot_stx_conf_mat.py +0 -0
  145. scitex/dev/plt/plot_stx_contour.py +0 -0
  146. scitex/dev/plt/plot_stx_ecdf.py +0 -0
  147. scitex/dev/plt/plot_stx_errorbar.py +0 -0
  148. scitex/dev/plt/plot_stx_fill_between.py +0 -0
  149. scitex/dev/plt/plot_stx_fillv.py +0 -0
  150. scitex/dev/plt/plot_stx_heatmap.py +0 -0
  151. scitex/dev/plt/plot_stx_image.py +0 -0
  152. scitex/dev/plt/plot_stx_imshow.py +0 -0
  153. scitex/dev/plt/plot_stx_joyplot.py +0 -0
  154. scitex/dev/plt/plot_stx_kde.py +0 -0
  155. scitex/dev/plt/plot_stx_line.py +0 -0
  156. scitex/dev/plt/plot_stx_mean_ci.py +0 -0
  157. scitex/dev/plt/plot_stx_mean_std.py +0 -0
  158. scitex/dev/plt/plot_stx_median_iqr.py +0 -0
  159. scitex/dev/plt/plot_stx_raster.py +0 -0
  160. scitex/dev/plt/plot_stx_rectangle.py +0 -0
  161. scitex/dev/plt/plot_stx_scatter.py +0 -0
  162. scitex/dev/plt/plot_stx_shaded_line.py +0 -0
  163. scitex/dev/plt/plot_stx_violin.py +0 -0
  164. scitex/dev/plt/plot_stx_violinplot.py +0 -0
  165. scitex/diagram/README.md +197 -0
  166. scitex/diagram/__init__.py +48 -0
  167. scitex/diagram/_compile.py +312 -0
  168. scitex/diagram/_diagram.py +355 -0
  169. scitex/diagram/_presets.py +173 -0
  170. scitex/diagram/_schema.py +182 -0
  171. scitex/diagram/_split.py +278 -0
  172. scitex/dict/_pop_keys.py +1 -7
  173. scitex/dsp/__init__.py +15 -10
  174. scitex/dsp/add_noise.py +5 -2
  175. scitex/dsp/example.py +35 -22
  176. scitex/dsp/filt.py +8 -3
  177. scitex/dsp/reference.py +3 -2
  178. scitex/dsp/utils/__init__.py +2 -1
  179. scitex/dsp/utils/_differential_bandpass_filters.py +14 -4
  180. scitex/dt/__init__.py +39 -2
  181. scitex/errors.py +82 -521
  182. scitex/fig/__init__.py +4 -4
  183. scitex/fig/editor/__init__.py +5 -2
  184. scitex/fig/editor/_dearpygui_editor.py +1 -1
  185. scitex/fig/editor/_mpl_editor.py +1 -1
  186. scitex/fig/editor/_qt_editor.py +1 -1
  187. scitex/fig/editor/_tkinter_editor.py +1 -1
  188. scitex/fig/editor/edit/__init__.py +50 -0
  189. scitex/fig/editor/edit/backend_detector.py +109 -0
  190. scitex/fig/editor/edit/bundle_resolver.py +240 -0
  191. scitex/fig/editor/edit/editor_launcher.py +239 -0
  192. scitex/fig/editor/edit/manual_handler.py +53 -0
  193. scitex/fig/editor/edit/panel_loader.py +232 -0
  194. scitex/fig/editor/edit/path_resolver.py +67 -0
  195. scitex/fig/editor/flask_editor/_bbox.py +23 -0
  196. scitex/fig/editor/flask_editor/_core.py +908 -103
  197. scitex/fig/editor/flask_editor/_renderer.py +74 -0
  198. scitex/fig/editor/flask_editor/static/css/base/reset.css +41 -0
  199. scitex/fig/editor/flask_editor/static/css/base/typography.css +16 -0
  200. scitex/fig/editor/flask_editor/static/css/base/variables.css +85 -0
  201. scitex/fig/editor/flask_editor/static/css/components/buttons.css +217 -0
  202. scitex/fig/editor/flask_editor/static/css/components/context-menu.css +93 -0
  203. scitex/fig/editor/flask_editor/static/css/components/dropdown.css +57 -0
  204. scitex/fig/editor/flask_editor/static/css/components/forms.css +112 -0
  205. scitex/fig/editor/flask_editor/static/css/components/modal.css +59 -0
  206. scitex/fig/editor/flask_editor/static/css/components/sections.css +212 -0
  207. scitex/fig/editor/flask_editor/static/css/features/canvas.css +176 -0
  208. scitex/fig/editor/flask_editor/static/css/features/element-inspector.css +190 -0
  209. scitex/fig/editor/flask_editor/static/css/features/loading.css +59 -0
  210. scitex/fig/editor/flask_editor/static/css/features/overlay.css +45 -0
  211. scitex/fig/editor/flask_editor/static/css/features/panel-grid.css +95 -0
  212. scitex/fig/editor/flask_editor/static/css/features/selection.css +101 -0
  213. scitex/fig/editor/flask_editor/static/css/features/statistics.css +138 -0
  214. scitex/fig/editor/flask_editor/static/css/index.css +31 -0
  215. scitex/fig/editor/flask_editor/static/css/layout/container.css +7 -0
  216. scitex/fig/editor/flask_editor/static/css/layout/controls.css +56 -0
  217. scitex/fig/editor/flask_editor/static/css/layout/preview.css +78 -0
  218. scitex/fig/editor/flask_editor/static/js/alignment/axis.js +314 -0
  219. scitex/fig/editor/flask_editor/static/js/alignment/basic.js +107 -0
  220. scitex/fig/editor/flask_editor/static/js/alignment/distribute.js +54 -0
  221. scitex/fig/editor/flask_editor/static/js/canvas/canvas.js +172 -0
  222. scitex/fig/editor/flask_editor/static/js/canvas/dragging.js +258 -0
  223. scitex/fig/editor/flask_editor/static/js/canvas/resize.js +48 -0
  224. scitex/fig/editor/flask_editor/static/js/canvas/selection.js +71 -0
  225. scitex/fig/editor/flask_editor/static/js/core/api.js +288 -0
  226. scitex/fig/editor/flask_editor/static/js/core/state.js +143 -0
  227. scitex/fig/editor/flask_editor/static/js/core/utils.js +245 -0
  228. scitex/fig/editor/flask_editor/static/js/dev/element-inspector.js +992 -0
  229. scitex/fig/editor/flask_editor/static/js/editor/bbox.js +339 -0
  230. scitex/fig/editor/flask_editor/static/js/editor/element-drag.js +286 -0
  231. scitex/fig/editor/flask_editor/static/js/editor/overlay.js +371 -0
  232. scitex/fig/editor/flask_editor/static/js/editor/preview.js +293 -0
  233. scitex/fig/editor/flask_editor/static/js/main.js +426 -0
  234. scitex/fig/editor/flask_editor/static/js/shortcuts/context-menu.js +152 -0
  235. scitex/fig/editor/flask_editor/static/js/shortcuts/keyboard.js +265 -0
  236. scitex/fig/editor/flask_editor/static/js/ui/controls.js +184 -0
  237. scitex/fig/editor/flask_editor/static/js/ui/download.js +57 -0
  238. scitex/fig/editor/flask_editor/static/js/ui/help.js +100 -0
  239. scitex/fig/editor/flask_editor/static/js/ui/theme.js +34 -0
  240. scitex/fig/editor/flask_editor/templates/__init__.py +95 -5
  241. scitex/fig/editor/flask_editor/templates/_html.py +27 -9
  242. scitex/fig/editor/flask_editor/templates/_scripts.py +1928 -131
  243. scitex/fig/editor/flask_editor/templates/_styles.py +363 -51
  244. scitex/fig/io/_bundle.py +104 -19
  245. scitex/fts/README.md +262 -0
  246. scitex/fts/TODO.md +66 -0
  247. scitex/fts/__init__.py +90 -0
  248. scitex/fts/_bundle/README_IN_BUNDLE.md +102 -0
  249. scitex/fts/_bundle/_FTS.py +657 -0
  250. scitex/fts/_bundle/__init__.py +38 -0
  251. scitex/fts/_bundle/_children.py +216 -0
  252. scitex/fts/_bundle/_conversion/__init__.py +15 -0
  253. scitex/fts/_bundle/_conversion/_bundle2dict.py +44 -0
  254. scitex/fts/_bundle/_conversion/_dict2bundle.py +50 -0
  255. scitex/fts/_bundle/_dataclasses/_Axes.py +57 -0
  256. scitex/fts/_bundle/_dataclasses/_BBox.py +54 -0
  257. scitex/fts/_bundle/_dataclasses/_ColumnDef.py +72 -0
  258. scitex/fts/_bundle/_dataclasses/_DataFormat.py +40 -0
  259. scitex/fts/_bundle/_dataclasses/_DataInfo.py +135 -0
  260. scitex/fts/_bundle/_dataclasses/_DataSource.py +44 -0
  261. scitex/fts/_bundle/_dataclasses/_Node.py +319 -0
  262. scitex/fts/_bundle/_dataclasses/_NodeRefs.py +45 -0
  263. scitex/fts/_bundle/_dataclasses/_SizeMM.py +38 -0
  264. scitex/fts/_bundle/_dataclasses/__init__.py +35 -0
  265. scitex/fts/_bundle/_extractors/__init__.py +32 -0
  266. scitex/fts/_bundle/_extractors/_extract_bar.py +131 -0
  267. scitex/fts/_bundle/_extractors/_extract_line.py +71 -0
  268. scitex/fts/_bundle/_extractors/_extract_scatter.py +79 -0
  269. scitex/fts/_bundle/_loader.py +134 -0
  270. scitex/fts/_bundle/_mpl_helpers.py +389 -0
  271. scitex/fts/_bundle/_saver.py +269 -0
  272. scitex/fts/_bundle/_storage.py +200 -0
  273. scitex/fts/_bundle/_utils/__init__.py +55 -0
  274. scitex/fts/_bundle/_utils/_const.py +26 -0
  275. scitex/fts/_bundle/_utils/_errors.py +73 -0
  276. scitex/fts/_bundle/_utils/_generate.py +21 -0
  277. scitex/fts/_bundle/_utils/_types.py +76 -0
  278. scitex/fts/_bundle/_validation.py +434 -0
  279. scitex/fts/_bundle/_zipbundle.py +165 -0
  280. scitex/fts/_fig/__init__.py +22 -0
  281. scitex/fts/_fig/_backend/__init__.py +53 -0
  282. scitex/fts/_fig/_backend/_export.py +165 -0
  283. scitex/fts/_fig/_backend/_parser.py +188 -0
  284. scitex/fts/_fig/_backend/_render.py +538 -0
  285. scitex/fts/_fig/_composite.py +345 -0
  286. scitex/fts/_fig/_dataclasses/_ChannelEncoding.py +46 -0
  287. scitex/fts/_fig/_dataclasses/_Encoding.py +82 -0
  288. scitex/fts/_fig/_dataclasses/_Theme.py +441 -0
  289. scitex/fts/_fig/_dataclasses/_TraceEncoding.py +52 -0
  290. scitex/fts/_fig/_dataclasses/__init__.py +47 -0
  291. scitex/fts/_fig/_editor/__init__.py +14 -0
  292. scitex/fts/_fig/_editor/_cui/__init__.py +33 -0
  293. scitex/fts/_fig/_editor/_cui/_backend_detector.py +39 -0
  294. scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +366 -0
  295. scitex/fts/_fig/_editor/_cui/_editor_launcher.py +175 -0
  296. scitex/fts/_fig/_editor/_cui/_manual_handler.py +52 -0
  297. scitex/fts/_fig/_editor/_cui/_panel_loader.py +246 -0
  298. scitex/fts/_fig/_editor/_cui/_path_resolver.py +66 -0
  299. scitex/fts/_fig/_editor/_defaults.py +300 -0
  300. scitex/fts/_fig/_editor/_gui/__init__.py +11 -0
  301. scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +20 -0
  302. scitex/fts/_fig/_editor/_gui/_flask_editor/_bbox.py +1339 -0
  303. scitex/fts/_fig/_editor/_gui/_flask_editor/_core.py +1688 -0
  304. scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +664 -0
  305. scitex/fts/_fig/_editor/_gui/_flask_editor/_renderer.py +853 -0
  306. scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +79 -0
  307. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +41 -0
  308. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +16 -0
  309. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +85 -0
  310. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +217 -0
  311. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +93 -0
  312. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +57 -0
  313. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +112 -0
  314. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +59 -0
  315. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +212 -0
  316. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/canvas.css +176 -0
  317. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +190 -0
  318. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +59 -0
  319. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +45 -0
  320. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +95 -0
  321. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +101 -0
  322. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +138 -0
  323. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +31 -0
  324. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +7 -0
  325. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +56 -0
  326. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +78 -0
  327. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +314 -0
  328. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +107 -0
  329. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +54 -0
  330. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +172 -0
  331. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +258 -0
  332. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +48 -0
  333. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +71 -0
  334. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +288 -0
  335. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +143 -0
  336. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +245 -0
  337. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +992 -0
  338. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +339 -0
  339. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +286 -0
  340. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +371 -0
  341. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +293 -0
  342. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +426 -0
  343. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +152 -0
  344. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +265 -0
  345. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +184 -0
  346. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +57 -0
  347. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +100 -0
  348. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +34 -0
  349. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +124 -0
  350. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +851 -0
  351. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +4932 -0
  352. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +1657 -0
  353. scitex/fts/_fig/_editor/_gui/_flask_editor.py +36 -0
  354. scitex/fts/_fig/_models/_Annotations.py +115 -0
  355. scitex/fts/_fig/_models/_Axes.py +152 -0
  356. scitex/fts/_fig/_models/_Figure.py +138 -0
  357. scitex/fts/_fig/_models/_Guides.py +104 -0
  358. scitex/fts/_fig/_models/_Plot.py +123 -0
  359. scitex/fts/_fig/_models/_Styles.py +245 -0
  360. scitex/fts/_fig/_models/__init__.py +80 -0
  361. scitex/fts/_fig/_models/_plot_types/__init__.py +156 -0
  362. scitex/fts/_fig/_models/_plot_types/_bar.py +43 -0
  363. scitex/fts/_fig/_models/_plot_types/_box.py +38 -0
  364. scitex/fts/_fig/_models/_plot_types/_distribution.py +36 -0
  365. scitex/fts/_fig/_models/_plot_types/_errorbar.py +60 -0
  366. scitex/fts/_fig/_models/_plot_types/_histogram.py +30 -0
  367. scitex/fts/_fig/_models/_plot_types/_image.py +61 -0
  368. scitex/fts/_fig/_models/_plot_types/_line.py +57 -0
  369. scitex/fts/_fig/_models/_plot_types/_scatter.py +30 -0
  370. scitex/fts/_fig/_models/_plot_types/_seaborn.py +121 -0
  371. scitex/fts/_fig/_models/_plot_types/_violin.py +36 -0
  372. scitex/fts/_fig/_utils/__init__.py +129 -0
  373. scitex/fts/_fig/_utils/_auto_layout.py +127 -0
  374. scitex/fts/_fig/_utils/_calc_bounds.py +111 -0
  375. scitex/fts/_fig/_utils/_const_sizes.py +48 -0
  376. scitex/fts/_fig/_utils/_convert_coords.py +77 -0
  377. scitex/fts/_fig/_utils/_get_template.py +178 -0
  378. scitex/fts/_fig/_utils/_normalize.py +73 -0
  379. scitex/fts/_fig/_utils/_plot_layout.py +397 -0
  380. scitex/fts/_fig/_utils/_validate.py +197 -0
  381. scitex/fts/_kinds/__init__.py +45 -0
  382. scitex/fts/_kinds/_figure/__init__.py +19 -0
  383. scitex/fts/_kinds/_figure/_composite.py +345 -0
  384. scitex/fts/_kinds/_plot/__init__.py +25 -0
  385. scitex/fts/_kinds/_plot/_backend/__init__.py +53 -0
  386. scitex/fts/_kinds/_plot/_backend/_export.py +165 -0
  387. scitex/fts/_kinds/_plot/_backend/_parser.py +188 -0
  388. scitex/fts/_kinds/_plot/_backend/_render.py +538 -0
  389. scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +46 -0
  390. scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +82 -0
  391. scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +441 -0
  392. scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +52 -0
  393. scitex/fts/_kinds/_plot/_dataclasses/__init__.py +47 -0
  394. scitex/fts/_kinds/_plot/_models/_Annotations.py +115 -0
  395. scitex/fts/_kinds/_plot/_models/_Axes.py +152 -0
  396. scitex/fts/_kinds/_plot/_models/_Figure.py +138 -0
  397. scitex/fts/_kinds/_plot/_models/_Guides.py +104 -0
  398. scitex/fts/_kinds/_plot/_models/_Plot.py +123 -0
  399. scitex/fts/_kinds/_plot/_models/_Styles.py +245 -0
  400. scitex/fts/_kinds/_plot/_models/__init__.py +80 -0
  401. scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +156 -0
  402. scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +43 -0
  403. scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +38 -0
  404. scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +36 -0
  405. scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +60 -0
  406. scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +30 -0
  407. scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +61 -0
  408. scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +57 -0
  409. scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +30 -0
  410. scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +121 -0
  411. scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +36 -0
  412. scitex/fts/_kinds/_plot/_utils/__init__.py +129 -0
  413. scitex/fts/_kinds/_plot/_utils/_auto_layout.py +127 -0
  414. scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +111 -0
  415. scitex/fts/_kinds/_plot/_utils/_const_sizes.py +48 -0
  416. scitex/fts/_kinds/_plot/_utils/_convert_coords.py +77 -0
  417. scitex/fts/_kinds/_plot/_utils/_get_template.py +178 -0
  418. scitex/fts/_kinds/_plot/_utils/_normalize.py +73 -0
  419. scitex/fts/_kinds/_plot/_utils/_plot_layout.py +397 -0
  420. scitex/fts/_kinds/_plot/_utils/_validate.py +197 -0
  421. scitex/fts/_kinds/_shape/__init__.py +141 -0
  422. scitex/fts/_kinds/_stats/__init__.py +56 -0
  423. scitex/fts/_kinds/_stats/_dataclasses/_Stats.py +423 -0
  424. scitex/fts/_kinds/_stats/_dataclasses/__init__.py +48 -0
  425. scitex/fts/_kinds/_table/__init__.py +72 -0
  426. scitex/fts/_kinds/_table/_latex/__init__.py +93 -0
  427. scitex/fts/_kinds/_table/_latex/_editor/__init__.py +11 -0
  428. scitex/fts/_kinds/_table/_latex/_editor/_app.py +725 -0
  429. scitex/fts/_kinds/_table/_latex/_export.py +279 -0
  430. scitex/fts/_kinds/_table/_latex/_figure_exporter.py +153 -0
  431. scitex/fts/_kinds/_table/_latex/_stats_formatter.py +274 -0
  432. scitex/fts/_kinds/_table/_latex/_table_exporter.py +362 -0
  433. scitex/fts/_kinds/_table/_latex/_utils.py +369 -0
  434. scitex/fts/_kinds/_table/_latex/_validator.py +445 -0
  435. scitex/fts/_kinds/_text/__init__.py +77 -0
  436. scitex/fts/_schemas/data_info.schema.json +75 -0
  437. scitex/fts/_schemas/encoding.schema.json +90 -0
  438. scitex/fts/_schemas/node.schema.json +145 -0
  439. scitex/fts/_schemas/render_manifest.schema.json +62 -0
  440. scitex/fts/_schemas/stats.schema.json +132 -0
  441. scitex/fts/_schemas/theme.schema.json +141 -0
  442. scitex/fts/_stats/__init__.py +48 -0
  443. scitex/fts/_stats/_dataclasses/_Stats.py +423 -0
  444. scitex/fts/_stats/_dataclasses/__init__.py +48 -0
  445. scitex/fts/_tables/__init__.py +65 -0
  446. scitex/fts/_tables/_latex/__init__.py +93 -0
  447. scitex/fts/_tables/_latex/_editor/__init__.py +11 -0
  448. scitex/fts/_tables/_latex/_editor/_app.py +725 -0
  449. scitex/fts/_tables/_latex/_export.py +279 -0
  450. scitex/fts/_tables/_latex/_figure_exporter.py +153 -0
  451. scitex/fts/_tables/_latex/_stats_formatter.py +274 -0
  452. scitex/fts/_tables/_latex/_table_exporter.py +362 -0
  453. scitex/fts/_tables/_latex/_utils.py +369 -0
  454. scitex/fts/_tables/_latex/_validator.py +445 -0
  455. scitex/gen/__init__.py +66 -25
  456. scitex/gen/misc.py +28 -0
  457. scitex/io/__init__.py +47 -20
  458. scitex/io/_load.py +87 -36
  459. scitex/io/_load_modules/__init__.py +10 -7
  460. scitex/io/_load_modules/_pandas.py +6 -1
  461. scitex/io/_save.py +299 -1556
  462. scitex/io/_save_modules/__init__.py +76 -19
  463. scitex/io/_save_modules/_figure_utils.py +90 -0
  464. scitex/io/_save_modules/_image_csv.py +497 -0
  465. scitex/io/_save_modules/_legends.py +91 -0
  466. scitex/io/_save_modules/_pltz_bundle.py +356 -0
  467. scitex/io/_save_modules/_pltz_stx.py +536 -0
  468. scitex/io/_save_modules/_stx_bundle.py +104 -0
  469. scitex/io/_save_modules/_symlink.py +96 -0
  470. scitex/io/_save_modules/_yaml.py +1 -1
  471. scitex/io/_save_modules/_zarr.py +64 -18
  472. scitex/io/bundle/README.md +212 -0
  473. scitex/io/bundle/__init__.py +110 -0
  474. scitex/io/{_bundle.py → bundle/_core.py} +219 -89
  475. scitex/io/bundle/_nested.py +713 -0
  476. scitex/io/bundle/_types.py +74 -0
  477. scitex/io/bundle/_zip.py +487 -0
  478. scitex/io/utils/h5_to_zarr.py +1 -1
  479. scitex/logging/__init__.py +108 -13
  480. scitex/logging/_errors.py +508 -0
  481. scitex/logging/_formatters.py +30 -6
  482. scitex/logging/_warnings.py +261 -0
  483. scitex/plt/__init__.py +4 -1
  484. scitex/plt/_figrecipe.py +236 -0
  485. scitex/plt/_subplots/_AxisWrapper.py +6 -0
  486. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +0 -0
  487. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +0 -0
  488. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +0 -0
  489. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +0 -0
  490. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +0 -0
  491. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +0 -0
  492. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +0 -0
  493. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +0 -0
  494. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +0 -0
  495. scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +0 -0
  496. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +0 -0
  497. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +0 -0
  498. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +0 -0
  499. scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +112 -1
  500. scitex/plt/_subplots/_FigWrapper.py +15 -0
  501. scitex/plt/_subplots/_SubplotsWrapper.py +125 -489
  502. scitex/plt/_subplots/_export_as_csv.py +11 -0
  503. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +2 -0
  504. scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py +66 -0
  505. scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py +62 -0
  506. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +0 -0
  507. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +0 -0
  508. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +0 -0
  509. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +0 -0
  510. scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +208 -0
  511. scitex/plt/_subplots/_fonts.py +71 -0
  512. scitex/plt/_subplots/_mm_layout.py +282 -0
  513. scitex/plt/gallery/__init__.py +99 -2
  514. scitex/plt/io/_layered_bundle.py +0 -0
  515. scitex/plt/styles/_plot_postprocess.py +3 -1
  516. scitex/plt/utils/_configure_mpl.py +16 -19
  517. scitex/repro/_RandomStateManager.py +13 -8
  518. scitex/resource/__init__.py +19 -1
  519. scitex/resource/_utils/_get_env_info.py +13 -25
  520. scitex/schema/__init__.py +149 -160
  521. scitex/schema/_encoding.py +273 -0
  522. scitex/schema/_figure_elements.py +406 -0
  523. scitex/schema/_plot.py +0 -0
  524. scitex/schema/_theme.py +360 -0
  525. scitex/schema/_validation.py +0 -98
  526. scitex/scholar/__init__.py +56 -14
  527. scitex/scholar/auth/ScholarAuthManager.py +1 -1
  528. scitex/scholar/auth/__init__.py +11 -2
  529. scitex/scholar/auth/providers/BaseAuthenticator.py +1 -1
  530. scitex/scholar/auth/providers/EZProxyAuthenticator.py +1 -1
  531. scitex/scholar/auth/providers/OpenAthensAuthenticator.py +1 -1
  532. scitex/scholar/auth/providers/ShibbolethAuthenticator.py +1 -1
  533. scitex/scholar/config/ScholarConfig.py +1 -1
  534. scitex/scholar/core/Scholar.py +1 -1
  535. scitex/session/_decorator.py +18 -16
  536. scitex/session/_lifecycle.py +9 -11
  537. scitex/session/template.py +9 -8
  538. scitex/sh/test_sh.py +72 -0
  539. scitex/sh/test_sh_simple.py +61 -0
  540. scitex/stats/__init__.py +221 -97
  541. scitex/stats/_schema.py +21 -22
  542. scitex/stats/descriptive/_circular.py +212 -351
  543. scitex/stats/descriptive/_describe.py +81 -132
  544. scitex/stats/descriptive/_nan.py +205 -433
  545. scitex/stats/descriptive/_real.py +127 -141
  546. scitex/str/_format_plot_text.py +5 -5
  547. scitex/str/_latex.py +26 -84
  548. scitex/str/_latex_fallback.py +53 -47
  549. scitex/web/_search_pubmed.py +5 -4
  550. scitex/writer/tests/test_diff_between.py +451 -0
  551. scitex/writer/tests/test_document_section.py +311 -0
  552. scitex/writer/tests/test_document_workflow.py +393 -0
  553. scitex/writer/tests/test_writer.py +361 -0
  554. scitex/writer/tests/test_writer_integration.py +303 -0
  555. {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/METADATA +364 -181
  556. {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/RECORD +479 -108
  557. scitex/fig/editor/_edit.py +0 -751
  558. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/ARCHITECTURE_EXAMPLE.md +0 -905
  559. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/BULLETIN_BOARD_EXAMPLE.md +0 -99
  560. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/PROJECT_DESCRIPTION_EXAMPLE.md +0 -96
  561. {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/WHEEL +0 -0
  562. {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/entry_points.txt +0 -0
  563. {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/licenses/LICENSE +0 -0
scitex/fig/io/_bundle.py CHANGED
@@ -132,15 +132,15 @@ def load_figz_bundle(bundle_dir: Path) -> Dict[str, Any]:
132
132
  # Load from .pltz.d directories
133
133
  for pltz_dir in bundle_dir.glob("*.pltz.d"):
134
134
  plot_name = pltz_dir.stem.replace(".pltz", "")
135
- from scitex.io._bundle import load_bundle
136
- result["plots"][plot_name] = load_bundle(pltz_dir)
135
+ from scitex.io.bundle import load
136
+ result["plots"][plot_name] = load(pltz_dir)
137
137
 
138
138
  # Load from .pltz ZIP files
139
139
  for pltz_zip in bundle_dir.glob("*.pltz"):
140
140
  if pltz_zip.is_file():
141
141
  plot_name = pltz_zip.stem
142
- from scitex.io._bundle import load_bundle
143
- result["plots"][plot_name] = load_bundle(pltz_zip)
142
+ from scitex.io.bundle import load
143
+ result["plots"][plot_name] = load(pltz_zip)
144
144
 
145
145
  return result
146
146
 
@@ -333,32 +333,58 @@ def _copy_nested_pltz_bundles(plots: Dict[str, Any], dir_path: Path) -> None:
333
333
 
334
334
  Args:
335
335
  plots: Dict mapping panel IDs to either:
336
- - source_path: Path to existing .pltz.d directory
336
+ - source_path: Path to existing .pltz.d directory or .pltz zip
337
337
  - bundle_data: Dict with spec/data (will use save_bundle)
338
338
  dir_path: Target figz directory.
339
339
  """
340
340
  for panel_id, plot_source in plots.items():
341
- target_path = dir_path / f"{panel_id}.pltz.d"
342
-
343
341
  if isinstance(plot_source, (str, Path)):
344
342
  # Direct copy from source path
345
343
  source_path = Path(plot_source)
346
- if source_path.exists() and source_path.is_dir():
344
+
345
+ if source_path.is_dir() and str(source_path).endswith('.pltz.d'):
346
+ # Source is .pltz.d directory - copy as directory
347
+ target_path = dir_path / f"{panel_id}.pltz.d"
347
348
  if target_path.exists():
348
349
  shutil.rmtree(target_path)
349
350
  shutil.copytree(source_path, target_path)
351
+
352
+ elif source_path.is_file() and str(source_path).endswith('.pltz'):
353
+ # Source is .pltz zip file - copy as zip file (preserving zip format)
354
+ target_path = dir_path / f"{panel_id}.pltz"
355
+ if target_path.exists():
356
+ target_path.unlink()
357
+ shutil.copy2(source_path, target_path)
358
+
359
+ elif source_path.exists():
360
+ # Unknown format - try to copy as directory
361
+ target_path = dir_path / f"{panel_id}.pltz.d"
362
+ if source_path.is_dir():
363
+ if target_path.exists():
364
+ shutil.rmtree(target_path)
365
+ shutil.copytree(source_path, target_path)
366
+
350
367
  elif isinstance(plot_source, dict):
351
368
  # Check if it has source_path for direct copy
352
369
  if "source_path" in plot_source:
353
370
  source_path = Path(plot_source["source_path"])
354
- if source_path.exists() and source_path.is_dir():
371
+ if source_path.is_file() and str(source_path).endswith('.pltz'):
372
+ # .pltz zip file
373
+ target_path = dir_path / f"{panel_id}.pltz"
374
+ if target_path.exists():
375
+ target_path.unlink()
376
+ shutil.copy2(source_path, target_path)
377
+ elif source_path.exists() and source_path.is_dir():
378
+ # .pltz.d directory
379
+ target_path = dir_path / f"{panel_id}.pltz.d"
355
380
  if target_path.exists():
356
381
  shutil.rmtree(target_path)
357
382
  shutil.copytree(source_path, target_path)
358
383
  else:
359
- # Fallback to save_bundle (will lose images)
360
- from scitex.io._bundle import save_bundle, BundleType
361
- save_bundle(plot_source, target_path, bundle_type=BundleType.PLTZ)
384
+ # Fallback to save (will lose images)
385
+ from scitex.io.bundle import save, BundleType
386
+ target_path = dir_path / f"{panel_id}.pltz.d"
387
+ save(plot_source, target_path, bundle_type=BundleType.PLTZ)
362
388
 
363
389
 
364
390
  def _generate_figz_overview(dir_path: Path, spec: Dict, data: Dict, basename: str) -> None:
@@ -376,9 +402,33 @@ def _generate_figz_overview(dir_path: Path, spec: Dict, data: Dict, basename: st
376
402
  from PIL import Image
377
403
  import numpy as np
378
404
  import warnings
405
+ import tempfile
406
+ import zipfile
407
+
408
+ # Find all panel bundles (both .pltz.d directories and .pltz zip files)
409
+ panel_dirs = []
410
+ temp_dirs_to_cleanup = []
411
+
412
+ for item in dir_path.iterdir():
413
+ if item.is_dir() and str(item).endswith('.pltz.d'):
414
+ panel_dirs.append(item)
415
+ elif item.is_file() and str(item).endswith('.pltz'):
416
+ # Extract .pltz zip to temp directory for overview generation
417
+ temp_dir = tempfile.mkdtemp(prefix=f'scitex_overview_{item.stem}_')
418
+ temp_dirs_to_cleanup.append(temp_dir)
419
+ with zipfile.ZipFile(item, 'r') as zf:
420
+ zf.extractall(temp_dir)
421
+ # Find the extracted .pltz.d directory
422
+ extracted = Path(temp_dir)
423
+ for subitem in extracted.iterdir():
424
+ if subitem.is_dir() and str(subitem).endswith('.pltz.d'):
425
+ panel_dirs.append(subitem)
426
+ break
427
+ else:
428
+ # Use temp dir directly if no .pltz.d subfolder
429
+ panel_dirs.append(extracted)
379
430
 
380
- # Find all panel directories
381
- panel_dirs = sorted(dir_path.glob("*.pltz.d"))
431
+ panel_dirs = sorted(panel_dirs, key=lambda x: x.name)
382
432
  n_panels = len(panel_dirs)
383
433
 
384
434
  if n_panels == 0:
@@ -519,6 +569,13 @@ def _generate_figz_overview(dir_path: Path, spec: Dict, data: Dict, basename: st
519
569
  fig.savefig(overview_path, dpi=150, bbox_inches="tight", facecolor="white")
520
570
  plt.close(fig)
521
571
 
572
+ # Cleanup temp directories
573
+ for temp_dir in temp_dirs_to_cleanup:
574
+ try:
575
+ shutil.rmtree(temp_dir)
576
+ except Exception:
577
+ pass
578
+
522
579
 
523
580
  def _draw_bboxes_from_geometry(ax, geometry_data: Dict) -> None:
524
581
  """Draw bboxes from geometry data on an axes.
@@ -745,6 +802,8 @@ def _generate_figz_geometry_cache(dir_path: Path, spec: Dict, basename: str) ->
745
802
  basename: Base filename for bundle files.
746
803
  """
747
804
  from datetime import datetime
805
+ import tempfile
806
+ import zipfile
748
807
 
749
808
  cache_dir = dir_path / "cache"
750
809
  cache_dir.mkdir(parents=True, exist_ok=True)
@@ -756,11 +815,30 @@ def _generate_figz_geometry_cache(dir_path: Path, spec: Dict, basename: str) ->
756
815
  "generated_at": datetime.now().isoformat(),
757
816
  }
758
817
 
759
- # Find all panel directories
760
- panel_dirs = sorted(dir_path.glob("*.pltz.d"))
818
+ # Find all panel bundles (both .pltz.d directories and .pltz zip files)
819
+ panel_sources = []
820
+ temp_dirs_to_cleanup = []
821
+
822
+ for item in dir_path.iterdir():
823
+ if item.is_dir() and str(item).endswith('.pltz.d'):
824
+ panel_sources.append((item.stem.replace('.pltz', ''), item))
825
+ elif item.is_file() and str(item).endswith('.pltz'):
826
+ # Extract .pltz zip to temp directory
827
+ temp_dir = tempfile.mkdtemp(prefix=f'scitex_geom_{item.stem}_')
828
+ temp_dirs_to_cleanup.append(temp_dir)
829
+ with zipfile.ZipFile(item, 'r') as zf:
830
+ zf.extractall(temp_dir)
831
+ extracted = Path(temp_dir)
832
+ for subitem in extracted.iterdir():
833
+ if subitem.is_dir() and str(subitem).endswith('.pltz.d'):
834
+ panel_sources.append((item.stem, subitem))
835
+ break
836
+ else:
837
+ panel_sources.append((item.stem, extracted))
761
838
 
762
- for panel_dir in panel_dirs:
763
- panel_id = panel_dir.stem.replace(".pltz", "")
839
+ panel_sources = sorted(panel_sources, key=lambda x: x[0])
840
+
841
+ for panel_id, panel_dir in panel_sources:
764
842
 
765
843
  # Load panel geometry
766
844
  panel_geometry_path = panel_dir / "cache" / "geometry_px.json"
@@ -790,7 +868,7 @@ def _generate_figz_geometry_cache(dir_path: Path, spec: Dict, basename: str) ->
790
868
  "figure_id": basename,
791
869
  "generated_at": datetime.now().isoformat(),
792
870
  "size_mm": [size.get("width_mm", 0), size.get("height_mm", 0)],
793
- "panels_count": len(panel_dirs),
871
+ "panels_count": len(panel_sources),
794
872
  "schema": spec.get("schema", {}),
795
873
  }
796
874
 
@@ -798,6 +876,13 @@ def _generate_figz_geometry_cache(dir_path: Path, spec: Dict, basename: str) ->
798
876
  with open(manifest_path, "w") as f:
799
877
  json.dump(manifest, f, indent=2)
800
878
 
879
+ # Cleanup temp directories
880
+ for temp_dir in temp_dirs_to_cleanup:
881
+ try:
882
+ shutil.rmtree(temp_dir)
883
+ except Exception:
884
+ pass
885
+
801
886
 
802
887
  def _embed_metadata_in_export(
803
888
  file_path: Path, spec: Dict[str, Any], fmt: str
scitex/fts/README.md ADDED
@@ -0,0 +1,262 @@
1
+ <!-- ---
2
+ !-- Timestamp: 2025-12-20 07:20:45
3
+ !-- Author: ywatanabe
4
+ !-- File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/README.md
5
+ !-- --- -->
6
+
7
+ # SciTeX FTS (Figure-Table-Statistics)
8
+
9
+ **FTS is the single source of truth for bundle schemas in SciTeX.**
10
+
11
+ FTS defines a standardized, self-contained format for reproducible scientific figures with:
12
+ - Complete data provenance
13
+ - Statistical analysis results
14
+ - Visual encoding specifications
15
+ - Theme/aesthetic configuration
16
+
17
+ ## Design Philosophy
18
+
19
+ ### Separation of Concerns
20
+
21
+ FTS strictly separates:
22
+
23
+ | Layer | File | Purpose | Affects Science? |
24
+ |-------|------|---------|------------------|
25
+ | **Node** | `spec.json` | Structure (id, type, bbox, children) | Yes |
26
+ | **Encoding** | `encoding.json` | Data-to-Visual mapping (columns, scales) | Yes |
27
+ | **Theme** | `theme.json` | Aesthetics (colors, fonts, lines) | No |
28
+ | **Stats** | `stats.json` | Statistical results with provenance | Yes |
29
+ | **Data Info** | `data_info.json` | Column metadata, units, data source | Yes |
30
+
31
+ **Key insight**: Theme changes don't affect reproducibility. Encoding changes do.
32
+
33
+ ### Canonical vs Artifacts
34
+
35
+ ```
36
+ bundle_root/
37
+ ├── canonical/ # Source of truth (editable, human-readable)
38
+ │ ├── spec.json # Main specification
39
+ │ ├── data.csv # Source data
40
+ │ ├── encoding.json # Data-to-visual mappings
41
+ │ ├── theme.json # Visual aesthetics
42
+ │ ├── stats.json # Statistical results
43
+ │ ├── data_info.json # Column metadata
44
+ │ └── runtime.json # Runtime configuration
45
+ ├── artifacts/ # Derived/cached (can be deleted and regenerated)
46
+ │ ├── cache/
47
+ │ │ ├── geometry_px.json
48
+ │ │ └── render_manifest.json
49
+ │ └── exports/
50
+ │ ├── figure.svg
51
+ │ ├── figure.png
52
+ │ └── figure.pdf
53
+ └── children/ # Child bundles (for multi-panel figures)
54
+ ├── panel_a/
55
+ └── panel_b/
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```python
61
+ from scitex import fts
62
+
63
+ # Create a new bundle
64
+ bundle = fts.FTS("my_plot.zip", create=True, node_type="plot", name="My Plot")
65
+
66
+ # Set encoding (data-to-visual mapping)
67
+ bundle.encoding = {
68
+ "traces": [
69
+ {
70
+ "trace_id": "main",
71
+ "data_ref": "data/experiment.csv",
72
+ "x": {"column": "time", "scale": "linear"},
73
+ "y": {"column": "amplitude", "scale": "log"},
74
+ "color": {"column": "condition"},
75
+ }
76
+ ]
77
+ }
78
+
79
+ # Set theme (pure aesthetics)
80
+ bundle.theme = {
81
+ "colors": {"palette": ["#1f77b4", "#ff7f0e", "#2ca02c"]},
82
+ "typography": {"family": "Arial", "size_pt": 10},
83
+ "lines": {"width_pt": 1.5},
84
+ }
85
+
86
+ # Save
87
+ bundle.save()
88
+ ```
89
+
90
+ ## Module Structure
91
+
92
+ ```
93
+ scitex/fts/
94
+ ├── __init__.py # Public API exports
95
+ ├── _bundle.py # FTS class
96
+ ├── _models.py # Core models (Node, BBox, SizeMM, Axes)
97
+ ├── _encoding.py # Encoding models (TraceEncoding, ChannelEncoding)
98
+ ├── _theme.py # Theme models (Theme, Colors, Typography)
99
+ ├── _stats.py # Stats models (Analysis, StatResult, EffectSize)
100
+ ├── _data_info.py # Data info models (DataInfo, ColumnDef)
101
+ ├── _validation.py # JSON schema validation
102
+ ├── _conversion.py # scitex to FTS format conversion
103
+ └── schemas/ # JSON Schema definitions
104
+ ├── node.schema.json
105
+ ├── encoding.schema.json
106
+ ├── theme.schema.json
107
+ ├── stats.schema.json
108
+ └── data_info.schema.json
109
+ ```
110
+
111
+ ## Core Models
112
+
113
+ ### Node (spec.json)
114
+
115
+ Structural metadata for the bundle:
116
+
117
+ ```python
118
+ from scitex.fts import Node, BBox, SizeMM
119
+
120
+ node = Node(
121
+ id="plot_001",
122
+ type="plot", # figure, plot, text, shape, image
123
+ name="Figure 1A",
124
+ bbox_norm=BBox(x0=0, y0=0, x1=1, y1=1),
125
+ size_mm=SizeMM(width=85, height=60), # Single column
126
+ children=["panel_a", "panel_b"], # For figures
127
+ )
128
+ ```
129
+
130
+ ### Encoding (encoding.json)
131
+
132
+ Data-to-visual channel mappings:
133
+
134
+ ```python
135
+ from scitex.fts import Encoding, TraceEncoding, ChannelEncoding
136
+
137
+ encoding = Encoding(
138
+ traces=[
139
+ TraceEncoding(
140
+ trace_id="line_1",
141
+ data_ref="data/timeseries.csv",
142
+ x=ChannelEncoding(column="time_ms", scale="linear"),
143
+ y=ChannelEncoding(column="voltage_mV", scale="linear"),
144
+ color=ChannelEncoding(column="channel", scale="categorical"),
145
+ )
146
+ ]
147
+ )
148
+ ```
149
+
150
+ ### Theme (theme.json)
151
+
152
+ Pure aesthetics (doesn't affect scientific meaning):
153
+
154
+ ```python
155
+ from scitex.fts import Theme, Colors, Typography
156
+
157
+ theme = Theme(
158
+ colors=Colors(
159
+ palette=["#1f77b4", "#ff7f0e", "#2ca02c"],
160
+ background="#ffffff",
161
+ text="#000000",
162
+ ),
163
+ typography=Typography(
164
+ family="Arial",
165
+ size_pt=8,
166
+ title_size_pt=10,
167
+ ),
168
+ preset="nature", # Named presets: nature, science, dark
169
+ )
170
+ ```
171
+
172
+ ### Stats (stats/stats.json)
173
+
174
+ Statistical analysis results with full provenance:
175
+
176
+ ```python
177
+ from scitex.fts import Stats, Analysis, StatMethod, StatResult, EffectSize
178
+
179
+ stats = Stats(
180
+ analyses=[
181
+ Analysis(
182
+ result_id="ttest_1",
183
+ method=StatMethod(
184
+ name="t-test",
185
+ variant="independent",
186
+ parameters={"equal_var": False},
187
+ ),
188
+ inputs={
189
+ "groups": ["control", "treatment"],
190
+ "n_per_group": [30, 28],
191
+ },
192
+ results=StatResult(
193
+ statistic=2.45,
194
+ statistic_name="t",
195
+ p_value=0.018,
196
+ df=56,
197
+ effect_size=EffectSize(
198
+ name="cohens_d",
199
+ value=0.65,
200
+ ci_lower=0.12,
201
+ ci_upper=1.18,
202
+ ),
203
+ ),
204
+ )
205
+ ],
206
+ software={"python": "3.11", "scipy": "1.11.0"},
207
+ )
208
+ ```
209
+
210
+ ## Validation
211
+
212
+ Validate bundles against JSON schemas:
213
+
214
+ ```python
215
+ from scitex.fts import validate_bundle, validate_node
216
+
217
+ # Validate entire bundle
218
+ errors = validate_bundle("my_figure.zip")
219
+ if errors:
220
+ for filename, error_list in errors.items():
221
+ print(f"{filename}: {error_list}")
222
+
223
+ # Validate individual components
224
+ node_errors = validate_node({"id": "test", "type": "plot", "bbox_norm": {...}})
225
+ ```
226
+
227
+ ## Conversion Utilities
228
+
229
+ Convert between scitex internal format and FTS format:
230
+
231
+ ```python
232
+ from scitex.fts import from_scitex_spec, to_scitex_spec
233
+
234
+ # scitex spec to FTS format
235
+ fts_data = from_scitex_spec(spec_dict, style_dict)
236
+ # Returns: {"node": {...}, "encoding": {...}, "theme": {...}}
237
+
238
+ # FTS bundle to scitex format
239
+ spec, style = to_scitex_spec(bundle)
240
+ ```
241
+
242
+ ## Backward Compatibility
243
+
244
+ FTS is also available via the legacy import path:
245
+
246
+ ```python
247
+ # Old path (still works)
248
+ from scitex import fsb # Alias for fts
249
+
250
+ # New path (preferred)
251
+ from scitex import fts
252
+ ```
253
+
254
+ ## Best Practices
255
+
256
+ 1. **Always specify units in data_info.json** - Critical for reproducibility
257
+ 2. **Use encoding for data-driven styling** - Color by condition, size by value
258
+ 3. **Keep theme separate from encoding** - Enables style changes without data loss
259
+ 4. **Include stats provenance** - Software versions, parameters, correction methods
260
+ 5. **Use canonical/ for source files** - artifacts/ can be regenerated
261
+
262
+ <!-- EOF -->
scitex/fts/TODO.md ADDED
@@ -0,0 +1,66 @@
1
+ <!-- ---
2
+ !-- Timestamp: 2025-12-21 11:02:24
3
+ !-- Author: ywatanabe
4
+ !-- File: /home/ywatanabe/proj/scitex-code/src/scitex/fts/TODO.md
5
+ !-- --- -->
6
+
7
+ ## Simplify Things
8
+ ## Explict Names
9
+ ## Kinds
10
+ ### figure
11
+ ### plot
12
+
13
+ #### Current
14
+ ```
15
+ ├── artifacts
16
+ │   ├── cache
17
+ │   │   ├── geometry_px.json
18
+ │   │   ├── hitmap.png
19
+ │   │   ├── hitmap.svg
20
+ │   │   └── render_manifest.json
21
+ │   └── exports
22
+ │   ├── figure.pdf
23
+ │   ├── figure.png
24
+ │   └── figure.svg
25
+ ├── canonical
26
+ │   ├── data_info.json
27
+ │   ├── encoding.json
28
+ │   ├── spec.json
29
+ │   └── theme.json
30
+ ├── children
31
+ └── payload
32
+ └── data.csv
33
+
34
+ ```
35
+
36
+ #### Revised
37
+ ```
38
+ ├── artifacts
39
+ │   ├── cache
40
+ │   │   ├── coordinates/
41
+
42
+ │   │   ├── hitmap.png
43
+ │   │   ├── hitmap.svg
44
+ │   │   └── render_manifest.json
45
+ │   └── exports
46
+ │   ├── figure.pdf
47
+ │   ├── figure.png
48
+ │   └── figure.svg
49
+ ├── canonical
50
+ │   ├── data_info.json
51
+ │   ├── encoding.json
52
+ │   ├── spec.json
53
+ │   └── theme.json
54
+ ├── children
55
+ └── payload
56
+ └── data.csv
57
+
58
+ ```
59
+
60
+ ### image
61
+ ### shape
62
+ ### stats
63
+ ### table
64
+ ### text
65
+
66
+ <!-- EOF -->
scitex/fts/__init__.py ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-12-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fts/__init__.py
4
+
5
+ """
6
+ SciTeX FTS (Figure-Table-Statistics) - The single source of truth for bundle schemas.
7
+
8
+ FTS defines a standardized format for reproducible scientific figures and tables:
9
+ - Self-contained bundles with data, visualization spec, and stats
10
+ - Clear separation: Node (structure), Encoding (data mapping), Theme (aesthetics)
11
+ - Full provenance tracking for scientific reproducibility
12
+
13
+ Usage:
14
+ from scitex.fts import FTS, Node, Encoding, Theme
15
+
16
+ # Create new bundle
17
+ bundle = FTS("my_plot.zip", create=True, node_type="plot")
18
+ bundle.encoding = {"traces": [{"trace_id": "t1", "x": {"column": "time"}}]}
19
+ bundle.save()
20
+
21
+ # Load existing bundle
22
+ bundle = FTS("my_plot.zip")
23
+ print(bundle.node.type) # "plot"
24
+ """
25
+
26
+ # Version
27
+ __version__ = "1.0.0"
28
+
29
+ # =============================================================================
30
+ # Public API - What users need
31
+ # =============================================================================
32
+
33
+ # FTS class (main entry point)
34
+ from ._bundle import FTS, create_bundle, from_matplotlib, load_bundle
35
+
36
+ # Core dataclasses users interact with
37
+ from ._bundle import Node, BBox, SizeMM, DataInfo
38
+ from ._fig import Encoding, Theme
39
+ from ._stats import Stats
40
+
41
+ # Type enumeration
42
+ from ._bundle import NodeType
43
+
44
+ # Error classes for exception handling
45
+ from ._bundle import (
46
+ BundleError,
47
+ BundleNotFoundError,
48
+ BundleValidationError,
49
+ )
50
+
51
+ # Availability flags
52
+ FTS_AVAILABLE = True
53
+ FTS_VERSION = __version__
54
+
55
+ # Legacy aliases for backwards compatibility
56
+ FSB = FTS
57
+ FSB_AVAILABLE = FTS_AVAILABLE
58
+ FSB_VERSION = FTS_VERSION
59
+
60
+ __all__ = [
61
+ # Version
62
+ "__version__",
63
+ "FTS_AVAILABLE",
64
+ "FTS_VERSION",
65
+ # Legacy aliases
66
+ "FSB_AVAILABLE",
67
+ "FSB_VERSION",
68
+ "FSB",
69
+ # FTS class
70
+ "FTS",
71
+ "load_bundle",
72
+ "create_bundle",
73
+ "from_matplotlib",
74
+ # Core dataclasses
75
+ "Node",
76
+ "Encoding",
77
+ "Theme",
78
+ "Stats",
79
+ "BBox",
80
+ "SizeMM",
81
+ "DataInfo",
82
+ # Types
83
+ "NodeType",
84
+ # Errors
85
+ "BundleError",
86
+ "BundleNotFoundError",
87
+ "BundleValidationError",
88
+ ]
89
+
90
+ # EOF