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
@@ -0,0 +1,255 @@
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/__init__.py
5
+
6
+ """
7
+ MS Word (DOCX) import/export utilities for SciTeX.
8
+
9
+ This module provides high-level functions to convert between
10
+ MS Word .docx files and SciTeX's internal writer document model.
11
+
12
+ Strategy:
13
+ ---------
14
+ - Word users write text only (paragraphs, minimal formatting)
15
+ - SciTeX handles: figures, tables, references, LaTeX generation
16
+ - SciTeX JSON is the "source of truth", Word is just a view/edit layer
17
+
18
+ Typical usage:
19
+ --------------
20
+ from scitex.msword import load_docx, save_docx, list_profiles
21
+
22
+ # Import from Word
23
+ doc = load_docx("input.docx", profile="generic")
24
+
25
+ # Manipulate via scitex.writer...
26
+ # doc.normalize()
27
+
28
+ # Export to Word (different journal template)
29
+ save_docx(doc, "output.docx", profile="mdpi-ijerph")
30
+
31
+ Available profiles:
32
+ -------------------
33
+ - generic: Standard Word with Heading 1/2/3
34
+ - mdpi-ijerph: MDPI IJERPH journal template
35
+ - resna-2025: RESNA 2025 scientific paper template
36
+ - iop-double-anonymous: IOP double-anonymous template
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ from pathlib import Path
42
+ from typing import Any, Optional
43
+
44
+ from .profiles import (
45
+ BaseWordProfile,
46
+ get_profile,
47
+ list_profiles,
48
+ register_profile,
49
+ )
50
+ from .reader import WordReader
51
+ from .writer import WordWriter
52
+ from .utils import (
53
+ link_captions_to_images,
54
+ link_captions_to_images_by_proximity,
55
+ normalize_section_headings,
56
+ validate_document,
57
+ create_post_import_hook,
58
+ )
59
+
60
+
61
+ def load_docx(
62
+ path: str | Path,
63
+ profile: str | None = None,
64
+ extract_images: bool = True,
65
+ ) -> dict[str, Any]:
66
+ """
67
+ Load a DOCX file and convert it into a SciTeX writer document.
68
+
69
+ Parameters
70
+ ----------
71
+ path : str | Path
72
+ Path to the .docx file.
73
+ profile : str | None
74
+ Optional profile name that specifies how to interpret Word styles
75
+ (e.g., "mdpi-ijerph", "resna-2025"). If None, "generic" is used.
76
+ extract_images : bool
77
+ If True, extract embedded images and store references.
78
+
79
+ Returns
80
+ -------
81
+ dict
82
+ A SciTeX writer document structure containing:
83
+ - blocks: List of document blocks (headings, paragraphs, captions, etc.)
84
+ - metadata: Profile and source file information
85
+ - images: Extracted image references (if extract_images=True)
86
+ - references: Parsed reference entries
87
+
88
+ Examples
89
+ --------
90
+ >>> from scitex.msword import load_docx
91
+ >>> doc = load_docx("manuscript.docx", profile="mdpi-ijerph")
92
+ >>> print(doc["metadata"]["profile"])
93
+ 'mdpi-ijerph'
94
+ """
95
+ path = Path(path)
96
+ profile_obj: BaseWordProfile = get_profile(profile)
97
+ reader = WordReader(profile=profile_obj, extract_images=extract_images)
98
+ return reader.read(path)
99
+
100
+
101
+ def save_docx(
102
+ writer_doc: dict[str, Any] | Any,
103
+ path: str | Path,
104
+ profile: str | None = None,
105
+ overwrite: bool = True,
106
+ template_path: str | Path | None = None,
107
+ ) -> Path:
108
+ """
109
+ Save a SciTeX writer document as a DOCX file.
110
+
111
+ Parameters
112
+ ----------
113
+ writer_doc : dict | Any
114
+ SciTeX writer document instance to export.
115
+ path : str | Path
116
+ Output path for the .docx file.
117
+ profile : str | None
118
+ Optional profile name that controls how sections, headings,
119
+ figures, tables and references are mapped to Word styles.
120
+ If None, "generic" is used.
121
+ overwrite : bool
122
+ If False and the file already exists, raises FileExistsError.
123
+ template_path : str | Path | None
124
+ Optional path to a Word template (.dotx/.docx) to use as base.
125
+ This allows using journal-specific formatting.
126
+
127
+ Returns
128
+ -------
129
+ Path
130
+ The path to the written .docx file.
131
+
132
+ Examples
133
+ --------
134
+ >>> from scitex.msword import save_docx
135
+ >>> save_docx(doc, "submission_resna_2025.docx", profile="resna-2025")
136
+ PosixPath('submission_resna_2025.docx')
137
+ """
138
+ output_path = Path(path)
139
+ if output_path.exists() and not overwrite:
140
+ raise FileExistsError(f"File already exists: {output_path}")
141
+
142
+ profile_obj: BaseWordProfile = get_profile(profile)
143
+ writer = WordWriter(profile=profile_obj, template_path=template_path)
144
+ writer.write(writer_doc, output_path)
145
+ return output_path
146
+
147
+
148
+ def convert_docx_to_tex(
149
+ input_path: str | Path,
150
+ output_path: str | Path,
151
+ profile: str | None = None,
152
+ *,
153
+ image_dir: str | Path | None = None,
154
+ link_images: bool = True,
155
+ link_mode: str = "by-number",
156
+ normalize_headings: bool = True,
157
+ validate: bool = True,
158
+ ) -> Path:
159
+ """
160
+ Convert a DOCX file directly to LaTeX.
161
+
162
+ This is a convenience function that:
163
+ 1. Loads the DOCX file into SciTeX intermediate format
164
+ 2. (Optionally) normalizes headings
165
+ 3. (Optionally) links figure captions to images
166
+ 4. (Optionally) validates the document and adds warnings
167
+ 5. Exports to LaTeX (including figures via image_dir)
168
+
169
+ Parameters
170
+ ----------
171
+ input_path : str | Path
172
+ Path to the input .docx file.
173
+ output_path : str | Path
174
+ Path for the output .tex file.
175
+ profile : str | None
176
+ Word profile for interpreting styles
177
+ (e.g., "resna-2025", "iop-double-anonymous").
178
+ image_dir : str | Path | None, optional
179
+ Directory where extracted figure image files will be saved.
180
+ If None, the LaTeX exporter will create "<tex_stem>_figures"
181
+ next to `output_path`.
182
+ link_images : bool, default True
183
+ Whether to link figure captions to extracted images so that
184
+ LaTeX can generate \\includegraphics inside figure environments.
185
+ link_mode : {"by-number", "by-proximity"}, default "by-number"
186
+ Strategy for linking captions to images:
187
+ - "by-number": Figure 1 -> first image, Figure 2 -> second image...
188
+ - "by-proximity": assign images in document order, useful when
189
+ figure numbers and image order don't match.
190
+ normalize_headings : bool, default True
191
+ If True, apply common heading normalizations
192
+ (e.g., "intro" -> "Introduction").
193
+ validate : bool, default True
194
+ If True, run basic structural checks and populate
195
+ doc["warnings"] with any issues.
196
+
197
+ Returns
198
+ -------
199
+ Path
200
+ The path to the written .tex file.
201
+
202
+ Examples
203
+ --------
204
+ >>> from scitex.msword import convert_docx_to_tex
205
+ >>> convert_docx_to_tex(
206
+ ... "RESNA 2025 Scientific Paper Template.docx",
207
+ ... "manuscript.tex",
208
+ ... profile="resna-2025",
209
+ ... image_dir="figures",
210
+ ... )
211
+ PosixPath('manuscript.tex')
212
+ """
213
+ # Import here to avoid circular imports
214
+ from scitex.tex import export_tex
215
+
216
+ # 1. DOCX -> SciTeX intermediate format
217
+ doc = load_docx(input_path, profile=profile, extract_images=True)
218
+
219
+ # 2. Normalize headings (optional)
220
+ if normalize_headings:
221
+ doc = normalize_section_headings(doc)
222
+
223
+ # 3. Link captions to images (optional)
224
+ if link_images and doc.get("images"):
225
+ if link_mode == "by-proximity":
226
+ doc = link_captions_to_images_by_proximity(doc)
227
+ else:
228
+ # Default: link by figure number
229
+ doc = link_captions_to_images(doc)
230
+
231
+ # 4. Validate document structure (optional)
232
+ if validate:
233
+ doc = validate_document(doc)
234
+
235
+ # 5. SciTeX -> LaTeX (with figures)
236
+ return export_tex(doc, output_path, image_dir=image_dir)
237
+
238
+
239
+ __all__ = [
240
+ "load_docx",
241
+ "save_docx",
242
+ "convert_docx_to_tex",
243
+ "list_profiles",
244
+ "get_profile",
245
+ "register_profile",
246
+ "BaseWordProfile",
247
+ "WordReader",
248
+ "WordWriter",
249
+ # Utility functions for post-processing
250
+ "link_captions_to_images",
251
+ "link_captions_to_images_by_proximity",
252
+ "normalize_section_headings",
253
+ "validate_document",
254
+ "create_post_import_hook",
255
+ ]
@@ -0,0 +1,357 @@
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/profiles.py
5
+
6
+ """
7
+ Profiles for mapping MS Word styles to SciTeX writer structures.
8
+
9
+ Each profile corresponds to a journal / conference template, such as:
10
+ - "generic"
11
+ - "mdpi-ijerph"
12
+ - "resna-2025"
13
+ - "iop-double-anonymous"
14
+
15
+ The profiles define:
16
+ - Which Word style names correspond to section headings
17
+ - How to detect captions for figures and tables
18
+ - How to handle references, lists, equations, etc.
19
+ - Layout settings (columns, margins, fonts)
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from dataclasses import dataclass, field
25
+ from typing import Dict, List, Optional, Callable
26
+
27
+
28
+ @dataclass
29
+ class BaseWordProfile:
30
+ """
31
+ Base configuration for mapping between DOCX and SciTeX writer documents.
32
+
33
+ Attributes
34
+ ----------
35
+ name : str
36
+ Profile identifier (e.g., "mdpi-ijerph").
37
+ description : str
38
+ Human-readable description.
39
+ heading_styles : dict[int, str]
40
+ Mapping from section depth (1, 2, 3...) to Word style names
41
+ (e.g., {1: "Heading 1", 2: "Heading 2"}).
42
+ caption_style : str
43
+ Word style name used for figure/table captions.
44
+ normal_style : str
45
+ Default paragraph style.
46
+ reference_section_titles : list[str]
47
+ Titles that indicate the start of the reference section.
48
+ figure_caption_prefixes : list[str]
49
+ Prefixes that identify figure captions (e.g., ["Figure", "Fig."]).
50
+ table_caption_prefixes : list[str]
51
+ Prefixes that identify table captions (e.g., ["Table"]).
52
+ list_styles : dict[str, str]
53
+ Mapping for list styles (bullet, numbered).
54
+ equation_style : str | None
55
+ Style name for equations, if any.
56
+ columns : int
57
+ Number of columns in the layout (1 or 2).
58
+ double_anonymous : bool
59
+ Whether this profile requires double-anonymous formatting.
60
+ """
61
+
62
+ name: str
63
+ description: str
64
+ heading_styles: Dict[int, str] = field(default_factory=dict)
65
+ caption_style: str = "Caption"
66
+ normal_style: str = "Normal"
67
+ reference_section_titles: List[str] = field(
68
+ default_factory=lambda: ["References", "REFERENCES"]
69
+ )
70
+ figure_caption_prefixes: List[str] = field(
71
+ default_factory=lambda: ["Figure", "Fig.", "Fig"]
72
+ )
73
+ table_caption_prefixes: List[str] = field(
74
+ default_factory=lambda: ["Table", "Tab.", "Tab"]
75
+ )
76
+ list_styles: Dict[str, str] = field(
77
+ default_factory=lambda: {
78
+ "bullet": "List Bullet",
79
+ "numbered": "List Number",
80
+ }
81
+ )
82
+ equation_style: Optional[str] = None
83
+ columns: int = 1
84
+ double_anonymous: bool = False
85
+
86
+ # Post-processing hooks
87
+ post_import_hooks: List[Callable] = field(default_factory=list)
88
+ pre_export_hooks: List[Callable] = field(default_factory=list)
89
+
90
+
91
+ # --- Concrete profiles ------------------------------------------------------
92
+
93
+
94
+ def _generic_profile() -> BaseWordProfile:
95
+ """
96
+ Generic Word template profile.
97
+
98
+ This profile is intentionally conservative and assumes that:
99
+ - "Heading 1/2/3" are used for section headings.
100
+ - "Caption" is used for figure/table captions.
101
+ - "Normal" is the default body text.
102
+
103
+ This should work reasonably well for many simple manuscripts.
104
+ """
105
+ return BaseWordProfile(
106
+ name="generic",
107
+ description="Generic Word mapping with standard Heading styles.",
108
+ heading_styles={
109
+ 1: "Heading 1",
110
+ 2: "Heading 2",
111
+ 3: "Heading 3",
112
+ 4: "Heading 4",
113
+ },
114
+ caption_style="Caption",
115
+ normal_style="Normal",
116
+ reference_section_titles=["References", "REFERENCES", "Bibliography"],
117
+ )
118
+
119
+
120
+ def _mdpi_ijerph_profile() -> BaseWordProfile:
121
+ """
122
+ MDPI IJERPH template profile.
123
+
124
+ Based on the MDPI Word template structure:
125
+ - Section headings use built-in heading styles.
126
+ - References section is titled "References".
127
+ - Single column layout.
128
+ - Specific section order: Introduction, Materials and Methods,
129
+ Results, Discussion, Conclusions.
130
+ """
131
+ return BaseWordProfile(
132
+ name="mdpi-ijerph",
133
+ description="MDPI IJERPH (Int. J. Environ. Res. Public Health) Word template.",
134
+ heading_styles={
135
+ 1: "Heading 1",
136
+ 2: "Heading 2",
137
+ 3: "Heading 3",
138
+ },
139
+ caption_style="Caption",
140
+ normal_style="Normal",
141
+ reference_section_titles=["References"],
142
+ columns=1,
143
+ )
144
+
145
+
146
+ def _resna_2025_profile() -> BaseWordProfile:
147
+ """
148
+ RESNA 2025 scientific paper template profile.
149
+
150
+ The RESNA template:
151
+ - Uses all-caps section headings (INTRODUCTION, METHODS, etc.)
152
+ - Strict 4-page layout
153
+ - Two-column format
154
+ """
155
+ return BaseWordProfile(
156
+ name="resna-2025",
157
+ description="RESNA 2025 Scientific Paper Word template.",
158
+ heading_styles={
159
+ 1: "Heading 1", # INTRODUCTION, METHODS, etc.
160
+ 2: "Heading 2", # First-level sub-heading
161
+ },
162
+ caption_style="Caption",
163
+ normal_style="Normal",
164
+ reference_section_titles=["References", "REFERENCES"],
165
+ columns=2,
166
+ )
167
+
168
+
169
+ def _iop_double_anonymous_profile() -> BaseWordProfile:
170
+ """
171
+ IOP double-anonymous Word template profile.
172
+
173
+ The IOP template uses custom styles:
174
+ - IOPH1, IOPH2, IOPH3 for headings
175
+ - IOPTitle for title
176
+ - IOPAbsText for abstract
177
+ - IOPAff for affiliations
178
+ - Requires removal of author-identifying information
179
+ """
180
+ return BaseWordProfile(
181
+ name="iop-double-anonymous",
182
+ description="IOP double-anonymous Word template.",
183
+ heading_styles={
184
+ 1: "IOPH1",
185
+ 2: "IOPH2",
186
+ 3: "IOPH3",
187
+ },
188
+ caption_style="Caption",
189
+ normal_style="Normal",
190
+ reference_section_titles=["References"],
191
+ double_anonymous=True,
192
+ )
193
+
194
+
195
+ def _ieee_profile() -> BaseWordProfile:
196
+ """
197
+ IEEE conference/journal template profile.
198
+
199
+ The IEEE template:
200
+ - Two-column format
201
+ - Roman numeral section numbering
202
+ - Specific citation style
203
+ """
204
+ return BaseWordProfile(
205
+ name="ieee",
206
+ description="IEEE conference/journal Word template.",
207
+ heading_styles={
208
+ 1: "Heading 1",
209
+ 2: "Heading 2",
210
+ 3: "Heading 3",
211
+ },
212
+ caption_style="Caption",
213
+ normal_style="Normal",
214
+ reference_section_titles=["References", "REFERENCES"],
215
+ columns=2,
216
+ )
217
+
218
+
219
+ def _springer_profile() -> BaseWordProfile:
220
+ """
221
+ Springer Nature journal template profile.
222
+ """
223
+ return BaseWordProfile(
224
+ name="springer",
225
+ description="Springer Nature journal Word template.",
226
+ heading_styles={
227
+ 1: "Heading 1",
228
+ 2: "Heading 2",
229
+ 3: "Heading 3",
230
+ },
231
+ caption_style="Caption",
232
+ normal_style="Normal",
233
+ reference_section_titles=["References"],
234
+ columns=1,
235
+ )
236
+
237
+
238
+ def _elsevier_profile() -> BaseWordProfile:
239
+ """
240
+ Elsevier journal template profile.
241
+ """
242
+ return BaseWordProfile(
243
+ name="elsevier",
244
+ description="Elsevier journal Word template.",
245
+ heading_styles={
246
+ 1: "Heading 1",
247
+ 2: "Heading 2",
248
+ 3: "Heading 3",
249
+ },
250
+ caption_style="Caption",
251
+ normal_style="Normal",
252
+ reference_section_titles=["References"],
253
+ columns=1,
254
+ )
255
+
256
+
257
+ # Registry of known profiles
258
+ _PROFILES: Dict[str, BaseWordProfile] = {
259
+ "generic": _generic_profile(),
260
+ "mdpi-ijerph": _mdpi_ijerph_profile(),
261
+ "mdpi": _mdpi_ijerph_profile(), # Alias
262
+ "resna-2025": _resna_2025_profile(),
263
+ "resna": _resna_2025_profile(), # Alias
264
+ "iop-double-anonymous": _iop_double_anonymous_profile(),
265
+ "iop": _iop_double_anonymous_profile(), # Alias
266
+ "ieee": _ieee_profile(),
267
+ "springer": _springer_profile(),
268
+ "elsevier": _elsevier_profile(),
269
+ }
270
+
271
+
272
+ def list_profiles() -> list[str]:
273
+ """
274
+ List available MS Word profiles.
275
+
276
+ Returns
277
+ -------
278
+ list[str]
279
+ List of profile names (e.g., ["generic", "mdpi-ijerph", ...]).
280
+
281
+ Examples
282
+ --------
283
+ >>> from scitex.msword import list_profiles
284
+ >>> profiles = list_profiles()
285
+ >>> "generic" in profiles
286
+ True
287
+ """
288
+ return sorted(_PROFILES.keys())
289
+
290
+
291
+ def get_profile(name: str | None) -> BaseWordProfile:
292
+ """
293
+ Get a Word profile by name.
294
+
295
+ Parameters
296
+ ----------
297
+ name : str | None
298
+ Profile name. If None, "generic" is used.
299
+
300
+ Returns
301
+ -------
302
+ BaseWordProfile
303
+ The requested profile.
304
+
305
+ Raises
306
+ ------
307
+ KeyError
308
+ If the profile name is unknown.
309
+
310
+ Examples
311
+ --------
312
+ >>> from scitex.msword import get_profile
313
+ >>> profile = get_profile("mdpi-ijerph")
314
+ >>> profile.columns
315
+ 1
316
+ """
317
+ if name is None:
318
+ return _PROFILES["generic"]
319
+ try:
320
+ return _PROFILES[name]
321
+ except KeyError as exc:
322
+ available = ", ".join(list_profiles())
323
+ raise KeyError(
324
+ f"Unknown MS Word profile: {name!r}. " f"Available profiles: {available}"
325
+ ) from exc
326
+
327
+
328
+ def register_profile(profile: BaseWordProfile) -> None:
329
+ """
330
+ Register a custom Word profile.
331
+
332
+ Parameters
333
+ ----------
334
+ profile : BaseWordProfile
335
+ The profile to register.
336
+
337
+ Examples
338
+ --------
339
+ >>> from scitex.msword import BaseWordProfile, register_profile
340
+ >>> custom = BaseWordProfile(
341
+ ... name="my-journal",
342
+ ... description="My custom journal template",
343
+ ... heading_styles={1: "Title", 2: "Subtitle"},
344
+ ... )
345
+ >>> register_profile(custom)
346
+ >>> "my-journal" in list_profiles()
347
+ True
348
+ """
349
+ _PROFILES[profile.name] = profile
350
+
351
+
352
+ __all__ = [
353
+ "BaseWordProfile",
354
+ "list_profiles",
355
+ "get_profile",
356
+ "register_profile",
357
+ ]