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,393 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # File: ./src/scitex/vis/editor/flask_editor/renderer.py
4
- """Figure rendering for Flask editor - supports single and multi-axis figures."""
5
-
6
- from typing import Dict, Any, Tuple, Optional, List
7
- import base64
8
- import io
9
-
10
- import matplotlib
11
-
12
- matplotlib.use("Agg")
13
- import matplotlib.pyplot as plt
14
- from matplotlib.ticker import MaxNLocator
15
- from PIL import Image
16
- import numpy as np
17
-
18
- from ._plotter import plot_from_csv, plot_from_recipe
19
- from ._bbox import extract_bboxes, extract_bboxes_multi
20
-
21
- # mm to pt conversion factor
22
- MM_TO_PT = 2.83465
23
-
24
-
25
- def render_preview_with_bboxes(
26
- csv_data, overrides: Dict[str, Any], axis_fontsize: int = 7,
27
- metadata: Optional[Dict[str, Any]] = None,
28
- ) -> Tuple[str, Dict[str, Any], Dict[str, int]]:
29
- """Render figure and return base64 PNG along with element bounding boxes.
30
-
31
- Args:
32
- csv_data: DataFrame containing CSV data
33
- overrides: Dictionary with override settings
34
- axis_fontsize: Default font size for axis labels
35
- metadata: Optional JSON metadata (new schema with axes dict)
36
-
37
- Returns:
38
- tuple: (base64_image_data, bboxes_dict, image_size)
39
- """
40
- # Check if this is a multi-axis figure (new schema)
41
- if metadata and "axes" in metadata and isinstance(metadata.get("axes"), dict):
42
- return render_multi_axis_preview(csv_data, overrides, metadata)
43
-
44
- # Fall back to single-axis rendering
45
- return render_single_axis_preview(csv_data, overrides, axis_fontsize)
46
-
47
-
48
- def render_single_axis_preview(
49
- csv_data, overrides: Dict[str, Any], axis_fontsize: int = 7
50
- ) -> Tuple[str, Dict[str, Any], Dict[str, int]]:
51
- """Render single-axis figure (legacy mode)."""
52
- o = overrides
53
-
54
- # Dimensions
55
- dpi = o.get("dpi", 300)
56
- fig_size = o.get("fig_size", [3.15, 2.68])
57
-
58
- # Font sizes
59
- axis_fontsize = o.get("axis_fontsize", 7)
60
- tick_fontsize = o.get("tick_fontsize", 7)
61
- title_fontsize = o.get("title_fontsize", 8)
62
-
63
- # Line/axis thickness
64
- linewidth_pt = o.get("linewidth", 0.57)
65
- axis_width_pt = o.get("axis_width", 0.2) * MM_TO_PT
66
- tick_length_pt = o.get("tick_length", 0.8) * MM_TO_PT
67
- tick_width_pt = o.get("tick_width", 0.2) * MM_TO_PT
68
- tick_direction = o.get("tick_direction", "out")
69
- x_n_ticks = o.get("x_n_ticks", o.get("n_ticks", 4))
70
- y_n_ticks = o.get("y_n_ticks", o.get("n_ticks", 4))
71
- hide_x_ticks = o.get("hide_x_ticks", False)
72
- hide_y_ticks = o.get("hide_y_ticks", False)
73
-
74
- transparent = o.get("transparent", True)
75
-
76
- # Create figure
77
- fig, ax = plt.subplots(figsize=fig_size, dpi=dpi)
78
- _apply_background(fig, ax, o, transparent)
79
-
80
- # Plot from CSV data
81
- if csv_data is not None:
82
- plot_from_csv(ax, csv_data, overrides, linewidth=linewidth_pt)
83
- else:
84
- ax.text(
85
- 0.5,
86
- 0.5,
87
- "No plot data available\n(CSV not found)",
88
- ha="center",
89
- va="center",
90
- transform=ax.transAxes,
91
- fontsize=axis_fontsize,
92
- )
93
-
94
- # Apply labels
95
- _apply_labels(ax, o, title_fontsize, axis_fontsize)
96
-
97
- # Tick styling
98
- _apply_tick_styling(
99
- ax,
100
- tick_fontsize,
101
- tick_length_pt,
102
- tick_width_pt,
103
- tick_direction,
104
- x_n_ticks,
105
- y_n_ticks,
106
- hide_x_ticks,
107
- hide_y_ticks,
108
- )
109
-
110
- # Apply grid, limits, spines
111
- _apply_style(ax, o, axis_width_pt)
112
-
113
- # Apply annotations
114
- _apply_annotations(ax, o, axis_fontsize)
115
-
116
- fig.tight_layout()
117
-
118
- # Get element bounding boxes BEFORE saving (need renderer)
119
- fig.canvas.draw()
120
- renderer = fig.canvas.get_renderer()
121
-
122
- # Save to buffer first to get actual image size
123
- buf = io.BytesIO()
124
- fig.savefig(
125
- buf, format="png", dpi=dpi, bbox_inches="tight", transparent=transparent
126
- )
127
- buf.seek(0)
128
-
129
- # Get actual saved image dimensions
130
- img = Image.open(buf)
131
- img_width, img_height = img.size
132
- buf.seek(0)
133
-
134
- # Get bboxes
135
- bboxes = extract_bboxes(fig, ax, renderer, img_width, img_height)
136
-
137
- img_data = base64.b64encode(buf.read()).decode("utf-8")
138
- plt.close(fig)
139
-
140
- return img_data, bboxes, {"width": img_width, "height": img_height}
141
-
142
-
143
- def render_multi_axis_preview(
144
- csv_data, overrides: Dict[str, Any], metadata: Dict[str, Any]
145
- ) -> Tuple[str, Dict[str, Any], Dict[str, int]]:
146
- """Render multi-axis figure from new schema (scitex.plt.figure.recipe).
147
-
148
- Args:
149
- csv_data: DataFrame containing CSV data
150
- overrides: Dictionary with override settings
151
- metadata: JSON metadata with axes dict
152
-
153
- Returns:
154
- tuple: (base64_image_data, bboxes_dict, image_size)
155
- """
156
- o = overrides
157
- axes_spec = metadata.get("axes", {})
158
- fig_spec = metadata.get("figure", {})
159
-
160
- # Get grid dimensions from axes positions
161
- nrows, ncols = _get_grid_dimensions(axes_spec)
162
-
163
- # Figure dimensions
164
- dpi = fig_spec.get("dpi", o.get("dpi", 300))
165
- size_mm = fig_spec.get("size_mm", [176, 106])
166
- # Convert mm to inches (1 inch = 25.4 mm)
167
- fig_size = (size_mm[0] / 25.4, size_mm[1] / 25.4)
168
-
169
- # Font sizes (from overrides)
170
- axis_fontsize = o.get("axis_fontsize", 7)
171
- tick_fontsize = o.get("tick_fontsize", 7)
172
- title_fontsize = o.get("title_fontsize", 8)
173
-
174
- # Line/axis thickness
175
- linewidth_pt = o.get("linewidth", 0.57)
176
- axis_width_pt = o.get("axis_width", 0.2) * MM_TO_PT
177
- tick_length_pt = o.get("tick_length", 0.8) * MM_TO_PT
178
- tick_width_pt = o.get("tick_width", 0.2) * MM_TO_PT
179
- tick_direction = o.get("tick_direction", "out")
180
- x_n_ticks = o.get("x_n_ticks", o.get("n_ticks", 4))
181
- y_n_ticks = o.get("y_n_ticks", o.get("n_ticks", 4))
182
-
183
- transparent = o.get("transparent", True)
184
-
185
- # Create multi-axis figure
186
- fig, axes_array = plt.subplots(nrows, ncols, figsize=fig_size, dpi=dpi)
187
-
188
- # Handle 1D or 2D array
189
- if nrows == 1 and ncols == 1:
190
- axes_array = np.array([[axes_array]])
191
- elif nrows == 1:
192
- axes_array = axes_array.reshape(1, -1)
193
- elif ncols == 1:
194
- axes_array = axes_array.reshape(-1, 1)
195
-
196
- # Apply background to figure
197
- if transparent:
198
- fig.patch.set_facecolor("none")
199
- elif o.get("facecolor"):
200
- fig.patch.set_facecolor(o["facecolor"])
201
-
202
- # Map axes by their ID
203
- axes_map = {}
204
- for ax_id, ax_spec in axes_spec.items():
205
- pos = ax_spec.get("grid_position", {})
206
- row = pos.get("row", 0)
207
- col = pos.get("col", 0)
208
- ax = axes_array[row, col]
209
- axes_map[ax_id] = ax
210
-
211
- # Apply background
212
- if transparent:
213
- ax.patch.set_facecolor("none")
214
- elif o.get("facecolor"):
215
- ax.patch.set_facecolor(o["facecolor"])
216
-
217
- # Plot data from recipe
218
- if csv_data is not None:
219
- plot_from_recipe(ax, csv_data, ax_spec, overrides, linewidth_pt, ax_id=ax_id)
220
-
221
- # Get panel-specific overrides (e.g., ax_00_panel)
222
- panel_key = f"{ax_id}_panel"
223
- element_overrides = o.get("element_overrides", {})
224
- panel_overrides = element_overrides.get(panel_key, {})
225
-
226
- # Apply axis labels from spec, with panel overrides taking precedence
227
- xaxis = ax_spec.get("xaxis", {})
228
- yaxis = ax_spec.get("yaxis", {})
229
-
230
- # Panel title (from overrides or spec)
231
- panel_title = panel_overrides.get("title")
232
- if panel_title:
233
- ax.set_title(panel_title, fontsize=title_fontsize)
234
-
235
- # X/Y labels (panel overrides take precedence over spec)
236
- xlabel = panel_overrides.get("xlabel") or xaxis.get("label")
237
- ylabel = panel_overrides.get("ylabel") or yaxis.get("label")
238
-
239
- if xlabel:
240
- ax.set_xlabel(xlabel, fontsize=axis_fontsize)
241
- if ylabel:
242
- ax.set_ylabel(ylabel, fontsize=axis_fontsize)
243
-
244
- # Apply axis limits
245
- if xaxis.get("lim"):
246
- ax.set_xlim(xaxis["lim"])
247
- if yaxis.get("lim"):
248
- ax.set_ylim(yaxis["lim"])
249
-
250
- # Tick styling
251
- _apply_tick_styling(
252
- ax,
253
- tick_fontsize,
254
- tick_length_pt,
255
- tick_width_pt,
256
- tick_direction,
257
- x_n_ticks,
258
- y_n_ticks,
259
- False, # hide_x_ticks
260
- False, # hide_y_ticks
261
- )
262
-
263
- # Apply spines
264
- if o.get("hide_top_spine", True):
265
- ax.spines["top"].set_visible(False)
266
- if o.get("hide_right_spine", True):
267
- ax.spines["right"].set_visible(False)
268
- for spine in ax.spines.values():
269
- spine.set_linewidth(axis_width_pt)
270
-
271
- fig.tight_layout()
272
-
273
- # Get element bounding boxes
274
- fig.canvas.draw()
275
- renderer = fig.canvas.get_renderer()
276
-
277
- # Save to buffer
278
- buf = io.BytesIO()
279
- fig.savefig(
280
- buf, format="png", dpi=dpi, bbox_inches="tight", transparent=transparent
281
- )
282
- buf.seek(0)
283
-
284
- # Get actual saved image dimensions
285
- img = Image.open(buf)
286
- img_width, img_height = img.size
287
- buf.seek(0)
288
-
289
- # Get bboxes for all axes
290
- bboxes = extract_bboxes_multi(fig, axes_map, renderer, img_width, img_height)
291
-
292
- img_data = base64.b64encode(buf.read()).decode("utf-8")
293
- plt.close(fig)
294
-
295
- return img_data, bboxes, {"width": img_width, "height": img_height}
296
-
297
-
298
- def _get_grid_dimensions(axes_spec: Dict[str, Any]) -> Tuple[int, int]:
299
- """Get grid dimensions from axes specifications."""
300
- max_row = 0
301
- max_col = 0
302
- for ax_id, ax_spec in axes_spec.items():
303
- pos = ax_spec.get("grid_position", {})
304
- max_row = max(max_row, pos.get("row", 0))
305
- max_col = max(max_col, pos.get("col", 0))
306
- return max_row + 1, max_col + 1
307
-
308
-
309
- def _apply_background(fig, ax, o, transparent):
310
- """Apply background settings to figure."""
311
- if transparent:
312
- fig.patch.set_facecolor("none")
313
- ax.patch.set_facecolor("none")
314
- elif o.get("facecolor"):
315
- fig.patch.set_facecolor(o["facecolor"])
316
- ax.patch.set_facecolor(o["facecolor"])
317
-
318
-
319
- def _apply_labels(ax, o, title_fontsize, axis_fontsize):
320
- """Apply title and axis labels."""
321
- if o.get("title"):
322
- ax.set_title(o["title"], fontsize=title_fontsize)
323
- if o.get("xlabel"):
324
- ax.set_xlabel(o["xlabel"], fontsize=axis_fontsize)
325
- if o.get("ylabel"):
326
- ax.set_ylabel(o["ylabel"], fontsize=axis_fontsize)
327
-
328
-
329
- def _apply_tick_styling(
330
- ax,
331
- tick_fontsize,
332
- tick_length_pt,
333
- tick_width_pt,
334
- tick_direction,
335
- x_n_ticks,
336
- y_n_ticks,
337
- hide_x_ticks,
338
- hide_y_ticks,
339
- ):
340
- """Apply tick styling to axes."""
341
- ax.tick_params(
342
- axis="both",
343
- labelsize=tick_fontsize,
344
- length=tick_length_pt,
345
- width=tick_width_pt,
346
- direction=tick_direction,
347
- )
348
-
349
- if hide_x_ticks:
350
- ax.xaxis.set_ticks([])
351
- ax.xaxis.set_ticklabels([])
352
- else:
353
- ax.xaxis.set_major_locator(MaxNLocator(nbins=x_n_ticks))
354
- if hide_y_ticks:
355
- ax.yaxis.set_ticks([])
356
- ax.yaxis.set_ticklabels([])
357
- else:
358
- ax.yaxis.set_major_locator(MaxNLocator(nbins=y_n_ticks))
359
-
360
-
361
- def _apply_style(ax, o, axis_width_pt):
362
- """Apply grid, axis limits, and spine settings."""
363
- if o.get("grid"):
364
- ax.grid(True, linewidth=axis_width_pt, alpha=0.3)
365
-
366
- if o.get("xlim"):
367
- ax.set_xlim(o["xlim"])
368
- if o.get("ylim"):
369
- ax.set_ylim(o["ylim"])
370
-
371
- if o.get("hide_top_spine", True):
372
- ax.spines["top"].set_visible(False)
373
- if o.get("hide_right_spine", True):
374
- ax.spines["right"].set_visible(False)
375
-
376
- for spine in ax.spines.values():
377
- spine.set_linewidth(axis_width_pt)
378
-
379
-
380
- def _apply_annotations(ax, o, axis_fontsize):
381
- """Apply text annotations to figure."""
382
- for annot in o.get("annotations", []):
383
- if annot.get("type") == "text":
384
- ax.text(
385
- annot.get("x", 0.5),
386
- annot.get("y", 0.5),
387
- annot.get("text", ""),
388
- transform=ax.transAxes,
389
- fontsize=annot.get("fontsize", axis_fontsize),
390
- )
391
-
392
-
393
- # EOF