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
@@ -18,6 +18,8 @@ assert_csv_json_consistency : function
18
18
  Assert CSV columns match JSON metadata
19
19
  verify_csv_json_consistency : function
20
20
  Verify CSV-JSON consistency and return detailed results
21
+ export_editable_figure : function
22
+ Export figure with geometry data for interactive editing (schema v0.3)
21
23
  """
22
24
 
23
25
  # Import public API from core module
@@ -27,10 +29,33 @@ from ._data_linkage import (
27
29
  verify_csv_json_consistency,
28
30
  collect_recipe_metadata,
29
31
  )
32
+ from ._geometry_extraction import (
33
+ extract_axes_bbox_px,
34
+ data_to_axes_px,
35
+ extract_line_geometry,
36
+ extract_scatter_geometry,
37
+ extract_polygon_geometry,
38
+ extract_rectangle_geometry,
39
+ extract_bar_group_geometry,
40
+ extract_text_geometry,
41
+ extract_image_geometry,
42
+ )
43
+ from ._editable_export import export_editable_figure
30
44
 
31
45
  __all__ = [
32
46
  "collect_figure_metadata",
33
47
  "collect_recipe_metadata",
34
48
  "assert_csv_json_consistency",
35
49
  "verify_csv_json_consistency",
50
+ "export_editable_figure",
51
+ # Geometry extraction
52
+ "extract_axes_bbox_px",
53
+ "data_to_axes_px",
54
+ "extract_line_geometry",
55
+ "extract_scatter_geometry",
56
+ "extract_polygon_geometry",
57
+ "extract_rectangle_geometry",
58
+ "extract_bar_group_geometry",
59
+ "extract_text_geometry",
60
+ "extract_image_geometry",
36
61
  ]
@@ -12,6 +12,10 @@ the collection of all metadata from matplotlib figures and axes.
12
12
  from typing import Dict
13
13
  import numpy as np
14
14
 
15
+ from scitex import logging
16
+
17
+ logger = logging.getLogger(__name__)
18
+
15
19
  # Import sub-modules
16
20
  from ._figure_metadata import _initialize_metadata_structure, _collect_figure_metadata
17
21
  from ._axes_metadata import _collect_all_axes_metadata
@@ -87,16 +91,14 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
87
91
  try:
88
92
  metadata["figure"] = _extract_figure_dimensions(fig)
89
93
  except Exception as e:
90
- import warnings
91
- warnings.warn(f"Could not extract figure dimension info: {e}")
94
+ logger.warning(f"Could not extract figure dimension info: {e}")
92
95
 
93
96
  # Collect axes metadata
94
97
  if all_axes:
95
98
  try:
96
99
  metadata["axes"] = _collect_all_axes_metadata(all_axes, fig, grid_shape)
97
100
  except Exception as e:
98
- import warnings
99
- warnings.warn(f"Could not extract axes metadata: {e}")
101
+ logger.warning(f"Could not extract axes metadata: {e}")
100
102
 
101
103
  # Extract style metadata
102
104
  try:
@@ -136,10 +138,8 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
136
138
  metadata["style"]["global"]["fonts"]["family_actual"] = actual_font
137
139
 
138
140
  if requested_font != actual_font:
139
- import warnings
140
- warnings.warn(
141
- f"Font mismatch: Requested '{requested_font}' but using '{actual_font}'",
142
- UserWarning,
141
+ logger.warning(
142
+ f"Font mismatch: Requested '{requested_font}' but using '{actual_font}'"
143
143
  )
144
144
  else:
145
145
  metadata["runtime"]["font_family_actual"] = actual_font
@@ -199,8 +199,7 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
199
199
  pass # Data hash is optional
200
200
 
201
201
  except Exception as e:
202
- import warnings
203
- warnings.warn(f"Could not extract plot content: {e}")
202
+ logger.warning(f"Could not extract plot content: {e}")
204
203
 
205
204
  # Apply precision rounding
206
205
  metadata = _round_metadata(metadata)
@@ -9,9 +9,12 @@ This module provides functions to extract size, position, and bounding box
9
9
  information from matplotlib figures and axes in multiple units (mm, inch, px).
10
10
  """
11
11
 
12
- import warnings
13
12
  from typing import Dict
14
13
 
14
+ from scitex import logging
15
+
16
+ logger = logging.getLogger(__name__)
17
+
15
18
 
16
19
  def _extract_axes_dimensions(fig, ax, ax_index: int) -> dict:
17
20
  """
@@ -80,7 +83,7 @@ def _extract_axes_dimensions(fig, ax, ax_index: int) -> dict:
80
83
  ax_metadata["bbox_inch"] = _normalize_bbox(bbox)
81
84
 
82
85
  except Exception as e:
83
- warnings.warn(f"Could not extract dimension info for axes {ax_index}: {e}")
86
+ logger.warning(f"Could not extract dimension info for axes {ax_index}: {e}")
84
87
 
85
88
  return ax_metadata
86
89
 
@@ -190,7 +193,7 @@ def _extract_figure_dimensions(fig) -> dict:
190
193
  fig_metadata["size_px"] = [width_inch * dpi, height_inch * dpi]
191
194
 
192
195
  except Exception as e:
193
- warnings.warn(f"Could not extract figure dimensions: {e}")
196
+ logger.warning(f"Could not extract figure dimensions: {e}")
194
197
 
195
198
  return fig_metadata
196
199
 
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-12-10 (ywatanabe)"
4
+ # File: scitex/plt/utils/metadata/_editable_export.py
5
+
6
+ """
7
+ Main export function for Schema v0.3 (scitex.plt.figure.editable).
8
+
9
+ This module provides the top-level export_editable_figure() function that
10
+ orchestrates geometry extraction for all elements in a matplotlib figure,
11
+ producing a JSON-serializable dictionary suitable for interactive editing.
12
+ """
13
+
14
+ from typing import Dict, Any, Optional, List
15
+ import numpy as np
16
+ from datetime import datetime
17
+
18
+ from ._geometry_extraction import (
19
+ extract_axes_bbox_px,
20
+ extract_line_geometry,
21
+ extract_scatter_geometry,
22
+ extract_polygon_geometry,
23
+ extract_rectangle_geometry,
24
+ extract_bar_group_geometry,
25
+ extract_text_geometry,
26
+ extract_image_geometry,
27
+ )
28
+
29
+
30
+ def export_editable_figure(
31
+ fig,
32
+ title: str = "",
33
+ description: str = "",
34
+ include_full_paths: bool = False,
35
+ simplify_threshold: float = 0.5,
36
+ ) -> Dict[str, Any]:
37
+ """
38
+ Export a matplotlib figure with geometry data for interactive editing.
39
+
40
+ This produces a Schema v0.3 compliant dictionary with axes-local pixel
41
+ coordinates for all visual elements, suitable for shape-based hit testing.
42
+
43
+ Parameters
44
+ ----------
45
+ fig : matplotlib.figure.Figure or scitex.plt.FigureWrapper
46
+ The figure to export
47
+ title : str
48
+ Optional title for the figure metadata
49
+ description : str
50
+ Optional description for the figure metadata
51
+ include_full_paths : bool
52
+ If True, include full (unsimplified) paths for lines. Default False.
53
+ simplify_threshold : float
54
+ Maximum pixel error for path simplification. Default 0.5.
55
+
56
+ Returns
57
+ -------
58
+ dict
59
+ Schema v0.3 compliant dictionary with structure:
60
+ - scitex_schema: "scitex.plt.figure.editable"
61
+ - scitex_schema_version: "0.3.0"
62
+ - figure: {size_px, dpi, ...}
63
+ - axes: {ax_id: {bbox_px, ...}, ...}
64
+ - elements: {elem_id: {geometry_px, style, ...}, ...}
65
+ - statistics: {} (placeholder for stats integration)
66
+ - data: {} (placeholder for linked data)
67
+ - output: {} (rendering metadata)
68
+ """
69
+ # Handle scitex FigureWrapper
70
+ mpl_fig = fig.figure if hasattr(fig, 'figure') else fig
71
+
72
+ # Ensure we have a renderer
73
+ try:
74
+ renderer = mpl_fig.canvas.get_renderer()
75
+ except Exception:
76
+ mpl_fig.canvas.draw()
77
+ renderer = mpl_fig.canvas.get_renderer()
78
+
79
+ # Figure dimensions
80
+ fig_width_px = int(mpl_fig.get_figwidth() * mpl_fig.dpi)
81
+ fig_height_px = int(mpl_fig.get_figheight() * mpl_fig.dpi)
82
+
83
+ # Build output structure
84
+ output = {
85
+ "scitex_schema": "scitex.plt.figure.editable",
86
+ "scitex_schema_version": "0.3.0",
87
+ "meta": {
88
+ "title": title,
89
+ "description": description,
90
+ "exported_at": datetime.now().isoformat(),
91
+ },
92
+ "figure": {
93
+ "size_px": [fig_width_px, fig_height_px],
94
+ "dpi": mpl_fig.dpi,
95
+ "figsize_inches": [mpl_fig.get_figwidth(), mpl_fig.get_figheight()],
96
+ },
97
+ "axes": {},
98
+ "elements": {},
99
+ "statistics": {},
100
+ "data": {},
101
+ "output": {
102
+ "format": "png",
103
+ "width_px": fig_width_px,
104
+ "height_px": fig_height_px,
105
+ },
106
+ }
107
+
108
+ # Get all axes
109
+ axes_list = mpl_fig.get_axes()
110
+
111
+ for ax_idx, ax in enumerate(axes_list):
112
+ # Handle scitex AxisWrapper
113
+ mpl_ax = ax._axis_mpl if hasattr(ax, '_axis_mpl') else ax
114
+
115
+ ax_id = f"ax_{ax_idx:02d}"
116
+
117
+ # Extract axes bbox
118
+ axes_bbox = extract_axes_bbox_px(mpl_ax, mpl_fig)
119
+ output["axes"][ax_id] = {
120
+ "bbox_px": axes_bbox,
121
+ "position": list(mpl_ax.get_position().bounds),
122
+ "xlim": list(mpl_ax.get_xlim()),
123
+ "ylim": list(mpl_ax.get_ylim()),
124
+ }
125
+
126
+ # Extract elements from this axes
127
+ elements = _extract_axes_elements(
128
+ mpl_ax, mpl_fig, ax_id, renderer,
129
+ include_full_paths=include_full_paths,
130
+ simplify_threshold=simplify_threshold,
131
+ )
132
+ output["elements"].update(elements)
133
+
134
+ return output
135
+
136
+
137
+ def _extract_axes_elements(
138
+ ax, fig, ax_id: str, renderer,
139
+ include_full_paths: bool = False,
140
+ simplify_threshold: float = 0.5,
141
+ ) -> Dict[str, Any]:
142
+ """
143
+ Extract all visual elements from a single axes.
144
+
145
+ Parameters
146
+ ----------
147
+ ax : matplotlib.axes.Axes
148
+ The axes object
149
+ fig : matplotlib.figure.Figure
150
+ The figure object
151
+ ax_id : str
152
+ Identifier for the axes (e.g., "ax_00")
153
+ renderer : RendererBase
154
+ Matplotlib renderer for text bbox extraction
155
+ include_full_paths : bool
156
+ Include unsimplified paths
157
+ simplify_threshold : float
158
+ Path simplification threshold in pixels
159
+
160
+ Returns
161
+ -------
162
+ dict
163
+ Dictionary of {element_id: element_data}
164
+ """
165
+ elements = {}
166
+ zorder_counter = 0
167
+
168
+ # Extract lines (Line2D)
169
+ for idx, line in enumerate(ax.lines):
170
+ elem_id = f"{ax_id}_line_{idx:02d}"
171
+ label = line.get_label()
172
+ if label is None or label.startswith('_'):
173
+ label = f"line_{idx}"
174
+
175
+ geom = extract_line_geometry(line, ax, fig, simplify_threshold)
176
+
177
+ elements[elem_id] = {
178
+ "id": elem_id,
179
+ "axes_id": ax_id,
180
+ "element_type": "line",
181
+ "label": label,
182
+ "geometry_px": geom,
183
+ "style": _extract_line_style(line),
184
+ "editable_styles": ["color", "linewidth", "linestyle", "alpha", "marker"],
185
+ "zorder": line.get_zorder(),
186
+ "visible": line.get_visible(),
187
+ }
188
+ zorder_counter += 1
189
+
190
+ # Extract collections (scatter, polygon fills, etc.)
191
+ for idx, coll in enumerate(ax.collections):
192
+ coll_type = type(coll).__name__
193
+
194
+ if coll_type == "PathCollection":
195
+ # Scatter plot
196
+ elem_id = f"{ax_id}_scatter_{idx:02d}"
197
+ label = coll.get_label()
198
+ if label is None or label.startswith('_'):
199
+ label = f"scatter_{idx}"
200
+
201
+ geom = extract_scatter_geometry(coll, ax, fig)
202
+
203
+ elements[elem_id] = {
204
+ "id": elem_id,
205
+ "axes_id": ax_id,
206
+ "element_type": "scatter",
207
+ "label": label,
208
+ "geometry_px": geom,
209
+ "style": _extract_scatter_style(coll),
210
+ "editable_styles": ["facecolor", "edgecolor", "s", "alpha", "marker"],
211
+ "zorder": coll.get_zorder(),
212
+ "visible": coll.get_visible(),
213
+ }
214
+
215
+ elif coll_type in ("PolyCollection", "FillBetweenPolyCollection"):
216
+ # Fill_between, violin, etc.
217
+ elem_id = f"{ax_id}_fill_{idx:02d}"
218
+ label = coll.get_label()
219
+ if label is None or label.startswith('_'):
220
+ label = f"fill_{idx}"
221
+
222
+ geom = extract_polygon_geometry(coll, ax, fig)
223
+
224
+ elements[elem_id] = {
225
+ "id": elem_id,
226
+ "axes_id": ax_id,
227
+ "element_type": "fill",
228
+ "label": label,
229
+ "geometry_px": geom,
230
+ "style": _extract_polygon_style(coll),
231
+ "editable_styles": ["facecolor", "edgecolor", "alpha"],
232
+ "zorder": coll.get_zorder(),
233
+ "visible": coll.get_visible(),
234
+ }
235
+
236
+ elif coll_type == "LineCollection":
237
+ # Multiple lines (e.g., errorbar caps)
238
+ elem_id = f"{ax_id}_linecoll_{idx:02d}"
239
+ elements[elem_id] = {
240
+ "id": elem_id,
241
+ "axes_id": ax_id,
242
+ "element_type": "line_collection",
243
+ "label": f"linecoll_{idx}",
244
+ "geometry_px": {"coord_space": "axes", "bbox": None},
245
+ "style": {},
246
+ "editable_styles": ["color", "linewidth", "alpha"],
247
+ "zorder": coll.get_zorder(),
248
+ "visible": coll.get_visible(),
249
+ }
250
+
251
+ # Extract patches (bars, rectangles)
252
+ bar_patches = []
253
+ other_patches = []
254
+
255
+ for patch in ax.patches:
256
+ patch_type = type(patch).__name__
257
+ if patch_type == "Rectangle":
258
+ # Check if it's part of a bar plot (has nonzero width and height)
259
+ if patch.get_width() != 0 and patch.get_height() != 0:
260
+ bar_patches.append(patch)
261
+ else:
262
+ other_patches.append(patch)
263
+ else:
264
+ other_patches.append(patch)
265
+
266
+ # Group bar patches by similar x position (bars) or y position (horizontal bars)
267
+ if bar_patches:
268
+ elem_id = f"{ax_id}_bars"
269
+ geom = extract_bar_group_geometry(bar_patches, ax, fig)
270
+
271
+ elements[elem_id] = {
272
+ "id": elem_id,
273
+ "axes_id": ax_id,
274
+ "element_type": "bar",
275
+ "label": "bars",
276
+ "geometry_px": geom,
277
+ "style": _extract_bar_style(bar_patches[0] if bar_patches else None),
278
+ "editable_styles": ["facecolor", "edgecolor", "alpha", "linewidth"],
279
+ "zorder": bar_patches[0].get_zorder() if bar_patches else 0,
280
+ "visible": True,
281
+ }
282
+
283
+ # Extract images
284
+ for idx, img in enumerate(ax.images):
285
+ elem_id = f"{ax_id}_image_{idx:02d}"
286
+ geom = extract_image_geometry(img, ax, fig)
287
+
288
+ elements[elem_id] = {
289
+ "id": elem_id,
290
+ "axes_id": ax_id,
291
+ "element_type": "image",
292
+ "label": f"image_{idx}",
293
+ "geometry_px": geom,
294
+ "style": {"cmap": str(img.get_cmap().name), "alpha": img.get_alpha()},
295
+ "editable_styles": ["cmap", "alpha", "clim"],
296
+ "zorder": img.get_zorder(),
297
+ "visible": img.get_visible(),
298
+ }
299
+
300
+ # Extract texts (excluding axis labels and title which are handled separately)
301
+ for idx, text in enumerate(ax.texts):
302
+ if not text.get_text():
303
+ continue
304
+
305
+ elem_id = f"{ax_id}_text_{idx:02d}"
306
+ geom = extract_text_geometry(text, ax, fig)
307
+
308
+ elements[elem_id] = {
309
+ "id": elem_id,
310
+ "axes_id": ax_id,
311
+ "element_type": "text",
312
+ "label": text.get_text()[:20],
313
+ "text": text.get_text(),
314
+ "geometry_px": geom,
315
+ "style": _extract_text_style(text),
316
+ "editable_styles": ["fontsize", "color", "fontweight", "alpha"],
317
+ "zorder": text.get_zorder(),
318
+ "visible": text.get_visible(),
319
+ }
320
+
321
+ return elements
322
+
323
+
324
+ def _extract_line_style(line) -> Dict[str, Any]:
325
+ """Extract style properties from a Line2D."""
326
+ color = line.get_color()
327
+ if isinstance(color, np.ndarray):
328
+ color = color.tolist()
329
+
330
+ return {
331
+ "color": color,
332
+ "linewidth": line.get_linewidth(),
333
+ "linestyle": line.get_linestyle(),
334
+ "alpha": line.get_alpha(),
335
+ "marker": line.get_marker(),
336
+ "markersize": line.get_markersize(),
337
+ }
338
+
339
+
340
+ def _extract_scatter_style(coll) -> Dict[str, Any]:
341
+ """Extract style properties from a PathCollection (scatter)."""
342
+ facecolors = coll.get_facecolors()
343
+ edgecolors = coll.get_edgecolors()
344
+
345
+ fc = facecolors[0].tolist() if len(facecolors) > 0 else [0, 0, 0, 1]
346
+ ec = edgecolors[0].tolist() if len(edgecolors) > 0 else [0, 0, 0, 1]
347
+
348
+ sizes = coll.get_sizes()
349
+ s = float(sizes[0]) if len(sizes) > 0 else 36
350
+
351
+ return {
352
+ "facecolor": fc,
353
+ "edgecolor": ec,
354
+ "s": s,
355
+ "alpha": coll.get_alpha(),
356
+ }
357
+
358
+
359
+ def _extract_polygon_style(coll) -> Dict[str, Any]:
360
+ """Extract style properties from a PolyCollection."""
361
+ facecolors = coll.get_facecolors()
362
+ edgecolors = coll.get_edgecolors()
363
+
364
+ fc = facecolors[0].tolist() if len(facecolors) > 0 else [0, 0, 0, 0.3]
365
+ ec = edgecolors[0].tolist() if len(edgecolors) > 0 else [0, 0, 0, 1]
366
+
367
+ return {
368
+ "facecolor": fc,
369
+ "edgecolor": ec,
370
+ "alpha": coll.get_alpha(),
371
+ }
372
+
373
+
374
+ def _extract_bar_style(patch) -> Dict[str, Any]:
375
+ """Extract style properties from a Rectangle patch."""
376
+ if patch is None:
377
+ return {}
378
+
379
+ fc = patch.get_facecolor()
380
+ ec = patch.get_edgecolor()
381
+
382
+ return {
383
+ "facecolor": list(fc) if hasattr(fc, '__iter__') else fc,
384
+ "edgecolor": list(ec) if hasattr(ec, '__iter__') else ec,
385
+ "linewidth": patch.get_linewidth(),
386
+ "alpha": patch.get_alpha(),
387
+ }
388
+
389
+
390
+ def _extract_text_style(text) -> Dict[str, Any]:
391
+ """Extract style properties from a Text object."""
392
+ return {
393
+ "fontsize": text.get_fontsize(),
394
+ "color": text.get_color(),
395
+ "fontweight": text.get_fontweight(),
396
+ "fontstyle": text.get_fontstyle(),
397
+ "fontfamily": text.get_fontfamily(),
398
+ "alpha": text.get_alpha(),
399
+ "ha": text.get_ha(),
400
+ "va": text.get_va(),
401
+ "rotation": text.get_rotation(),
402
+ }
403
+
404
+
405
+ # EOF