scitex 2.7.0__py3-none-any.whl → 2.7.3__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 (297) 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/fig/__init__.py +352 -0
  79. scitex/{vis → fig}/backend/_parser.py +1 -1
  80. scitex/{vis → fig}/canvas.py +1 -1
  81. scitex/{vis → fig}/editor/_defaults.py +70 -5
  82. scitex/fig/editor/_edit.py +751 -0
  83. scitex/{vis → fig}/editor/_qt_editor.py +181 -1
  84. scitex/fig/editor/flask_editor/_bbox.py +1276 -0
  85. scitex/fig/editor/flask_editor/_core.py +624 -0
  86. scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
  87. scitex/fig/editor/flask_editor/_renderer.py +739 -0
  88. scitex/{vis → fig}/editor/flask_editor/templates/__init__.py +1 -1
  89. scitex/fig/editor/flask_editor/templates/_html.py +834 -0
  90. scitex/fig/editor/flask_editor/templates/_scripts.py +3136 -0
  91. scitex/{vis → fig}/editor/flask_editor/templates/_styles.py +625 -18
  92. scitex/{vis → fig}/io/__init__.py +13 -1
  93. scitex/fig/io/_bundle.py +973 -0
  94. scitex/{vis → fig}/io/_canvas.py +1 -1
  95. scitex/{vis → fig}/io/_data.py +1 -1
  96. scitex/{vis → fig}/io/_export.py +1 -1
  97. scitex/{vis → fig}/io/_load.py +1 -1
  98. scitex/{vis → fig}/io/_panel.py +1 -1
  99. scitex/{vis → fig}/io/_save.py +1 -1
  100. scitex/{vis → fig}/model/__init__.py +1 -1
  101. scitex/{vis → fig}/model/_annotations.py +1 -1
  102. scitex/{vis → fig}/model/_axes.py +1 -1
  103. scitex/{vis → fig}/model/_figure.py +1 -1
  104. scitex/{vis → fig}/model/_guides.py +1 -1
  105. scitex/{vis → fig}/model/_plot.py +1 -1
  106. scitex/{vis → fig}/model/_styles.py +1 -1
  107. scitex/{vis → fig}/utils/__init__.py +1 -1
  108. scitex/io/__init__.py +10 -26
  109. scitex/io/_bundle.py +434 -0
  110. scitex/io/_flush.py +5 -2
  111. scitex/io/_load.py +98 -0
  112. scitex/io/_load_modules/_H5Explorer.py +5 -2
  113. scitex/io/_load_modules/_canvas.py +2 -2
  114. scitex/io/_load_modules/_image.py +3 -4
  115. scitex/io/_load_modules/_txt.py +4 -2
  116. scitex/io/_metadata.py +34 -324
  117. scitex/io/_metadata_modules/__init__.py +46 -0
  118. scitex/io/_metadata_modules/_embed.py +70 -0
  119. scitex/io/_metadata_modules/_read.py +64 -0
  120. scitex/io/_metadata_modules/_utils.py +79 -0
  121. scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
  122. scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
  123. scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
  124. scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
  125. scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
  126. scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
  127. scitex/io/_metadata_modules/read_metadata_png.py +39 -0
  128. scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
  129. scitex/io/_qr_utils.py +5 -3
  130. scitex/io/_save.py +548 -30
  131. scitex/io/_save_modules/_canvas.py +3 -3
  132. scitex/io/_save_modules/_image.py +5 -9
  133. scitex/io/_save_modules/_tex.py +7 -4
  134. scitex/io/utils/h5_to_zarr.py +11 -9
  135. scitex/msword/__init__.py +255 -0
  136. scitex/msword/profiles.py +357 -0
  137. scitex/msword/reader.py +753 -0
  138. scitex/msword/utils.py +289 -0
  139. scitex/msword/writer.py +362 -0
  140. scitex/plt/__init__.py +5 -2
  141. scitex/plt/_subplots/_AxesWrapper.py +6 -6
  142. scitex/plt/_subplots/_AxisWrapper.py +15 -9
  143. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
  144. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
  145. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
  146. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
  147. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
  148. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
  149. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
  150. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
  151. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
  152. scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
  153. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
  154. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
  155. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
  156. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
  157. scitex/plt/_subplots/_FigWrapper.py +6 -6
  158. scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
  159. scitex/plt/_subplots/_export_as_csv.py +35 -5
  160. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
  161. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
  162. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
  163. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
  164. scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
  165. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
  166. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
  167. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
  168. scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
  169. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
  170. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
  171. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
  172. scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
  173. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
  174. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
  175. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
  176. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
  177. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
  178. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
  179. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
  180. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
  181. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
  182. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
  183. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
  184. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
  185. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
  186. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
  187. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
  188. scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
  189. scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
  190. scitex/plt/gallery/_generate.py +421 -14
  191. scitex/plt/io/__init__.py +53 -0
  192. scitex/plt/io/_bundle.py +490 -0
  193. scitex/plt/io/_layered_bundle.py +1343 -0
  194. scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
  195. scitex/plt/styles/__init__.py +14 -0
  196. scitex/plt/styles/presets.py +78 -0
  197. scitex/plt/utils/__init__.py +13 -1
  198. scitex/plt/utils/_collect_figure_metadata.py +10 -14
  199. scitex/plt/utils/_configure_mpl.py +6 -18
  200. scitex/plt/utils/_crop.py +32 -14
  201. scitex/plt/utils/_csv_column_naming.py +54 -0
  202. scitex/plt/utils/_figure_mm.py +116 -1
  203. scitex/plt/utils/_hitmap.py +1643 -0
  204. scitex/plt/utils/metadata/__init__.py +25 -0
  205. scitex/plt/utils/metadata/_core.py +9 -10
  206. scitex/plt/utils/metadata/_dimensions.py +6 -3
  207. scitex/plt/utils/metadata/_editable_export.py +405 -0
  208. scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
  209. scitex/schema/__init__.py +109 -16
  210. scitex/schema/_canvas.py +1 -1
  211. scitex/schema/_plot.py +1015 -0
  212. scitex/schema/_stats.py +2 -2
  213. scitex/stats/__init__.py +117 -0
  214. scitex/stats/io/__init__.py +29 -0
  215. scitex/stats/io/_bundle.py +156 -0
  216. scitex/tex/__init__.py +4 -0
  217. scitex/tex/_export.py +890 -0
  218. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/METADATA +11 -1
  219. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/RECORD +238 -170
  220. scitex/io/memo.md +0 -2827
  221. scitex/plt/REQUESTS.md +0 -191
  222. scitex/plt/_subplots/TODO.md +0 -53
  223. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
  224. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
  225. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
  226. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
  227. scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
  228. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
  229. scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
  230. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
  231. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
  232. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
  233. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
  234. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
  235. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
  236. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
  237. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
  238. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
  239. scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
  240. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
  241. scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
  242. scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
  243. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
  244. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
  245. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
  246. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
  247. scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
  248. scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
  249. scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
  250. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
  251. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
  252. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
  253. scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
  254. scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
  255. scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
  256. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
  257. scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
  258. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
  259. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
  260. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
  261. scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
  262. scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
  263. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
  264. scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
  265. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
  266. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
  267. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
  268. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
  269. scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
  270. scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
  271. scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
  272. scitex/vis/__init__.py +0 -177
  273. scitex/vis/editor/_edit.py +0 -390
  274. scitex/vis/editor/flask_editor/_bbox.py +0 -529
  275. scitex/vis/editor/flask_editor/_core.py +0 -168
  276. scitex/vis/editor/flask_editor/_renderer.py +0 -393
  277. scitex/vis/editor/flask_editor/templates/_html.py +0 -513
  278. scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
  279. /scitex/{vis → fig}/README.md +0 -0
  280. /scitex/{vis → fig}/backend/__init__.py +0 -0
  281. /scitex/{vis → fig}/backend/_export.py +0 -0
  282. /scitex/{vis → fig}/backend/_render.py +0 -0
  283. /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
  284. /scitex/{vis → fig}/editor/__init__.py +0 -0
  285. /scitex/{vis → fig}/editor/_dearpygui_editor.py +0 -0
  286. /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
  287. /scitex/{vis → fig}/editor/_mpl_editor.py +0 -0
  288. /scitex/{vis → fig}/editor/_tkinter_editor.py +0 -0
  289. /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
  290. /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
  291. /scitex/{vis → fig}/io/_directory.py +0 -0
  292. /scitex/{vis → fig}/model/_plot_types.py +0 -0
  293. /scitex/{vis → fig}/utils/_defaults.py +0 -0
  294. /scitex/{vis → fig}/utils/_validate.py +0 -0
  295. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/WHEEL +0 -0
  296. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/entry_points.txt +0 -0
  297. {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,1609 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Timestamp: "2025-12-01 12:00:00 (ywatanabe)"
4
- # File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py
5
- # ----------------------------------------
6
- import os
7
-
8
- __FILE__ = __file__
9
- __DIR__ = os.path.dirname(__FILE__)
10
- # ----------------------------------------
11
-
12
- from functools import wraps
13
- from typing import Any, Dict, List, Optional, Tuple, Union
14
-
15
- import matplotlib
16
- import numpy as np
17
- import pandas as pd
18
- from scipy.stats import gaussian_kde
19
-
20
- from scitex.pd import to_xyz
21
- from scitex.types import ArrayLike
22
- from scitex.plt.utils import mm_to_pt
23
-
24
-
25
- # ============================================================================
26
- # Constants for default styling (same as styles/_plot_defaults.py)
27
- # ============================================================================
28
- DEFAULT_LINE_WIDTH_MM = 0.2
29
- DEFAULT_MARKER_SIZE_MM = 0.8
30
- DEFAULT_FILL_ALPHA = 0.3
31
-
32
-
33
- class MatplotlibPlotMixin:
34
- """Mixin class for basic plotting operations."""
35
-
36
- def _get_ax_module(self):
37
- """Lazy import ax module to avoid circular imports."""
38
- from ....plt import ax as ax_module
39
-
40
- return ax_module
41
-
42
- def _apply_scitex_postprocess(
43
- self, method_name, result=None, kwargs=None, args=None
44
- ):
45
- """Apply scitex post-processing styling after plotting.
46
-
47
- This ensures all scitex wrapper methods get the same styling
48
- as matplotlib methods going through __getattr__ (tick locator, spines, etc.).
49
- """
50
- from scitex.plt.styles import apply_plot_postprocess
51
-
52
- apply_plot_postprocess(method_name, result, self._axis_mpl, kwargs or {}, args)
53
-
54
- def stx_image(
55
- self,
56
- arr_2d: ArrayLike,
57
- track: bool = True,
58
- id: Optional[str] = None,
59
- **kwargs,
60
- ) -> None:
61
- # Method Name for downstream csv exporting
62
- method_name = "stx_image"
63
-
64
- # Plotting with pure matplotlib methods under non-tracking context
65
- with self._no_tracking():
66
- self._axis_mpl = self._get_ax_module().stx_image(
67
- self._axis_mpl, arr_2d, **kwargs
68
- )
69
-
70
- # Tracking
71
- tracked_dict = {"image_df": pd.DataFrame(arr_2d)}
72
- if kwargs.get("xyz", False):
73
- tracked_dict["image_df"] = to_xyz(tracked_dict["image_df"])
74
- self._track(
75
- track,
76
- id,
77
- method_name,
78
- tracked_dict,
79
- None,
80
- )
81
-
82
- # Apply post-processing (tick locator, spines, etc.)
83
- self._apply_scitex_postprocess(method_name)
84
-
85
- return self._axis_mpl
86
-
87
- def stx_kde(
88
- self,
89
- values_1d: ArrayLike,
90
- cumulative=False,
91
- fill=False,
92
- track: bool = True,
93
- id: Optional[str] = None,
94
- **kwargs,
95
- ) -> None:
96
- # Method Name for downstream csv exporting
97
- method_name = "stx_kde"
98
-
99
- # Sample count as label
100
- n_samples = (~np.isnan(values_1d)).sum()
101
- if kwargs.get("label"):
102
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
103
-
104
- # Xlim (kwargs["xlim"] is not accepted in downstream plotters)
105
- xlim = kwargs.pop("xlim", None)
106
- if not xlim:
107
- xlim = (np.nanmin(values_1d), np.nanmax(values_1d))
108
-
109
- # X
110
- xx = np.linspace(xlim[0], xlim[1], int(1e3))
111
-
112
- # Y
113
- density = gaussian_kde(values_1d)(xx)
114
- density /= density.sum()
115
-
116
- # Cumulative
117
- if cumulative:
118
- density = np.cumsum(density)
119
-
120
- # Plotting with pure matplotlib methods under non-tracking context
121
- with self._no_tracking():
122
- # Get line width from kwargs or use default (0.2mm for KDE)
123
- from scitex.plt.utils import mm_to_pt
124
-
125
- if "linewidth" not in kwargs and "lw" not in kwargs:
126
- kwargs["linewidth"] = mm_to_pt(0.2) # Default 0.2mm for KDE
127
-
128
- # Set default color to black (customizable via color kwarg)
129
- if "color" not in kwargs and "c" not in kwargs:
130
- kwargs["color"] = "black"
131
-
132
- # Set default linestyle to dashed (customizable via linestyle kwarg)
133
- if "linestyle" not in kwargs and "ls" not in kwargs:
134
- kwargs["linestyle"] = "--"
135
-
136
- # Filled Line
137
- if fill:
138
- self._axis_mpl.fill_between(
139
- xx,
140
- density,
141
- **kwargs,
142
- )
143
- # Simple Line
144
- else:
145
- self._axis_mpl.plot(xx, density, **kwargs)
146
-
147
- # Tracking
148
- tracked_dict = {
149
- "x": xx,
150
- "kde": density,
151
- "n": n_samples,
152
- }
153
- self._track(
154
- track,
155
- id,
156
- method_name,
157
- tracked_dict,
158
- None,
159
- )
160
-
161
- # Apply post-processing (tick locator, spines, etc.)
162
- self._apply_scitex_postprocess(method_name)
163
-
164
- return self._axis_mpl
165
-
166
- def stx_conf_mat(
167
- self,
168
- conf_mat_2d: ArrayLike,
169
- x_labels: Optional[List[str]] = None,
170
- y_labels: Optional[List[str]] = None,
171
- title: str = "Confusion Matrix",
172
- cmap: str = "Blues",
173
- cbar: bool = True,
174
- cbar_kw: Dict[str, Any] = {},
175
- label_rotation_xy: Tuple[float, float] = (15, 15),
176
- x_extend_ratio: float = 1.0,
177
- y_extend_ratio: float = 1.0,
178
- calc_bacc: bool = False,
179
- track: bool = True,
180
- id: Optional[str] = None,
181
- **kwargs,
182
- ) -> None:
183
- # Method Name for downstream csv exporting
184
- method_name = "stx_conf_mat"
185
-
186
- # Plotting with pure matplotlib methods under non-tracking context
187
- with self._no_tracking():
188
- self._axis_mpl, bacc_val = self._get_ax_module().stx_conf_mat(
189
- self._axis_mpl,
190
- conf_mat_2d,
191
- x_labels=x_labels,
192
- y_labels=y_labels,
193
- title=title,
194
- cmap=cmap,
195
- cbar=cbar,
196
- cbar_kw=cbar_kw,
197
- label_rotation_xy=label_rotation_xy,
198
- x_extend_ratio=x_extend_ratio,
199
- y_extend_ratio=y_extend_ratio,
200
- calc_bacc=calc_bacc,
201
- **kwargs,
202
- )
203
-
204
- tracked_dict = {"balanced_accuracy": bacc_val}
205
- # Tracking
206
- self._track(track, id, method_name, tracked_dict, None)
207
-
208
- # Apply post-processing (tick locator, spines, etc.)
209
- self._apply_scitex_postprocess(method_name)
210
-
211
- return self._axis_mpl, bacc_val
212
-
213
- # @wraps removed to avoid circular import
214
- def stx_rectangle(
215
- self,
216
- xx: float,
217
- yy: float,
218
- width: float,
219
- height: float,
220
- track: bool = True,
221
- id: Optional[str] = None,
222
- **kwargs,
223
- ) -> None:
224
- # Method Name for downstream csv exporting
225
- method_name = "stx_rectangle"
226
-
227
- # Plotting with pure matplotlib methods under non-tracking context
228
- with self._no_tracking():
229
- self._axis_mpl = self._get_ax_module().stx_rectangle(
230
- self._axis_mpl, xx, yy, width, height, **kwargs
231
- )
232
-
233
- # Tracking - use "x", "y" to match formatter expected keys
234
- tracked_dict = {"x": xx, "y": yy, "width": width, "height": height}
235
- self._track(track, id, method_name, tracked_dict, None)
236
-
237
- # Apply post-processing (tick locator, spines, etc.)
238
- self._apply_scitex_postprocess(method_name)
239
-
240
- return self._axis_mpl
241
-
242
- # @wraps removed to avoid circular import
243
- def stx_fillv(
244
- self,
245
- starts_1d: ArrayLike,
246
- ends_1d: ArrayLike,
247
- color: str = "red",
248
- alpha: float = 0.2,
249
- track: bool = True,
250
- id: Optional[str] = None,
251
- **kwargs,
252
- ) -> None:
253
- # Method Name for downstream csv exporting
254
- method_name = "stx_fillv"
255
-
256
- # Plotting with pure matplotlib methods under non-tracking context
257
- with self._no_tracking():
258
- self._axis_mpl = self._get_ax_module().stx_fillv(
259
- self._axis_mpl, starts_1d, ends_1d, color=color, alpha=alpha
260
- )
261
-
262
- # Tracking
263
- tracked_dict = {"starts": starts_1d, "ends": ends_1d}
264
- self._track(track, id, method_name, tracked_dict, None)
265
-
266
- # Apply post-processing (tick locator, spines, etc.)
267
- self._apply_scitex_postprocess(method_name)
268
-
269
- return self._axis_mpl
270
-
271
- def stx_box(
272
- self,
273
- values_list: ArrayLike,
274
- colors: Optional[List] = None,
275
- track: bool = True,
276
- id: Optional[str] = None,
277
- **kwargs,
278
- ) -> dict:
279
- # Method Name for downstream csv exporting
280
- method_name = "stx_box"
281
-
282
- # Copy data
283
- _data = values_list.copy()
284
-
285
- # Sample count per group as label (show range if variable)
286
- if kwargs.get("label"):
287
- n_per_group = [len(g) for g in values_list]
288
- n_min, n_max = min(n_per_group), max(n_per_group)
289
- n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
290
- kwargs["label"] = kwargs["label"] + f" ($n$={n_str})"
291
-
292
- # Enable patch_artist for styling (fill colors, edges)
293
- if "patch_artist" not in kwargs:
294
- kwargs["patch_artist"] = True
295
-
296
- # Plotting with pure matplotlib methods under non-tracking context
297
- with self._no_tracking():
298
- result = self._axis_mpl.boxplot(values_list, **kwargs)
299
-
300
- # Tracking - calculate sample size per group
301
- n_per_group = [len(g) for g in values_list]
302
- tracked_dict = {
303
- "data": _data,
304
- "n": n_per_group,
305
- }
306
- self._track(track, id, method_name, tracked_dict, None)
307
-
308
- # Apply style_boxplot automatically for publication quality
309
- # Uses scitex palette by default, or custom colors if provided
310
- from scitex.plt.ax import style_boxplot
311
-
312
- style_boxplot(result, colors=colors)
313
-
314
- # Apply post-processing (tick locator, spines, etc.)
315
- self._apply_scitex_postprocess(method_name, result)
316
-
317
- return result
318
-
319
- def hist(
320
- self,
321
- x: ArrayLike,
322
- bins: Union[int, str, ArrayLike] = 10,
323
- range: Optional[Tuple[float, float]] = None,
324
- align_bins: bool = True,
325
- track: bool = True,
326
- id: Optional[str] = None,
327
- **kwargs,
328
- ) -> None:
329
- """
330
- Plot a histogram.
331
-
332
- This is an override of the standard matplotlib hist function to ensure
333
- that histogram bin data is properly tracked for CSV export and bins are
334
- aligned for histograms on the same axis.
335
-
336
- Args:
337
- x: Input data
338
- bins: Bin specification (count, edges, or algorithm)
339
- range: Optional histogram range (min, max)
340
- align_bins: Whether to align bins with other histograms on this axis
341
- track: Whether to track this operation
342
- id: Identifier for tracking
343
- **kwargs: Additional keywords passed to matplotlib hist
344
-
345
- Returns:
346
- Histogram output
347
- """
348
- # Method Name for downstream csv exporting
349
- method_name = "hist"
350
-
351
- # Get the axis ID for bin alignment
352
- axis_id = str(hash(self._axis_mpl))
353
- hist_id = id if id is not None else str(self.id)
354
-
355
- # Align bins if requested and not the first histogram on this axis
356
- if align_bins:
357
- from ....plt.utils import histogram_bin_manager
358
-
359
- bins, range = histogram_bin_manager.register_histogram(
360
- axis_id, hist_id, x, bins, range
361
- )
362
-
363
- # Plotting with pure matplotlib methods under non-tracking context
364
- with self._no_tracking():
365
- hist_data = self._axis_mpl.hist(x, bins=bins, range=range, **kwargs)
366
-
367
- # Save histogram result for CSV export
368
- # hist_data[0] = counts, hist_data[1] = bin_edges
369
- tracked_dict = {
370
- "args": (x,),
371
- "hist_result": (hist_data[0], hist_data[1]),
372
- "bins": bins,
373
- "range": range,
374
- }
375
-
376
- self._track(track, id, method_name, tracked_dict, kwargs)
377
-
378
- # Apply post-processing (tick locator, spines, etc.)
379
- self._apply_scitex_postprocess(method_name, hist_data)
380
-
381
- return hist_data
382
-
383
- # @wraps removed to avoid circular import
384
- def stx_raster(
385
- self,
386
- spike_times_list: List[ArrayLike],
387
- time: Optional[ArrayLike] = None,
388
- labels: Optional[List[str]] = None,
389
- colors: Optional[List[str]] = None,
390
- track: bool = True,
391
- id: Optional[str] = None,
392
- **kwargs,
393
- ) -> None:
394
- # Method Name for downstream csv exporting
395
- method_name = "stx_raster"
396
-
397
- # Plotting with pure matplotlib methods under non-tracking context
398
- with self._no_tracking():
399
- self._axis_mpl, raster_digit_df = self._get_ax_module().stx_raster(
400
- self._axis_mpl, spike_times_list, time=time
401
- )
402
-
403
- # Tracking
404
- tracked_dict = {"raster_digit_df": raster_digit_df}
405
- self._track(track, id, method_name, tracked_dict, None)
406
-
407
- # Apply post-processing (tick locator, spines, etc.)
408
- self._apply_scitex_postprocess(method_name)
409
-
410
- return self._axis_mpl, raster_digit_df
411
-
412
- # @wraps removed to avoid circular import
413
- def stx_ecdf(
414
- self,
415
- values_1d: ArrayLike,
416
- track: bool = True,
417
- id: Optional[str] = None,
418
- **kwargs,
419
- ) -> None:
420
- # Method Name for downstream csv exporting
421
- method_name = "stx_ecdf"
422
-
423
- # Plotting with pure matplotlib methods under non-tracking context
424
- with self._no_tracking():
425
- self._axis_mpl, ecdf_df = self._get_ax_module().stx_ecdf(
426
- self._axis_mpl, values_1d, **kwargs
427
- )
428
-
429
- # Tracking
430
- tracked_dict = {"ecdf_df": ecdf_df}
431
- self._track(track, id, method_name, tracked_dict, None)
432
-
433
- # Apply post-processing (tick locator, spines, etc.)
434
- self._apply_scitex_postprocess(method_name)
435
-
436
- return self._axis_mpl, ecdf_df
437
-
438
- # @wraps removed to avoid circular import
439
- def stx_joyplot(
440
- self,
441
- arrays: ArrayLike,
442
- track: bool = True,
443
- id: Optional[str] = None,
444
- **kwargs,
445
- ) -> None:
446
- # Method Name for downstream csv exporting
447
- method_name = "stx_joyplot"
448
-
449
- # Plotting with pure matplotlib methods under non-tracking context
450
- with self._no_tracking():
451
- self._axis_mpl = self._get_ax_module().stx_joyplot(
452
- self._axis_mpl, arrays, **kwargs
453
- )
454
-
455
- # Tracking - use "joyplot_data" to match formatter expected key
456
- tracked_dict = {"joyplot_data": arrays}
457
- self._track(track, id, method_name, tracked_dict, None)
458
-
459
- # Apply post-processing (tick locator, spines, etc.)
460
- self._apply_scitex_postprocess(method_name)
461
-
462
- return self._axis_mpl
463
-
464
- # @wraps removed to avoid circular import
465
- def stx_scatter_hist(
466
- self,
467
- x: ArrayLike,
468
- y: ArrayLike,
469
- hist_bins: int = 20,
470
- scatter_alpha: float = 0.6,
471
- scatter_size: float = 20,
472
- scatter_color: str = "blue",
473
- hist_color_x: str = "blue",
474
- hist_color_y: str = "red",
475
- hist_alpha: float = 0.5,
476
- scatter_ratio: float = 0.8,
477
- track: bool = True,
478
- id: Optional[str] = None,
479
- **kwargs,
480
- ) -> None:
481
- """Plot a scatter plot with marginal histograms."""
482
- # Method Name for downstream csv exporting
483
- method_name = "stx_scatter_hist"
484
-
485
- # Plotting with pure matplotlib methods under non-tracking context
486
- with self._no_tracking():
487
- self._axis_mpl, ax_histx, ax_histy, hist_data = (
488
- self._get_ax_module().stx_scatter_hist(
489
- self._axis_mpl,
490
- x,
491
- y,
492
- hist_bins=hist_bins,
493
- scatter_alpha=scatter_alpha,
494
- scatter_size=scatter_size,
495
- scatter_color=scatter_color,
496
- hist_color_x=hist_color_x,
497
- hist_color_y=hist_color_y,
498
- hist_alpha=hist_alpha,
499
- scatter_ratio=scatter_ratio,
500
- **kwargs,
501
- )
502
- )
503
-
504
- # Tracking
505
- tracked_dict = {
506
- "x": x,
507
- "y": y,
508
- "hist_x": hist_data["hist_x"],
509
- "hist_y": hist_data["hist_y"],
510
- "bin_edges_x": hist_data["bin_edges_x"],
511
- "bin_edges_y": hist_data["bin_edges_y"],
512
- }
513
- self._track(track, id, method_name, tracked_dict, None)
514
-
515
- # Apply post-processing (tick locator, spines, etc.)
516
- self._apply_scitex_postprocess(method_name)
517
-
518
- return self._axis_mpl, ax_histx, ax_histy, hist_data
519
-
520
- # @wraps removed to avoid circular import
521
- def stx_heatmap(
522
- self,
523
- values_2d: ArrayLike,
524
- x_labels: Optional[List[str]] = None,
525
- y_labels: Optional[List[str]] = None,
526
- cmap: str = "viridis",
527
- cbar_label: str = "ColorBar Label",
528
- value_format: str = "{x:.1f}",
529
- show_annot: bool = True,
530
- annot_color_lighter: str = "white",
531
- annot_color_darker: str = "black",
532
- track: bool = True,
533
- id: Optional[str] = None,
534
- **kwargs,
535
- ) -> Tuple[matplotlib.image.AxesImage, matplotlib.colorbar.Colorbar]:
536
- """Plot a heatmap on the axes."""
537
- # Method Name for downstream csv exporting
538
- method_name = "stx_heatmap"
539
-
540
- # Plotting with pure matplotlib methods under non-tracking context
541
- with self._no_tracking():
542
- ax, im, cbar = self._get_ax_module().stx_heatmap(
543
- self._axis_mpl,
544
- values_2d,
545
- x_labels=x_labels,
546
- y_labels=y_labels,
547
- cmap=cmap,
548
- cbar_label=cbar_label,
549
- value_format=value_format,
550
- show_annot=show_annot,
551
- annot_color_lighter=annot_color_lighter,
552
- annot_color_darker=annot_color_darker,
553
- **kwargs,
554
- )
555
-
556
- # Tracking
557
- tracked_dict = {
558
- "data": values_2d,
559
- "x_labels": x_labels,
560
- "y_labels": y_labels,
561
- }
562
- self._track(track, id, method_name, tracked_dict, None)
563
-
564
- # Apply post-processing (tick locator, spines, etc.)
565
- self._apply_scitex_postprocess(method_name)
566
-
567
- return ax, im, cbar
568
-
569
- # @wraps removed to avoid circular import
570
- def stx_violin(
571
- self,
572
- values_list: Union[pd.DataFrame, List, ArrayLike],
573
- x=None,
574
- y=None,
575
- hue=None,
576
- labels=None,
577
- colors=None,
578
- half=False,
579
- track: bool = True,
580
- id: Optional[str] = None,
581
- **kwargs,
582
- ) -> None:
583
- """Plot a violin plot."""
584
- # Method Name for downstream csv exporting
585
- method_name = "stx_violin"
586
-
587
- # Plotting with pure matplotlib methods under non-tracking context
588
- with self._no_tracking():
589
- # Handle the list-style input case
590
- if isinstance(values_list, list) and all(
591
- isinstance(item, (list, np.ndarray)) for item in values_list
592
- ):
593
- self._axis_mpl = self._get_ax_module().stx_violin(
594
- self._axis_mpl,
595
- values_list=values_list,
596
- labels=labels,
597
- colors=colors,
598
- half=half,
599
- **kwargs,
600
- )
601
- # Handle DataFrame or other inputs
602
- else:
603
- self._axis_mpl = self._get_ax_module().stx_violin(
604
- self._axis_mpl,
605
- data=values_list,
606
- x=x,
607
- y=y,
608
- hue=hue,
609
- half=half,
610
- **kwargs,
611
- )
612
-
613
- # Tracking
614
- tracked_dict = {
615
- "data": values_list,
616
- "x": x,
617
- "y": y,
618
- "hue": hue,
619
- "half": half,
620
- "labels": labels,
621
- "colors": colors,
622
- }
623
- self._track(track, id, method_name, tracked_dict, None)
624
-
625
- # Apply post-processing (tick locator, spines, etc.)
626
- self._apply_scitex_postprocess(method_name)
627
-
628
- return self._axis_mpl
629
-
630
- # def plot_area(
631
- # self,
632
- # x: ArrayLike,
633
- # y: ArrayLike,
634
- # stacked: bool = False,
635
- # fill: bool = True,
636
- # alpha: float = 0.5,
637
- # track: bool = True,
638
- # id: Optional[str] = None,
639
- # **kwargs,
640
- # ) -> None:
641
- # """Plot an area plot."""
642
- # # Method Name for downstream csv exporting
643
- # method_name = "plot_area"
644
-
645
- # # Plotting with pure matplotlib methods under non-tracking context
646
- # with self._no_tracking():
647
- # self._axis_mpl = self._get_ax_module().plot_area(
648
- # self._axis_mpl,
649
- # x,
650
- # y,
651
- # stacked=stacked,
652
- # fill=fill,
653
- # alpha=alpha,
654
- # **kwargs,
655
- # )
656
-
657
- # # Tracking
658
- # tracked_dict = {"x": x, "y": y}
659
- # self._track(track, id, method_name, tracked_dict, None)
660
-
661
- # return self._axis_mpl
662
-
663
- # def plot_radar(
664
- # self,
665
- # data: ArrayLike,
666
- # categories: List[str],
667
- # groups: Optional[List[str]] = None,
668
- # fill: bool = True,
669
- # alpha: float = 0.2,
670
- # grid_step: int = 5,
671
- # track: bool = True,
672
- # id: Optional[str] = None,
673
- # **kwargs,
674
- # ) -> None:
675
- # """Plot a radar/spider chart."""
676
- # # Method Name for downstream csv exporting
677
- # method_name = "plot_radar"
678
-
679
- # # Convert data to DataFrame if not already
680
- # if not isinstance(data, pd.DataFrame):
681
- # if groups is not None:
682
- # data = pd.DataFrame(data, columns=categories, index=groups)
683
- # else:
684
- # data = pd.DataFrame(data, columns=categories)
685
-
686
- # # Plotting with pure matplotlib methods under non-tracking context
687
- # with self._no_tracking():
688
- # self._axis_mpl = self._get_ax_module().plot_radar(
689
- # self._axis_mpl,
690
- # data,
691
- # categories=categories,
692
- # fill=fill,
693
- # alpha=alpha,
694
- # grid_step=grid_step,
695
- # **kwargs,
696
- # )
697
-
698
- # # Tracking
699
- # tracked_dict = {"radar_data": data}
700
- # self._track(track, id, method_name, tracked_dict, None)
701
-
702
- # return self._axis_mpl
703
-
704
- # def plot_bubble(
705
- # self,
706
- # x: ArrayLike,
707
- # y: ArrayLike,
708
- # size: ArrayLike,
709
- # color: Optional[ArrayLike] = None,
710
- # size_scale: float = 1000.0,
711
- # alpha: float = 0.6,
712
- # colormap: str = "viridis",
713
- # show_colorbar: bool = True,
714
- # colorbar_label: str = "",
715
- # track: bool = True,
716
- # id: Optional[str] = None,
717
- # **kwargs,
718
- # ) -> None:
719
- # """Plot a bubble chart."""
720
- # # Method Name for downstream csv exporting
721
- # method_name = "plot_bubble"
722
-
723
- # # Plotting with pure matplotlib methods under non-tracking context
724
- # with self._no_tracking():
725
- # self._axis_mpl = self._get_ax_module().plot_bubble(
726
- # self._axis_mpl,
727
- # x,
728
- # y,
729
- # size,
730
- # color=color,
731
- # size_scale=size_scale,
732
- # alpha=alpha,
733
- # colormap=colormap,
734
- # show_colorbar=show_colorbar,
735
- # colorbar_label=colorbar_label,
736
- # **kwargs,
737
- # )
738
-
739
- # # Tracking
740
- # tracked_dict = {"x": x, "y": y, "size": size}
741
- # if color is not None:
742
- # tracked_dict["color"] = color
743
-
744
- # self._track(track, id, method_name, tracked_dict, None)
745
-
746
- # return self._axis_mpl
747
-
748
- # def plot_ridgeline(
749
- # self,
750
- # data: ArrayLike,
751
- # labels: Optional[List[str]] = None,
752
- # overlap: float = 0.8,
753
- # fill: bool = True,
754
- # alpha: float = 0.6,
755
- # colormap: str = "viridis",
756
- # bandwidth: Optional[float] = None,
757
- # track: bool = True,
758
- # id: Optional[str] = None,
759
- # **kwargs,
760
- # ) -> None:
761
- # """Plot a ridgeline plot (similar to joyplot but with KDE)."""
762
- # # Method Name for downstream csv exporting
763
- # method_name = "plot_ridgeline"
764
-
765
- # # Ensure data is in correct format
766
- # if isinstance(data, pd.DataFrame):
767
- # _data = [data[col].dropna().values for col in data.columns]
768
- # if labels is None:
769
- # labels = list(data.columns)
770
- # elif isinstance(data, list):
771
- # _data = data
772
- # else:
773
- # _data = [data]
774
-
775
- # # Plotting with pure matplotlib methods under non-tracking context
776
- # with self._no_tracking():
777
- # self._axis_mpl, ridge_data = self._get_ax_module().plot_ridgeline(
778
- # self._axis_mpl,
779
- # _data,
780
- # labels=labels,
781
- # overlap=overlap,
782
- # fill=fill,
783
- # alpha=alpha,
784
- # colormap=colormap,
785
- # bandwidth=bandwidth,
786
- # **kwargs,
787
- # )
788
-
789
- # # Tracking
790
- # tracked_dict = {
791
- # "ridgeline_data": _data,
792
- # "kde_x": ridge_data["kde_x"],
793
- # "kde_y": ridge_data["kde_y"],
794
- # }
795
- # if labels is not None:
796
- # tracked_dict["labels"] = labels
797
- # self._track(track, id, method_name, tracked_dict, None)
798
-
799
- # return self._axis_mpl, ridge_data
800
-
801
- # def plot_parallel_coordinates(
802
- # self,
803
- # data: pd.DataFrame,
804
- # class_column: Optional[str] = None,
805
- # colormap: str = "viridis",
806
- # alpha: float = 0.5,
807
- # track: bool = True,
808
- # id: Optional[str] = None,
809
- # **kwargs,
810
- # ) -> None:
811
- # """Plot parallel coordinates."""
812
- # # Method Name for downstream csv exporting
813
- # method_name = "plot_parallel_coordinates"
814
-
815
- # # Plotting with pure matplotlib methods under non-tracking context
816
- # with self._no_tracking():
817
- # self._axis_mpl = self._get_ax_module().plot_parallel_coordinates(
818
- # self._axis_mpl,
819
- # data,
820
- # class_column=class_column,
821
- # colormap=colormap,
822
- # alpha=alpha,
823
- # **kwargs,
824
- # )
825
-
826
- # # Tracking
827
- # tracked_dict = {"parallel_data": data}
828
- # self._track(track, id, method_name, tracked_dict, None)
829
-
830
- # return self._axis_mpl
831
-
832
- # @wraps removed to avoid circular import
833
- def stx_line(
834
- self,
835
- values_1d: ArrayLike,
836
- xx: Optional[ArrayLike] = None,
837
- track: bool = True,
838
- id: Optional[str] = None,
839
- **kwargs,
840
- ) -> None:
841
- """Plot a simple line."""
842
- # Method Name for downstream csv exporting
843
- method_name = "stx_line"
844
-
845
- # Plotting with pure matplotlib methods under non-tracking context
846
- with self._no_tracking():
847
- self._axis_mpl, plot_df = self._get_ax_module().stx_line(
848
- self._axis_mpl, values_1d, xx=xx, **kwargs
849
- )
850
-
851
- # Tracking
852
- tracked_dict = {"plot_df": plot_df}
853
- self._track(track, id, method_name, tracked_dict, kwargs)
854
-
855
- # Apply post-processing (tick locator, spines, etc.)
856
- self._apply_scitex_postprocess(method_name)
857
-
858
- return self._axis_mpl, plot_df
859
-
860
- # @wraps removed to avoid circular import
861
- def stx_mean_std(
862
- self,
863
- values_2d: ArrayLike,
864
- xx: Optional[ArrayLike] = None,
865
- sd: float = 1,
866
- track: bool = True,
867
- id: Optional[str] = None,
868
- **kwargs,
869
- ) -> None:
870
- """Plot mean line with standard deviation shading."""
871
- # Method Name for downstream csv exporting
872
- method_name = "stx_mean_std"
873
-
874
- # Plotting with pure matplotlib methods under non-tracking context
875
- with self._no_tracking():
876
- self._axis_mpl, plot_df = self._get_ax_module().stx_mean_std(
877
- self._axis_mpl, values_2d, xx=xx, sd=sd, **kwargs
878
- )
879
-
880
- # Tracking
881
- tracked_dict = {"plot_df": plot_df}
882
- self._track(track, id, method_name, tracked_dict, None)
883
-
884
- # Apply post-processing (tick locator, spines, etc.)
885
- self._apply_scitex_postprocess(method_name)
886
-
887
- return self._axis_mpl, plot_df
888
-
889
- # @wraps removed to avoid circular import
890
- def stx_mean_ci(
891
- self,
892
- values_2d: ArrayLike,
893
- xx: Optional[ArrayLike] = None,
894
- perc: float = 95,
895
- track: bool = True,
896
- id: Optional[str] = None,
897
- **kwargs,
898
- ) -> None:
899
- """Plot mean line with confidence interval shading."""
900
- # Method Name for downstream csv exporting
901
- method_name = "stx_mean_ci"
902
-
903
- # Plotting with pure matplotlib methods under non-tracking context
904
- with self._no_tracking():
905
- self._axis_mpl, plot_df = self._get_ax_module().stx_mean_ci(
906
- self._axis_mpl, values_2d, xx=xx, perc=perc, **kwargs
907
- )
908
-
909
- # Tracking
910
- tracked_dict = {"plot_df": plot_df}
911
- self._track(track, id, method_name, tracked_dict, None)
912
-
913
- # Apply post-processing (tick locator, spines, etc.)
914
- self._apply_scitex_postprocess(method_name)
915
-
916
- return self._axis_mpl, plot_df
917
-
918
- # @wraps removed to avoid circular import
919
- def stx_median_iqr(
920
- self,
921
- values_2d: ArrayLike,
922
- xx: Optional[ArrayLike] = None,
923
- track: bool = True,
924
- id: Optional[str] = None,
925
- **kwargs,
926
- ) -> None:
927
- """Plot median line with interquartile range shading."""
928
- # Method Name for downstream csv exporting
929
- method_name = "stx_median_iqr"
930
-
931
- # Plotting with pure matplotlib methods under non-tracking context
932
- with self._no_tracking():
933
- self._axis_mpl, plot_df = self._get_ax_module().stx_median_iqr(
934
- self._axis_mpl, values_2d, xx=xx, **kwargs
935
- )
936
-
937
- # Tracking
938
- tracked_dict = {"plot_df": plot_df}
939
- self._track(track, id, method_name, tracked_dict, None)
940
-
941
- # Apply post-processing (tick locator, spines, etc.)
942
- self._apply_scitex_postprocess(method_name)
943
-
944
- return self._axis_mpl, plot_df
945
-
946
- # @wraps removed to avoid circular import
947
- def stx_shaded_line(
948
- self,
949
- xs: ArrayLike,
950
- ys_lower: ArrayLike,
951
- ys_middle: ArrayLike,
952
- ys_upper: ArrayLike,
953
- color: str or Optional[Union[str, List[str]]] = None,
954
- label: str or Optional[Union[str, List[str]]] = None,
955
- track: bool = True,
956
- id: Optional[str] = None,
957
- **kwargs,
958
- ) -> None:
959
- """Plot a line with shaded area between lower and upper bounds."""
960
- # Method Name for downstream csv exporting
961
- method_name = "stx_shaded_line"
962
-
963
- # Plotting with pure matplotlib methods under non-tracking context
964
- with self._no_tracking():
965
- self._axis_mpl, plot_df = self._get_ax_module().stx_shaded_line(
966
- self._axis_mpl,
967
- xs,
968
- ys_lower,
969
- ys_middle,
970
- ys_upper,
971
- color=color,
972
- label=label,
973
- **kwargs,
974
- )
975
-
976
- # Tracking
977
- tracked_dict = {"plot_df": plot_df}
978
- self._track(track, id, method_name, tracked_dict, None)
979
-
980
- # Apply post-processing (tick locator, spines, etc.)
981
- self._apply_scitex_postprocess(method_name)
982
-
983
- return self._axis_mpl, plot_df
984
-
985
- # =========================================================================
986
- # stx_ aliases for standard matplotlib methods
987
- # These provide a consistent stx_ prefix for all scitex wrapper methods
988
- # =========================================================================
989
-
990
- def stx_bar(
991
- self, x, height, track: bool = True, id: Optional[str] = None, **kwargs
992
- ):
993
- """Bar plot with scitex styling and tracking.
994
-
995
- Parameters
996
- ----------
997
- x : array-like
998
- The x coordinates of the bars
999
- height : array-like
1000
- The heights of the bars
1001
- track : bool
1002
- Whether to track data for CSV export
1003
- id : str, optional
1004
- Identifier for tracking
1005
- **kwargs
1006
- Additional arguments passed to matplotlib bar
1007
- """
1008
- method_name = "stx_bar"
1009
-
1010
- # Add sample size to label if provided
1011
- if kwargs.get("label"):
1012
- n_samples = len(x)
1013
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1014
-
1015
- with self._no_tracking():
1016
- result = self._axis_mpl.bar(x, height, **kwargs)
1017
-
1018
- # Track bar data
1019
- tracked_dict = {"bar_df": pd.DataFrame({"x": x, "height": height})}
1020
- self._track(track, id, method_name, tracked_dict, None)
1021
-
1022
- # Apply style_barplot automatically for publication quality
1023
- from scitex.plt.ax import style_barplot
1024
-
1025
- style_barplot(result)
1026
-
1027
- # Apply post-processing (tick locator, spines, etc.)
1028
- self._apply_scitex_postprocess(method_name, result)
1029
-
1030
- return result
1031
-
1032
- def stx_barh(
1033
- self, y, width, track: bool = True, id: Optional[str] = None, **kwargs
1034
- ):
1035
- """Horizontal bar plot with scitex styling and tracking.
1036
-
1037
- Parameters
1038
- ----------
1039
- y : array-like
1040
- The y coordinates of the bars
1041
- width : array-like
1042
- The widths of the bars
1043
- track : bool
1044
- Whether to track data for CSV export
1045
- id : str, optional
1046
- Identifier for tracking
1047
- **kwargs
1048
- Additional arguments passed to matplotlib barh
1049
- """
1050
- method_name = "stx_barh"
1051
-
1052
- # Add sample size to label if provided
1053
- if kwargs.get("label"):
1054
- n_samples = len(y)
1055
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1056
-
1057
- with self._no_tracking():
1058
- result = self._axis_mpl.barh(y, width, **kwargs)
1059
-
1060
- # Track bar data
1061
- tracked_dict = {"barh_df": pd.DataFrame({"y": y, "width": width})}
1062
- self._track(track, id, method_name, tracked_dict, None)
1063
-
1064
- # Apply post-processing (tick locator, spines, etc.)
1065
- self._apply_scitex_postprocess(method_name, result)
1066
-
1067
- return result
1068
-
1069
- def stx_scatter(self, x, y, track: bool = True, id: Optional[str] = None, **kwargs):
1070
- """Scatter plot with scitex styling and tracking.
1071
-
1072
- Parameters
1073
- ----------
1074
- x : array-like
1075
- The x coordinates of the points
1076
- y : array-like
1077
- The y coordinates of the points
1078
- track : bool
1079
- Whether to track data for CSV export
1080
- id : str, optional
1081
- Identifier for tracking
1082
- **kwargs
1083
- Additional arguments passed to matplotlib scatter
1084
- """
1085
- method_name = "stx_scatter"
1086
-
1087
- # Add sample size to label if provided
1088
- if kwargs.get("label"):
1089
- n_samples = len(x)
1090
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1091
-
1092
- with self._no_tracking():
1093
- result = self._axis_mpl.scatter(x, y, **kwargs)
1094
-
1095
- # Track scatter data
1096
- tracked_dict = {"scatter_df": pd.DataFrame({"x": x, "y": y})}
1097
- self._track(track, id, method_name, tracked_dict, None)
1098
-
1099
- # Apply style_scatter automatically for publication quality
1100
- from scitex.plt.ax import style_scatter
1101
-
1102
- style_scatter(result)
1103
-
1104
- # Apply post-processing (tick locator, spines, etc.)
1105
- self._apply_scitex_postprocess(method_name, result)
1106
-
1107
- return result
1108
-
1109
- def stx_errorbar(
1110
- self,
1111
- x,
1112
- y,
1113
- yerr=None,
1114
- xerr=None,
1115
- track: bool = True,
1116
- id: Optional[str] = None,
1117
- **kwargs,
1118
- ):
1119
- """Error bar plot with scitex styling and tracking.
1120
-
1121
- Parameters
1122
- ----------
1123
- x : array-like
1124
- The x coordinates of the data points
1125
- y : array-like
1126
- The y coordinates of the data points
1127
- yerr : array-like, optional
1128
- The y error values
1129
- xerr : array-like, optional
1130
- The x error values
1131
- track : bool
1132
- Whether to track data for CSV export
1133
- id : str, optional
1134
- Identifier for tracking
1135
- **kwargs
1136
- Additional arguments passed to matplotlib errorbar
1137
- """
1138
- method_name = "stx_errorbar"
1139
-
1140
- # Add sample size to label if provided
1141
- if kwargs.get("label"):
1142
- n_samples = len(x)
1143
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1144
-
1145
- with self._no_tracking():
1146
- result = self._axis_mpl.errorbar(x, y, yerr=yerr, xerr=xerr, **kwargs)
1147
-
1148
- # Track errorbar data
1149
- df_dict = {"x": x, "y": y}
1150
- if yerr is not None:
1151
- df_dict["yerr"] = yerr
1152
- if xerr is not None:
1153
- df_dict["xerr"] = xerr
1154
- tracked_dict = {"errorbar_df": pd.DataFrame(df_dict)}
1155
- self._track(track, id, method_name, tracked_dict, None)
1156
-
1157
- # Apply style_errorbar automatically for publication quality
1158
- from scitex.plt.ax import style_errorbar
1159
-
1160
- style_errorbar(result)
1161
-
1162
- # Apply post-processing (tick locator, spines, etc.)
1163
- self._apply_scitex_postprocess(method_name, result)
1164
-
1165
- return result
1166
-
1167
- def stx_fill_between(
1168
- self, x, y1, y2=0, track: bool = True, id: Optional[str] = None, **kwargs
1169
- ):
1170
- """Fill between plot with scitex styling and tracking.
1171
-
1172
- Parameters
1173
- ----------
1174
- x : array-like
1175
- The x coordinates
1176
- y1 : array-like
1177
- The first y boundary
1178
- y2 : array-like or scalar, optional
1179
- The second y boundary (default 0)
1180
- track : bool
1181
- Whether to track data for CSV export
1182
- id : str, optional
1183
- Identifier for tracking
1184
- **kwargs
1185
- Additional arguments passed to matplotlib fill_between
1186
- """
1187
- method_name = "stx_fill_between"
1188
-
1189
- with self._no_tracking():
1190
- result = self._axis_mpl.fill_between(x, y1, y2, **kwargs)
1191
-
1192
- # Track fill_between data
1193
- tracked_dict = {
1194
- "fill_between_df": pd.DataFrame(
1195
- {
1196
- "x": x,
1197
- "y1": y1,
1198
- "y2": y2 if hasattr(y2, "__len__") else [y2] * len(x),
1199
- }
1200
- )
1201
- }
1202
- self._track(track, id, method_name, tracked_dict, None)
1203
-
1204
- # Apply post-processing (tick locator, spines, etc.)
1205
- self._apply_scitex_postprocess(method_name, result)
1206
-
1207
- return result
1208
-
1209
- def stx_contour(
1210
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1211
- ):
1212
- """Contour plot with scitex styling and tracking.
1213
-
1214
- Parameters
1215
- ----------
1216
- *args
1217
- Positional arguments passed to matplotlib contour (X, Y, Z)
1218
- track : bool
1219
- Whether to track data for CSV export
1220
- id : str, optional
1221
- Identifier for tracking
1222
- **kwargs
1223
- Additional arguments passed to matplotlib contour
1224
- """
1225
- method_name = "stx_contour"
1226
-
1227
- with self._no_tracking():
1228
- result = self._axis_mpl.contour(*args, **kwargs)
1229
-
1230
- # Track contour data
1231
- if len(args) >= 3:
1232
- X, Y, Z = args[0], args[1], args[2]
1233
- tracked_dict = {
1234
- "contour_df": pd.DataFrame(
1235
- {"X": np.ravel(X), "Y": np.ravel(Y), "Z": np.ravel(Z)}
1236
- )
1237
- }
1238
- self._track(track, id, method_name, tracked_dict, None)
1239
-
1240
- # Apply post-processing (tick locator, spines, etc.)
1241
- self._apply_scitex_postprocess(method_name, result)
1242
-
1243
- return result
1244
-
1245
- def stx_imshow(self, data, track: bool = True, id: Optional[str] = None, **kwargs):
1246
- """Image display with scitex styling and tracking.
1247
-
1248
- Parameters
1249
- ----------
1250
- data : array-like
1251
- 2D array of image data
1252
- track : bool
1253
- Whether to track data for CSV export
1254
- id : str, optional
1255
- Identifier for tracking
1256
- **kwargs
1257
- Additional arguments passed to matplotlib imshow
1258
- """
1259
- method_name = "stx_imshow"
1260
-
1261
- with self._no_tracking():
1262
- result = self._axis_mpl.imshow(data, **kwargs)
1263
-
1264
- # Track image data
1265
- if hasattr(data, "shape") and len(data.shape) == 2:
1266
- n_rows, n_cols = data.shape
1267
- df = pd.DataFrame(data, columns=[f"col_{i}" for i in range(n_cols)])
1268
- else:
1269
- df = pd.DataFrame(data)
1270
- tracked_dict = {"imshow_df": df}
1271
- self._track(track, id, method_name, tracked_dict, None)
1272
-
1273
- # Apply post-processing (tick locator, spines, etc.)
1274
- self._apply_scitex_postprocess(method_name, result)
1275
-
1276
- return result
1277
-
1278
- def stx_boxplot(
1279
- self,
1280
- data,
1281
- colors: Optional[List] = None,
1282
- track: bool = True,
1283
- id: Optional[str] = None,
1284
- **kwargs,
1285
- ):
1286
- """Boxplot with scitex styling and tracking (alias for stx_box).
1287
-
1288
- Parameters
1289
- ----------
1290
- data : list of array-like
1291
- List of data arrays for each box
1292
- colors : list, optional
1293
- Colors for each box
1294
- track : bool
1295
- Whether to track data for CSV export
1296
- id : str, optional
1297
- Identifier for tracking
1298
- **kwargs
1299
- Additional arguments passed to matplotlib boxplot
1300
- """
1301
- return self.stx_box(data, colors=colors, track=track, id=id, **kwargs)
1302
-
1303
- def stx_violinplot(
1304
- self,
1305
- data,
1306
- colors: Optional[List] = None,
1307
- track: bool = True,
1308
- id: Optional[str] = None,
1309
- **kwargs,
1310
- ):
1311
- """Violinplot with scitex styling and tracking (alias for stx_violin).
1312
-
1313
- Parameters
1314
- ----------
1315
- data : list of array-like or DataFrame
1316
- Data for violin plot
1317
- colors : list, optional
1318
- Colors for each violin
1319
- track : bool
1320
- Whether to track data for CSV export
1321
- id : str, optional
1322
- Identifier for tracking
1323
- **kwargs
1324
- Additional arguments passed to stx_violin
1325
- """
1326
- return self.stx_violin(data, colors=colors, track=track, id=id, **kwargs)
1327
-
1328
- # Standard matplotlib plot methods with plot_ prefix
1329
- def plot_bar(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
1330
- """Wrapper for matplotlib bar plot with tracking support."""
1331
- method_name = "plot_bar"
1332
-
1333
- with self._no_tracking():
1334
- result = self._axis_mpl.bar(*args, **kwargs)
1335
-
1336
- # Track bar data
1337
- if len(args) >= 2:
1338
- tracked_dict = {"bar_df": pd.DataFrame({"x": args[0], "height": args[1]})}
1339
- self._track(track, id, method_name, tracked_dict, None)
1340
-
1341
- # Apply post-processing (tick locator, spines, etc.)
1342
- self._apply_scitex_postprocess(method_name, result)
1343
-
1344
- return result
1345
-
1346
- def plot_barh(self, *args, track: bool = True, id: Optional[str] = None, **kwargs):
1347
- """Wrapper for matplotlib horizontal bar plot with tracking support."""
1348
- method_name = "plot_barh"
1349
-
1350
- with self._no_tracking():
1351
- result = self._axis_mpl.barh(*args, **kwargs)
1352
-
1353
- # Track bar data
1354
- if len(args) >= 2:
1355
- tracked_dict = {"barh_df": pd.DataFrame({"y": args[0], "width": args[1]})}
1356
- self._track(track, id, method_name, tracked_dict, None)
1357
-
1358
- # Apply post-processing (tick locator, spines, etc.)
1359
- self._apply_scitex_postprocess(method_name, result)
1360
-
1361
- return result
1362
-
1363
- def plot_scatter(
1364
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1365
- ):
1366
- """Wrapper for matplotlib scatter plot with tracking support."""
1367
- method_name = "plot_scatter"
1368
-
1369
- # Add sample size to label if provided
1370
- if kwargs.get("label") and len(args) >= 1:
1371
- n_samples = len(args[0])
1372
- kwargs["label"] = f"{kwargs['label']} ($n$={n_samples})"
1373
-
1374
- with self._no_tracking():
1375
- result = self._axis_mpl.scatter(*args, **kwargs)
1376
-
1377
- # Track scatter data
1378
- if len(args) >= 2:
1379
- tracked_dict = {"scatter_df": pd.DataFrame({"x": args[0], "y": args[1]})}
1380
- self._track(track, id, method_name, tracked_dict, None)
1381
-
1382
- # Apply post-processing (tick locator, spines, etc.)
1383
- self._apply_scitex_postprocess(method_name, result)
1384
-
1385
- return result
1386
-
1387
- def plot_errorbar(
1388
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1389
- ):
1390
- """Wrapper for matplotlib errorbar plot with tracking support."""
1391
- method_name = "plot_errorbar"
1392
-
1393
- with self._no_tracking():
1394
- result = self._axis_mpl.errorbar(*args, **kwargs)
1395
-
1396
- # Track errorbar data
1397
- if len(args) >= 2:
1398
- df_dict = {"x": args[0], "y": args[1]}
1399
- if "yerr" in kwargs:
1400
- df_dict["yerr"] = kwargs["yerr"]
1401
- if "xerr" in kwargs:
1402
- df_dict["xerr"] = kwargs["xerr"]
1403
- tracked_dict = {"errorbar_df": pd.DataFrame(df_dict)}
1404
- self._track(track, id, method_name, tracked_dict, None)
1405
-
1406
- # Apply post-processing (tick locator, spines, etc.)
1407
- self._apply_scitex_postprocess(method_name, result)
1408
-
1409
- return result
1410
-
1411
- def plot_fill_between(
1412
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1413
- ):
1414
- """Wrapper for matplotlib fill_between with tracking support."""
1415
- method_name = "plot_fill_between"
1416
-
1417
- with self._no_tracking():
1418
- result = self._axis_mpl.fill_between(*args, **kwargs)
1419
-
1420
- # Track fill_between data
1421
- if len(args) >= 3:
1422
- tracked_dict = {
1423
- "fill_between_df": pd.DataFrame(
1424
- {"x": args[0], "y1": args[1], "y2": args[2] if len(args) > 2 else 0}
1425
- )
1426
- }
1427
- self._track(track, id, method_name, tracked_dict, None)
1428
-
1429
- # Apply post-processing (tick locator, spines, etc.)
1430
- self._apply_scitex_postprocess(method_name, result)
1431
-
1432
- return result
1433
-
1434
- def plot_contour(
1435
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1436
- ):
1437
- """Wrapper for matplotlib contour plot with tracking support."""
1438
- method_name = "plot_contour"
1439
-
1440
- with self._no_tracking():
1441
- result = self._axis_mpl.contour(*args, **kwargs)
1442
-
1443
- # Track contour data
1444
- if len(args) >= 3:
1445
- # Flatten 2D arrays for CSV export
1446
- X, Y, Z = args[0], args[1], args[2]
1447
- tracked_dict = {
1448
- "contour_df": pd.DataFrame(
1449
- {"X": np.ravel(X), "Y": np.ravel(Y), "Z": np.ravel(Z)}
1450
- )
1451
- }
1452
- self._track(track, id, method_name, tracked_dict, None)
1453
-
1454
- # Apply post-processing (tick locator, spines, etc.)
1455
- self._apply_scitex_postprocess(method_name, result)
1456
-
1457
- return result
1458
-
1459
- def plot_imshow(
1460
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1461
- ):
1462
- """Wrapper for matplotlib imshow with tracking support."""
1463
- method_name = "plot_imshow"
1464
-
1465
- with self._no_tracking():
1466
- result = self._axis_mpl.imshow(*args, **kwargs)
1467
-
1468
- # Track image data
1469
- if len(args) >= 1:
1470
- # Create DataFrame with unique column names to avoid duplicates
1471
- img_data = args[0]
1472
- if hasattr(img_data, "shape") and len(img_data.shape) == 2:
1473
- n_rows, n_cols = img_data.shape
1474
- # Use column names like "col_0", "col_1", etc. instead of just integers
1475
- df = pd.DataFrame(img_data, columns=[f"col_{i}" for i in range(n_cols)])
1476
- else:
1477
- df = pd.DataFrame(args[0])
1478
- tracked_dict = {"imshow_df": df}
1479
- self._track(track, id, method_name, tracked_dict, None)
1480
-
1481
- # Apply post-processing (tick locator, spines, etc.)
1482
- self._apply_scitex_postprocess(method_name, result)
1483
-
1484
- return result
1485
-
1486
- def plot_boxplot(
1487
- self,
1488
- *args,
1489
- colors: Optional[List] = None,
1490
- track: bool = True,
1491
- id: Optional[str] = None,
1492
- **kwargs,
1493
- ):
1494
- """Wrapper for matplotlib boxplot with tracking support and auto-styling."""
1495
- method_name = "plot_boxplot"
1496
-
1497
- # Add sample size per group to label if provided (show range if variable)
1498
- if kwargs.get("label") and len(args) >= 1:
1499
- data = args[0]
1500
- if isinstance(data, list):
1501
- n_per_group = [len(g) for g in data]
1502
- n_min, n_max = min(n_per_group), max(n_per_group)
1503
- n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
1504
- kwargs["label"] = f"{kwargs['label']} ($n$={n_str})"
1505
-
1506
- # Enable patch_artist for styling (fill colors, edges)
1507
- if "patch_artist" not in kwargs:
1508
- kwargs["patch_artist"] = True
1509
-
1510
- with self._no_tracking():
1511
- result = self._axis_mpl.boxplot(*args, **kwargs)
1512
-
1513
- # Track boxplot data
1514
- if len(args) >= 1:
1515
- data = args[0]
1516
- if isinstance(data, list):
1517
- tracked_dict = {"boxplot_df": pd.DataFrame(data)}
1518
- else:
1519
- tracked_dict = {"boxplot_df": pd.DataFrame({"data": data})}
1520
- self._track(track, id, method_name, tracked_dict, None)
1521
-
1522
- # Apply style_boxplot automatically for publication quality
1523
- # Uses scitex palette by default, or custom colors if provided
1524
- from scitex.plt.ax import style_boxplot
1525
-
1526
- style_boxplot(result, colors=colors)
1527
-
1528
- # Apply post-processing (tick locator, spines, etc.)
1529
- self._apply_scitex_postprocess(method_name, result)
1530
-
1531
- return result
1532
-
1533
- def plot_violinplot(
1534
- self, *args, track: bool = True, id: Optional[str] = None, **kwargs
1535
- ):
1536
- """Wrapper for matplotlib violinplot with tracking support."""
1537
- method_name = "plot_violinplot"
1538
-
1539
- # Add sample size per group to label if provided (show range if variable)
1540
- if kwargs.get("label") and len(args) >= 1:
1541
- data = args[0]
1542
- if isinstance(data, list):
1543
- n_per_group = [len(g) for g in data]
1544
- n_min, n_max = min(n_per_group), max(n_per_group)
1545
- n_str = str(n_min) if n_min == n_max else f"{n_min}-{n_max}"
1546
- kwargs["label"] = f"{kwargs['label']} ($n$={n_str})"
1547
-
1548
- with self._no_tracking():
1549
- result = self._axis_mpl.violinplot(*args, **kwargs)
1550
-
1551
- # Track violin data
1552
- if len(args) >= 1:
1553
- data = args[0]
1554
- if isinstance(data, list):
1555
- tracked_dict = {"violinplot_df": pd.DataFrame(data)}
1556
- else:
1557
- tracked_dict = {"violinplot_df": pd.DataFrame({"data": data})}
1558
- self._track(track, id, method_name, tracked_dict, None)
1559
-
1560
- # Apply post-processing (tick locator, spines, etc.)
1561
- self._apply_scitex_postprocess(method_name, result, kwargs, args)
1562
-
1563
- return result
1564
-
1565
-
1566
-
1567
- # EOF
1568
-
1569
-
1570
- # =============================================================================
1571
- # Deprecated plot_ aliases for stx_ methods (backward compatibility)
1572
- # These are defined outside the class to use the decorator properly
1573
- # =============================================================================
1574
- from scitex.decorators import deprecated
1575
-
1576
-
1577
- def _add_deprecated_aliases():
1578
- """Add deprecated plot_ method aliases to MatplotlibPlotMixin."""
1579
- deprecated_methods = [
1580
- ("plot_image", "stx_image"),
1581
- ("plot_kde", "stx_kde"),
1582
- ("plot_conf_mat", "stx_conf_mat"),
1583
- ("plot_rectangle", "stx_rectangle"),
1584
- ("plot_fillv", "stx_fillv"),
1585
- ("plot_box", "stx_box"),
1586
- ("plot_raster", "stx_raster"),
1587
- ("plot_ecdf", "stx_ecdf"),
1588
- ("plot_joyplot", "stx_joyplot"),
1589
- ("plot_line", "stx_line"),
1590
- ("plot_scatter_hist", "stx_scatter_hist"),
1591
- ("plot_heatmap", "stx_heatmap"),
1592
- ("plot_violin", "stx_violin"),
1593
- ("plot_mean_std", "stx_mean_std"),
1594
- ("plot_mean_ci", "stx_mean_ci"),
1595
- ("plot_median_iqr", "stx_median_iqr"),
1596
- ("plot_shaded_line", "stx_shaded_line"),
1597
- ]
1598
-
1599
- for old_name, new_name in deprecated_methods:
1600
- def make_deprecated_method(target_name):
1601
- @deprecated(reason=f"Use {target_name} instead")
1602
- def method(self, *args, **kwargs):
1603
- return getattr(self, target_name)(*args, **kwargs)
1604
- return method
1605
-
1606
- setattr(MatplotlibPlotMixin, old_name, make_deprecated_method(new_name))
1607
-
1608
-
1609
- _add_deprecated_aliases()