scitex 2.7.0__py3-none-any.whl → 2.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. scitex/__init__.py +6 -2
  2. scitex/__version__.py +1 -1
  3. scitex/audio/README.md +52 -0
  4. scitex/audio/__init__.py +384 -0
  5. scitex/audio/__main__.py +129 -0
  6. scitex/audio/_tts.py +334 -0
  7. scitex/audio/engines/__init__.py +44 -0
  8. scitex/audio/engines/base.py +275 -0
  9. scitex/audio/engines/elevenlabs_engine.py +143 -0
  10. scitex/audio/engines/gtts_engine.py +162 -0
  11. scitex/audio/engines/pyttsx3_engine.py +131 -0
  12. scitex/audio/mcp_server.py +757 -0
  13. scitex/bridge/_helpers.py +1 -1
  14. scitex/bridge/_plt_vis.py +1 -1
  15. scitex/bridge/_stats_vis.py +1 -1
  16. scitex/dev/plt/__init__.py +272 -0
  17. scitex/dev/plt/plot_mpl_axhline.py +28 -0
  18. scitex/dev/plt/plot_mpl_axhspan.py +28 -0
  19. scitex/dev/plt/plot_mpl_axvline.py +28 -0
  20. scitex/dev/plt/plot_mpl_axvspan.py +28 -0
  21. scitex/dev/plt/plot_mpl_bar.py +29 -0
  22. scitex/dev/plt/plot_mpl_barh.py +29 -0
  23. scitex/dev/plt/plot_mpl_boxplot.py +28 -0
  24. scitex/dev/plt/plot_mpl_contour.py +31 -0
  25. scitex/dev/plt/plot_mpl_contourf.py +31 -0
  26. scitex/dev/plt/plot_mpl_errorbar.py +30 -0
  27. scitex/dev/plt/plot_mpl_eventplot.py +28 -0
  28. scitex/dev/plt/plot_mpl_fill.py +30 -0
  29. scitex/dev/plt/plot_mpl_fill_between.py +31 -0
  30. scitex/dev/plt/plot_mpl_hexbin.py +28 -0
  31. scitex/dev/plt/plot_mpl_hist.py +28 -0
  32. scitex/dev/plt/plot_mpl_hist2d.py +28 -0
  33. scitex/dev/plt/plot_mpl_imshow.py +29 -0
  34. scitex/dev/plt/plot_mpl_pcolormesh.py +31 -0
  35. scitex/dev/plt/plot_mpl_pie.py +29 -0
  36. scitex/dev/plt/plot_mpl_plot.py +29 -0
  37. scitex/dev/plt/plot_mpl_quiver.py +31 -0
  38. scitex/dev/plt/plot_mpl_scatter.py +28 -0
  39. scitex/dev/plt/plot_mpl_stackplot.py +31 -0
  40. scitex/dev/plt/plot_mpl_stem.py +29 -0
  41. scitex/dev/plt/plot_mpl_step.py +29 -0
  42. scitex/dev/plt/plot_mpl_violinplot.py +28 -0
  43. scitex/dev/plt/plot_sns_barplot.py +29 -0
  44. scitex/dev/plt/plot_sns_boxplot.py +29 -0
  45. scitex/dev/plt/plot_sns_heatmap.py +28 -0
  46. scitex/dev/plt/plot_sns_histplot.py +29 -0
  47. scitex/dev/plt/plot_sns_kdeplot.py +29 -0
  48. scitex/dev/plt/plot_sns_lineplot.py +31 -0
  49. scitex/dev/plt/plot_sns_scatterplot.py +29 -0
  50. scitex/dev/plt/plot_sns_stripplot.py +29 -0
  51. scitex/dev/plt/plot_sns_swarmplot.py +29 -0
  52. scitex/dev/plt/plot_sns_violinplot.py +29 -0
  53. scitex/dev/plt/plot_stx_bar.py +29 -0
  54. scitex/dev/plt/plot_stx_barh.py +29 -0
  55. scitex/dev/plt/plot_stx_box.py +28 -0
  56. scitex/dev/plt/plot_stx_boxplot.py +28 -0
  57. scitex/dev/plt/plot_stx_conf_mat.py +28 -0
  58. scitex/dev/plt/plot_stx_contour.py +31 -0
  59. scitex/dev/plt/plot_stx_ecdf.py +28 -0
  60. scitex/dev/plt/plot_stx_errorbar.py +30 -0
  61. scitex/dev/plt/plot_stx_fill_between.py +31 -0
  62. scitex/dev/plt/plot_stx_fillv.py +28 -0
  63. scitex/dev/plt/plot_stx_heatmap.py +28 -0
  64. scitex/dev/plt/plot_stx_image.py +28 -0
  65. scitex/dev/plt/plot_stx_imshow.py +28 -0
  66. scitex/dev/plt/plot_stx_joyplot.py +28 -0
  67. scitex/dev/plt/plot_stx_kde.py +28 -0
  68. scitex/dev/plt/plot_stx_line.py +28 -0
  69. scitex/dev/plt/plot_stx_mean_ci.py +28 -0
  70. scitex/dev/plt/plot_stx_mean_std.py +28 -0
  71. scitex/dev/plt/plot_stx_median_iqr.py +28 -0
  72. scitex/dev/plt/plot_stx_raster.py +28 -0
  73. scitex/dev/plt/plot_stx_rectangle.py +28 -0
  74. scitex/dev/plt/plot_stx_scatter.py +29 -0
  75. scitex/dev/plt/plot_stx_shaded_line.py +29 -0
  76. scitex/dev/plt/plot_stx_violin.py +28 -0
  77. scitex/dev/plt/plot_stx_violinplot.py +28 -0
  78. scitex/diagram/README.md +197 -0
  79. scitex/diagram/__init__.py +48 -0
  80. scitex/diagram/_compile.py +312 -0
  81. scitex/diagram/_diagram.py +355 -0
  82. scitex/diagram/_presets.py +173 -0
  83. scitex/diagram/_schema.py +182 -0
  84. scitex/diagram/_split.py +278 -0
  85. scitex/fig/__init__.py +352 -0
  86. scitex/{vis → fig}/backend/_parser.py +1 -1
  87. scitex/{vis → fig}/canvas.py +1 -1
  88. scitex/{vis → fig}/editor/__init__.py +5 -2
  89. scitex/{vis → fig}/editor/_dearpygui_editor.py +1 -1
  90. scitex/{vis → fig}/editor/_defaults.py +70 -5
  91. scitex/{vis → fig}/editor/_mpl_editor.py +1 -1
  92. scitex/{vis → fig}/editor/_qt_editor.py +182 -2
  93. scitex/{vis → fig}/editor/_tkinter_editor.py +1 -1
  94. scitex/fig/editor/edit/__init__.py +50 -0
  95. scitex/fig/editor/edit/backend_detector.py +109 -0
  96. scitex/fig/editor/edit/bundle_resolver.py +240 -0
  97. scitex/fig/editor/edit/editor_launcher.py +239 -0
  98. scitex/fig/editor/edit/manual_handler.py +53 -0
  99. scitex/fig/editor/edit/panel_loader.py +232 -0
  100. scitex/fig/editor/edit/path_resolver.py +67 -0
  101. scitex/fig/editor/flask_editor/_bbox.py +1299 -0
  102. scitex/fig/editor/flask_editor/_core.py +1429 -0
  103. scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
  104. scitex/fig/editor/flask_editor/_renderer.py +813 -0
  105. scitex/fig/editor/flask_editor/static/css/base/reset.css +41 -0
  106. scitex/fig/editor/flask_editor/static/css/base/typography.css +16 -0
  107. scitex/fig/editor/flask_editor/static/css/base/variables.css +85 -0
  108. scitex/fig/editor/flask_editor/static/css/components/buttons.css +217 -0
  109. scitex/fig/editor/flask_editor/static/css/components/context-menu.css +93 -0
  110. scitex/fig/editor/flask_editor/static/css/components/dropdown.css +57 -0
  111. scitex/fig/editor/flask_editor/static/css/components/forms.css +112 -0
  112. scitex/fig/editor/flask_editor/static/css/components/modal.css +59 -0
  113. scitex/fig/editor/flask_editor/static/css/components/sections.css +212 -0
  114. scitex/fig/editor/flask_editor/static/css/features/canvas.css +176 -0
  115. scitex/fig/editor/flask_editor/static/css/features/element-inspector.css +190 -0
  116. scitex/fig/editor/flask_editor/static/css/features/loading.css +59 -0
  117. scitex/fig/editor/flask_editor/static/css/features/overlay.css +45 -0
  118. scitex/fig/editor/flask_editor/static/css/features/panel-grid.css +95 -0
  119. scitex/fig/editor/flask_editor/static/css/features/selection.css +101 -0
  120. scitex/fig/editor/flask_editor/static/css/features/statistics.css +138 -0
  121. scitex/fig/editor/flask_editor/static/css/index.css +31 -0
  122. scitex/fig/editor/flask_editor/static/css/layout/container.css +7 -0
  123. scitex/fig/editor/flask_editor/static/css/layout/controls.css +56 -0
  124. scitex/fig/editor/flask_editor/static/css/layout/preview.css +78 -0
  125. scitex/fig/editor/flask_editor/static/js/alignment/axis.js +314 -0
  126. scitex/fig/editor/flask_editor/static/js/alignment/basic.js +107 -0
  127. scitex/fig/editor/flask_editor/static/js/alignment/distribute.js +54 -0
  128. scitex/fig/editor/flask_editor/static/js/canvas/canvas.js +172 -0
  129. scitex/fig/editor/flask_editor/static/js/canvas/dragging.js +258 -0
  130. scitex/fig/editor/flask_editor/static/js/canvas/resize.js +48 -0
  131. scitex/fig/editor/flask_editor/static/js/canvas/selection.js +71 -0
  132. scitex/fig/editor/flask_editor/static/js/core/api.js +288 -0
  133. scitex/fig/editor/flask_editor/static/js/core/state.js +143 -0
  134. scitex/fig/editor/flask_editor/static/js/core/utils.js +245 -0
  135. scitex/fig/editor/flask_editor/static/js/dev/element-inspector.js +992 -0
  136. scitex/fig/editor/flask_editor/static/js/editor/bbox.js +339 -0
  137. scitex/fig/editor/flask_editor/static/js/editor/element-drag.js +286 -0
  138. scitex/fig/editor/flask_editor/static/js/editor/overlay.js +371 -0
  139. scitex/fig/editor/flask_editor/static/js/editor/preview.js +293 -0
  140. scitex/fig/editor/flask_editor/static/js/main.js +426 -0
  141. scitex/fig/editor/flask_editor/static/js/shortcuts/context-menu.js +152 -0
  142. scitex/fig/editor/flask_editor/static/js/shortcuts/keyboard.js +265 -0
  143. scitex/fig/editor/flask_editor/static/js/ui/controls.js +184 -0
  144. scitex/fig/editor/flask_editor/static/js/ui/download.js +57 -0
  145. scitex/fig/editor/flask_editor/static/js/ui/help.js +100 -0
  146. scitex/fig/editor/flask_editor/static/js/ui/theme.js +34 -0
  147. scitex/fig/editor/flask_editor/templates/__init__.py +123 -0
  148. scitex/fig/editor/flask_editor/templates/_html.py +852 -0
  149. scitex/fig/editor/flask_editor/templates/_scripts.py +4933 -0
  150. scitex/fig/editor/flask_editor/templates/_styles.py +1658 -0
  151. scitex/{vis → fig}/io/__init__.py +13 -1
  152. scitex/fig/io/_bundle.py +1058 -0
  153. scitex/{vis → fig}/io/_canvas.py +1 -1
  154. scitex/{vis → fig}/io/_data.py +1 -1
  155. scitex/{vis → fig}/io/_export.py +1 -1
  156. scitex/{vis → fig}/io/_load.py +1 -1
  157. scitex/{vis → fig}/io/_panel.py +1 -1
  158. scitex/{vis → fig}/io/_save.py +1 -1
  159. scitex/{vis → fig}/model/__init__.py +1 -1
  160. scitex/{vis → fig}/model/_annotations.py +1 -1
  161. scitex/{vis → fig}/model/_axes.py +1 -1
  162. scitex/{vis → fig}/model/_figure.py +1 -1
  163. scitex/{vis → fig}/model/_guides.py +1 -1
  164. scitex/{vis → fig}/model/_plot.py +1 -1
  165. scitex/{vis → fig}/model/_styles.py +1 -1
  166. scitex/{vis → fig}/utils/__init__.py +1 -1
  167. scitex/io/__init__.py +22 -26
  168. scitex/io/_bundle.py +493 -0
  169. scitex/io/_flush.py +5 -2
  170. scitex/io/_load.py +98 -0
  171. scitex/io/_load_modules/_H5Explorer.py +5 -2
  172. scitex/io/_load_modules/_canvas.py +2 -2
  173. scitex/io/_load_modules/_image.py +3 -4
  174. scitex/io/_load_modules/_txt.py +4 -2
  175. scitex/io/_metadata.py +34 -324
  176. scitex/io/_metadata_modules/__init__.py +46 -0
  177. scitex/io/_metadata_modules/_embed.py +70 -0
  178. scitex/io/_metadata_modules/_read.py +64 -0
  179. scitex/io/_metadata_modules/_utils.py +79 -0
  180. scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
  181. scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
  182. scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
  183. scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
  184. scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
  185. scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
  186. scitex/io/_metadata_modules/read_metadata_png.py +39 -0
  187. scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
  188. scitex/io/_qr_utils.py +5 -3
  189. scitex/io/_save.py +548 -30
  190. scitex/io/_save_modules/_canvas.py +3 -3
  191. scitex/io/_save_modules/_image.py +5 -9
  192. scitex/io/_save_modules/_tex.py +7 -4
  193. scitex/io/_zip_bundle.py +439 -0
  194. scitex/io/utils/h5_to_zarr.py +11 -9
  195. scitex/msword/__init__.py +255 -0
  196. scitex/msword/profiles.py +357 -0
  197. scitex/msword/reader.py +753 -0
  198. scitex/msword/utils.py +289 -0
  199. scitex/msword/writer.py +362 -0
  200. scitex/plt/__init__.py +5 -2
  201. scitex/plt/_subplots/_AxesWrapper.py +6 -6
  202. scitex/plt/_subplots/_AxisWrapper.py +15 -9
  203. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
  204. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
  205. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
  206. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
  207. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
  208. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
  209. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
  210. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
  211. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
  212. scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
  213. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
  214. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
  215. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
  216. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
  217. scitex/plt/_subplots/_FigWrapper.py +6 -6
  218. scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
  219. scitex/plt/_subplots/_export_as_csv.py +35 -5
  220. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
  221. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
  222. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
  223. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
  224. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
  225. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
  226. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
  227. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
  228. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
  229. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
  230. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
  231. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
  232. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
  233. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
  234. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
  235. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
  236. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
  237. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
  238. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
  239. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
  240. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
  241. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
  242. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
  243. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
  244. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
  245. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
  246. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
  247. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
  248. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
  249. scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
  250. scitex/plt/gallery/_generate.py +421 -14
  251. scitex/plt/io/__init__.py +53 -0
  252. scitex/plt/io/_bundle.py +490 -0
  253. scitex/plt/io/_layered_bundle.py +1343 -0
  254. scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
  255. scitex/plt/styles/__init__.py +14 -0
  256. scitex/plt/styles/presets.py +78 -0
  257. scitex/plt/utils/__init__.py +13 -1
  258. scitex/plt/utils/_collect_figure_metadata.py +10 -14
  259. scitex/plt/utils/_configure_mpl.py +6 -18
  260. scitex/plt/utils/_crop.py +32 -14
  261. scitex/plt/utils/_csv_column_naming.py +54 -0
  262. scitex/plt/utils/_figure_mm.py +116 -1
  263. scitex/plt/utils/_hitmap.py +1643 -0
  264. scitex/plt/utils/metadata/__init__.py +25 -0
  265. scitex/plt/utils/metadata/_core.py +9 -10
  266. scitex/plt/utils/metadata/_dimensions.py +6 -3
  267. scitex/plt/utils/metadata/_editable_export.py +405 -0
  268. scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
  269. scitex/schema/__init__.py +109 -16
  270. scitex/schema/_canvas.py +1 -1
  271. scitex/schema/_plot.py +1015 -0
  272. scitex/schema/_stats.py +2 -2
  273. scitex/stats/__init__.py +117 -0
  274. scitex/stats/io/__init__.py +29 -0
  275. scitex/stats/io/_bundle.py +156 -0
  276. scitex/tex/__init__.py +4 -0
  277. scitex/tex/_export.py +890 -0
  278. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/METADATA +11 -1
  279. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/RECORD +294 -170
  280. scitex/io/memo.md +0 -2827
  281. scitex/plt/REQUESTS.md +0 -191
  282. scitex/plt/_subplots/TODO.md +0 -53
  283. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
  284. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
  285. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
  286. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
  287. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
  288. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
  289. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
  290. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
  291. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
  292. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
  293. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
  294. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
  295. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
  296. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
  297. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
  298. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
  299. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
  300. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
  301. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
  302. scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
  303. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
  304. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
  305. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
  306. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
  307. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
  308. scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
  309. scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
  310. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
  311. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
  312. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
  313. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
  314. scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
  315. scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
  316. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
  317. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
  318. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
  319. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
  320. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
  321. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
  322. scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
  323. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
  324. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
  325. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
  326. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
  327. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
  328. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
  329. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
  330. scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
  331. scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
  332. scitex/vis/__init__.py +0 -177
  333. scitex/vis/editor/_edit.py +0 -390
  334. scitex/vis/editor/flask_editor/_bbox.py +0 -529
  335. scitex/vis/editor/flask_editor/_core.py +0 -168
  336. scitex/vis/editor/flask_editor/_renderer.py +0 -393
  337. scitex/vis/editor/flask_editor/templates/__init__.py +0 -33
  338. scitex/vis/editor/flask_editor/templates/_html.py +0 -513
  339. scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
  340. scitex/vis/editor/flask_editor/templates/_styles.py +0 -739
  341. /scitex/{vis → fig}/README.md +0 -0
  342. /scitex/{vis → fig}/backend/__init__.py +0 -0
  343. /scitex/{vis → fig}/backend/_export.py +0 -0
  344. /scitex/{vis → fig}/backend/_render.py +0 -0
  345. /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
  346. /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
  347. /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
  348. /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
  349. /scitex/{vis → fig}/io/_directory.py +0 -0
  350. /scitex/{vis → fig}/model/_plot_types.py +0 -0
  351. /scitex/{vis → fig}/utils/_defaults.py +0 -0
  352. /scitex/{vis → fig}/utils/_validate.py +0 -0
  353. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/WHEEL +0 -0
  354. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/entry_points.txt +0 -0
  355. {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/licenses/LICENSE +0 -0
scitex/msword/utils.py ADDED
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: 2025-12-11 16:45:00
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/msword/utils.py
5
+
6
+ """
7
+ Utility functions for processing MS Word documents.
8
+
9
+ These functions can be used as post_import_hooks or called directly
10
+ to process document structures.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, Dict, List
16
+
17
+
18
+ def link_captions_to_images(doc: Dict[str, Any]) -> Dict[str, Any]:
19
+ """
20
+ Link figure captions to images by matching order.
21
+
22
+ This function pairs figure captions with images based on their
23
+ sequential order in the document. Each figure caption is assigned
24
+ an `image_hash` that corresponds to the image at the same position.
25
+
26
+ Parameters
27
+ ----------
28
+ doc : dict
29
+ SciTeX writer document with 'blocks' and 'images' keys.
30
+
31
+ Returns
32
+ -------
33
+ dict
34
+ The same document with image_hash added to figure captions.
35
+
36
+ Examples
37
+ --------
38
+ >>> from scitex.msword import load_docx
39
+ >>> from scitex.msword.utils import link_captions_to_images
40
+ >>> doc = load_docx("manuscript.docx")
41
+ >>> doc = link_captions_to_images(doc)
42
+ >>> # Now captions have image_hash for LaTeX export
43
+ """
44
+ blocks = doc.get("blocks", [])
45
+ images = doc.get("images", [])
46
+
47
+ # Find all figure captions
48
+ figure_captions = [
49
+ b for b in blocks
50
+ if b.get("type") == "caption" and b.get("caption_type") == "figure"
51
+ ]
52
+
53
+ # Link by order (figure 1 -> image 0, figure 2 -> image 1, etc.)
54
+ for caption in figure_captions:
55
+ fig_num = caption.get("number")
56
+ if fig_num is not None and isinstance(fig_num, int):
57
+ # Figure numbers are typically 1-indexed
58
+ img_idx = fig_num - 1
59
+ if 0 <= img_idx < len(images):
60
+ caption["image_hash"] = images[img_idx].get("hash")
61
+
62
+ return doc
63
+
64
+
65
+ def link_captions_to_images_by_proximity(doc: Dict[str, Any]) -> Dict[str, Any]:
66
+ """
67
+ Link figure captions to images by document proximity.
68
+
69
+ This function uses the image blocks (type="image") that are inserted
70
+ at their actual positions in the document body. It finds the nearest
71
+ unlinked image block to each figure caption.
72
+
73
+ Parameters
74
+ ----------
75
+ doc : dict
76
+ SciTeX writer document.
77
+
78
+ Returns
79
+ -------
80
+ dict
81
+ Document with image_hash added to captions.
82
+ """
83
+ blocks = doc.get("blocks", [])
84
+
85
+ # Collect image blocks and figure captions with their indices
86
+ image_blocks = []
87
+ figure_captions = []
88
+
89
+ for i, block in enumerate(blocks):
90
+ if block.get("type") == "image":
91
+ image_blocks.append((i, block))
92
+ elif block.get("type") == "caption" and block.get("caption_type") == "figure":
93
+ figure_captions.append((i, block))
94
+
95
+ if not image_blocks:
96
+ # Fallback to old behavior using doc["images"] list
97
+ images = doc.get("images", [])
98
+ if not images:
99
+ return doc
100
+ image_hashes = [img.get("hash") for img in images]
101
+ for idx, (_, caption) in enumerate(figure_captions):
102
+ if idx < len(image_hashes):
103
+ caption["image_hash"] = image_hashes[idx]
104
+ return doc
105
+
106
+ used_images = set()
107
+
108
+ # For each caption, find the nearest preceding image block
109
+ for cap_idx, caption in figure_captions:
110
+ best_img_idx = None
111
+ best_img_hash = None
112
+ best_distance = float("inf")
113
+
114
+ for img_idx, img_block in image_blocks:
115
+ img_hash = img_block.get("image_hash")
116
+ if img_hash in used_images:
117
+ continue
118
+
119
+ # Prefer images that come before the caption (typical layout)
120
+ distance = cap_idx - img_idx
121
+ if distance >= 0 and distance < best_distance:
122
+ best_distance = distance
123
+ best_img_idx = img_idx
124
+ best_img_hash = img_hash
125
+
126
+ # If no preceding image, try following images
127
+ if best_img_hash is None:
128
+ for img_idx, img_block in image_blocks:
129
+ img_hash = img_block.get("image_hash")
130
+ if img_hash in used_images:
131
+ continue
132
+
133
+ distance = abs(cap_idx - img_idx)
134
+ if distance < best_distance:
135
+ best_distance = distance
136
+ best_img_idx = img_idx
137
+ best_img_hash = img_hash
138
+
139
+ if best_img_hash:
140
+ caption["image_hash"] = best_img_hash
141
+ used_images.add(best_img_hash)
142
+
143
+ return doc
144
+
145
+
146
+ def normalize_section_headings(doc: Dict[str, Any]) -> Dict[str, Any]:
147
+ """
148
+ Normalize section headings for consistency.
149
+
150
+ Converts common section titles to standard academic format:
151
+ - "intro" -> "Introduction"
152
+ - "method" -> "Methods"
153
+ - etc.
154
+
155
+ Parameters
156
+ ----------
157
+ doc : dict
158
+ SciTeX writer document.
159
+
160
+ Returns
161
+ -------
162
+ dict
163
+ Document with normalized headings.
164
+ """
165
+ blocks = doc.get("blocks", [])
166
+
167
+ # Common normalizations
168
+ normalizations = {
169
+ "intro": "Introduction",
170
+ "introduction": "Introduction",
171
+ "method": "Methods",
172
+ "methods": "Methods",
173
+ "materials and methods": "Materials and Methods",
174
+ "result": "Results",
175
+ "results": "Results",
176
+ "discussion": "Discussion",
177
+ "conclusion": "Conclusions",
178
+ "conclusions": "Conclusions",
179
+ "acknowledgement": "Acknowledgements",
180
+ "acknowledgements": "Acknowledgements",
181
+ "reference": "References",
182
+ "references": "References",
183
+ "bibliography": "References",
184
+ }
185
+
186
+ for block in blocks:
187
+ if block.get("type") == "heading" and block.get("level") == 1:
188
+ text = block.get("text", "").strip().lower()
189
+ if text in normalizations:
190
+ block["text"] = normalizations[text]
191
+
192
+ return doc
193
+
194
+
195
+ def validate_document(doc: Dict[str, Any]) -> Dict[str, Any]:
196
+ """
197
+ Validate document structure and add warnings.
198
+
199
+ Checks for common issues:
200
+ - Missing required sections
201
+ - Unmatched caption numbers
202
+ - Empty references section
203
+ - Duplicate figure numbers
204
+
205
+ Parameters
206
+ ----------
207
+ doc : dict
208
+ SciTeX writer document.
209
+
210
+ Returns
211
+ -------
212
+ dict
213
+ Document with warnings added.
214
+ """
215
+ blocks = doc.get("blocks", [])
216
+ warnings = doc.get("warnings", [])
217
+
218
+ # Check for required sections
219
+ headings = [b.get("text", "").lower() for b in blocks if b.get("type") == "heading"]
220
+
221
+ required_sections = ["introduction", "methods", "results", "discussion", "references"]
222
+ for section in required_sections:
223
+ if not any(section in h for h in headings):
224
+ warnings.append(f"Missing section: {section.title()}")
225
+
226
+ # Check for duplicate figure numbers
227
+ figure_numbers = [
228
+ b.get("number") for b in blocks
229
+ if b.get("type") == "caption" and b.get("caption_type") == "figure"
230
+ ]
231
+ seen = set()
232
+ for num in figure_numbers:
233
+ if num in seen:
234
+ warnings.append(f"Duplicate figure number: {num}")
235
+ seen.add(num)
236
+
237
+ # Check for missing references
238
+ references = doc.get("references", [])
239
+ if not references:
240
+ ref_blocks = [b for b in blocks if b.get("type") == "reference-paragraph"]
241
+ if not ref_blocks:
242
+ warnings.append("No references found in document")
243
+
244
+ doc["warnings"] = warnings
245
+ return doc
246
+
247
+
248
+ def create_post_import_hook(*functions):
249
+ """
250
+ Create a composite post_import_hook from multiple functions.
251
+
252
+ Parameters
253
+ ----------
254
+ *functions : callable
255
+ Functions to apply in sequence.
256
+
257
+ Returns
258
+ -------
259
+ callable
260
+ A single hook that applies all functions.
261
+
262
+ Examples
263
+ --------
264
+ >>> from scitex.msword.utils import (
265
+ ... link_captions_to_images,
266
+ ... normalize_section_headings,
267
+ ... create_post_import_hook,
268
+ ... )
269
+ >>> hook = create_post_import_hook(
270
+ ... link_captions_to_images,
271
+ ... normalize_section_headings,
272
+ ... )
273
+ >>> # Use with custom profile
274
+ >>> profile.post_import_hooks = [hook]
275
+ """
276
+ def composite_hook(doc: Dict[str, Any]) -> Dict[str, Any]:
277
+ for func in functions:
278
+ doc = func(doc)
279
+ return doc
280
+ return composite_hook
281
+
282
+
283
+ __all__ = [
284
+ "link_captions_to_images",
285
+ "link_captions_to_images_by_proximity",
286
+ "normalize_section_headings",
287
+ "validate_document",
288
+ "create_post_import_hook",
289
+ ]
@@ -0,0 +1,362 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: 2025-12-11 15:15:00
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/msword/writer.py
5
+
6
+ """
7
+ SciTeX writer document -> DOCX converter.
8
+
9
+ This module exports SciTeX documents to MS Word .docx files,
10
+ applying journal-specific styles and formatting.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from .profiles import BaseWordProfile
19
+
20
+ # Lazy import for python-docx
21
+ try:
22
+ import docx
23
+ from docx.document import Document as DocxDocument
24
+ from docx.shared import Inches, Pt, Cm
25
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
26
+ from docx.enum.style import WD_STYLE_TYPE
27
+
28
+ DOCX_AVAILABLE = True
29
+ _DOCX_IMPORT_ERROR = None
30
+ except ImportError as exc:
31
+ DOCX_AVAILABLE = False
32
+ _DOCX_IMPORT_ERROR = exc
33
+
34
+
35
+ class WordWriter:
36
+ """
37
+ Export a SciTeX writer document to a DOCX file.
38
+
39
+ This writer handles:
40
+ - Section headings with proper styles
41
+ - Paragraphs with formatting
42
+ - Figure and table captions
43
+ - References section
44
+ - Image embedding
45
+ - Journal-specific template application
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ profile: BaseWordProfile,
51
+ template_path: Optional[Path] = None,
52
+ ):
53
+ """
54
+ Parameters
55
+ ----------
56
+ profile : BaseWordProfile
57
+ Mapping from writer structures to Word styles.
58
+ template_path : Path | None
59
+ Optional path to a Word template (.dotx/.docx) to use as base.
60
+ """
61
+ if not DOCX_AVAILABLE:
62
+ raise ImportError(
63
+ "python-docx is required for scitex.msword.WordWriter. "
64
+ "Install it via `pip install python-docx`."
65
+ ) from _DOCX_IMPORT_ERROR
66
+ self.profile = profile
67
+ self.template_path = template_path
68
+
69
+ def write(
70
+ self,
71
+ writer_doc: Dict[str, Any] | Any,
72
+ path: Path,
73
+ ) -> None:
74
+ """
75
+ Write a SciTeX writer document to a DOCX file.
76
+
77
+ Parameters
78
+ ----------
79
+ writer_doc : dict | Any
80
+ Writer document or intermediate structure.
81
+ path : Path
82
+ Output path for the DOCX file.
83
+ """
84
+ # Create document (from template if specified)
85
+ if self.template_path and Path(self.template_path).exists():
86
+ doc = docx.Document(str(self.template_path))
87
+ # Clear existing content but keep styles
88
+ self._clear_document_content(doc)
89
+ else:
90
+ doc = docx.Document()
91
+
92
+ # Run pre-export hooks
93
+ for hook in self.profile.pre_export_hooks:
94
+ writer_doc = hook(writer_doc)
95
+
96
+ # Extract blocks from writer_doc
97
+ if isinstance(writer_doc, dict) and "blocks" in writer_doc:
98
+ blocks = writer_doc["blocks"]
99
+ images = writer_doc.get("images", [])
100
+ else:
101
+ blocks = list(writer_doc)
102
+ images = []
103
+
104
+ # Build image lookup by hash
105
+ image_lookup = {img.get("hash"): img for img in images if "hash" in img}
106
+
107
+ # Process each block
108
+ for block in blocks:
109
+ self._add_block(doc, block, image_lookup)
110
+
111
+ # Apply double-anonymous processing if needed
112
+ if self.profile.double_anonymous:
113
+ self._apply_double_anonymous(doc, writer_doc)
114
+
115
+ # Save document
116
+ doc.save(str(path))
117
+
118
+ def _clear_document_content(self, doc: DocxDocument) -> None:
119
+ """Clear document content while preserving styles."""
120
+ for element in doc.element.body[:]:
121
+ doc.element.body.remove(element)
122
+
123
+ def _add_block(
124
+ self,
125
+ doc: DocxDocument,
126
+ block: Dict[str, Any],
127
+ image_lookup: Dict[str, Any],
128
+ ) -> None:
129
+ """Add a single block to the document."""
130
+ btype = block.get("type", "paragraph")
131
+ text = block.get("text", "")
132
+
133
+ if not text and btype not in ("table", "image"):
134
+ return
135
+
136
+ if btype == "heading":
137
+ level = block.get("level", 1)
138
+ self._add_heading(doc, text, level)
139
+
140
+ elif btype == "caption":
141
+ self._add_caption(doc, block)
142
+
143
+ elif btype == "reference-paragraph":
144
+ self._add_reference(doc, block)
145
+
146
+ elif btype == "table":
147
+ self._add_table(doc, block)
148
+
149
+ elif btype == "image":
150
+ self._add_image(doc, block, image_lookup)
151
+
152
+ elif btype == "list-item":
153
+ self._add_list_item(doc, block)
154
+
155
+ else:
156
+ # Default: paragraph
157
+ self._add_paragraph(doc, text, block.get("runs"))
158
+
159
+ def _add_heading(
160
+ self,
161
+ doc: DocxDocument,
162
+ text: str,
163
+ level: int,
164
+ ) -> None:
165
+ """Add a heading paragraph at the given logical level."""
166
+ style_name = self.profile.heading_styles.get(level)
167
+
168
+ if style_name and self._style_exists(doc, style_name):
169
+ p = doc.add_paragraph(text)
170
+ p.style = style_name
171
+ else:
172
+ # Fallback to built-in heading
173
+ doc.add_heading(text, level=min(level, 9))
174
+
175
+ def _add_paragraph(
176
+ self,
177
+ doc: DocxDocument,
178
+ text: str,
179
+ runs: Optional[List[Dict[str, Any]]] = None,
180
+ ) -> None:
181
+ """Add a paragraph with optional formatted runs."""
182
+ p = doc.add_paragraph()
183
+
184
+ if runs:
185
+ # Add formatted runs
186
+ for run_data in runs:
187
+ run = p.add_run(run_data.get("text", ""))
188
+ if run_data.get("bold"):
189
+ run.bold = True
190
+ if run_data.get("italic"):
191
+ run.italic = True
192
+ if run_data.get("underline"):
193
+ run.underline = True
194
+ if run_data.get("font_size"):
195
+ run.font.size = Pt(run_data["font_size"])
196
+ if run_data.get("font_name"):
197
+ run.font.name = run_data["font_name"]
198
+ else:
199
+ p.add_run(text)
200
+
201
+ # Apply normal style
202
+ if self._style_exists(doc, self.profile.normal_style):
203
+ try:
204
+ p.style = self.profile.normal_style
205
+ except Exception:
206
+ pass
207
+
208
+ def _add_caption(
209
+ self,
210
+ doc: DocxDocument,
211
+ block: Dict[str, Any],
212
+ ) -> None:
213
+ """Add a figure or table caption."""
214
+ caption_type = block.get("caption_type", "")
215
+ number = block.get("number", "")
216
+ caption_text = block.get("caption_text", block.get("text", ""))
217
+
218
+ # Build caption text
219
+ if caption_type == "figure" and number:
220
+ full_text = f"Figure {number}. {caption_text}"
221
+ elif caption_type == "table" and number:
222
+ full_text = f"Table {number}. {caption_text}"
223
+ else:
224
+ full_text = block.get("text", caption_text)
225
+
226
+ p = doc.add_paragraph(full_text)
227
+
228
+ if self._style_exists(doc, self.profile.caption_style):
229
+ try:
230
+ p.style = self.profile.caption_style
231
+ except Exception:
232
+ pass
233
+
234
+ def _add_reference(
235
+ self,
236
+ doc: DocxDocument,
237
+ block: Dict[str, Any],
238
+ ) -> None:
239
+ """Add a reference entry."""
240
+ ref_number = block.get("ref_number")
241
+ ref_text = block.get("ref_text", block.get("text", ""))
242
+
243
+ if ref_number is not None:
244
+ full_text = f"[{ref_number}] {ref_text}"
245
+ else:
246
+ full_text = ref_text
247
+
248
+ p = doc.add_paragraph(full_text)
249
+
250
+ if self._style_exists(doc, self.profile.normal_style):
251
+ try:
252
+ p.style = self.profile.normal_style
253
+ except Exception:
254
+ pass
255
+
256
+ def _add_table(
257
+ self,
258
+ doc: DocxDocument,
259
+ block: Dict[str, Any],
260
+ ) -> None:
261
+ """Add a table."""
262
+ rows = block.get("rows", [])
263
+ if not rows:
264
+ return
265
+
266
+ num_rows = len(rows)
267
+ num_cols = len(rows[0]) if rows else 0
268
+
269
+ table = doc.add_table(rows=num_rows, cols=num_cols)
270
+ table.style = "Table Grid"
271
+
272
+ for i, row_data in enumerate(rows):
273
+ row = table.rows[i]
274
+ for j, cell_text in enumerate(row_data):
275
+ if j < len(row.cells):
276
+ row.cells[j].text = str(cell_text)
277
+
278
+ def _add_image(
279
+ self,
280
+ doc: DocxDocument,
281
+ block: Dict[str, Any],
282
+ image_lookup: Dict[str, Any],
283
+ ) -> None:
284
+ """Add an image."""
285
+ image_hash = block.get("image_hash")
286
+ image_data = block.get("data")
287
+
288
+ if image_hash and image_hash in image_lookup:
289
+ image_info = image_lookup[image_hash]
290
+ image_data = image_info.get("data")
291
+
292
+ if image_data:
293
+ from io import BytesIO
294
+
295
+ image_stream = BytesIO(image_data)
296
+ width = block.get("width_inches", 5.0)
297
+ doc.add_picture(image_stream, width=Inches(width))
298
+
299
+ def _add_list_item(
300
+ self,
301
+ doc: DocxDocument,
302
+ block: Dict[str, Any],
303
+ ) -> None:
304
+ """Add a list item (bullet or numbered)."""
305
+ text = block.get("text", "")
306
+ list_type = block.get("list_type", "bullet")
307
+
308
+ p = doc.add_paragraph(text)
309
+
310
+ style_key = "bullet" if list_type == "bullet" else "numbered"
311
+ style_name = self.profile.list_styles.get(style_key)
312
+
313
+ if style_name and self._style_exists(doc, style_name):
314
+ try:
315
+ p.style = style_name
316
+ except Exception:
317
+ pass
318
+
319
+ def _style_exists(self, doc: DocxDocument, style_name: str) -> bool:
320
+ """Check if a style exists in the document."""
321
+ try:
322
+ _ = doc.styles[style_name]
323
+ return True
324
+ except KeyError:
325
+ return False
326
+
327
+ def _apply_double_anonymous(
328
+ self,
329
+ doc: DocxDocument,
330
+ writer_doc: Dict[str, Any],
331
+ ) -> None:
332
+ """
333
+ Apply double-anonymous formatting.
334
+
335
+ This removes or masks author-identifying information.
336
+ """
337
+ # Get author info to mask
338
+ metadata = writer_doc.get("metadata", {})
339
+ author = metadata.get("author", "")
340
+
341
+ if not author:
342
+ return
343
+
344
+ # Search and replace author names with placeholder
345
+ # This is a simple implementation; more sophisticated
346
+ # masking may be needed for real use
347
+ for para in doc.paragraphs:
348
+ if author.lower() in para.text.lower():
349
+ for run in para.runs:
350
+ if author.lower() in run.text.lower():
351
+ # Mask author name
352
+ import re
353
+
354
+ run.text = re.sub(
355
+ re.escape(author),
356
+ "[Author]",
357
+ run.text,
358
+ flags=re.IGNORECASE,
359
+ )
360
+
361
+
362
+ __all__ = ["WordWriter"]
scitex/plt/__init__.py CHANGED
@@ -31,6 +31,10 @@ import matplotlib.font_manager as fm
31
31
  import matplotlib as mpl
32
32
  import matplotlib.pyplot as plt
33
33
 
34
+ from scitex import logging as _logging
35
+
36
+ _logger = _logging.getLogger(__name__)
37
+
34
38
  # =============================================================================
35
39
  # Auto-configure matplotlib with SciTeX style on import
36
40
  # =============================================================================
@@ -316,7 +320,6 @@ def load(path, apply_manual=True):
316
320
  """
317
321
  from pathlib import Path
318
322
  import hashlib
319
- import warnings
320
323
  import scitex as stx
321
324
 
322
325
  path = Path(path)
@@ -345,7 +348,7 @@ def load(path, apply_manual=True):
345
348
  if "base_hash" in manual_data:
346
349
  current_hash = _compute_file_hash(json_path)
347
350
  if manual_data["base_hash"] != current_hash:
348
- warnings.warn(
351
+ _logger.warning(
349
352
  f"Manual overrides may be stale: base data changed since manual edits.\n"
350
353
  f" Expected hash: {manual_data['base_hash'][:16]}...\n"
351
354
  f" Current hash: {current_hash[:16]}...\n"
@@ -14,6 +14,10 @@ from functools import wraps
14
14
  import numpy as np
15
15
  import pandas as pd
16
16
 
17
+ from scitex import logging
18
+
19
+ logger = logging.getLogger(__name__)
20
+
17
21
 
18
22
  class AxesWrapper:
19
23
  def __init__(self, fig_scitex, axes_scitex):
@@ -124,14 +128,10 @@ class AxesWrapper:
124
128
  Returns:
125
129
  np.ndarray: Array of wrapped axes with the same shape
126
130
  """
127
- import warnings
128
-
129
131
  # Show a warning to help users avoid common mistakes
130
- warnings.warn(
132
+ logger.warning(
131
133
  "Converting AxesWrapper to numpy array. If you're trying to flatten "
132
- "the axes, use 'list(axes.flatten())' instead of 'np.array(axes).flatten()'.",
133
- UserWarning,
134
- stacklevel=2,
134
+ "the axes, use 'list(axes.flatten())' instead of 'np.array(axes).flatten()'."
135
135
  )
136
136
 
137
137
  # Convert the underlying axes to a compatible numpy array representation