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.
- scitex/__init__.py +6 -2
- scitex/__version__.py +1 -1
- scitex/audio/README.md +52 -0
- scitex/audio/__init__.py +384 -0
- scitex/audio/__main__.py +129 -0
- scitex/audio/_tts.py +334 -0
- scitex/audio/engines/__init__.py +44 -0
- scitex/audio/engines/base.py +275 -0
- scitex/audio/engines/elevenlabs_engine.py +143 -0
- scitex/audio/engines/gtts_engine.py +162 -0
- scitex/audio/engines/pyttsx3_engine.py +131 -0
- scitex/audio/mcp_server.py +757 -0
- scitex/bridge/_helpers.py +1 -1
- scitex/bridge/_plt_vis.py +1 -1
- scitex/bridge/_stats_vis.py +1 -1
- scitex/dev/plt/__init__.py +272 -0
- scitex/dev/plt/plot_mpl_axhline.py +28 -0
- scitex/dev/plt/plot_mpl_axhspan.py +28 -0
- scitex/dev/plt/plot_mpl_axvline.py +28 -0
- scitex/dev/plt/plot_mpl_axvspan.py +28 -0
- scitex/dev/plt/plot_mpl_bar.py +29 -0
- scitex/dev/plt/plot_mpl_barh.py +29 -0
- scitex/dev/plt/plot_mpl_boxplot.py +28 -0
- scitex/dev/plt/plot_mpl_contour.py +31 -0
- scitex/dev/plt/plot_mpl_contourf.py +31 -0
- scitex/dev/plt/plot_mpl_errorbar.py +30 -0
- scitex/dev/plt/plot_mpl_eventplot.py +28 -0
- scitex/dev/plt/plot_mpl_fill.py +30 -0
- scitex/dev/plt/plot_mpl_fill_between.py +31 -0
- scitex/dev/plt/plot_mpl_hexbin.py +28 -0
- scitex/dev/plt/plot_mpl_hist.py +28 -0
- scitex/dev/plt/plot_mpl_hist2d.py +28 -0
- scitex/dev/plt/plot_mpl_imshow.py +29 -0
- scitex/dev/plt/plot_mpl_pcolormesh.py +31 -0
- scitex/dev/plt/plot_mpl_pie.py +29 -0
- scitex/dev/plt/plot_mpl_plot.py +29 -0
- scitex/dev/plt/plot_mpl_quiver.py +31 -0
- scitex/dev/plt/plot_mpl_scatter.py +28 -0
- scitex/dev/plt/plot_mpl_stackplot.py +31 -0
- scitex/dev/plt/plot_mpl_stem.py +29 -0
- scitex/dev/plt/plot_mpl_step.py +29 -0
- scitex/dev/plt/plot_mpl_violinplot.py +28 -0
- scitex/dev/plt/plot_sns_barplot.py +29 -0
- scitex/dev/plt/plot_sns_boxplot.py +29 -0
- scitex/dev/plt/plot_sns_heatmap.py +28 -0
- scitex/dev/plt/plot_sns_histplot.py +29 -0
- scitex/dev/plt/plot_sns_kdeplot.py +29 -0
- scitex/dev/plt/plot_sns_lineplot.py +31 -0
- scitex/dev/plt/plot_sns_scatterplot.py +29 -0
- scitex/dev/plt/plot_sns_stripplot.py +29 -0
- scitex/dev/plt/plot_sns_swarmplot.py +29 -0
- scitex/dev/plt/plot_sns_violinplot.py +29 -0
- scitex/dev/plt/plot_stx_bar.py +29 -0
- scitex/dev/plt/plot_stx_barh.py +29 -0
- scitex/dev/plt/plot_stx_box.py +28 -0
- scitex/dev/plt/plot_stx_boxplot.py +28 -0
- scitex/dev/plt/plot_stx_conf_mat.py +28 -0
- scitex/dev/plt/plot_stx_contour.py +31 -0
- scitex/dev/plt/plot_stx_ecdf.py +28 -0
- scitex/dev/plt/plot_stx_errorbar.py +30 -0
- scitex/dev/plt/plot_stx_fill_between.py +31 -0
- scitex/dev/plt/plot_stx_fillv.py +28 -0
- scitex/dev/plt/plot_stx_heatmap.py +28 -0
- scitex/dev/plt/plot_stx_image.py +28 -0
- scitex/dev/plt/plot_stx_imshow.py +28 -0
- scitex/dev/plt/plot_stx_joyplot.py +28 -0
- scitex/dev/plt/plot_stx_kde.py +28 -0
- scitex/dev/plt/plot_stx_line.py +28 -0
- scitex/dev/plt/plot_stx_mean_ci.py +28 -0
- scitex/dev/plt/plot_stx_mean_std.py +28 -0
- scitex/dev/plt/plot_stx_median_iqr.py +28 -0
- scitex/dev/plt/plot_stx_raster.py +28 -0
- scitex/dev/plt/plot_stx_rectangle.py +28 -0
- scitex/dev/plt/plot_stx_scatter.py +29 -0
- scitex/dev/plt/plot_stx_shaded_line.py +29 -0
- scitex/dev/plt/plot_stx_violin.py +28 -0
- scitex/dev/plt/plot_stx_violinplot.py +28 -0
- scitex/fig/__init__.py +352 -0
- scitex/{vis → fig}/backend/_parser.py +1 -1
- scitex/{vis → fig}/canvas.py +1 -1
- scitex/{vis → fig}/editor/_defaults.py +70 -5
- scitex/fig/editor/_edit.py +751 -0
- scitex/{vis → fig}/editor/_qt_editor.py +181 -1
- scitex/fig/editor/flask_editor/_bbox.py +1276 -0
- scitex/fig/editor/flask_editor/_core.py +624 -0
- scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
- scitex/fig/editor/flask_editor/_renderer.py +739 -0
- scitex/{vis → fig}/editor/flask_editor/templates/__init__.py +1 -1
- scitex/fig/editor/flask_editor/templates/_html.py +834 -0
- scitex/fig/editor/flask_editor/templates/_scripts.py +3136 -0
- scitex/{vis → fig}/editor/flask_editor/templates/_styles.py +625 -18
- scitex/{vis → fig}/io/__init__.py +13 -1
- scitex/fig/io/_bundle.py +973 -0
- scitex/{vis → fig}/io/_canvas.py +1 -1
- scitex/{vis → fig}/io/_data.py +1 -1
- scitex/{vis → fig}/io/_export.py +1 -1
- scitex/{vis → fig}/io/_load.py +1 -1
- scitex/{vis → fig}/io/_panel.py +1 -1
- scitex/{vis → fig}/io/_save.py +1 -1
- scitex/{vis → fig}/model/__init__.py +1 -1
- scitex/{vis → fig}/model/_annotations.py +1 -1
- scitex/{vis → fig}/model/_axes.py +1 -1
- scitex/{vis → fig}/model/_figure.py +1 -1
- scitex/{vis → fig}/model/_guides.py +1 -1
- scitex/{vis → fig}/model/_plot.py +1 -1
- scitex/{vis → fig}/model/_styles.py +1 -1
- scitex/{vis → fig}/utils/__init__.py +1 -1
- scitex/io/__init__.py +10 -26
- scitex/io/_bundle.py +434 -0
- scitex/io/_flush.py +5 -2
- scitex/io/_load.py +98 -0
- scitex/io/_load_modules/_H5Explorer.py +5 -2
- scitex/io/_load_modules/_canvas.py +2 -2
- scitex/io/_load_modules/_image.py +3 -4
- scitex/io/_load_modules/_txt.py +4 -2
- scitex/io/_metadata.py +34 -324
- scitex/io/_metadata_modules/__init__.py +46 -0
- scitex/io/_metadata_modules/_embed.py +70 -0
- scitex/io/_metadata_modules/_read.py +64 -0
- scitex/io/_metadata_modules/_utils.py +79 -0
- scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
- scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
- scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
- scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
- scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
- scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
- scitex/io/_metadata_modules/read_metadata_png.py +39 -0
- scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
- scitex/io/_qr_utils.py +5 -3
- scitex/io/_save.py +548 -30
- scitex/io/_save_modules/_canvas.py +3 -3
- scitex/io/_save_modules/_image.py +5 -9
- scitex/io/_save_modules/_tex.py +7 -4
- scitex/io/utils/h5_to_zarr.py +11 -9
- scitex/msword/__init__.py +255 -0
- scitex/msword/profiles.py +357 -0
- scitex/msword/reader.py +753 -0
- scitex/msword/utils.py +289 -0
- scitex/msword/writer.py +362 -0
- scitex/plt/__init__.py +5 -2
- scitex/plt/_subplots/_AxesWrapper.py +6 -6
- scitex/plt/_subplots/_AxisWrapper.py +15 -9
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
- scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
- scitex/plt/_subplots/_FigWrapper.py +6 -6
- scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
- scitex/plt/_subplots/_export_as_csv.py +35 -5
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
- scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
- scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
- scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
- scitex/plt/gallery/_generate.py +421 -14
- scitex/plt/io/__init__.py +53 -0
- scitex/plt/io/_bundle.py +490 -0
- scitex/plt/io/_layered_bundle.py +1343 -0
- scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
- scitex/plt/styles/__init__.py +14 -0
- scitex/plt/styles/presets.py +78 -0
- scitex/plt/utils/__init__.py +13 -1
- scitex/plt/utils/_collect_figure_metadata.py +10 -14
- scitex/plt/utils/_configure_mpl.py +6 -18
- scitex/plt/utils/_crop.py +32 -14
- scitex/plt/utils/_csv_column_naming.py +54 -0
- scitex/plt/utils/_figure_mm.py +116 -1
- scitex/plt/utils/_hitmap.py +1643 -0
- scitex/plt/utils/metadata/__init__.py +25 -0
- scitex/plt/utils/metadata/_core.py +9 -10
- scitex/plt/utils/metadata/_dimensions.py +6 -3
- scitex/plt/utils/metadata/_editable_export.py +405 -0
- scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
- scitex/schema/__init__.py +109 -16
- scitex/schema/_canvas.py +1 -1
- scitex/schema/_plot.py +1015 -0
- scitex/schema/_stats.py +2 -2
- scitex/stats/__init__.py +117 -0
- scitex/stats/io/__init__.py +29 -0
- scitex/stats/io/_bundle.py +156 -0
- scitex/tex/__init__.py +4 -0
- scitex/tex/_export.py +890 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/METADATA +11 -1
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/RECORD +238 -170
- scitex/io/memo.md +0 -2827
- scitex/plt/REQUESTS.md +0 -191
- scitex/plt/_subplots/TODO.md +0 -53
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
- scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
- scitex/vis/__init__.py +0 -177
- scitex/vis/editor/_edit.py +0 -390
- scitex/vis/editor/flask_editor/_bbox.py +0 -529
- scitex/vis/editor/flask_editor/_core.py +0 -168
- scitex/vis/editor/flask_editor/_renderer.py +0 -393
- scitex/vis/editor/flask_editor/templates/_html.py +0 -513
- scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
- /scitex/{vis → fig}/README.md +0 -0
- /scitex/{vis → fig}/backend/__init__.py +0 -0
- /scitex/{vis → fig}/backend/_export.py +0 -0
- /scitex/{vis → fig}/backend/_render.py +0 -0
- /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
- /scitex/{vis → fig}/editor/__init__.py +0 -0
- /scitex/{vis → fig}/editor/_dearpygui_editor.py +0 -0
- /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
- /scitex/{vis → fig}/editor/_mpl_editor.py +0 -0
- /scitex/{vis → fig}/editor/_tkinter_editor.py +0 -0
- /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
- /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
- /scitex/{vis → fig}/io/_directory.py +0 -0
- /scitex/{vis → fig}/model/_plot_types.py +0 -0
- /scitex/{vis → fig}/utils/_defaults.py +0 -0
- /scitex/{vis → fig}/utils/_validate.py +0 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/WHEEL +0 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -56,6 +56,7 @@ class QtEditor:
|
|
|
56
56
|
- Real-time preview updates
|
|
57
57
|
- Save to .manual.json
|
|
58
58
|
- SciTeX style defaults pre-filled
|
|
59
|
+
- Hitmap-based element selection (when available)
|
|
59
60
|
"""
|
|
60
61
|
|
|
61
62
|
def __init__(
|
|
@@ -65,12 +66,32 @@ class QtEditor:
|
|
|
65
66
|
csv_data: Optional[Any] = None,
|
|
66
67
|
png_path: Optional[Path] = None,
|
|
67
68
|
manual_overrides: Optional[Dict[str, Any]] = None,
|
|
69
|
+
hitmap_path: Optional[Path] = None,
|
|
70
|
+
bundle_spec: Optional[Dict[str, Any]] = None,
|
|
68
71
|
):
|
|
69
72
|
self.json_path = Path(json_path)
|
|
70
73
|
self.metadata = metadata
|
|
71
74
|
self.csv_data = csv_data
|
|
72
75
|
self.png_path = Path(png_path) if png_path else None
|
|
73
76
|
self.manual_overrides = manual_overrides or {}
|
|
77
|
+
self.hitmap_path = Path(hitmap_path) if hitmap_path else None
|
|
78
|
+
self.bundle_spec = bundle_spec or {}
|
|
79
|
+
|
|
80
|
+
# Load hitmap image if available
|
|
81
|
+
self.hitmap_array = None
|
|
82
|
+
if self.hitmap_path and self.hitmap_path.exists():
|
|
83
|
+
try:
|
|
84
|
+
from PIL import Image
|
|
85
|
+
import numpy as np
|
|
86
|
+
hitmap_img = Image.open(self.hitmap_path).convert('RGB')
|
|
87
|
+
self.hitmap_array = np.array(hitmap_img)
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
# Extract hit_regions and selectable_regions from spec
|
|
92
|
+
self.hit_regions = self.bundle_spec.get('hit_regions', {})
|
|
93
|
+
self.selectable_regions = self.bundle_spec.get('selectable_regions', {})
|
|
94
|
+
self.color_map = self.hit_regions.get('color_map', {})
|
|
74
95
|
|
|
75
96
|
# Get SciTeX defaults and merge with metadata
|
|
76
97
|
from ._defaults import get_scitex_defaults, extract_defaults_from_metadata
|
|
@@ -164,7 +185,7 @@ class QtEditorWindow:
|
|
|
164
185
|
self.window.show()
|
|
165
186
|
|
|
166
187
|
def _create_canvas_panel(self, parent):
|
|
167
|
-
"""Create the matplotlib canvas panel."""
|
|
188
|
+
"""Create the matplotlib canvas panel with hitmap-based selection."""
|
|
168
189
|
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
|
|
169
190
|
from matplotlib.backends.backend_qtagg import NavigationToolbar2QT
|
|
170
191
|
from matplotlib.figure import Figure
|
|
@@ -184,8 +205,167 @@ class QtEditorWindow:
|
|
|
184
205
|
toolbar = NavigationToolbar2QT(self.canvas, canvas_widget)
|
|
185
206
|
canvas_layout.addWidget(toolbar)
|
|
186
207
|
|
|
208
|
+
# Connect click event for hitmap-based selection
|
|
209
|
+
self.canvas.mpl_connect('button_press_event', self._on_canvas_click)
|
|
210
|
+
|
|
211
|
+
# Selection info label
|
|
212
|
+
self.selection_label = self.QtWidgets.QLabel("Click on figure to select element")
|
|
213
|
+
self.selection_label.setStyleSheet("padding: 5px; background: #f0f0f0; border-radius: 3px;")
|
|
214
|
+
canvas_layout.addWidget(self.selection_label)
|
|
215
|
+
|
|
187
216
|
parent.addWidget(canvas_widget)
|
|
188
217
|
|
|
218
|
+
def _on_canvas_click(self, event):
|
|
219
|
+
"""Handle canvas click - use hitmap to identify clicked element."""
|
|
220
|
+
if event.inaxes is None:
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
# Get pixel coordinates
|
|
224
|
+
x_px = int(event.x)
|
|
225
|
+
y_px = int(self.canvas.get_width_height()[1] - event.y) # Flip Y
|
|
226
|
+
|
|
227
|
+
# First check selectable_regions (bounding boxes for axis elements)
|
|
228
|
+
selection_info = self._check_selectable_regions(x_px, y_px)
|
|
229
|
+
|
|
230
|
+
# If no selectable_region hit, try hitmap for data elements
|
|
231
|
+
if selection_info is None and self.editor.hitmap_array is not None:
|
|
232
|
+
selection_info = self._check_hitmap(x_px, y_px)
|
|
233
|
+
|
|
234
|
+
# Update selection display
|
|
235
|
+
if selection_info:
|
|
236
|
+
self._show_selection(selection_info)
|
|
237
|
+
else:
|
|
238
|
+
self.selection_label.setText(f"No element at ({x_px}, {y_px})")
|
|
239
|
+
self.status_bar.showMessage(f"Click at ({x_px}, {y_px}) - no element found")
|
|
240
|
+
|
|
241
|
+
def _check_selectable_regions(self, x_px: int, y_px: int) -> Optional[Dict[str, Any]]:
|
|
242
|
+
"""Check if click is within any selectable_region bounding box."""
|
|
243
|
+
regions = self.editor.selectable_regions
|
|
244
|
+
if not regions or 'axes' not in regions:
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
for ax_info in regions['axes']:
|
|
248
|
+
ax_idx = ax_info.get('index', 0)
|
|
249
|
+
|
|
250
|
+
# Check title
|
|
251
|
+
if 'title' in ax_info:
|
|
252
|
+
bbox = ax_info['title'].get('bbox_px', [])
|
|
253
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
254
|
+
return {
|
|
255
|
+
'type': 'title',
|
|
256
|
+
'axes_index': ax_idx,
|
|
257
|
+
'text': ax_info['title'].get('text', ''),
|
|
258
|
+
'element': 'title',
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# Check xlabel
|
|
262
|
+
if 'xlabel' in ax_info:
|
|
263
|
+
bbox = ax_info['xlabel'].get('bbox_px', [])
|
|
264
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
265
|
+
return {
|
|
266
|
+
'type': 'xlabel',
|
|
267
|
+
'axes_index': ax_idx,
|
|
268
|
+
'text': ax_info['xlabel'].get('text', ''),
|
|
269
|
+
'element': 'xlabel',
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Check ylabel
|
|
273
|
+
if 'ylabel' in ax_info:
|
|
274
|
+
bbox = ax_info['ylabel'].get('bbox_px', [])
|
|
275
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
276
|
+
return {
|
|
277
|
+
'type': 'ylabel',
|
|
278
|
+
'axes_index': ax_idx,
|
|
279
|
+
'text': ax_info['ylabel'].get('text', ''),
|
|
280
|
+
'element': 'ylabel',
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Check legend
|
|
284
|
+
if 'legend' in ax_info:
|
|
285
|
+
bbox = ax_info['legend'].get('bbox_px', [])
|
|
286
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
287
|
+
return {
|
|
288
|
+
'type': 'legend',
|
|
289
|
+
'axes_index': ax_idx,
|
|
290
|
+
'element': 'legend',
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
# Check xaxis elements
|
|
294
|
+
if 'xaxis' in ax_info:
|
|
295
|
+
xaxis = ax_info['xaxis']
|
|
296
|
+
if 'spine' in xaxis and xaxis['spine']:
|
|
297
|
+
bbox = xaxis['spine'].get('bbox_px', [])
|
|
298
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
299
|
+
return {'type': 'xaxis_spine', 'axes_index': ax_idx, 'element': 'xaxis'}
|
|
300
|
+
|
|
301
|
+
# Check yaxis elements
|
|
302
|
+
if 'yaxis' in ax_info:
|
|
303
|
+
yaxis = ax_info['yaxis']
|
|
304
|
+
if 'spine' in yaxis and yaxis['spine']:
|
|
305
|
+
bbox = yaxis['spine'].get('bbox_px', [])
|
|
306
|
+
if len(bbox) == 4 and self._point_in_bbox(x_px, y_px, bbox):
|
|
307
|
+
return {'type': 'yaxis_spine', 'axes_index': ax_idx, 'element': 'yaxis'}
|
|
308
|
+
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
def _check_hitmap(self, x_px: int, y_px: int) -> Optional[Dict[str, Any]]:
|
|
312
|
+
"""Check hitmap for data element at pixel position."""
|
|
313
|
+
hitmap = self.editor.hitmap_array
|
|
314
|
+
color_map = self.editor.color_map
|
|
315
|
+
|
|
316
|
+
if hitmap is None or not color_map:
|
|
317
|
+
return None
|
|
318
|
+
|
|
319
|
+
# Bounds check
|
|
320
|
+
h, w = hitmap.shape[:2]
|
|
321
|
+
if x_px < 0 or x_px >= w or y_px < 0 or y_px >= h:
|
|
322
|
+
return None
|
|
323
|
+
|
|
324
|
+
# Get RGB at position
|
|
325
|
+
r, g, b = hitmap[y_px, x_px]
|
|
326
|
+
|
|
327
|
+
# Skip background (black) and axes elements (dark gray)
|
|
328
|
+
if (r, g, b) == (0, 0, 0): # Background
|
|
329
|
+
return None
|
|
330
|
+
if (r, g, b) == (64, 64, 64): # Axes color (#404040)
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
# Convert RGB to ID
|
|
334
|
+
element_id = r * 65536 + g * 256 + b
|
|
335
|
+
|
|
336
|
+
# Look up in color_map
|
|
337
|
+
if str(element_id) in color_map:
|
|
338
|
+
info = color_map[str(element_id)]
|
|
339
|
+
return {
|
|
340
|
+
'type': 'data_element',
|
|
341
|
+
'element_id': element_id,
|
|
342
|
+
'element_type': info.get('type', 'unknown'),
|
|
343
|
+
'label': info.get('label', ''),
|
|
344
|
+
'axes_index': info.get('axes_index', 0),
|
|
345
|
+
'rgb': [r, g, b],
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return None
|
|
349
|
+
|
|
350
|
+
def _point_in_bbox(self, x: int, y: int, bbox: list) -> bool:
|
|
351
|
+
"""Check if point (x, y) is within bounding box [x0, y0, x1, y1]."""
|
|
352
|
+
x0, y0, x1, y1 = bbox
|
|
353
|
+
return x0 <= x <= x1 and y0 <= y <= y1
|
|
354
|
+
|
|
355
|
+
def _show_selection(self, info: Dict[str, Any]):
|
|
356
|
+
"""Display selection info in UI."""
|
|
357
|
+
if info['type'] == 'data_element':
|
|
358
|
+
text = f"Selected: {info['element_type']} - {info.get('label', 'unnamed')}"
|
|
359
|
+
detail = f"ID: {info['element_id']}, Axes: {info['axes_index']}"
|
|
360
|
+
else:
|
|
361
|
+
text = f"Selected: {info['type']}"
|
|
362
|
+
if 'text' in info:
|
|
363
|
+
text += f" - \"{info['text']}\""
|
|
364
|
+
detail = f"Axes: {info.get('axes_index', 0)}"
|
|
365
|
+
|
|
366
|
+
self.selection_label.setText(f"{text}\n{detail}")
|
|
367
|
+
self.status_bar.showMessage(text)
|
|
368
|
+
|
|
189
369
|
def _create_control_panel(self, parent):
|
|
190
370
|
"""Create the control panel with property editors."""
|
|
191
371
|
scroll_area = self.QtWidgets.QScrollArea()
|