scitex 2.7.0__py3-none-any.whl → 2.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/diagram/README.md +197 -0
- scitex/diagram/__init__.py +48 -0
- scitex/diagram/_compile.py +312 -0
- scitex/diagram/_diagram.py +355 -0
- scitex/diagram/_presets.py +173 -0
- scitex/diagram/_schema.py +182 -0
- scitex/diagram/_split.py +278 -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/__init__.py +5 -2
- scitex/{vis → fig}/editor/_dearpygui_editor.py +1 -1
- scitex/{vis → fig}/editor/_defaults.py +70 -5
- scitex/{vis → fig}/editor/_mpl_editor.py +1 -1
- scitex/{vis → fig}/editor/_qt_editor.py +182 -2
- scitex/{vis → fig}/editor/_tkinter_editor.py +1 -1
- scitex/fig/editor/edit/__init__.py +50 -0
- scitex/fig/editor/edit/backend_detector.py +109 -0
- scitex/fig/editor/edit/bundle_resolver.py +240 -0
- scitex/fig/editor/edit/editor_launcher.py +239 -0
- scitex/fig/editor/edit/manual_handler.py +53 -0
- scitex/fig/editor/edit/panel_loader.py +232 -0
- scitex/fig/editor/edit/path_resolver.py +67 -0
- scitex/fig/editor/flask_editor/_bbox.py +1299 -0
- scitex/fig/editor/flask_editor/_core.py +1429 -0
- scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
- scitex/fig/editor/flask_editor/_renderer.py +813 -0
- scitex/fig/editor/flask_editor/static/css/base/reset.css +41 -0
- scitex/fig/editor/flask_editor/static/css/base/typography.css +16 -0
- scitex/fig/editor/flask_editor/static/css/base/variables.css +85 -0
- scitex/fig/editor/flask_editor/static/css/components/buttons.css +217 -0
- scitex/fig/editor/flask_editor/static/css/components/context-menu.css +93 -0
- scitex/fig/editor/flask_editor/static/css/components/dropdown.css +57 -0
- scitex/fig/editor/flask_editor/static/css/components/forms.css +112 -0
- scitex/fig/editor/flask_editor/static/css/components/modal.css +59 -0
- scitex/fig/editor/flask_editor/static/css/components/sections.css +212 -0
- scitex/fig/editor/flask_editor/static/css/features/canvas.css +176 -0
- scitex/fig/editor/flask_editor/static/css/features/element-inspector.css +190 -0
- scitex/fig/editor/flask_editor/static/css/features/loading.css +59 -0
- scitex/fig/editor/flask_editor/static/css/features/overlay.css +45 -0
- scitex/fig/editor/flask_editor/static/css/features/panel-grid.css +95 -0
- scitex/fig/editor/flask_editor/static/css/features/selection.css +101 -0
- scitex/fig/editor/flask_editor/static/css/features/statistics.css +138 -0
- scitex/fig/editor/flask_editor/static/css/index.css +31 -0
- scitex/fig/editor/flask_editor/static/css/layout/container.css +7 -0
- scitex/fig/editor/flask_editor/static/css/layout/controls.css +56 -0
- scitex/fig/editor/flask_editor/static/css/layout/preview.css +78 -0
- scitex/fig/editor/flask_editor/static/js/alignment/axis.js +314 -0
- scitex/fig/editor/flask_editor/static/js/alignment/basic.js +107 -0
- scitex/fig/editor/flask_editor/static/js/alignment/distribute.js +54 -0
- scitex/fig/editor/flask_editor/static/js/canvas/canvas.js +172 -0
- scitex/fig/editor/flask_editor/static/js/canvas/dragging.js +258 -0
- scitex/fig/editor/flask_editor/static/js/canvas/resize.js +48 -0
- scitex/fig/editor/flask_editor/static/js/canvas/selection.js +71 -0
- scitex/fig/editor/flask_editor/static/js/core/api.js +288 -0
- scitex/fig/editor/flask_editor/static/js/core/state.js +143 -0
- scitex/fig/editor/flask_editor/static/js/core/utils.js +245 -0
- scitex/fig/editor/flask_editor/static/js/dev/element-inspector.js +992 -0
- scitex/fig/editor/flask_editor/static/js/editor/bbox.js +339 -0
- scitex/fig/editor/flask_editor/static/js/editor/element-drag.js +286 -0
- scitex/fig/editor/flask_editor/static/js/editor/overlay.js +371 -0
- scitex/fig/editor/flask_editor/static/js/editor/preview.js +293 -0
- scitex/fig/editor/flask_editor/static/js/main.js +426 -0
- scitex/fig/editor/flask_editor/static/js/shortcuts/context-menu.js +152 -0
- scitex/fig/editor/flask_editor/static/js/shortcuts/keyboard.js +265 -0
- scitex/fig/editor/flask_editor/static/js/ui/controls.js +184 -0
- scitex/fig/editor/flask_editor/static/js/ui/download.js +57 -0
- scitex/fig/editor/flask_editor/static/js/ui/help.js +100 -0
- scitex/fig/editor/flask_editor/static/js/ui/theme.js +34 -0
- scitex/fig/editor/flask_editor/templates/__init__.py +123 -0
- scitex/fig/editor/flask_editor/templates/_html.py +852 -0
- scitex/fig/editor/flask_editor/templates/_scripts.py +4933 -0
- scitex/fig/editor/flask_editor/templates/_styles.py +1658 -0
- scitex/{vis → fig}/io/__init__.py +13 -1
- scitex/fig/io/_bundle.py +1058 -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 +22 -26
- scitex/io/_bundle.py +493 -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/_zip_bundle.py +439 -0
- 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.8.1.dist-info}/METADATA +11 -1
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/RECORD +294 -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/__init__.py +0 -33
- scitex/vis/editor/flask_editor/templates/_html.py +0 -513
- scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
- scitex/vis/editor/flask_editor/templates/_styles.py +0 -739
- /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/_flask_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.8.1.dist-info}/WHEEL +0 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-14 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/editor_launcher.py
|
|
5
|
+
|
|
6
|
+
"""Main edit function for launching visual editor."""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Union, Literal
|
|
10
|
+
|
|
11
|
+
from .backend_detector import print_available_backends, detect_best_backend
|
|
12
|
+
from .path_resolver import resolve_figure_paths
|
|
13
|
+
from .bundle_resolver import resolve_pltz_bundle, resolve_figz_bundle
|
|
14
|
+
|
|
15
|
+
__all__ = ["edit"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def edit(
|
|
19
|
+
path: Union[str, Path],
|
|
20
|
+
backend: Literal["auto", "flask", "dearpygui", "qt", "tkinter", "mpl"] = "auto",
|
|
21
|
+
apply_manual: bool = True,
|
|
22
|
+
port: int = 5050,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Launch interactive editor for figure style/annotation editing.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
path : str or Path
|
|
30
|
+
Path to figure file. Can be:
|
|
31
|
+
- .pltz.d directory bundle (recommended for hitmap selection)
|
|
32
|
+
- .pltz ZIP bundle
|
|
33
|
+
- .figz or .figz.d multi-panel bundle
|
|
34
|
+
- JSON file (figure.json or figure.manual.json)
|
|
35
|
+
- CSV file (figure.csv) - for data-only start
|
|
36
|
+
- PNG file (figure.png)
|
|
37
|
+
backend : str, optional
|
|
38
|
+
GUI backend to use (default: "auto"):
|
|
39
|
+
- "auto": Pick best available (flask -> dearpygui -> qt -> tkinter -> mpl)
|
|
40
|
+
- "flask": Browser-based editor (Flask, modern UI)
|
|
41
|
+
- "dearpygui": GPU-accelerated modern GUI
|
|
42
|
+
- "qt": Rich desktop editor (requires PyQt5/6 or PySide2/6)
|
|
43
|
+
- "tkinter": Built-in Python GUI
|
|
44
|
+
- "mpl": Minimal matplotlib interactive mode
|
|
45
|
+
apply_manual : bool, optional
|
|
46
|
+
If True, load .manual.json overrides if exists (default: True)
|
|
47
|
+
port : int, optional
|
|
48
|
+
Port number for web-based editors. Default: 5050.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
None
|
|
53
|
+
Editor runs in GUI event loop. Changes saved to .manual.json.
|
|
54
|
+
"""
|
|
55
|
+
path = Path(path)
|
|
56
|
+
spath = str(path)
|
|
57
|
+
parent_str = str(path.parent) if path.is_file() else ""
|
|
58
|
+
|
|
59
|
+
# Panel info for multi-panel figures
|
|
60
|
+
panel_info = None
|
|
61
|
+
|
|
62
|
+
# Resolve paths based on input type
|
|
63
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = _resolve_paths(
|
|
64
|
+
path, spath, parent_str
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if not json_path.exists():
|
|
68
|
+
raise FileNotFoundError(f"JSON file not found: {json_path}")
|
|
69
|
+
|
|
70
|
+
# Load data
|
|
71
|
+
import scitex as stx
|
|
72
|
+
|
|
73
|
+
metadata = bundle_spec if bundle_spec else stx.io.load(json_path)
|
|
74
|
+
csv_data = None
|
|
75
|
+
if csv_path and csv_path.exists():
|
|
76
|
+
csv_data = stx.io.load(csv_path)
|
|
77
|
+
|
|
78
|
+
# Load manual overrides if exists
|
|
79
|
+
manual_path = json_path.with_suffix(".manual.json")
|
|
80
|
+
manual_overrides = None
|
|
81
|
+
if apply_manual and manual_path.exists():
|
|
82
|
+
manual_data = stx.io.load(manual_path)
|
|
83
|
+
manual_overrides = manual_data.get("overrides", {})
|
|
84
|
+
|
|
85
|
+
# Resolve backend if "auto"
|
|
86
|
+
if backend == "auto":
|
|
87
|
+
backend = detect_best_backend()
|
|
88
|
+
|
|
89
|
+
# Print status
|
|
90
|
+
print_available_backends()
|
|
91
|
+
print(f"Launching {backend} editor for: {json_path}")
|
|
92
|
+
|
|
93
|
+
# Launch appropriate backend
|
|
94
|
+
_launch_backend(
|
|
95
|
+
backend=backend,
|
|
96
|
+
json_path=json_path,
|
|
97
|
+
metadata=metadata,
|
|
98
|
+
csv_data=csv_data,
|
|
99
|
+
png_path=png_path,
|
|
100
|
+
hitmap_path=hitmap_path,
|
|
101
|
+
manual_overrides=manual_overrides,
|
|
102
|
+
bundle_spec=bundle_spec,
|
|
103
|
+
panel_info=panel_info,
|
|
104
|
+
port=port,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _resolve_paths(path: Path, spath: str, parent_str: str) -> tuple:
|
|
109
|
+
"""Resolve paths based on input type."""
|
|
110
|
+
panel_info = None
|
|
111
|
+
hitmap_path = None
|
|
112
|
+
bundle_spec = None
|
|
113
|
+
|
|
114
|
+
# Check if this is a .figz bundle (multi-panel figure)
|
|
115
|
+
if spath.endswith('.figz.d') or spath.endswith('.figz'):
|
|
116
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = resolve_figz_bundle(path)
|
|
117
|
+
# Check if this is a .pltz bundle
|
|
118
|
+
elif spath.endswith('.pltz.d') or spath.endswith('.pltz') or parent_str.endswith('.pltz.d'):
|
|
119
|
+
bundle_path = path.parent if parent_str.endswith('.pltz.d') else path
|
|
120
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec = resolve_pltz_bundle(bundle_path)
|
|
121
|
+
# Check if file is inside a .figz.d
|
|
122
|
+
elif parent_str.endswith('.figz.d') or (path.parent.parent and str(path.parent.parent).endswith('.figz.d')):
|
|
123
|
+
figz_path = path.parent if parent_str.endswith('.figz.d') else path.parent.parent
|
|
124
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = resolve_figz_bundle(figz_path)
|
|
125
|
+
else:
|
|
126
|
+
# Standard file paths
|
|
127
|
+
json_path, csv_path, png_path = resolve_figure_paths(path)
|
|
128
|
+
|
|
129
|
+
return json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _launch_backend(
|
|
133
|
+
backend: str,
|
|
134
|
+
json_path: Path,
|
|
135
|
+
metadata: dict,
|
|
136
|
+
csv_data,
|
|
137
|
+
png_path,
|
|
138
|
+
hitmap_path,
|
|
139
|
+
manual_overrides,
|
|
140
|
+
bundle_spec,
|
|
141
|
+
panel_info,
|
|
142
|
+
port: int,
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Launch the specified editor backend."""
|
|
145
|
+
if backend == "flask":
|
|
146
|
+
_launch_flask(json_path, metadata, csv_data, png_path, hitmap_path, manual_overrides, port, panel_info)
|
|
147
|
+
elif backend == "dearpygui":
|
|
148
|
+
_launch_dearpygui(json_path, metadata, csv_data, png_path, manual_overrides)
|
|
149
|
+
elif backend == "qt":
|
|
150
|
+
_launch_qt(json_path, metadata, csv_data, png_path, manual_overrides, hitmap_path, bundle_spec)
|
|
151
|
+
elif backend == "tkinter":
|
|
152
|
+
_launch_tkinter(json_path, metadata, csv_data, manual_overrides)
|
|
153
|
+
elif backend == "mpl":
|
|
154
|
+
_launch_mpl(json_path, metadata, csv_data, manual_overrides)
|
|
155
|
+
else:
|
|
156
|
+
raise ValueError(
|
|
157
|
+
f"Unknown backend: {backend}. "
|
|
158
|
+
"Use 'auto', 'flask', 'dearpygui', 'qt', 'tkinter', or 'mpl'."
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _launch_flask(json_path, metadata, csv_data, png_path, hitmap_path, manual_overrides, port, panel_info):
|
|
163
|
+
"""Launch Flask web editor."""
|
|
164
|
+
try:
|
|
165
|
+
from .._flask_editor import WebEditor
|
|
166
|
+
editor = WebEditor(
|
|
167
|
+
json_path=json_path,
|
|
168
|
+
metadata=metadata,
|
|
169
|
+
csv_data=csv_data,
|
|
170
|
+
png_path=png_path,
|
|
171
|
+
hitmap_path=hitmap_path,
|
|
172
|
+
manual_overrides=manual_overrides,
|
|
173
|
+
port=port,
|
|
174
|
+
panel_info=panel_info,
|
|
175
|
+
)
|
|
176
|
+
editor.run()
|
|
177
|
+
except ImportError as e:
|
|
178
|
+
raise ImportError("Flask backend requires Flask. Install with: pip install flask") from e
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _launch_dearpygui(json_path, metadata, csv_data, png_path, manual_overrides):
|
|
182
|
+
"""Launch DearPyGui editor."""
|
|
183
|
+
try:
|
|
184
|
+
from .._dearpygui_editor import DearPyGuiEditor
|
|
185
|
+
editor = DearPyGuiEditor(
|
|
186
|
+
json_path=json_path,
|
|
187
|
+
metadata=metadata,
|
|
188
|
+
csv_data=csv_data,
|
|
189
|
+
png_path=png_path,
|
|
190
|
+
manual_overrides=manual_overrides,
|
|
191
|
+
)
|
|
192
|
+
editor.run()
|
|
193
|
+
except ImportError as e:
|
|
194
|
+
raise ImportError("DearPyGui backend requires dearpygui. Install with: pip install dearpygui") from e
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _launch_qt(json_path, metadata, csv_data, png_path, manual_overrides, hitmap_path, bundle_spec):
|
|
198
|
+
"""Launch Qt editor."""
|
|
199
|
+
try:
|
|
200
|
+
from .._qt_editor import QtEditor
|
|
201
|
+
editor = QtEditor(
|
|
202
|
+
json_path=json_path,
|
|
203
|
+
metadata=metadata,
|
|
204
|
+
csv_data=csv_data,
|
|
205
|
+
png_path=png_path,
|
|
206
|
+
manual_overrides=manual_overrides,
|
|
207
|
+
hitmap_path=hitmap_path,
|
|
208
|
+
bundle_spec=bundle_spec,
|
|
209
|
+
)
|
|
210
|
+
editor.run()
|
|
211
|
+
except ImportError as e:
|
|
212
|
+
raise ImportError("Qt backend requires PyQt5/PyQt6 or PySide2/PySide6. Install with: pip install PyQt6") from e
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _launch_tkinter(json_path, metadata, csv_data, manual_overrides):
|
|
216
|
+
"""Launch Tkinter editor."""
|
|
217
|
+
from .._tkinter_editor import TkinterEditor
|
|
218
|
+
editor = TkinterEditor(
|
|
219
|
+
json_path=json_path,
|
|
220
|
+
metadata=metadata,
|
|
221
|
+
csv_data=csv_data,
|
|
222
|
+
manual_overrides=manual_overrides,
|
|
223
|
+
)
|
|
224
|
+
editor.run()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _launch_mpl(json_path, metadata, csv_data, manual_overrides):
|
|
228
|
+
"""Launch matplotlib editor."""
|
|
229
|
+
from .._mpl_editor import MplEditor
|
|
230
|
+
editor = MplEditor(
|
|
231
|
+
json_path=json_path,
|
|
232
|
+
metadata=metadata,
|
|
233
|
+
csv_data=csv_data,
|
|
234
|
+
manual_overrides=manual_overrides,
|
|
235
|
+
)
|
|
236
|
+
editor.run()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# EOF
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-14 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/manual_handler.py
|
|
5
|
+
|
|
6
|
+
"""Manual override handling for figure editor."""
|
|
7
|
+
|
|
8
|
+
import hashlib
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
__all__ = ["compute_file_hash", "save_manual_overrides"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def compute_file_hash(path: Path) -> str:
|
|
15
|
+
"""Compute SHA256 hash of file contents."""
|
|
16
|
+
with open(path, "rb") as f:
|
|
17
|
+
return hashlib.sha256(f.read()).hexdigest()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def save_manual_overrides(json_path: Path, overrides: dict) -> Path:
|
|
21
|
+
"""
|
|
22
|
+
Save manual overrides to .manual.json file.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
json_path : Path
|
|
27
|
+
Path to base JSON file
|
|
28
|
+
overrides : dict
|
|
29
|
+
Override settings (styles, annotations, etc.)
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
Path
|
|
34
|
+
Path to saved manual.json file
|
|
35
|
+
"""
|
|
36
|
+
import scitex as stx
|
|
37
|
+
|
|
38
|
+
manual_path = json_path.with_suffix(".manual.json")
|
|
39
|
+
|
|
40
|
+
# Compute hash of base JSON for staleness detection
|
|
41
|
+
base_hash = compute_file_hash(json_path)
|
|
42
|
+
|
|
43
|
+
manual_data = {
|
|
44
|
+
"base_file": json_path.name,
|
|
45
|
+
"base_hash": base_hash,
|
|
46
|
+
"overrides": overrides,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
stx.io.save(manual_data, manual_path)
|
|
50
|
+
return manual_path
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# EOF
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-14 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/panel_loader.py
|
|
5
|
+
|
|
6
|
+
"""Panel data loading for figure editor."""
|
|
7
|
+
|
|
8
|
+
import io
|
|
9
|
+
import json as json_module
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional, Union, Dict, Any
|
|
12
|
+
|
|
13
|
+
__all__ = ["load_panel_data"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_panel_data(panel_path: Union[Path, str], is_zip: bool = None) -> Optional[Dict[str, Any]]:
|
|
17
|
+
"""
|
|
18
|
+
Load panel data from either a .pltz.d directory or a .pltz zip file.
|
|
19
|
+
|
|
20
|
+
Handles both formats transparently using in-memory reading for zips.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
panel_path : Path or str
|
|
25
|
+
Path to .pltz.d directory or .pltz zip file
|
|
26
|
+
is_zip : bool, optional
|
|
27
|
+
If True, treat as zip file. If False, treat as directory.
|
|
28
|
+
If None, auto-detect based on path suffix and existence.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
dict or None
|
|
33
|
+
Dictionary with keys: metadata, csv_data, png_bytes, hitmap_bytes, img_size
|
|
34
|
+
For directories, also includes: json_path, png_path, hitmap_path
|
|
35
|
+
Returns None if panel cannot be loaded
|
|
36
|
+
"""
|
|
37
|
+
from PIL import Image
|
|
38
|
+
|
|
39
|
+
panel_path = Path(panel_path)
|
|
40
|
+
|
|
41
|
+
# Auto-detect if not specified
|
|
42
|
+
if is_zip is None:
|
|
43
|
+
spath = str(panel_path)
|
|
44
|
+
if spath.endswith('.pltz') and not spath.endswith('.pltz.d'):
|
|
45
|
+
is_zip = panel_path.is_file()
|
|
46
|
+
else:
|
|
47
|
+
is_zip = False
|
|
48
|
+
|
|
49
|
+
if is_zip:
|
|
50
|
+
return _load_from_zip(panel_path)
|
|
51
|
+
else:
|
|
52
|
+
return _load_from_directory(panel_path)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _load_from_zip(panel_path: Path) -> Optional[Dict[str, Any]]:
|
|
56
|
+
"""Load panel data from a .pltz zip file."""
|
|
57
|
+
from PIL import Image
|
|
58
|
+
from scitex.io._zip_bundle import ZipBundle
|
|
59
|
+
|
|
60
|
+
if not panel_path.exists():
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
with ZipBundle(panel_path, mode="r") as zb:
|
|
65
|
+
# Load spec.json for metadata
|
|
66
|
+
try:
|
|
67
|
+
metadata = zb.read_json("spec.json")
|
|
68
|
+
except FileNotFoundError:
|
|
69
|
+
metadata = {}
|
|
70
|
+
|
|
71
|
+
# Load style.json if exists
|
|
72
|
+
try:
|
|
73
|
+
style = zb.read_json("style.json")
|
|
74
|
+
metadata["style"] = style
|
|
75
|
+
except FileNotFoundError:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
# Find and read PNG
|
|
79
|
+
png_bytes = None
|
|
80
|
+
for name in zb.namelist():
|
|
81
|
+
if name.endswith('.png') and '_hitmap' not in name and '_overview' not in name:
|
|
82
|
+
if 'exports/' in name:
|
|
83
|
+
png_bytes = zb.read_bytes(name)
|
|
84
|
+
break
|
|
85
|
+
|
|
86
|
+
# If no PNG in exports/, try root level
|
|
87
|
+
if not png_bytes:
|
|
88
|
+
for name in zb.namelist():
|
|
89
|
+
if name.endswith('.png') and '_hitmap' not in name and '_overview' not in name:
|
|
90
|
+
png_bytes = zb.read_bytes(name)
|
|
91
|
+
break
|
|
92
|
+
|
|
93
|
+
# Get image size
|
|
94
|
+
img_size = None
|
|
95
|
+
if png_bytes:
|
|
96
|
+
img = Image.open(io.BytesIO(png_bytes))
|
|
97
|
+
img_size = {"width": img.size[0], "height": img.size[1]}
|
|
98
|
+
img.close()
|
|
99
|
+
|
|
100
|
+
# Find and read hitmap
|
|
101
|
+
hitmap_bytes = None
|
|
102
|
+
for name in zb.namelist():
|
|
103
|
+
if '_hitmap.png' in name:
|
|
104
|
+
hitmap_bytes = zb.read_bytes(name)
|
|
105
|
+
break
|
|
106
|
+
|
|
107
|
+
# Load geometry_px.json if available
|
|
108
|
+
geometry_data = None
|
|
109
|
+
try:
|
|
110
|
+
geometry_data = zb.read_json("cache/geometry_px.json")
|
|
111
|
+
except FileNotFoundError:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
"metadata": metadata,
|
|
116
|
+
"png_bytes": png_bytes,
|
|
117
|
+
"hitmap_bytes": hitmap_bytes,
|
|
118
|
+
"img_size": img_size,
|
|
119
|
+
"geometry_data": geometry_data,
|
|
120
|
+
"is_zip": True,
|
|
121
|
+
}
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(f"Error loading panel zip {panel_path}: {e}")
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _load_from_directory(panel_path: Path) -> Optional[Dict[str, Any]]:
|
|
128
|
+
"""Load panel data from a .pltz.d directory."""
|
|
129
|
+
import scitex as stx
|
|
130
|
+
|
|
131
|
+
panel_dir = panel_path
|
|
132
|
+
if not panel_dir.exists():
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
# Check for layered vs legacy format
|
|
136
|
+
spec_path = panel_dir / "spec.json"
|
|
137
|
+
if spec_path.exists():
|
|
138
|
+
return _load_layered_directory(panel_dir)
|
|
139
|
+
else:
|
|
140
|
+
return _load_legacy_directory(panel_dir)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _load_layered_directory(panel_dir: Path) -> Dict[str, Any]:
|
|
144
|
+
"""Load panel data from layered format directory."""
|
|
145
|
+
import scitex as stx
|
|
146
|
+
from scitex.plt.io import load_layered_pltz_bundle
|
|
147
|
+
|
|
148
|
+
bundle_data = load_layered_pltz_bundle(panel_dir)
|
|
149
|
+
metadata = bundle_data.get("merged", {})
|
|
150
|
+
|
|
151
|
+
# Find CSV
|
|
152
|
+
csv_data = None
|
|
153
|
+
for f in panel_dir.glob("*.csv"):
|
|
154
|
+
csv_data = stx.io.load(f)
|
|
155
|
+
break
|
|
156
|
+
|
|
157
|
+
# Find exports - prefer PNG over SVG (PIL can't open SVG)
|
|
158
|
+
png_path = None
|
|
159
|
+
svg_path = None
|
|
160
|
+
hitmap_path = None
|
|
161
|
+
exports_dir = panel_dir / "exports"
|
|
162
|
+
if exports_dir.exists():
|
|
163
|
+
for f in exports_dir.iterdir():
|
|
164
|
+
name = f.name
|
|
165
|
+
if name.endswith('_hitmap.png'):
|
|
166
|
+
hitmap_path = f
|
|
167
|
+
elif name.endswith('.png') and '_hitmap' not in name and '_overview' not in name:
|
|
168
|
+
png_path = f
|
|
169
|
+
elif name.endswith('.svg') and '_hitmap' not in name and svg_path is None:
|
|
170
|
+
svg_path = f
|
|
171
|
+
|
|
172
|
+
if png_path is None:
|
|
173
|
+
png_path = svg_path
|
|
174
|
+
|
|
175
|
+
# Load geometry_px.json if available
|
|
176
|
+
geometry_data = None
|
|
177
|
+
geometry_path = panel_dir / "cache" / "geometry_px.json"
|
|
178
|
+
if geometry_path.exists():
|
|
179
|
+
with open(geometry_path) as f:
|
|
180
|
+
geometry_data = json_module.load(f)
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
"json_path": panel_dir / "spec.json",
|
|
184
|
+
"metadata": metadata,
|
|
185
|
+
"csv_data": csv_data,
|
|
186
|
+
"png_path": png_path,
|
|
187
|
+
"hitmap_path": hitmap_path,
|
|
188
|
+
"geometry_data": geometry_data,
|
|
189
|
+
"is_zip": False,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _load_legacy_directory(panel_dir: Path) -> Optional[Dict[str, Any]]:
|
|
194
|
+
"""Load panel data from legacy format directory."""
|
|
195
|
+
import scitex as stx
|
|
196
|
+
|
|
197
|
+
json_path = None
|
|
198
|
+
csv_data = None
|
|
199
|
+
png_path = None
|
|
200
|
+
hitmap_path = None
|
|
201
|
+
|
|
202
|
+
for f in panel_dir.iterdir():
|
|
203
|
+
name = f.name
|
|
204
|
+
if name.endswith('.json') and not name.endswith('.manual.json'):
|
|
205
|
+
json_path = f
|
|
206
|
+
elif name.endswith('.csv'):
|
|
207
|
+
csv_data = stx.io.load(f)
|
|
208
|
+
elif name.endswith('_hitmap.png'):
|
|
209
|
+
hitmap_path = f
|
|
210
|
+
elif name.endswith('.svg') and '_hitmap' not in name:
|
|
211
|
+
png_path = f
|
|
212
|
+
elif name.endswith('.png') and '_hitmap' not in name and '_overview' not in name:
|
|
213
|
+
if png_path is None:
|
|
214
|
+
png_path = f
|
|
215
|
+
|
|
216
|
+
if json_path is None:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
with open(json_path, 'r') as f:
|
|
220
|
+
metadata = json_module.load(f)
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
"json_path": json_path,
|
|
224
|
+
"metadata": metadata,
|
|
225
|
+
"csv_data": csv_data,
|
|
226
|
+
"png_path": png_path,
|
|
227
|
+
"hitmap_path": hitmap_path,
|
|
228
|
+
"is_zip": False,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# EOF
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-14 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/path_resolver.py
|
|
5
|
+
|
|
6
|
+
"""Basic path resolution for figure files."""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Tuple
|
|
10
|
+
|
|
11
|
+
__all__ = ["resolve_figure_paths"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def resolve_figure_paths(path: Path) -> Tuple[Path, Optional[Path], Optional[Path]]:
|
|
15
|
+
"""
|
|
16
|
+
Resolve JSON, CSV, and PNG paths from any input file path.
|
|
17
|
+
|
|
18
|
+
Handles two patterns:
|
|
19
|
+
1. Flat (sibling): path/to/figure.{json,csv,png}
|
|
20
|
+
2. Organized (subdirs): path/to/{json,csv,png}/figure.{ext}
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
path : Path
|
|
25
|
+
Input path (can be JSON, CSV, or PNG)
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
tuple
|
|
30
|
+
(json_path, csv_path, png_path) - csv_path/png_path may be None if not found
|
|
31
|
+
"""
|
|
32
|
+
path = Path(path)
|
|
33
|
+
stem = path.stem
|
|
34
|
+
parent = path.parent
|
|
35
|
+
|
|
36
|
+
# Check if this is organized pattern (parent is json/, csv/, png/)
|
|
37
|
+
if parent.name in ("json", "csv", "png"):
|
|
38
|
+
base_dir = parent.parent
|
|
39
|
+
json_path = base_dir / "json" / f"{stem}.json"
|
|
40
|
+
csv_path = base_dir / "csv" / f"{stem}.csv"
|
|
41
|
+
png_path = base_dir / "png" / f"{stem}.png"
|
|
42
|
+
else:
|
|
43
|
+
# Flat pattern - sibling files
|
|
44
|
+
json_path = parent / f"{stem}.json"
|
|
45
|
+
csv_path = parent / f"{stem}.csv"
|
|
46
|
+
png_path = parent / f"{stem}.png"
|
|
47
|
+
|
|
48
|
+
# If input was .manual.json, get base json
|
|
49
|
+
if stem.endswith(".manual"):
|
|
50
|
+
base_stem = stem[:-7] # Remove '.manual'
|
|
51
|
+
if parent.name == "json":
|
|
52
|
+
json_path = parent / f"{base_stem}.json"
|
|
53
|
+
csv_path = parent.parent / "csv" / f"{base_stem}.csv"
|
|
54
|
+
png_path = parent.parent / "png" / f"{base_stem}.png"
|
|
55
|
+
else:
|
|
56
|
+
json_path = parent / f"{base_stem}.json"
|
|
57
|
+
csv_path = parent / f"{base_stem}.csv"
|
|
58
|
+
png_path = parent / f"{base_stem}.png"
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
json_path,
|
|
62
|
+
csv_path if csv_path.exists() else None,
|
|
63
|
+
png_path if png_path.exists() else None,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# EOF
|