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,279 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-12-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_export.py
4
+
5
+ """Main LaTeX export orchestration for FTS bundles."""
6
+
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING, List, Optional, Union
10
+
11
+ from ._figure_exporter import FigureExportOptions, export_figure_to_latex, generate_figure_preamble
12
+ from ._stats_formatter import FormattedStat, format_stat_note, format_stats_for_latex
13
+ from ._table_exporter import TableExportOptions, export_table_to_latex, generate_table_preamble
14
+ from ._validator import LaTeXError, ValidationResult, validate_latex
15
+
16
+ if TYPE_CHECKING:
17
+ from scitex.fts import FTS
18
+
19
+
20
+ @dataclass
21
+ class LaTeXExportOptions:
22
+ """Options for LaTeX export.
23
+
24
+ Attributes:
25
+ validate: Whether to validate output
26
+ validation_level: Validation level ("syntax", "semantic", "compile")
27
+ include_preamble: Include required packages in output
28
+ figure_options: Options for figure export
29
+ table_options: Options for table export
30
+ output_path: Where to save the .tex file
31
+ """
32
+
33
+ validate: bool = True
34
+ validation_level: str = "syntax"
35
+ include_preamble: bool = False
36
+ figure_options: Optional[FigureExportOptions] = None
37
+ table_options: Optional[TableExportOptions] = None
38
+ output_path: Optional[Path] = None
39
+
40
+
41
+ @dataclass
42
+ class LaTeXResult:
43
+ """Result of LaTeX export.
44
+
45
+ Attributes:
46
+ latex_code: Generated LaTeX code
47
+ preamble: Required preamble packages
48
+ validation: Validation result
49
+ output_path: Path where file was saved (if applicable)
50
+ stats: Formatted statistics (if applicable)
51
+ """
52
+
53
+ latex_code: str
54
+ preamble: str = ""
55
+ validation: Optional[ValidationResult] = None
56
+ output_path: Optional[Path] = None
57
+ stats: List[FormattedStat] = field(default_factory=list)
58
+
59
+ @property
60
+ def is_valid(self) -> bool:
61
+ """Check if export is valid."""
62
+ return self.validation is None or self.validation.is_valid
63
+
64
+ @property
65
+ def errors(self) -> List[LaTeXError]:
66
+ """Get validation errors."""
67
+ if self.validation:
68
+ return self.validation.errors
69
+ return []
70
+
71
+ @property
72
+ def warnings(self) -> List[LaTeXError]:
73
+ """Get validation warnings."""
74
+ if self.validation:
75
+ return self.validation.warnings
76
+ return []
77
+
78
+
79
+ def export_to_latex(
80
+ bundle: "FTS",
81
+ options: Optional[LaTeXExportOptions] = None,
82
+ ) -> LaTeXResult:
83
+ """Export an FTS bundle to LaTeX.
84
+
85
+ Automatically detects bundle type and uses appropriate exporter.
86
+
87
+ Args:
88
+ bundle: FTS bundle
89
+ options: Export options
90
+
91
+ Returns:
92
+ LaTeXResult with code, validation, and metadata
93
+ """
94
+ if options is None:
95
+ options = LaTeXExportOptions()
96
+
97
+ node_type = bundle.node.type
98
+ latex_code = ""
99
+ preamble_parts = []
100
+ stats = []
101
+
102
+ # Export based on type
103
+ if node_type in ("figure", "plot", "image"):
104
+ latex_code = export_figure_to_latex(
105
+ bundle,
106
+ options=options.figure_options,
107
+ )
108
+ preamble_parts.append(generate_figure_preamble())
109
+
110
+ elif node_type == "table":
111
+ table_opts = options.table_options or TableExportOptions()
112
+ latex_code = export_table_to_latex(
113
+ bundle,
114
+ options=table_opts,
115
+ )
116
+ preamble_parts.append(
117
+ generate_table_preamble(
118
+ use_booktabs=table_opts.use_booktabs,
119
+ use_siunitx=table_opts.use_siunitx,
120
+ )
121
+ )
122
+
123
+ elif node_type == "stats":
124
+ # Stats-only bundle - format as paragraph or inline
125
+ if bundle.stats:
126
+ stats = format_stats_for_latex(bundle.stats.to_dict())
127
+ latex_code = _format_stats_only(stats)
128
+
129
+ else:
130
+ raise ValueError(f"Unsupported node type for LaTeX export: {node_type}")
131
+
132
+ # Format statistics if available (for figures/tables with stats)
133
+ if bundle.stats and node_type != "stats":
134
+ stats = format_stats_for_latex(bundle.stats.to_dict())
135
+ if stats:
136
+ note = format_stat_note(stats)
137
+ if note:
138
+ latex_code += "\n\n" + note
139
+
140
+ # Combine preamble
141
+ preamble = "\n\n".join(preamble_parts)
142
+
143
+ # Validate if requested
144
+ validation = None
145
+ if options.validate:
146
+ validation = validate_latex(latex_code, level=options.validation_level)
147
+
148
+ # Create result
149
+ result = LaTeXResult(
150
+ latex_code=latex_code,
151
+ preamble=preamble,
152
+ validation=validation,
153
+ stats=stats,
154
+ )
155
+
156
+ # Save to file if path specified
157
+ output_path = options.output_path
158
+ if output_path is None:
159
+ # Default to exports directory
160
+ exports_dir = bundle.path / "exports"
161
+ exports_dir.mkdir(exist_ok=True)
162
+ output_path = exports_dir / f"{bundle.node.id}.tex"
163
+
164
+ if output_path:
165
+ _save_latex(latex_code, output_path, preamble if options.include_preamble else None)
166
+ result.output_path = output_path
167
+
168
+ return result
169
+
170
+
171
+ def _format_stats_only(stats: List[FormattedStat]) -> str:
172
+ """Format stats-only bundle as LaTeX.
173
+
174
+ Args:
175
+ stats: Formatted statistics
176
+
177
+ Returns:
178
+ LaTeX code
179
+ """
180
+ if not stats:
181
+ return "% No statistics to report"
182
+
183
+ lines = ["% Statistical Results", ""]
184
+ for stat in stats:
185
+ lines.append(f"% {stat.test_type}")
186
+ lines.append(stat.full_report)
187
+ lines.append("")
188
+
189
+ return "\n".join(lines)
190
+
191
+
192
+ def _save_latex(
193
+ latex_code: str,
194
+ output_path: Path,
195
+ preamble: Optional[str] = None,
196
+ ) -> None:
197
+ """Save LaTeX code to file.
198
+
199
+ Args:
200
+ latex_code: LaTeX code
201
+ output_path: Output path
202
+ preamble: Optional preamble to prepend
203
+ """
204
+ output_path = Path(output_path)
205
+ output_path.parent.mkdir(parents=True, exist_ok=True)
206
+
207
+ content = []
208
+ if preamble:
209
+ content.append(preamble)
210
+ content.append("")
211
+
212
+ content.append(latex_code)
213
+
214
+ output_path.write_text("\n".join(content), encoding="utf-8")
215
+
216
+
217
+ def export_multiple(
218
+ bundles: List["FTS"],
219
+ output_path: Path,
220
+ options: Optional[LaTeXExportOptions] = None,
221
+ ) -> LaTeXResult:
222
+ """Export multiple bundles to a single LaTeX file.
223
+
224
+ Args:
225
+ bundles: List of FTS bundles
226
+ output_path: Output path
227
+ options: Export options
228
+
229
+ Returns:
230
+ Combined LaTeXResult
231
+ """
232
+ if options is None:
233
+ options = LaTeXExportOptions()
234
+
235
+ all_code = []
236
+ all_preamble = set()
237
+ all_stats = []
238
+ all_errors = []
239
+ all_warnings = []
240
+
241
+ for bundle in bundles:
242
+ result = export_to_latex(bundle, options)
243
+ all_code.append(result.latex_code)
244
+ if result.preamble:
245
+ all_preamble.add(result.preamble)
246
+ all_stats.extend(result.stats)
247
+ all_errors.extend(result.errors)
248
+ all_warnings.extend(result.warnings)
249
+
250
+ combined_code = "\n\n".join(all_code)
251
+ combined_preamble = "\n\n".join(sorted(all_preamble))
252
+
253
+ # Save combined file
254
+ _save_latex(combined_code, output_path, combined_preamble if options.include_preamble else None)
255
+
256
+ # Create combined validation result
257
+ combined_validation = ValidationResult()
258
+ for error in all_errors:
259
+ combined_validation.add_error(error)
260
+ for warning in all_warnings:
261
+ combined_validation.add_error(warning)
262
+
263
+ return LaTeXResult(
264
+ latex_code=combined_code,
265
+ preamble=combined_preamble,
266
+ validation=combined_validation,
267
+ output_path=output_path,
268
+ stats=all_stats,
269
+ )
270
+
271
+
272
+ __all__ = [
273
+ "LaTeXExportOptions",
274
+ "LaTeXResult",
275
+ "export_to_latex",
276
+ "export_multiple",
277
+ ]
278
+
279
+ # EOF
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-12-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_figure_exporter.py
4
+
5
+ """Export FTS figures to LaTeX using includegraphics."""
6
+
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING, Optional
10
+
11
+ from ._utils import escape_latex_minimal, sanitize_label
12
+
13
+ if TYPE_CHECKING:
14
+ from scitex.fts import FTS
15
+
16
+
17
+ @dataclass
18
+ class FigureExportOptions:
19
+ """Options for figure LaTeX export.
20
+
21
+ Attributes:
22
+ width_mm: Figure width in mm (from node.size_mm if not specified)
23
+ placement: Float placement specifier (htbp, t, b, h, p, H)
24
+ centering: Whether to center the figure
25
+ include_caption: Whether to include caption
26
+ include_label: Whether to include label
27
+ pdf_path: Override path to PDF file
28
+ relative_path: Whether to use relative paths
29
+ """
30
+
31
+ width_mm: Optional[float] = None
32
+ placement: str = "htbp"
33
+ centering: bool = True
34
+ include_caption: bool = True
35
+ include_label: bool = True
36
+ pdf_path: Optional[str] = None
37
+ relative_path: bool = True
38
+
39
+
40
+ def export_figure_to_latex(
41
+ bundle: "FTS",
42
+ options: Optional[FigureExportOptions] = None,
43
+ ) -> str:
44
+ """Export a figure/plot bundle to LaTeX.
45
+
46
+ Generates a figure environment with includegraphics pointing to
47
+ a pre-rendered PDF file.
48
+
49
+ Args:
50
+ bundle: FTS bundle of type 'figure' or 'plot'
51
+ options: Export options
52
+
53
+ Returns:
54
+ LaTeX code string
55
+ """
56
+ if options is None:
57
+ options = FigureExportOptions()
58
+
59
+ node = bundle.node
60
+ node_type = node.type
61
+
62
+ # Validate type
63
+ if node_type not in ("figure", "plot", "image"):
64
+ raise ValueError(f"Cannot export node type '{node_type}' as figure. Expected 'figure', 'plot', or 'image'.")
65
+
66
+ # Get width
67
+ width_mm = options.width_mm
68
+ if width_mm is None and node.size_mm:
69
+ width_mm = node.size_mm.width
70
+ if width_mm is None:
71
+ width_mm = 80 # Default width
72
+
73
+ # Get PDF path
74
+ if options.pdf_path:
75
+ pdf_path = options.pdf_path
76
+ else:
77
+ # Look for existing PDF export
78
+ pdf_path = _find_pdf_export(bundle, options.relative_path)
79
+
80
+ # Get caption
81
+ caption = node.name or ""
82
+
83
+ # Get label
84
+ label = sanitize_label(node.id)
85
+ label_prefix = "fig" if node_type in ("figure", "plot") else "img"
86
+
87
+ # Build LaTeX
88
+ lines = []
89
+ lines.append(f"\\begin{{figure}}[{options.placement}]")
90
+
91
+ if options.centering:
92
+ lines.append(" \\centering")
93
+
94
+ lines.append(f" \\includegraphics[width={width_mm}mm]{{{pdf_path}}}")
95
+
96
+ if options.include_caption and caption:
97
+ escaped_caption = escape_latex_minimal(caption)
98
+ lines.append(f" \\caption{{{escaped_caption}}}")
99
+
100
+ if options.include_label:
101
+ lines.append(f" \\label{{{label_prefix}:{label}}}")
102
+
103
+ lines.append("\\end{figure}")
104
+
105
+ return "\n".join(lines)
106
+
107
+
108
+ def _find_pdf_export(bundle: "FTS", relative: bool = True) -> str:
109
+ """Find the PDF export path for a bundle.
110
+
111
+ Args:
112
+ bundle: FTS bundle
113
+ relative: Return relative path
114
+
115
+ Returns:
116
+ Path string for includegraphics
117
+ """
118
+ # Check exports directory
119
+ exports_dir = bundle.path / "exports"
120
+ if exports_dir.exists():
121
+ # Look for PDF files
122
+ pdf_files = list(exports_dir.glob("*.pdf"))
123
+ if pdf_files:
124
+ pdf_path = pdf_files[0]
125
+ if relative:
126
+ # Return path relative to exports/
127
+ return f"exports/{pdf_path.name}"
128
+ return str(pdf_path)
129
+
130
+ # No PDF found - generate a placeholder path
131
+ bundle_name = bundle.path.stem
132
+ return f"exports/{bundle_name}.pdf"
133
+
134
+
135
+ def generate_figure_preamble() -> str:
136
+ """Generate required LaTeX preamble for figures.
137
+
138
+ Returns:
139
+ Preamble code with required packages
140
+ """
141
+ return """% Required packages for figure export
142
+ \\usepackage{graphicx}
143
+ \\usepackage{float} % For [H] placement specifier
144
+ """
145
+
146
+
147
+ __all__ = [
148
+ "FigureExportOptions",
149
+ "export_figure_to_latex",
150
+ "generate_figure_preamble",
151
+ ]
152
+
153
+ # EOF
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-12-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_stats_formatter.py
4
+
5
+ """Format statistical results for LaTeX output."""
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ from ._utils import format_effect_size, format_p_value, format_statistic, significance_stars
11
+
12
+
13
+ @dataclass
14
+ class FormattedStat:
15
+ """A formatted statistical result.
16
+
17
+ Attributes:
18
+ test_type: Type of test (t-test, anova, etc.)
19
+ statistic: Formatted test statistic (e.g., "$t(48) = 2.31$")
20
+ p_value: Formatted p-value (e.g., ".023")
21
+ effect_size: Formatted effect size if available
22
+ stars: Significance stars
23
+ full_report: Complete inline report
24
+ """
25
+
26
+ test_type: str
27
+ statistic: str
28
+ p_value: str
29
+ effect_size: Optional[str] = None
30
+ stars: str = ""
31
+ full_report: str = ""
32
+
33
+
34
+ def format_stats_for_latex(stats_dict: Dict[str, Any]) -> List[FormattedStat]:
35
+ """Format stats.json contents for LaTeX.
36
+
37
+ Args:
38
+ stats_dict: Dictionary from stats.json
39
+
40
+ Returns:
41
+ List of FormattedStat objects
42
+ """
43
+ results = []
44
+
45
+ analyses = stats_dict.get("analyses", [])
46
+ for analysis in analyses:
47
+ formatted = _format_analysis(analysis)
48
+ if formatted:
49
+ results.append(formatted)
50
+
51
+ return results
52
+
53
+
54
+ def _format_analysis(analysis: Dict[str, Any]) -> Optional[FormattedStat]:
55
+ """Format a single analysis result.
56
+
57
+ Args:
58
+ analysis: Single analysis dictionary
59
+
60
+ Returns:
61
+ FormattedStat or None if cannot format
62
+ """
63
+ method = analysis.get("method", {})
64
+ result = analysis.get("results", {})
65
+
66
+ if not result:
67
+ return None
68
+
69
+ # Extract test info
70
+ test_name = method.get("name", "test")
71
+ variant = method.get("variant", "")
72
+
73
+ # Format statistic
74
+ stat_name = result.get("statistic_name", "t")
75
+ stat_value = result.get("statistic")
76
+ df = result.get("df")
77
+
78
+ if stat_value is None:
79
+ return None
80
+
81
+ statistic_str = format_statistic(stat_name, stat_value, df)
82
+
83
+ # Format p-value
84
+ p = result.get("p_value")
85
+ p_str = format_p_value(p) if p is not None else "---"
86
+ stars = significance_stars(p) if p is not None else ""
87
+
88
+ # Format effect size
89
+ effect = result.get("effect_size")
90
+ effect_str = None
91
+ if effect:
92
+ es_name = effect.get("name", "d")
93
+ es_value = effect.get("value")
94
+ ci_lower = effect.get("ci_lower")
95
+ ci_upper = effect.get("ci_upper")
96
+ if es_value is not None:
97
+ effect_str = format_effect_size(es_name, es_value, ci_lower, ci_upper)
98
+
99
+ # Build full report
100
+ full_parts = [statistic_str, f"$p = {p_str}$"]
101
+ if effect_str:
102
+ full_parts.append(effect_str)
103
+ full_report = ", ".join(full_parts)
104
+
105
+ # Determine test type label
106
+ test_type = _get_test_type_label(test_name, variant)
107
+
108
+ return FormattedStat(
109
+ test_type=test_type,
110
+ statistic=statistic_str,
111
+ p_value=p_str,
112
+ effect_size=effect_str,
113
+ stars=stars,
114
+ full_report=full_report,
115
+ )
116
+
117
+
118
+ def _get_test_type_label(name: str, variant: str = "") -> str:
119
+ """Get human-readable test type label.
120
+
121
+ Args:
122
+ name: Test method name
123
+ variant: Test variant
124
+
125
+ Returns:
126
+ Human-readable label
127
+ """
128
+ labels = {
129
+ "t_test": "t-test",
130
+ "t-test": "t-test",
131
+ "ttest": "t-test",
132
+ "anova": "ANOVA",
133
+ "one_way_anova": "one-way ANOVA",
134
+ "two_way_anova": "two-way ANOVA",
135
+ "repeated_measures_anova": "repeated-measures ANOVA",
136
+ "chi_squared": "chi-squared test",
137
+ "chi2": "chi-squared test",
138
+ "fisher_exact": "Fisher's exact test",
139
+ "mann_whitney": "Mann-Whitney U test",
140
+ "wilcoxon": "Wilcoxon signed-rank test",
141
+ "kruskal_wallis": "Kruskal-Wallis test",
142
+ "friedman": "Friedman test",
143
+ "correlation": "correlation",
144
+ "pearson": "Pearson correlation",
145
+ "spearman": "Spearman correlation",
146
+ "regression": "regression",
147
+ "linear_regression": "linear regression",
148
+ }
149
+
150
+ base = labels.get(name.lower(), name)
151
+
152
+ if variant:
153
+ variant_labels = {
154
+ "independent": "independent-samples",
155
+ "paired": "paired-samples",
156
+ "one_sample": "one-sample",
157
+ "two_sample": "two-sample",
158
+ "welch": "Welch's",
159
+ }
160
+ variant_str = variant_labels.get(variant.lower(), variant)
161
+ return f"{variant_str} {base}"
162
+
163
+ return base
164
+
165
+
166
+ def format_inline_stat(
167
+ statistic_name: str,
168
+ statistic_value: float,
169
+ p_value: float,
170
+ df: Optional[float] = None,
171
+ effect_name: Optional[str] = None,
172
+ effect_value: Optional[float] = None,
173
+ include_stars: bool = True,
174
+ ) -> str:
175
+ """Format a statistical result for inline reporting.
176
+
177
+ Args:
178
+ statistic_name: Name of test statistic (t, F, chi2, etc.)
179
+ statistic_value: Value of test statistic
180
+ p_value: P-value
181
+ df: Degrees of freedom
182
+ effect_name: Effect size name
183
+ effect_value: Effect size value
184
+ include_stars: Include significance stars
185
+
186
+ Returns:
187
+ LaTeX formatted inline report
188
+ """
189
+ parts = []
190
+
191
+ # Statistic
192
+ stat_str = format_statistic(statistic_name, statistic_value, df)
193
+ parts.append(stat_str)
194
+
195
+ # P-value
196
+ p_str = format_p_value(p_value)
197
+ parts.append(f"$p = {p_str}$")
198
+
199
+ # Effect size
200
+ if effect_name and effect_value is not None:
201
+ es_str = format_effect_size(effect_name, effect_value)
202
+ parts.append(es_str)
203
+
204
+ result = ", ".join(parts)
205
+
206
+ # Add stars
207
+ if include_stars:
208
+ stars = significance_stars(p_value)
209
+ if stars:
210
+ result += f" {stars}"
211
+
212
+ return result
213
+
214
+
215
+ def format_stat_note(stats: List[FormattedStat]) -> str:
216
+ """Generate a table note explaining significance levels.
217
+
218
+ Args:
219
+ stats: List of formatted statistics
220
+
221
+ Returns:
222
+ LaTeX note string
223
+ """
224
+ has_stars = any(s.stars for s in stats)
225
+
226
+ if not has_stars:
227
+ return ""
228
+
229
+ # Check which levels are used
230
+ max_stars = max((len(s.stars) for s in stats if s.stars), default=0)
231
+
232
+ note_parts = []
233
+ if max_stars >= 1:
234
+ note_parts.append("$^{*}p < .05$")
235
+ if max_stars >= 2:
236
+ note_parts.append("$^{**}p < .01$")
237
+ if max_stars >= 3:
238
+ note_parts.append("$^{***}p < .001$")
239
+
240
+ if note_parts:
241
+ return "\\textit{Note.} " + ", ".join(note_parts) + "."
242
+
243
+ return ""
244
+
245
+
246
+ def format_stats_paragraph(stats: List[FormattedStat]) -> str:
247
+ """Generate a results paragraph from formatted stats.
248
+
249
+ Args:
250
+ stats: List of formatted statistics
251
+
252
+ Returns:
253
+ LaTeX paragraph summarizing results
254
+ """
255
+ if not stats:
256
+ return ""
257
+
258
+ lines = []
259
+ for stat in stats:
260
+ line = f"The {stat.test_type} revealed {stat.full_report}."
261
+ lines.append(line)
262
+
263
+ return " ".join(lines)
264
+
265
+
266
+ __all__ = [
267
+ "FormattedStat",
268
+ "format_stats_for_latex",
269
+ "format_inline_stat",
270
+ "format_stat_note",
271
+ "format_stats_paragraph",
272
+ ]
273
+
274
+ # EOF