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
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: "2025-12-14 (ywatanabe)"
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/panel_loader.py
4
+
5
+ """Panel data loading for figure editor."""
6
+
7
+ import io
8
+ import json as json_module
9
+ from pathlib import Path
10
+ from typing import Any, Dict, Optional, Union
11
+
12
+ __all__ = ["load_panel_data"]
13
+
14
+
15
+ def load_panel_data(
16
+ panel_path: Union[Path, str], is_zip: bool = None
17
+ ) -> Optional[Dict[str, Any]]:
18
+ """
19
+ Load panel data from either a .pltz.d directory or a .pltz zip file.
20
+
21
+ Handles both formats transparently using in-memory reading for zips.
22
+
23
+ Parameters
24
+ ----------
25
+ panel_path : Path or str
26
+ Path to .pltz.d directory or .pltz zip file
27
+ is_zip : bool, optional
28
+ If True, treat as zip file. If False, treat as directory.
29
+ If None, auto-detect based on path suffix and existence.
30
+
31
+ Returns
32
+ -------
33
+ dict or None
34
+ Dictionary with keys: metadata, csv_data, png_bytes, hitmap_bytes, img_size
35
+ For directories, also includes: json_path, png_path, hitmap_path
36
+ Returns None if panel cannot be loaded
37
+ """
38
+
39
+ panel_path = Path(panel_path)
40
+
41
+ # Auto-detect if not specified
42
+ if is_zip is None:
43
+ spath = str(panel_path)
44
+ if spath.endswith(".pltz") and not spath.endswith(".pltz.d"):
45
+ is_zip = panel_path.is_file()
46
+ else:
47
+ is_zip = False
48
+
49
+ if is_zip:
50
+ return _load_from_zip(panel_path)
51
+ else:
52
+ return _load_from_directory(panel_path)
53
+
54
+
55
+ def _load_from_zip(panel_path: Path) -> Optional[Dict[str, Any]]:
56
+ """Load panel data from a .pltz zip file."""
57
+ from PIL import Image
58
+
59
+ from scitex.fts import FTS as ZipBundle
60
+
61
+ if not panel_path.exists():
62
+ return None
63
+
64
+ try:
65
+ with ZipBundle(panel_path, mode="r") as zb:
66
+ # Load spec.json for metadata
67
+ try:
68
+ metadata = zb.read_json("spec.json")
69
+ except FileNotFoundError:
70
+ metadata = {}
71
+
72
+ # Load style.json if exists
73
+ try:
74
+ style = zb.read_json("style.json")
75
+ metadata["style"] = style
76
+ except FileNotFoundError:
77
+ pass
78
+
79
+ # Find and read PNG
80
+ png_bytes = None
81
+ for name in zb.namelist():
82
+ if (
83
+ name.endswith(".png")
84
+ and "_hitmap" not in name
85
+ and "_overview" not in name
86
+ ):
87
+ if "exports/" in name:
88
+ png_bytes = zb.read_bytes(name)
89
+ break
90
+
91
+ # If no PNG in exports/, try root level
92
+ if not png_bytes:
93
+ for name in zb.namelist():
94
+ if (
95
+ name.endswith(".png")
96
+ and "_hitmap" not in name
97
+ and "_overview" not in name
98
+ ):
99
+ png_bytes = zb.read_bytes(name)
100
+ break
101
+
102
+ # Get image size
103
+ img_size = None
104
+ if png_bytes:
105
+ img = Image.open(io.BytesIO(png_bytes))
106
+ img_size = {"width": img.size[0], "height": img.size[1]}
107
+ img.close()
108
+
109
+ # Find and read hitmap
110
+ hitmap_bytes = None
111
+ for name in zb.namelist():
112
+ if "_hitmap.png" in name:
113
+ hitmap_bytes = zb.read_bytes(name)
114
+ break
115
+
116
+ # Load geometry_px.json if available
117
+ geometry_data = None
118
+ try:
119
+ geometry_data = zb.read_json("cache/geometry_px.json")
120
+ except FileNotFoundError:
121
+ pass
122
+
123
+ return {
124
+ "metadata": metadata,
125
+ "png_bytes": png_bytes,
126
+ "hitmap_bytes": hitmap_bytes,
127
+ "img_size": img_size,
128
+ "geometry_data": geometry_data,
129
+ "is_zip": True,
130
+ }
131
+ except Exception as e:
132
+ print(f"Error loading panel zip {panel_path}: {e}")
133
+ return None
134
+
135
+
136
+ def _load_from_directory(panel_path: Path) -> Optional[Dict[str, Any]]:
137
+ """Load panel data from a .pltz.d directory."""
138
+
139
+ panel_dir = panel_path
140
+ if not panel_dir.exists():
141
+ return None
142
+
143
+ # Check for layered vs legacy format
144
+ spec_path = panel_dir / "spec.json"
145
+ if spec_path.exists():
146
+ return _load_layered_directory(panel_dir)
147
+ else:
148
+ return _load_legacy_directory(panel_dir)
149
+
150
+
151
+ def _load_layered_directory(panel_dir: Path) -> Dict[str, Any]:
152
+ """Load panel data from layered format directory."""
153
+ import scitex as stx
154
+ from scitex.plt.io import load_layered_pltz_bundle
155
+
156
+ bundle_data = load_layered_pltz_bundle(panel_dir)
157
+ metadata = bundle_data.get("merged", {})
158
+
159
+ # Find CSV
160
+ csv_data = None
161
+ for f in panel_dir.glob("*.csv"):
162
+ csv_data = stx.io.load(f)
163
+ break
164
+
165
+ # Find exports - prefer PNG over SVG (PIL can't open SVG)
166
+ png_path = None
167
+ svg_path = None
168
+ hitmap_path = None
169
+ exports_dir = panel_dir / "exports"
170
+ if exports_dir.exists():
171
+ for f in exports_dir.iterdir():
172
+ name = f.name
173
+ if name.endswith("_hitmap.png"):
174
+ hitmap_path = f
175
+ elif (
176
+ name.endswith(".png")
177
+ and "_hitmap" not in name
178
+ and "_overview" not in name
179
+ ):
180
+ png_path = f
181
+ elif name.endswith(".svg") and "_hitmap" not in name and svg_path is None:
182
+ svg_path = f
183
+
184
+ if png_path is None:
185
+ png_path = svg_path
186
+
187
+ # Load geometry_px.json if available
188
+ geometry_data = None
189
+ geometry_path = panel_dir / "cache" / "geometry_px.json"
190
+ if geometry_path.exists():
191
+ with open(geometry_path) as f:
192
+ geometry_data = json_module.load(f)
193
+
194
+ return {
195
+ "json_path": panel_dir / "spec.json",
196
+ "metadata": metadata,
197
+ "csv_data": csv_data,
198
+ "png_path": png_path,
199
+ "hitmap_path": hitmap_path,
200
+ "geometry_data": geometry_data,
201
+ "is_zip": False,
202
+ }
203
+
204
+
205
+ def _load_legacy_directory(panel_dir: Path) -> Optional[Dict[str, Any]]:
206
+ """Load panel data from legacy format directory."""
207
+ import scitex as stx
208
+
209
+ json_path = None
210
+ csv_data = None
211
+ png_path = None
212
+ hitmap_path = None
213
+
214
+ for f in panel_dir.iterdir():
215
+ name = f.name
216
+ if name.endswith(".json") and not name.endswith(".manual.json"):
217
+ json_path = f
218
+ elif name.endswith(".csv"):
219
+ csv_data = stx.io.load(f)
220
+ elif name.endswith("_hitmap.png"):
221
+ hitmap_path = f
222
+ elif name.endswith(".svg") and "_hitmap" not in name:
223
+ png_path = f
224
+ elif (
225
+ name.endswith(".png") and "_hitmap" not in name and "_overview" not in name
226
+ ):
227
+ if png_path is None:
228
+ png_path = f
229
+
230
+ if json_path is None:
231
+ return None
232
+
233
+ with open(json_path) as f:
234
+ metadata = json_module.load(f)
235
+
236
+ return {
237
+ "json_path": json_path,
238
+ "metadata": metadata,
239
+ "csv_data": csv_data,
240
+ "png_path": png_path,
241
+ "hitmap_path": hitmap_path,
242
+ "is_zip": False,
243
+ }
244
+
245
+
246
+ # EOF
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: "2025-12-14 (ywatanabe)"
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/path_resolver.py
4
+
5
+ """Basic path resolution for figure files."""
6
+
7
+ from pathlib import Path
8
+ from typing import Optional, Tuple
9
+
10
+ __all__ = ["resolve_figure_paths"]
11
+
12
+
13
+ def resolve_figure_paths(path: Path) -> Tuple[Path, Optional[Path], Optional[Path]]:
14
+ """
15
+ Resolve JSON, CSV, and PNG paths from any input file path.
16
+
17
+ Handles two patterns:
18
+ 1. Flat (sibling): path/to/figure.{json,csv,png}
19
+ 2. Organized (subdirs): path/to/{json,csv,png}/figure.{ext}
20
+
21
+ Parameters
22
+ ----------
23
+ path : Path
24
+ Input path (can be JSON, CSV, or PNG)
25
+
26
+ Returns
27
+ -------
28
+ tuple
29
+ (json_path, csv_path, png_path) - csv_path/png_path may be None if not found
30
+ """
31
+ path = Path(path)
32
+ stem = path.stem
33
+ parent = path.parent
34
+
35
+ # Check if this is organized pattern (parent is json/, csv/, png/)
36
+ if parent.name in ("json", "csv", "png"):
37
+ base_dir = parent.parent
38
+ json_path = base_dir / "json" / f"{stem}.json"
39
+ csv_path = base_dir / "csv" / f"{stem}.csv"
40
+ png_path = base_dir / "png" / f"{stem}.png"
41
+ else:
42
+ # Flat pattern - sibling files
43
+ json_path = parent / f"{stem}.json"
44
+ csv_path = parent / f"{stem}.csv"
45
+ png_path = parent / f"{stem}.png"
46
+
47
+ # If input was .manual.json, get base json
48
+ if stem.endswith(".manual"):
49
+ base_stem = stem[:-7] # Remove '.manual'
50
+ if parent.name == "json":
51
+ json_path = parent / f"{base_stem}.json"
52
+ csv_path = parent.parent / "csv" / f"{base_stem}.csv"
53
+ png_path = parent.parent / "png" / f"{base_stem}.png"
54
+ else:
55
+ json_path = parent / f"{base_stem}.json"
56
+ csv_path = parent / f"{base_stem}.csv"
57
+ png_path = parent / f"{base_stem}.png"
58
+
59
+ return (
60
+ json_path,
61
+ csv_path if csv_path.exists() else None,
62
+ png_path if png_path.exists() else None,
63
+ )
64
+
65
+
66
+ # EOF
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env python3
2
+ # File: ./src/scitex/vis/editor/_defaults.py
3
+ """Default style settings for SciTeX visual editor."""
4
+
5
+ from scitex.plt.styles import get_default_dpi
6
+
7
+
8
+ def get_scitex_defaults():
9
+ """
10
+ Get default style values based on SciTeX publication standards.
11
+
12
+ Returns
13
+ -------
14
+ dict
15
+ Dictionary of default style settings
16
+ """
17
+ return {
18
+ # Font sizes (from _configure_mpl.py)
19
+ "fontsize": 7, # Base font size for publication
20
+ "title_fontsize": 8, # Title size
21
+ "axis_fontsize": 7, # Axis label size
22
+ "tick_fontsize": 7, # Tick label size
23
+ "legend_fontsize": 6, # Legend font size
24
+ # Line settings (in points, 1mm = 2.83465pt)
25
+ "linewidth": 0.57, # Default line width (0.2mm)
26
+ # Tick settings
27
+ "n_ticks": 4, # Number of ticks
28
+ "tick_length": 0.8, # Tick length in mm
29
+ "tick_width": 0.2, # Tick width in mm
30
+ "tick_direction": "out", # Tick direction
31
+ # Axes settings
32
+ "axis_width": 0.2, # Spine/axes line width in mm
33
+ "hide_top_spine": True, # Hide top spine
34
+ "hide_right_spine": True, # Hide right spine
35
+ # Grid settings
36
+ "grid": False, # Grid off by default
37
+ "grid_linewidth": 0.6,
38
+ "grid_alpha": 0.3,
39
+ # Figure settings
40
+ "dpi": get_default_dpi(), # From SCITEX_STYLE.yaml
41
+ "fig_size": [3.15, 2.68], # Default figure size in inches
42
+ # Colors (SciTeX defaults)
43
+ "facecolor": "#ffffff", # White background
44
+ "transparent": True, # Transparent background
45
+ # Legend
46
+ "legend_visible": True,
47
+ "legend_frameon": False,
48
+ "legend_loc": "best",
49
+ # Font family
50
+ "font_family": "Arial", # Sans-serif for publication
51
+ # Annotations
52
+ "annotations": [],
53
+ }
54
+
55
+
56
+ def get_scitex_colors():
57
+ """
58
+ Get SciTeX color palette.
59
+
60
+ Returns
61
+ -------
62
+ dict
63
+ Dictionary of named colors with hex values
64
+ """
65
+ # Based on scitex.plt.color.PARAMS
66
+ return {
67
+ "blue": "#1f77b4",
68
+ "orange": "#ff7f0e",
69
+ "green": "#2ca02c",
70
+ "red": "#d62728",
71
+ "purple": "#9467bd",
72
+ "brown": "#8c564b",
73
+ "pink": "#e377c2",
74
+ "gray": "#7f7f7f",
75
+ "olive": "#bcbd22",
76
+ "cyan": "#17becf",
77
+ # Additional publication colors
78
+ "black": "#000000",
79
+ "white": "#ffffff",
80
+ "dark_gray": "#404040",
81
+ "light_gray": "#d0d0d0",
82
+ }
83
+
84
+
85
+ def extract_defaults_from_metadata(metadata):
86
+ """
87
+ Extract style defaults from loaded figure metadata.
88
+
89
+ Parameters
90
+ ----------
91
+ metadata : dict
92
+ Figure metadata loaded from JSON
93
+
94
+ Returns
95
+ -------
96
+ dict
97
+ Dictionary of style values extracted from metadata
98
+ """
99
+ defaults = get_scitex_defaults()
100
+
101
+ if not metadata:
102
+ return defaults
103
+
104
+ # Extract from scitex section (new format)
105
+ scitex_meta = metadata.get("scitex", {})
106
+ style_mm = scitex_meta.get("style_mm", {})
107
+
108
+ # Font sizes from style_mm
109
+ if "axis_font_size_pt" in style_mm:
110
+ defaults["axis_fontsize"] = style_mm["axis_font_size_pt"]
111
+ if "tick_font_size_pt" in style_mm:
112
+ defaults["tick_fontsize"] = style_mm["tick_font_size_pt"]
113
+ if "title_font_size_pt" in style_mm:
114
+ defaults["title_fontsize"] = style_mm["title_font_size_pt"]
115
+ if "legend_font_size_pt" in style_mm:
116
+ defaults["legend_fontsize"] = style_mm["legend_font_size_pt"]
117
+
118
+ # Line/axis thickness from metadata (in mm)
119
+ if "trace_thickness_mm" in style_mm:
120
+ defaults["linewidth"] = style_mm["trace_thickness_mm"] * 2.83465 # mm to pt
121
+ if "axis_thickness_mm" in style_mm:
122
+ defaults["axis_width"] = style_mm["axis_thickness_mm"]
123
+ if "tick_length_mm" in style_mm:
124
+ defaults["tick_length"] = style_mm["tick_length_mm"]
125
+ if "tick_thickness_mm" in style_mm:
126
+ defaults["tick_width"] = style_mm["tick_thickness_mm"]
127
+ if "n_ticks" in style_mm:
128
+ defaults["n_ticks"] = style_mm["n_ticks"]
129
+
130
+ # Dimensions from metadata (support both old and new formats)
131
+ dimensions = metadata.get("dimensions", {})
132
+ if "dpi" in dimensions:
133
+ defaults["dpi"] = dimensions["dpi"]
134
+ if "figure_size_inch" in dimensions:
135
+ defaults["fig_size"] = dimensions["figure_size_inch"]
136
+
137
+ # New format: size.width_mm, size.height_mm, size.dpi
138
+ size = metadata.get("size", {})
139
+ if "dpi" in size:
140
+ defaults["dpi"] = size["dpi"]
141
+ if "width_mm" in size and "height_mm" in size:
142
+ # Convert mm to inches
143
+ width_inch = size["width_mm"] / 25.4
144
+ height_inch = size["height_mm"] / 25.4
145
+ defaults["fig_size"] = [width_inch, height_inch]
146
+
147
+ # Axis labels from metadata
148
+ if "xlabel" in metadata:
149
+ defaults["xlabel"] = metadata["xlabel"]
150
+ if "ylabel" in metadata:
151
+ defaults["ylabel"] = metadata["ylabel"]
152
+ if "title" in metadata:
153
+ defaults["title"] = metadata["title"]
154
+
155
+ # Try to extract from axes if present
156
+ axes = metadata.get("axes", {})
157
+ if isinstance(axes, dict):
158
+ # New format: {'x': {'label': ...}, 'y': {'label': ...}}
159
+ x_axis = axes.get("x", {})
160
+ y_axis = axes.get("y", {})
161
+ if "label" in x_axis:
162
+ unit = x_axis.get("unit", "")
163
+ label = x_axis["label"]
164
+ if unit:
165
+ defaults["xlabel"] = f"{label} [{unit}]"
166
+ else:
167
+ defaults["xlabel"] = label
168
+ if "label" in y_axis:
169
+ unit = y_axis.get("unit", "")
170
+ label = y_axis["label"]
171
+ if unit:
172
+ defaults["ylabel"] = f"{label} [{unit}]"
173
+ else:
174
+ defaults["ylabel"] = label
175
+ # Extract axis limits
176
+ if "lim" in x_axis:
177
+ defaults["xlim"] = x_axis["lim"]
178
+ if "lim" in y_axis:
179
+ defaults["ylim"] = y_axis["lim"]
180
+ elif isinstance(axes, list) and len(axes) > 0:
181
+ # Legacy format: list of axes
182
+ ax = axes[0]
183
+ if "xlabel" in ax:
184
+ defaults["xlabel"] = ax["xlabel"]
185
+ if "ylabel" in ax:
186
+ defaults["ylabel"] = ax["ylabel"]
187
+ if "title" in ax:
188
+ defaults["title"] = ax["title"]
189
+ if "grid" in ax:
190
+ defaults["grid"] = ax["grid"]
191
+ # Extract axis limits from list format
192
+ if "xlim" in ax:
193
+ defaults["xlim"] = ax["xlim"]
194
+ if "ylim" in ax:
195
+ defaults["ylim"] = ax["ylim"]
196
+
197
+ # Extract traces information - check multiple possible locations
198
+ traces = metadata.get("traces", [])
199
+
200
+ # Also check axes[].lines (pltz bundle format)
201
+ if not traces and isinstance(axes, list) and len(axes) > 0:
202
+ ax = axes[0]
203
+ lines = ax.get("lines", [])
204
+ if lines:
205
+ traces = lines
206
+
207
+ # Also check hit_regions.color_map for trace info
208
+ if not traces:
209
+ hit_regions = metadata.get("hit_regions", {})
210
+ color_map = hit_regions.get("color_map", {})
211
+ if color_map:
212
+ traces = []
213
+ for trace_id, trace_info in color_map.items():
214
+ traces.append(
215
+ {
216
+ "id": trace_id,
217
+ "label": trace_info.get("label", f"Trace {trace_id}"),
218
+ "type": trace_info.get("type", "line"),
219
+ }
220
+ )
221
+
222
+ if traces:
223
+ defaults["traces"] = traces
224
+
225
+ # Extract legend information from multiple possible locations
226
+ legend = metadata.get("legend", {})
227
+
228
+ # Also check selectable_regions.axes[0].legend (pltz bundle format)
229
+ if not legend:
230
+ selectable = metadata.get("selectable_regions", {})
231
+ sel_axes = selectable.get("axes", [])
232
+ if sel_axes and len(sel_axes) > 0:
233
+ legend = sel_axes[0].get("legend", {})
234
+
235
+ if legend:
236
+ defaults["legend_visible"] = legend.get("visible", True)
237
+ defaults["legend_frameon"] = legend.get("frameon", False)
238
+ # Support both old format (loc) and new format (location)
239
+ loc = legend.get("location") or legend.get("loc", "best")
240
+ # Convert numeric legend loc to string (matplotlib accepts both but GUI needs string)
241
+ defaults["legend_loc"] = _normalize_legend_loc(loc)
242
+ # Extract fontsize if present
243
+ if "fontsize" in legend:
244
+ defaults["legend_fontsize"] = legend["fontsize"]
245
+ # Extract ncols if present
246
+ if "ncols" in legend:
247
+ defaults["legend_ncols"] = legend["ncols"]
248
+ # Extract title if present
249
+ if "title" in legend:
250
+ defaults["legend_title"] = legend["title"]
251
+
252
+ # Extract legend entries if present
253
+ entries = legend.get("entries", [])
254
+ if entries and not traces:
255
+ # Use legend entries as trace labels
256
+ defaults["traces"] = [
257
+ {"label": e.get("text", f"Trace {i}")} for i, e in enumerate(entries)
258
+ ]
259
+
260
+ return defaults
261
+
262
+
263
+ def _normalize_legend_loc(loc):
264
+ """Convert legend location to string format for GUI compatibility.
265
+
266
+ Matplotlib accepts both numeric codes and string locations for legends.
267
+ This function ensures consistency by converting numeric codes to strings.
268
+
269
+ Parameters
270
+ ----------
271
+ loc : int or str
272
+ Legend location (numeric or string)
273
+
274
+ Returns
275
+ -------
276
+ str
277
+ String representation of legend location
278
+ """
279
+ if isinstance(loc, str):
280
+ return loc
281
+
282
+ # Numeric to string mapping (matplotlib legend location codes)
283
+ loc_map = {
284
+ 0: "best",
285
+ 1: "upper right",
286
+ 2: "upper left",
287
+ 3: "lower left",
288
+ 4: "lower right",
289
+ 5: "right",
290
+ 6: "center left",
291
+ 7: "center right",
292
+ 8: "lower center",
293
+ 9: "upper center",
294
+ 10: "center",
295
+ }
296
+
297
+ return loc_map.get(loc, "best")
298
+
299
+
300
+ # EOF
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-12-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_fig/_editor/_gui/__init__.py
4
+
5
+ """GUI-based FTS bundle editors (Flask only)."""
6
+
7
+ from ._flask_editor import WebEditor
8
+
9
+ __all__ = ["WebEditor"]
10
+
11
+ # EOF
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env python3
2
+ # File: ./src/scitex/vis/editor/flask_editor/__init__.py
3
+ """Flask-based web editor for SciTeX figures."""
4
+
5
+ from ._core import WebEditor
6
+ from ._plotter import plot_from_csv
7
+ from ._renderer import render_preview_with_bboxes
8
+ from ._utils import check_port_available, find_available_port, kill_process_on_port
9
+
10
+ __all__ = [
11
+ "WebEditor",
12
+ "find_available_port",
13
+ "kill_process_on_port",
14
+ "check_port_available",
15
+ "render_preview_with_bboxes",
16
+ "plot_from_csv",
17
+ ]
18
+
19
+
20
+ # EOF