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
@@ -228,7 +228,7 @@ class MplEditor:
228
228
 
229
229
  def _save(self, event):
230
230
  """Save to .manual.json."""
231
- from ._edit import save_manual_overrides
231
+ from .edit import save_manual_overrides
232
232
 
233
233
  try:
234
234
  manual_path = save_manual_overrides(self.json_path, self.current_overrides)
@@ -1017,7 +1017,7 @@ class QtEditorWindow:
1017
1017
 
1018
1018
  def _save_manual(self):
1019
1019
  """Save to .manual.json."""
1020
- from ._edit import save_manual_overrides
1020
+ from .edit import save_manual_overrides
1021
1021
 
1022
1022
  try:
1023
1023
  self._collect_overrides()
@@ -490,7 +490,7 @@ class TkinterEditor:
490
490
 
491
491
  def _save_manual(self):
492
492
  """Save current overrides to .manual.json."""
493
- from ._edit import save_manual_overrides
493
+ from .edit import save_manual_overrides
494
494
 
495
495
  try:
496
496
  manual_path = save_manual_overrides(self.json_path, self.current_overrides)
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-14 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/__init__.py
5
+
6
+ """Edit module for launching visual figure editors.
7
+
8
+ This module provides the main edit() function and supporting utilities for:
9
+ - Backend detection and selection (flask, dearpygui, qt, tkinter, mpl)
10
+ - Path resolution for figure files (.json, .csv, .png)
11
+ - Bundle resolution for .pltz and .figz formats
12
+ - Panel data loading for multi-panel figures
13
+ - Manual override handling (.manual.json)
14
+ """
15
+
16
+ from .editor_launcher import edit
17
+ from .backend_detector import (
18
+ detect_best_backend,
19
+ print_available_backends,
20
+ )
21
+ from .path_resolver import resolve_figure_paths
22
+ from .bundle_resolver import (
23
+ resolve_pltz_bundle,
24
+ resolve_figz_bundle,
25
+ resolve_layered_pltz_bundle,
26
+ )
27
+ from .panel_loader import load_panel_data
28
+ from .manual_handler import compute_file_hash, save_manual_overrides
29
+
30
+ __all__ = [
31
+ # Main entry point
32
+ "edit",
33
+ # Backend detection
34
+ "detect_best_backend",
35
+ "print_available_backends",
36
+ # Path resolution
37
+ "resolve_figure_paths",
38
+ # Bundle resolution
39
+ "resolve_pltz_bundle",
40
+ "resolve_figz_bundle",
41
+ "resolve_layered_pltz_bundle",
42
+ # Panel loading
43
+ "load_panel_data",
44
+ # Manual overrides
45
+ "compute_file_hash",
46
+ "save_manual_overrides",
47
+ ]
48
+
49
+
50
+ # EOF
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-14 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/backend_detector.py
5
+
6
+ """Backend detection and selection for figure editor."""
7
+
8
+ import warnings
9
+
10
+ __all__ = ["print_available_backends", "detect_best_backend"]
11
+
12
+ # Backend packages mapping
13
+ BACKENDS = {
14
+ "flask": ["flask"],
15
+ "dearpygui": ["dearpygui"],
16
+ "qt": ["PyQt6", "PyQt5", "PySide6", "PySide2"],
17
+ "tkinter": ["tkinter"],
18
+ "mpl": ["matplotlib"],
19
+ }
20
+
21
+
22
+ def print_available_backends() -> None:
23
+ """Print available backends status."""
24
+ print("\n" + "=" * 50)
25
+ print("SciTeX Visual Editor - Available Backends")
26
+ print("=" * 50)
27
+
28
+ for backend, packages in BACKENDS.items():
29
+ available = False
30
+ available_pkg = None
31
+ for pkg in packages:
32
+ try:
33
+ __import__(pkg)
34
+ available = True
35
+ available_pkg = pkg
36
+ break
37
+ except ImportError:
38
+ pass
39
+
40
+ status = f"[OK] {available_pkg}" if available else "[NOT INSTALLED]"
41
+ print(f" {backend:12s}: {status}")
42
+
43
+ print("=" * 50)
44
+ print("Install: pip install scitex[gui]")
45
+ print("=" * 50 + "\n")
46
+
47
+
48
+ def detect_best_backend() -> str:
49
+ """
50
+ Detect the best available GUI backend with graceful degradation.
51
+
52
+ Order: flask > dearpygui > qt > tkinter > mpl
53
+ Shows warnings when falling back to less capable backends.
54
+ """
55
+ # Try Flask - best for modern UI
56
+ try:
57
+ import flask
58
+ return "flask"
59
+ except ImportError:
60
+ pass
61
+
62
+ # Try DearPyGui - GPU-accelerated, modern
63
+ try:
64
+ import dearpygui
65
+ return "dearpygui"
66
+ except ImportError:
67
+ warnings.warn(
68
+ "Flask not available. Consider: pip install flask\nTrying DearPyGui..."
69
+ )
70
+
71
+ # Try DearPyGui again
72
+ try:
73
+ import dearpygui
74
+ return "dearpygui"
75
+ except ImportError:
76
+ pass
77
+
78
+ # Try Qt (richest desktop features)
79
+ for qt_pkg in ["PyQt6", "PyQt5", "PySide6", "PySide2"]:
80
+ try:
81
+ __import__(qt_pkg)
82
+ warnings.warn(
83
+ "DearPyGui not available. Consider: pip install dearpygui\n"
84
+ "Using Qt backend instead."
85
+ )
86
+ return "qt"
87
+ except ImportError:
88
+ pass
89
+
90
+ # Try Tkinter (built-in, good features)
91
+ try:
92
+ import tkinter
93
+ warnings.warn(
94
+ "Qt not available. Consider: pip install PyQt6\n"
95
+ "Using Tkinter backend (basic features)."
96
+ )
97
+ return "tkinter"
98
+ except ImportError:
99
+ pass
100
+
101
+ # Fall back to matplotlib interactive (always works)
102
+ warnings.warn(
103
+ "No GUI toolkit found. Using minimal matplotlib editor.\n"
104
+ "For better experience, install: pip install flask (web) or pip install PyQt6 (desktop)"
105
+ )
106
+ return "mpl"
107
+
108
+
109
+ # EOF
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-14 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/bundle_resolver.py
5
+
6
+ """Bundle path resolution for .pltz and .figz formats."""
7
+
8
+ import json as json_module
9
+ import tempfile
10
+ import zipfile
11
+ from pathlib import Path
12
+ from typing import Optional, Tuple, Dict, Any
13
+
14
+ __all__ = ["resolve_pltz_bundle", "resolve_figz_bundle", "resolve_layered_pltz_bundle"]
15
+
16
+
17
+ def resolve_figz_bundle(path: Path, panel_index: int = 0) -> Tuple:
18
+ """
19
+ Resolve paths from a .figz bundle (multi-panel figure).
20
+
21
+ Uses in-memory zip reading for .pltz panels - no disk extraction.
22
+
23
+ Parameters
24
+ ----------
25
+ path : Path
26
+ Path to .figz bundle (.figz or .figz.d)
27
+ panel_index : int, optional
28
+ Index of panel to open (default: 0 for first panel)
29
+
30
+ Returns
31
+ -------
32
+ tuple
33
+ (json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info)
34
+ """
35
+ spath = str(path)
36
+ figz_is_zip = False
37
+
38
+ # Handle ZIP vs directory for figz
39
+ if spath.endswith('.figz') and not spath.endswith('.figz.d'):
40
+ figz_is_zip = True
41
+ if not path.exists():
42
+ raise FileNotFoundError(f"Figz bundle not found: {path}")
43
+ # For figz zip, extract to access nested pltz
44
+ temp_dir = tempfile.mkdtemp(prefix='scitex_edit_figz_')
45
+ with zipfile.ZipFile(path, 'r') as zf:
46
+ zf.extractall(temp_dir)
47
+ bundle_dir = Path(temp_dir)
48
+ for item in bundle_dir.iterdir():
49
+ if item.is_dir() and str(item).endswith('.figz.d'):
50
+ bundle_dir = item
51
+ break
52
+ else:
53
+ bundle_dir = Path(path)
54
+ if not bundle_dir.exists():
55
+ raise FileNotFoundError(f"Figz bundle directory not found: {bundle_dir}")
56
+
57
+ # Find nested pltz bundles
58
+ panel_paths = []
59
+ panel_is_zip = []
60
+
61
+ for item in sorted(bundle_dir.iterdir(), key=lambda x: x.name):
62
+ if item.is_dir() and str(item).endswith('.pltz.d'):
63
+ panel_paths.append(str(item))
64
+ panel_is_zip.append(False)
65
+ elif item.is_file() and str(item).endswith('.pltz'):
66
+ panel_paths.append(str(item))
67
+ panel_is_zip.append(True)
68
+
69
+ if not panel_paths:
70
+ raise FileNotFoundError(f"No .pltz panels found in figz bundle: {bundle_dir}")
71
+
72
+ # Validate panel index
73
+ if panel_index < 0 or panel_index >= len(panel_paths):
74
+ panel_index = 0
75
+
76
+ selected_panel_path = panel_paths[panel_index]
77
+ panel_name = Path(selected_panel_path).name
78
+ print(f"Opening panel: {panel_name}")
79
+ if len(panel_paths) > 1:
80
+ print(f" (Figz contains {len(panel_paths)} panels)")
81
+
82
+ # Build panel info
83
+ panel_names = [Path(p).name for p in panel_paths]
84
+ panel_info = {
85
+ "panels": panel_names,
86
+ "panel_paths": panel_paths,
87
+ "panel_is_zip": panel_is_zip,
88
+ "current_index": panel_index,
89
+ "figz_dir": str(bundle_dir),
90
+ "figz_is_zip": figz_is_zip,
91
+ "bundle_path": str(path) if figz_is_zip else None, # Original figz zip path for export/download
92
+ }
93
+
94
+ # Resolve the selected panel
95
+ result = resolve_pltz_bundle(Path(selected_panel_path))
96
+ return result + (panel_info,)
97
+
98
+
99
+ def resolve_pltz_bundle(path: Path) -> Tuple:
100
+ """
101
+ Resolve paths from a .pltz bundle (directory or ZIP).
102
+
103
+ Supports both:
104
+ - Legacy format (single {basename}.json)
105
+ - Layered format v2.0 (spec.json + style.json + cache/)
106
+
107
+ Parameters
108
+ ----------
109
+ path : Path
110
+ Path to .pltz bundle (.pltz or .pltz.d)
111
+
112
+ Returns
113
+ -------
114
+ tuple
115
+ (json_path, csv_path, png_path, hitmap_path, bundle_spec)
116
+ """
117
+ spath = str(path)
118
+
119
+ # Handle ZIP vs directory
120
+ if spath.endswith('.pltz') and not spath.endswith('.pltz.d'):
121
+ if not path.exists():
122
+ raise FileNotFoundError(f"Bundle not found: {path}")
123
+ temp_dir = tempfile.mkdtemp(prefix='scitex_edit_')
124
+ with zipfile.ZipFile(path, 'r') as zf:
125
+ zf.extractall(temp_dir)
126
+ bundle_dir = Path(temp_dir)
127
+ for item in bundle_dir.iterdir():
128
+ if item.is_dir() and str(item).endswith('.pltz.d'):
129
+ bundle_dir = item
130
+ break
131
+ else:
132
+ bundle_dir = Path(path)
133
+ if not bundle_dir.exists():
134
+ raise FileNotFoundError(f"Bundle directory not found: {bundle_dir}")
135
+
136
+ # Check if this is a layered bundle (v2.0)
137
+ spec_path = bundle_dir / "spec.json"
138
+ if spec_path.exists():
139
+ return resolve_layered_pltz_bundle(bundle_dir)
140
+
141
+ # === Legacy format ===
142
+ json_path = None
143
+ csv_path = None
144
+ png_path = None
145
+ svg_path = None
146
+ hitmap_path = None
147
+ bundle_spec = None
148
+
149
+ for f in bundle_dir.iterdir():
150
+ name = f.name
151
+ if name.endswith('.json') and not name.endswith('.manual.json'):
152
+ json_path = f
153
+ elif name.endswith('.csv'):
154
+ csv_path = f
155
+ elif name.endswith('_hitmap.png'):
156
+ hitmap_path = f
157
+ elif name.endswith('.svg') and '_hitmap' not in name:
158
+ svg_path = f
159
+ elif name.endswith('.png') and '_hitmap' not in name and '_overview' not in name:
160
+ png_path = f
161
+
162
+ # Prefer SVG for display
163
+ if svg_path:
164
+ png_path = svg_path
165
+
166
+ if json_path and json_path.exists():
167
+ with open(json_path, 'r') as f:
168
+ bundle_spec = json_module.load(f)
169
+
170
+ return (
171
+ json_path,
172
+ csv_path if csv_path and csv_path.exists() else None,
173
+ png_path if png_path and png_path.exists() else None,
174
+ hitmap_path if hitmap_path and hitmap_path.exists() else None,
175
+ bundle_spec,
176
+ )
177
+
178
+
179
+ def resolve_layered_pltz_bundle(bundle_dir: Path) -> Tuple:
180
+ """
181
+ Resolve paths from a layered .pltz bundle (v2.0 format).
182
+
183
+ Layered format structure:
184
+ plot.pltz.d/
185
+ spec.json # Semantic
186
+ style.json # Appearance
187
+ {basename}.csv # Data
188
+ exports/ # PNG, SVG, hitmap
189
+ cache/ # geometry_px.json
190
+
191
+ Parameters
192
+ ----------
193
+ bundle_dir : Path
194
+ Path to .pltz.d bundle directory.
195
+
196
+ Returns
197
+ -------
198
+ tuple
199
+ (json_path, csv_path, png_path, hitmap_path, bundle_spec)
200
+ """
201
+ from scitex.plt.io import load_layered_pltz_bundle
202
+
203
+ bundle_data = load_layered_pltz_bundle(bundle_dir)
204
+ spec_path = bundle_dir / "spec.json"
205
+ csv_path = None
206
+ png_path = None
207
+ hitmap_path = None
208
+
209
+ # Find CSV
210
+ for f in bundle_dir.glob("*.csv"):
211
+ csv_path = f
212
+ break
213
+
214
+ # Find exports
215
+ exports_dir = bundle_dir / "exports"
216
+ if exports_dir.exists():
217
+ for f in exports_dir.iterdir():
218
+ name = f.name
219
+ if name.endswith('_hitmap.png'):
220
+ hitmap_path = f
221
+ elif name.endswith('.svg') and '_hitmap' not in name:
222
+ png_path = f
223
+ elif name.endswith('.png') and '_hitmap' not in name and png_path is None:
224
+ png_path = f
225
+
226
+ bundle_spec = bundle_data.get("merged", {})
227
+
228
+ if hitmap_path and "hit_regions" in bundle_spec:
229
+ bundle_spec["hit_regions"]["hit_map"] = str(hitmap_path.name)
230
+
231
+ return (
232
+ spec_path,
233
+ csv_path if csv_path and csv_path.exists() else None,
234
+ png_path if png_path and png_path.exists() else None,
235
+ hitmap_path if hitmap_path and hitmap_path.exists() else None,
236
+ bundle_spec,
237
+ )
238
+
239
+
240
+ # EOF
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-14 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/editor_launcher.py
5
+
6
+ """Main edit function for launching visual editor."""
7
+
8
+ from pathlib import Path
9
+ from typing import Union, Literal
10
+
11
+ from .backend_detector import print_available_backends, detect_best_backend
12
+ from .path_resolver import resolve_figure_paths
13
+ from .bundle_resolver import resolve_pltz_bundle, resolve_figz_bundle
14
+
15
+ __all__ = ["edit"]
16
+
17
+
18
+ def edit(
19
+ path: Union[str, Path],
20
+ backend: Literal["auto", "flask", "dearpygui", "qt", "tkinter", "mpl"] = "auto",
21
+ apply_manual: bool = True,
22
+ port: int = 5050,
23
+ ) -> None:
24
+ """
25
+ Launch interactive editor for figure style/annotation editing.
26
+
27
+ Parameters
28
+ ----------
29
+ path : str or Path
30
+ Path to figure file. Can be:
31
+ - .pltz.d directory bundle (recommended for hitmap selection)
32
+ - .pltz ZIP bundle
33
+ - .figz or .figz.d multi-panel bundle
34
+ - JSON file (figure.json or figure.manual.json)
35
+ - CSV file (figure.csv) - for data-only start
36
+ - PNG file (figure.png)
37
+ backend : str, optional
38
+ GUI backend to use (default: "auto"):
39
+ - "auto": Pick best available (flask -> dearpygui -> qt -> tkinter -> mpl)
40
+ - "flask": Browser-based editor (Flask, modern UI)
41
+ - "dearpygui": GPU-accelerated modern GUI
42
+ - "qt": Rich desktop editor (requires PyQt5/6 or PySide2/6)
43
+ - "tkinter": Built-in Python GUI
44
+ - "mpl": Minimal matplotlib interactive mode
45
+ apply_manual : bool, optional
46
+ If True, load .manual.json overrides if exists (default: True)
47
+ port : int, optional
48
+ Port number for web-based editors. Default: 5050.
49
+
50
+ Returns
51
+ -------
52
+ None
53
+ Editor runs in GUI event loop. Changes saved to .manual.json.
54
+ """
55
+ path = Path(path)
56
+ spath = str(path)
57
+ parent_str = str(path.parent) if path.is_file() else ""
58
+
59
+ # Panel info for multi-panel figures
60
+ panel_info = None
61
+
62
+ # Resolve paths based on input type
63
+ json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = _resolve_paths(
64
+ path, spath, parent_str
65
+ )
66
+
67
+ if not json_path.exists():
68
+ raise FileNotFoundError(f"JSON file not found: {json_path}")
69
+
70
+ # Load data
71
+ import scitex as stx
72
+
73
+ metadata = bundle_spec if bundle_spec else stx.io.load(json_path)
74
+ csv_data = None
75
+ if csv_path and csv_path.exists():
76
+ csv_data = stx.io.load(csv_path)
77
+
78
+ # Load manual overrides if exists
79
+ manual_path = json_path.with_suffix(".manual.json")
80
+ manual_overrides = None
81
+ if apply_manual and manual_path.exists():
82
+ manual_data = stx.io.load(manual_path)
83
+ manual_overrides = manual_data.get("overrides", {})
84
+
85
+ # Resolve backend if "auto"
86
+ if backend == "auto":
87
+ backend = detect_best_backend()
88
+
89
+ # Print status
90
+ print_available_backends()
91
+ print(f"Launching {backend} editor for: {json_path}")
92
+
93
+ # Launch appropriate backend
94
+ _launch_backend(
95
+ backend=backend,
96
+ json_path=json_path,
97
+ metadata=metadata,
98
+ csv_data=csv_data,
99
+ png_path=png_path,
100
+ hitmap_path=hitmap_path,
101
+ manual_overrides=manual_overrides,
102
+ bundle_spec=bundle_spec,
103
+ panel_info=panel_info,
104
+ port=port,
105
+ )
106
+
107
+
108
+ def _resolve_paths(path: Path, spath: str, parent_str: str) -> tuple:
109
+ """Resolve paths based on input type."""
110
+ panel_info = None
111
+ hitmap_path = None
112
+ bundle_spec = None
113
+
114
+ # Check if this is a .figz bundle (multi-panel figure)
115
+ if spath.endswith('.figz.d') or spath.endswith('.figz'):
116
+ json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = resolve_figz_bundle(path)
117
+ # Check if this is a .pltz bundle
118
+ elif spath.endswith('.pltz.d') or spath.endswith('.pltz') or parent_str.endswith('.pltz.d'):
119
+ bundle_path = path.parent if parent_str.endswith('.pltz.d') else path
120
+ json_path, csv_path, png_path, hitmap_path, bundle_spec = resolve_pltz_bundle(bundle_path)
121
+ # Check if file is inside a .figz.d
122
+ elif parent_str.endswith('.figz.d') or (path.parent.parent and str(path.parent.parent).endswith('.figz.d')):
123
+ figz_path = path.parent if parent_str.endswith('.figz.d') else path.parent.parent
124
+ json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = resolve_figz_bundle(figz_path)
125
+ else:
126
+ # Standard file paths
127
+ json_path, csv_path, png_path = resolve_figure_paths(path)
128
+
129
+ return json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info
130
+
131
+
132
+ def _launch_backend(
133
+ backend: str,
134
+ json_path: Path,
135
+ metadata: dict,
136
+ csv_data,
137
+ png_path,
138
+ hitmap_path,
139
+ manual_overrides,
140
+ bundle_spec,
141
+ panel_info,
142
+ port: int,
143
+ ) -> None:
144
+ """Launch the specified editor backend."""
145
+ if backend == "flask":
146
+ _launch_flask(json_path, metadata, csv_data, png_path, hitmap_path, manual_overrides, port, panel_info)
147
+ elif backend == "dearpygui":
148
+ _launch_dearpygui(json_path, metadata, csv_data, png_path, manual_overrides)
149
+ elif backend == "qt":
150
+ _launch_qt(json_path, metadata, csv_data, png_path, manual_overrides, hitmap_path, bundle_spec)
151
+ elif backend == "tkinter":
152
+ _launch_tkinter(json_path, metadata, csv_data, manual_overrides)
153
+ elif backend == "mpl":
154
+ _launch_mpl(json_path, metadata, csv_data, manual_overrides)
155
+ else:
156
+ raise ValueError(
157
+ f"Unknown backend: {backend}. "
158
+ "Use 'auto', 'flask', 'dearpygui', 'qt', 'tkinter', or 'mpl'."
159
+ )
160
+
161
+
162
+ def _launch_flask(json_path, metadata, csv_data, png_path, hitmap_path, manual_overrides, port, panel_info):
163
+ """Launch Flask web editor."""
164
+ try:
165
+ from .._flask_editor import WebEditor
166
+ editor = WebEditor(
167
+ json_path=json_path,
168
+ metadata=metadata,
169
+ csv_data=csv_data,
170
+ png_path=png_path,
171
+ hitmap_path=hitmap_path,
172
+ manual_overrides=manual_overrides,
173
+ port=port,
174
+ panel_info=panel_info,
175
+ )
176
+ editor.run()
177
+ except ImportError as e:
178
+ raise ImportError("Flask backend requires Flask. Install with: pip install flask") from e
179
+
180
+
181
+ def _launch_dearpygui(json_path, metadata, csv_data, png_path, manual_overrides):
182
+ """Launch DearPyGui editor."""
183
+ try:
184
+ from .._dearpygui_editor import DearPyGuiEditor
185
+ editor = DearPyGuiEditor(
186
+ json_path=json_path,
187
+ metadata=metadata,
188
+ csv_data=csv_data,
189
+ png_path=png_path,
190
+ manual_overrides=manual_overrides,
191
+ )
192
+ editor.run()
193
+ except ImportError as e:
194
+ raise ImportError("DearPyGui backend requires dearpygui. Install with: pip install dearpygui") from e
195
+
196
+
197
+ def _launch_qt(json_path, metadata, csv_data, png_path, manual_overrides, hitmap_path, bundle_spec):
198
+ """Launch Qt editor."""
199
+ try:
200
+ from .._qt_editor import QtEditor
201
+ editor = QtEditor(
202
+ json_path=json_path,
203
+ metadata=metadata,
204
+ csv_data=csv_data,
205
+ png_path=png_path,
206
+ manual_overrides=manual_overrides,
207
+ hitmap_path=hitmap_path,
208
+ bundle_spec=bundle_spec,
209
+ )
210
+ editor.run()
211
+ except ImportError as e:
212
+ raise ImportError("Qt backend requires PyQt5/PyQt6 or PySide2/PySide6. Install with: pip install PyQt6") from e
213
+
214
+
215
+ def _launch_tkinter(json_path, metadata, csv_data, manual_overrides):
216
+ """Launch Tkinter editor."""
217
+ from .._tkinter_editor import TkinterEditor
218
+ editor = TkinterEditor(
219
+ json_path=json_path,
220
+ metadata=metadata,
221
+ csv_data=csv_data,
222
+ manual_overrides=manual_overrides,
223
+ )
224
+ editor.run()
225
+
226
+
227
+ def _launch_mpl(json_path, metadata, csv_data, manual_overrides):
228
+ """Launch matplotlib editor."""
229
+ from .._mpl_editor import MplEditor
230
+ editor = MplEditor(
231
+ json_path=json_path,
232
+ metadata=metadata,
233
+ csv_data=csv_data,
234
+ manual_overrides=manual_overrides,
235
+ )
236
+ editor.run()
237
+
238
+
239
+ # EOF