scitex 2.7.3__py3-none-any.whl → 2.10.0__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 +15 -7
- scitex/__version__.py +1 -2
- scitex/_install_guide.py +250 -0
- scitex/_optional_deps.py +206 -39
- scitex/ai/_gen_ai/_Groq.py +2 -4
- scitex/ai/_gen_ai/_OpenAI.py +5 -2
- scitex/ai/_gen_ai/_Perplexity.py +20 -6
- scitex/audio/__init__.py +24 -15
- scitex/audio/_cross_process_lock.py +139 -0
- scitex/audio/_mcp_handlers.py +256 -0
- scitex/audio/_mcp_tool_schemas.py +203 -0
- scitex/audio/engines/elevenlabs_engine.py +5 -2
- scitex/audio/mcp_server.py +98 -457
- scitex/bridge/__init__.py +30 -19
- scitex/bridge/_figrecipe.py +245 -0
- scitex/bridge/_helpers.py +2 -1
- scitex/bridge/_plt_vis.py +23 -10
- scitex/bridge/_stats_plt.py +18 -5
- scitex/bridge/_stats_vis.py +16 -2
- scitex/browser/__init__.py +84 -44
- scitex/browser/automation/__init__.py +5 -1
- scitex/browser/core/BrowserMixin.py +17 -4
- scitex/browser/core/__init__.py +11 -2
- scitex/browser/remote/CaptchaHandler.py +1 -1
- scitex/browser/remote/ZenRowsAPIClient.py +1 -1
- scitex/capture/grid.py +487 -0
- scitex/capture/mcp_handlers.py +401 -0
- scitex/capture/mcp_tool_defs.py +192 -0
- scitex/capture/mcp_tools.py +241 -0
- scitex/capture/mcp_utils.py +30 -0
- scitex/cli/convert.py +421 -0
- scitex/cli/main.py +6 -4
- scitex/datetime/__init__.py +46 -0
- scitex/datetime/_linspace.py +100 -0
- scitex/datetime/_normalize_timestamp.py +306 -0
- scitex/db/_delete_duplicates.py +4 -4
- scitex/db/_sqlite3/_delete_duplicates.py +11 -2
- scitex/dev/plt/__init__.py +61 -62
- scitex/dev/plt/demo_plotters/__init__.py +0 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axhline.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axhspan.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axvline.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axvspan.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_bar.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_barh.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_boxplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_contour.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_contourf.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_errorbar.py +30 -0
- scitex/dev/plt/demo_plotters/plot_mpl_eventplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_fill.py +30 -0
- scitex/dev/plt/demo_plotters/plot_mpl_fill_between.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hexbin.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hist.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hist2d.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_imshow.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_pcolormesh.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_pie.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_plot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_quiver.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_scatter.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_stackplot.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_stem.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_step.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_violinplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_sns_barplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_boxplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_heatmap.py +28 -0
- scitex/dev/plt/demo_plotters/plot_sns_histplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_kdeplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_lineplot.py +31 -0
- scitex/dev/plt/demo_plotters/plot_sns_scatterplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_stripplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_swarmplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_violinplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_bar.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_barh.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_box.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_boxplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_conf_mat.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_contour.py +31 -0
- scitex/dev/plt/demo_plotters/plot_stx_ecdf.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_errorbar.py +30 -0
- scitex/dev/plt/demo_plotters/plot_stx_fill_between.py +31 -0
- scitex/dev/plt/demo_plotters/plot_stx_fillv.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_heatmap.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_image.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_imshow.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_joyplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_kde.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_line.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_mean_ci.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_mean_std.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_median_iqr.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_raster.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_rectangle.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_scatter.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_shaded_line.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_violin.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_violinplot.py +28 -0
- scitex/dev/plt/mpl/get_dir_ax.py +46 -0
- scitex/dev/plt/mpl/get_signatures.py +176 -0
- scitex/dev/plt/mpl/get_signatures_details.py +522 -0
- scitex/dev/plt/plot_mpl_axhline.py +0 -0
- scitex/dev/plt/plot_mpl_axhspan.py +0 -0
- scitex/dev/plt/plot_mpl_axvline.py +0 -0
- scitex/dev/plt/plot_mpl_axvspan.py +0 -0
- scitex/dev/plt/plot_mpl_bar.py +0 -0
- scitex/dev/plt/plot_mpl_barh.py +0 -0
- scitex/dev/plt/plot_mpl_boxplot.py +0 -0
- scitex/dev/plt/plot_mpl_contour.py +0 -0
- scitex/dev/plt/plot_mpl_contourf.py +0 -0
- scitex/dev/plt/plot_mpl_errorbar.py +0 -0
- scitex/dev/plt/plot_mpl_eventplot.py +0 -0
- scitex/dev/plt/plot_mpl_fill.py +0 -0
- scitex/dev/plt/plot_mpl_fill_between.py +0 -0
- scitex/dev/plt/plot_mpl_hexbin.py +0 -0
- scitex/dev/plt/plot_mpl_hist.py +0 -0
- scitex/dev/plt/plot_mpl_hist2d.py +0 -0
- scitex/dev/plt/plot_mpl_imshow.py +0 -0
- scitex/dev/plt/plot_mpl_pcolormesh.py +0 -0
- scitex/dev/plt/plot_mpl_pie.py +0 -0
- scitex/dev/plt/plot_mpl_plot.py +0 -0
- scitex/dev/plt/plot_mpl_quiver.py +0 -0
- scitex/dev/plt/plot_mpl_scatter.py +0 -0
- scitex/dev/plt/plot_mpl_stackplot.py +0 -0
- scitex/dev/plt/plot_mpl_stem.py +0 -0
- scitex/dev/plt/plot_mpl_step.py +0 -0
- scitex/dev/plt/plot_mpl_violinplot.py +0 -0
- scitex/dev/plt/plot_sns_barplot.py +0 -0
- scitex/dev/plt/plot_sns_boxplot.py +0 -0
- scitex/dev/plt/plot_sns_heatmap.py +0 -0
- scitex/dev/plt/plot_sns_histplot.py +0 -0
- scitex/dev/plt/plot_sns_kdeplot.py +0 -0
- scitex/dev/plt/plot_sns_lineplot.py +0 -0
- scitex/dev/plt/plot_sns_scatterplot.py +0 -0
- scitex/dev/plt/plot_sns_stripplot.py +0 -0
- scitex/dev/plt/plot_sns_swarmplot.py +0 -0
- scitex/dev/plt/plot_sns_violinplot.py +0 -0
- scitex/dev/plt/plot_stx_bar.py +0 -0
- scitex/dev/plt/plot_stx_barh.py +0 -0
- scitex/dev/plt/plot_stx_box.py +0 -0
- scitex/dev/plt/plot_stx_boxplot.py +0 -0
- scitex/dev/plt/plot_stx_conf_mat.py +0 -0
- scitex/dev/plt/plot_stx_contour.py +0 -0
- scitex/dev/plt/plot_stx_ecdf.py +0 -0
- scitex/dev/plt/plot_stx_errorbar.py +0 -0
- scitex/dev/plt/plot_stx_fill_between.py +0 -0
- scitex/dev/plt/plot_stx_fillv.py +0 -0
- scitex/dev/plt/plot_stx_heatmap.py +0 -0
- scitex/dev/plt/plot_stx_image.py +0 -0
- scitex/dev/plt/plot_stx_imshow.py +0 -0
- scitex/dev/plt/plot_stx_joyplot.py +0 -0
- scitex/dev/plt/plot_stx_kde.py +0 -0
- scitex/dev/plt/plot_stx_line.py +0 -0
- scitex/dev/plt/plot_stx_mean_ci.py +0 -0
- scitex/dev/plt/plot_stx_mean_std.py +0 -0
- scitex/dev/plt/plot_stx_median_iqr.py +0 -0
- scitex/dev/plt/plot_stx_raster.py +0 -0
- scitex/dev/plt/plot_stx_rectangle.py +0 -0
- scitex/dev/plt/plot_stx_scatter.py +0 -0
- scitex/dev/plt/plot_stx_shaded_line.py +0 -0
- scitex/dev/plt/plot_stx_violin.py +0 -0
- scitex/dev/plt/plot_stx_violinplot.py +0 -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/dict/_pop_keys.py +1 -7
- scitex/dsp/__init__.py +15 -10
- scitex/dsp/add_noise.py +5 -2
- scitex/dsp/example.py +35 -22
- scitex/dsp/filt.py +8 -3
- scitex/dsp/reference.py +3 -2
- scitex/dsp/utils/__init__.py +2 -1
- scitex/dsp/utils/_differential_bandpass_filters.py +14 -4
- scitex/dt/__init__.py +39 -2
- scitex/errors.py +82 -521
- scitex/fig/__init__.py +4 -4
- scitex/fig/editor/__init__.py +5 -2
- scitex/fig/editor/_dearpygui_editor.py +1 -1
- scitex/fig/editor/_mpl_editor.py +1 -1
- scitex/fig/editor/_qt_editor.py +1 -1
- scitex/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 +23 -0
- scitex/fig/editor/flask_editor/_core.py +908 -103
- scitex/fig/editor/flask_editor/_renderer.py +74 -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 +95 -5
- scitex/fig/editor/flask_editor/templates/_html.py +27 -9
- scitex/fig/editor/flask_editor/templates/_scripts.py +1928 -131
- scitex/fig/editor/flask_editor/templates/_styles.py +363 -51
- scitex/fig/io/_bundle.py +104 -19
- scitex/fts/README.md +262 -0
- scitex/fts/TODO.md +66 -0
- scitex/fts/__init__.py +90 -0
- scitex/fts/_bundle/README_IN_BUNDLE.md +102 -0
- scitex/fts/_bundle/_FTS.py +657 -0
- scitex/fts/_bundle/__init__.py +38 -0
- scitex/fts/_bundle/_children.py +216 -0
- scitex/fts/_bundle/_conversion/__init__.py +15 -0
- scitex/fts/_bundle/_conversion/_bundle2dict.py +44 -0
- scitex/fts/_bundle/_conversion/_dict2bundle.py +50 -0
- scitex/fts/_bundle/_dataclasses/_Axes.py +57 -0
- scitex/fts/_bundle/_dataclasses/_BBox.py +54 -0
- scitex/fts/_bundle/_dataclasses/_ColumnDef.py +72 -0
- scitex/fts/_bundle/_dataclasses/_DataFormat.py +40 -0
- scitex/fts/_bundle/_dataclasses/_DataInfo.py +135 -0
- scitex/fts/_bundle/_dataclasses/_DataSource.py +44 -0
- scitex/fts/_bundle/_dataclasses/_Node.py +319 -0
- scitex/fts/_bundle/_dataclasses/_NodeRefs.py +45 -0
- scitex/fts/_bundle/_dataclasses/_SizeMM.py +38 -0
- scitex/fts/_bundle/_dataclasses/__init__.py +35 -0
- scitex/fts/_bundle/_extractors/__init__.py +32 -0
- scitex/fts/_bundle/_extractors/_extract_bar.py +131 -0
- scitex/fts/_bundle/_extractors/_extract_line.py +71 -0
- scitex/fts/_bundle/_extractors/_extract_scatter.py +79 -0
- scitex/fts/_bundle/_loader.py +134 -0
- scitex/fts/_bundle/_mpl_helpers.py +389 -0
- scitex/fts/_bundle/_saver.py +269 -0
- scitex/fts/_bundle/_storage.py +200 -0
- scitex/fts/_bundle/_utils/__init__.py +55 -0
- scitex/fts/_bundle/_utils/_const.py +26 -0
- scitex/fts/_bundle/_utils/_errors.py +73 -0
- scitex/fts/_bundle/_utils/_generate.py +21 -0
- scitex/fts/_bundle/_utils/_types.py +76 -0
- scitex/fts/_bundle/_validation.py +434 -0
- scitex/fts/_bundle/_zipbundle.py +165 -0
- scitex/fts/_fig/__init__.py +22 -0
- scitex/fts/_fig/_backend/__init__.py +53 -0
- scitex/fts/_fig/_backend/_export.py +165 -0
- scitex/fts/_fig/_backend/_parser.py +188 -0
- scitex/fts/_fig/_backend/_render.py +538 -0
- scitex/fts/_fig/_composite.py +345 -0
- scitex/fts/_fig/_dataclasses/_ChannelEncoding.py +46 -0
- scitex/fts/_fig/_dataclasses/_Encoding.py +82 -0
- scitex/fts/_fig/_dataclasses/_Theme.py +441 -0
- scitex/fts/_fig/_dataclasses/_TraceEncoding.py +52 -0
- scitex/fts/_fig/_dataclasses/__init__.py +47 -0
- scitex/fts/_fig/_editor/__init__.py +14 -0
- scitex/fts/_fig/_editor/_cui/__init__.py +33 -0
- scitex/fts/_fig/_editor/_cui/_backend_detector.py +39 -0
- scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +366 -0
- scitex/fts/_fig/_editor/_cui/_editor_launcher.py +175 -0
- scitex/fts/_fig/_editor/_cui/_manual_handler.py +52 -0
- scitex/fts/_fig/_editor/_cui/_panel_loader.py +246 -0
- scitex/fts/_fig/_editor/_cui/_path_resolver.py +66 -0
- scitex/fts/_fig/_editor/_defaults.py +300 -0
- scitex/fts/_fig/_editor/_gui/__init__.py +11 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +20 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_bbox.py +1339 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_core.py +1688 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +664 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_renderer.py +853 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +79 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +41 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +16 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +85 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +217 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +93 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +57 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +112 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +59 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +212 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/canvas.css +176 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +190 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +59 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +45 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +95 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +101 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +138 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +31 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +7 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +56 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +78 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +314 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +107 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +54 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +172 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +258 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +48 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +71 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +288 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +143 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +245 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +992 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +339 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +286 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +371 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +293 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +426 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +152 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +265 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +184 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +57 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +100 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +34 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +124 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +851 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +4932 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +1657 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor.py +36 -0
- scitex/fts/_fig/_models/_Annotations.py +115 -0
- scitex/fts/_fig/_models/_Axes.py +152 -0
- scitex/fts/_fig/_models/_Figure.py +138 -0
- scitex/fts/_fig/_models/_Guides.py +104 -0
- scitex/fts/_fig/_models/_Plot.py +123 -0
- scitex/fts/_fig/_models/_Styles.py +245 -0
- scitex/fts/_fig/_models/__init__.py +80 -0
- scitex/fts/_fig/_models/_plot_types/__init__.py +156 -0
- scitex/fts/_fig/_models/_plot_types/_bar.py +43 -0
- scitex/fts/_fig/_models/_plot_types/_box.py +38 -0
- scitex/fts/_fig/_models/_plot_types/_distribution.py +36 -0
- scitex/fts/_fig/_models/_plot_types/_errorbar.py +60 -0
- scitex/fts/_fig/_models/_plot_types/_histogram.py +30 -0
- scitex/fts/_fig/_models/_plot_types/_image.py +61 -0
- scitex/fts/_fig/_models/_plot_types/_line.py +57 -0
- scitex/fts/_fig/_models/_plot_types/_scatter.py +30 -0
- scitex/fts/_fig/_models/_plot_types/_seaborn.py +121 -0
- scitex/fts/_fig/_models/_plot_types/_violin.py +36 -0
- scitex/fts/_fig/_utils/__init__.py +129 -0
- scitex/fts/_fig/_utils/_auto_layout.py +127 -0
- scitex/fts/_fig/_utils/_calc_bounds.py +111 -0
- scitex/fts/_fig/_utils/_const_sizes.py +48 -0
- scitex/fts/_fig/_utils/_convert_coords.py +77 -0
- scitex/fts/_fig/_utils/_get_template.py +178 -0
- scitex/fts/_fig/_utils/_normalize.py +73 -0
- scitex/fts/_fig/_utils/_plot_layout.py +397 -0
- scitex/fts/_fig/_utils/_validate.py +197 -0
- scitex/fts/_kinds/__init__.py +45 -0
- scitex/fts/_kinds/_figure/__init__.py +19 -0
- scitex/fts/_kinds/_figure/_composite.py +345 -0
- scitex/fts/_kinds/_plot/__init__.py +25 -0
- scitex/fts/_kinds/_plot/_backend/__init__.py +53 -0
- scitex/fts/_kinds/_plot/_backend/_export.py +165 -0
- scitex/fts/_kinds/_plot/_backend/_parser.py +188 -0
- scitex/fts/_kinds/_plot/_backend/_render.py +538 -0
- scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +46 -0
- scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +82 -0
- scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +441 -0
- scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +52 -0
- scitex/fts/_kinds/_plot/_dataclasses/__init__.py +47 -0
- scitex/fts/_kinds/_plot/_models/_Annotations.py +115 -0
- scitex/fts/_kinds/_plot/_models/_Axes.py +152 -0
- scitex/fts/_kinds/_plot/_models/_Figure.py +138 -0
- scitex/fts/_kinds/_plot/_models/_Guides.py +104 -0
- scitex/fts/_kinds/_plot/_models/_Plot.py +123 -0
- scitex/fts/_kinds/_plot/_models/_Styles.py +245 -0
- scitex/fts/_kinds/_plot/_models/__init__.py +80 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +156 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +43 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +38 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +36 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +60 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +30 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +61 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +57 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +30 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +121 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +36 -0
- scitex/fts/_kinds/_plot/_utils/__init__.py +129 -0
- scitex/fts/_kinds/_plot/_utils/_auto_layout.py +127 -0
- scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +111 -0
- scitex/fts/_kinds/_plot/_utils/_const_sizes.py +48 -0
- scitex/fts/_kinds/_plot/_utils/_convert_coords.py +77 -0
- scitex/fts/_kinds/_plot/_utils/_get_template.py +178 -0
- scitex/fts/_kinds/_plot/_utils/_normalize.py +73 -0
- scitex/fts/_kinds/_plot/_utils/_plot_layout.py +397 -0
- scitex/fts/_kinds/_plot/_utils/_validate.py +197 -0
- scitex/fts/_kinds/_shape/__init__.py +141 -0
- scitex/fts/_kinds/_stats/__init__.py +56 -0
- scitex/fts/_kinds/_stats/_dataclasses/_Stats.py +423 -0
- scitex/fts/_kinds/_stats/_dataclasses/__init__.py +48 -0
- scitex/fts/_kinds/_table/__init__.py +72 -0
- scitex/fts/_kinds/_table/_latex/__init__.py +93 -0
- scitex/fts/_kinds/_table/_latex/_editor/__init__.py +11 -0
- scitex/fts/_kinds/_table/_latex/_editor/_app.py +725 -0
- scitex/fts/_kinds/_table/_latex/_export.py +279 -0
- scitex/fts/_kinds/_table/_latex/_figure_exporter.py +153 -0
- scitex/fts/_kinds/_table/_latex/_stats_formatter.py +274 -0
- scitex/fts/_kinds/_table/_latex/_table_exporter.py +362 -0
- scitex/fts/_kinds/_table/_latex/_utils.py +369 -0
- scitex/fts/_kinds/_table/_latex/_validator.py +445 -0
- scitex/fts/_kinds/_text/__init__.py +77 -0
- scitex/fts/_schemas/data_info.schema.json +75 -0
- scitex/fts/_schemas/encoding.schema.json +90 -0
- scitex/fts/_schemas/node.schema.json +145 -0
- scitex/fts/_schemas/render_manifest.schema.json +62 -0
- scitex/fts/_schemas/stats.schema.json +132 -0
- scitex/fts/_schemas/theme.schema.json +141 -0
- scitex/fts/_stats/__init__.py +48 -0
- scitex/fts/_stats/_dataclasses/_Stats.py +423 -0
- scitex/fts/_stats/_dataclasses/__init__.py +48 -0
- scitex/fts/_tables/__init__.py +65 -0
- scitex/fts/_tables/_latex/__init__.py +93 -0
- scitex/fts/_tables/_latex/_editor/__init__.py +11 -0
- scitex/fts/_tables/_latex/_editor/_app.py +725 -0
- scitex/fts/_tables/_latex/_export.py +279 -0
- scitex/fts/_tables/_latex/_figure_exporter.py +153 -0
- scitex/fts/_tables/_latex/_stats_formatter.py +274 -0
- scitex/fts/_tables/_latex/_table_exporter.py +362 -0
- scitex/fts/_tables/_latex/_utils.py +369 -0
- scitex/fts/_tables/_latex/_validator.py +445 -0
- scitex/gen/__init__.py +66 -25
- scitex/gen/misc.py +28 -0
- scitex/io/__init__.py +47 -20
- scitex/io/_load.py +87 -36
- scitex/io/_load_modules/__init__.py +10 -7
- scitex/io/_load_modules/_pandas.py +6 -1
- scitex/io/_save.py +299 -1556
- scitex/io/_save_modules/__init__.py +76 -19
- scitex/io/_save_modules/_figure_utils.py +90 -0
- scitex/io/_save_modules/_image_csv.py +497 -0
- scitex/io/_save_modules/_legends.py +91 -0
- scitex/io/_save_modules/_pltz_bundle.py +356 -0
- scitex/io/_save_modules/_pltz_stx.py +536 -0
- scitex/io/_save_modules/_stx_bundle.py +104 -0
- scitex/io/_save_modules/_symlink.py +96 -0
- scitex/io/_save_modules/_yaml.py +1 -1
- scitex/io/_save_modules/_zarr.py +64 -18
- scitex/io/bundle/README.md +212 -0
- scitex/io/bundle/__init__.py +110 -0
- scitex/io/{_bundle.py → bundle/_core.py} +219 -89
- scitex/io/bundle/_nested.py +713 -0
- scitex/io/bundle/_types.py +74 -0
- scitex/io/bundle/_zip.py +487 -0
- scitex/io/utils/h5_to_zarr.py +1 -1
- scitex/logging/__init__.py +108 -13
- scitex/logging/_errors.py +508 -0
- scitex/logging/_formatters.py +30 -6
- scitex/logging/_warnings.py +261 -0
- scitex/plt/__init__.py +4 -1
- scitex/plt/_figrecipe.py +236 -0
- scitex/plt/_subplots/_AxisWrapper.py +6 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +112 -1
- scitex/plt/_subplots/_FigWrapper.py +15 -0
- scitex/plt/_subplots/_SubplotsWrapper.py +125 -489
- scitex/plt/_subplots/_export_as_csv.py +11 -0
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +2 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py +66 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py +62 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +208 -0
- scitex/plt/_subplots/_fonts.py +71 -0
- scitex/plt/_subplots/_mm_layout.py +282 -0
- scitex/plt/gallery/__init__.py +99 -2
- scitex/plt/io/_layered_bundle.py +0 -0
- scitex/plt/styles/_plot_postprocess.py +3 -1
- scitex/plt/utils/_configure_mpl.py +16 -19
- scitex/repro/_RandomStateManager.py +13 -8
- scitex/resource/__init__.py +19 -1
- scitex/resource/_utils/_get_env_info.py +13 -25
- scitex/schema/__init__.py +149 -160
- scitex/schema/_encoding.py +273 -0
- scitex/schema/_figure_elements.py +406 -0
- scitex/schema/_plot.py +0 -0
- scitex/schema/_theme.py +360 -0
- scitex/schema/_validation.py +0 -98
- scitex/scholar/__init__.py +56 -14
- scitex/scholar/auth/ScholarAuthManager.py +1 -1
- scitex/scholar/auth/__init__.py +11 -2
- scitex/scholar/auth/providers/BaseAuthenticator.py +1 -1
- scitex/scholar/auth/providers/EZProxyAuthenticator.py +1 -1
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +1 -1
- scitex/scholar/auth/providers/ShibbolethAuthenticator.py +1 -1
- scitex/scholar/config/ScholarConfig.py +1 -1
- scitex/scholar/core/Scholar.py +1 -1
- scitex/session/_decorator.py +18 -16
- scitex/session/_lifecycle.py +9 -11
- scitex/session/template.py +9 -8
- scitex/sh/test_sh.py +72 -0
- scitex/sh/test_sh_simple.py +61 -0
- scitex/stats/__init__.py +221 -97
- scitex/stats/_schema.py +21 -22
- scitex/stats/descriptive/_circular.py +212 -351
- scitex/stats/descriptive/_describe.py +81 -132
- scitex/stats/descriptive/_nan.py +205 -433
- scitex/stats/descriptive/_real.py +127 -141
- scitex/str/_format_plot_text.py +5 -5
- scitex/str/_latex.py +26 -84
- scitex/str/_latex_fallback.py +53 -47
- scitex/web/_search_pubmed.py +5 -4
- scitex/writer/tests/test_diff_between.py +451 -0
- scitex/writer/tests/test_document_section.py +311 -0
- scitex/writer/tests/test_document_workflow.py +393 -0
- scitex/writer/tests/test_writer.py +361 -0
- scitex/writer/tests/test_writer_integration.py +303 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/METADATA +364 -181
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/RECORD +479 -108
- scitex/fig/editor/_edit.py +0 -751
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/ARCHITECTURE_EXAMPLE.md +0 -905
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/BULLETIN_BOARD_EXAMPLE.md +0 -99
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/PROJECT_DESCRIPTION_EXAMPLE.md +0 -96
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/WHEEL +0 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/editor/edit/bundle_resolver.py
|
|
4
|
+
|
|
5
|
+
"""Bundle path resolution for FTS bundles (unified format)."""
|
|
6
|
+
|
|
7
|
+
import json as json_module
|
|
8
|
+
import tempfile
|
|
9
|
+
import zipfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Tuple
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"resolve_pltz_bundle",
|
|
15
|
+
"resolve_figz_bundle",
|
|
16
|
+
"resolve_layered_pltz_bundle",
|
|
17
|
+
"resolve_stx_bundle",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def resolve_figz_bundle(path: Path, panel_index: int = 0) -> Tuple:
|
|
22
|
+
"""
|
|
23
|
+
Resolve paths from a .figz bundle (multi-panel figure).
|
|
24
|
+
|
|
25
|
+
Uses in-memory zip reading for .pltz panels - no disk extraction.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
path : Path
|
|
30
|
+
Path to .figz bundle (.figz or .figz.d)
|
|
31
|
+
panel_index : int, optional
|
|
32
|
+
Index of panel to open (default: 0 for first panel)
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
tuple
|
|
37
|
+
(json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info)
|
|
38
|
+
"""
|
|
39
|
+
spath = str(path)
|
|
40
|
+
figz_is_zip = False
|
|
41
|
+
|
|
42
|
+
# Handle ZIP vs directory for figz
|
|
43
|
+
if spath.endswith(".figz") and not spath.endswith(".figz.d"):
|
|
44
|
+
figz_is_zip = True
|
|
45
|
+
if not path.exists():
|
|
46
|
+
raise FileNotFoundError(f"Figz bundle not found: {path}")
|
|
47
|
+
# For figz zip, extract to access nested pltz
|
|
48
|
+
temp_dir = tempfile.mkdtemp(prefix="scitex_edit_figz_")
|
|
49
|
+
with zipfile.ZipFile(path, "r") as zf:
|
|
50
|
+
zf.extractall(temp_dir)
|
|
51
|
+
bundle_dir = Path(temp_dir)
|
|
52
|
+
for item in bundle_dir.iterdir():
|
|
53
|
+
if item.is_dir() and str(item).endswith(".figz.d"):
|
|
54
|
+
bundle_dir = item
|
|
55
|
+
break
|
|
56
|
+
else:
|
|
57
|
+
bundle_dir = Path(path)
|
|
58
|
+
if not bundle_dir.exists():
|
|
59
|
+
raise FileNotFoundError(f"Figz bundle directory not found: {bundle_dir}")
|
|
60
|
+
|
|
61
|
+
# Find nested pltz bundles
|
|
62
|
+
panel_paths = []
|
|
63
|
+
panel_is_zip = []
|
|
64
|
+
|
|
65
|
+
for item in sorted(bundle_dir.iterdir(), key=lambda x: x.name):
|
|
66
|
+
if item.is_dir() and str(item).endswith(".pltz.d"):
|
|
67
|
+
panel_paths.append(str(item))
|
|
68
|
+
panel_is_zip.append(False)
|
|
69
|
+
elif item.is_file() and str(item).endswith(".pltz"):
|
|
70
|
+
panel_paths.append(str(item))
|
|
71
|
+
panel_is_zip.append(True)
|
|
72
|
+
|
|
73
|
+
if not panel_paths:
|
|
74
|
+
raise FileNotFoundError(f"No .pltz panels found in figz bundle: {bundle_dir}")
|
|
75
|
+
|
|
76
|
+
# Validate panel index
|
|
77
|
+
if panel_index < 0 or panel_index >= len(panel_paths):
|
|
78
|
+
panel_index = 0
|
|
79
|
+
|
|
80
|
+
selected_panel_path = panel_paths[panel_index]
|
|
81
|
+
panel_name = Path(selected_panel_path).name
|
|
82
|
+
print(f"Opening panel: {panel_name}")
|
|
83
|
+
if len(panel_paths) > 1:
|
|
84
|
+
print(f" (Figz contains {len(panel_paths)} panels)")
|
|
85
|
+
|
|
86
|
+
# Build panel info
|
|
87
|
+
panel_names = [Path(p).name for p in panel_paths]
|
|
88
|
+
panel_info = {
|
|
89
|
+
"panels": panel_names,
|
|
90
|
+
"panel_paths": panel_paths,
|
|
91
|
+
"panel_is_zip": panel_is_zip,
|
|
92
|
+
"current_index": panel_index,
|
|
93
|
+
"figz_dir": str(bundle_dir),
|
|
94
|
+
"figz_is_zip": figz_is_zip,
|
|
95
|
+
"bundle_path": (
|
|
96
|
+
str(path) if figz_is_zip else None
|
|
97
|
+
), # Original figz zip path for export/download
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Resolve the selected panel
|
|
101
|
+
result = resolve_pltz_bundle(Path(selected_panel_path))
|
|
102
|
+
return result + (panel_info,)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def resolve_pltz_bundle(path: Path) -> Tuple:
|
|
106
|
+
"""
|
|
107
|
+
Resolve paths from a .pltz bundle (directory or ZIP).
|
|
108
|
+
|
|
109
|
+
Supports both:
|
|
110
|
+
- Legacy format (single {basename}.json)
|
|
111
|
+
- Layered format v2.0 (spec.json + style.json + cache/)
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
path : Path
|
|
116
|
+
Path to .pltz bundle (.pltz or .pltz.d)
|
|
117
|
+
|
|
118
|
+
Returns
|
|
119
|
+
-------
|
|
120
|
+
tuple
|
|
121
|
+
(json_path, csv_path, png_path, hitmap_path, bundle_spec)
|
|
122
|
+
"""
|
|
123
|
+
spath = str(path)
|
|
124
|
+
|
|
125
|
+
# Handle ZIP vs directory
|
|
126
|
+
if spath.endswith(".pltz") and not spath.endswith(".pltz.d"):
|
|
127
|
+
if not path.exists():
|
|
128
|
+
raise FileNotFoundError(f"Bundle not found: {path}")
|
|
129
|
+
temp_dir = tempfile.mkdtemp(prefix="scitex_edit_")
|
|
130
|
+
with zipfile.ZipFile(path, "r") as zf:
|
|
131
|
+
zf.extractall(temp_dir)
|
|
132
|
+
bundle_dir = Path(temp_dir)
|
|
133
|
+
for item in bundle_dir.iterdir():
|
|
134
|
+
if item.is_dir() and str(item).endswith(".pltz.d"):
|
|
135
|
+
bundle_dir = item
|
|
136
|
+
break
|
|
137
|
+
else:
|
|
138
|
+
bundle_dir = Path(path)
|
|
139
|
+
if not bundle_dir.exists():
|
|
140
|
+
raise FileNotFoundError(f"Bundle directory not found: {bundle_dir}")
|
|
141
|
+
|
|
142
|
+
# Check if this is a layered bundle (v2.0)
|
|
143
|
+
spec_path = bundle_dir / "spec.json"
|
|
144
|
+
if spec_path.exists():
|
|
145
|
+
return resolve_layered_pltz_bundle(bundle_dir)
|
|
146
|
+
|
|
147
|
+
# === Legacy format ===
|
|
148
|
+
json_path = None
|
|
149
|
+
csv_path = None
|
|
150
|
+
png_path = None
|
|
151
|
+
svg_path = None
|
|
152
|
+
hitmap_path = None
|
|
153
|
+
bundle_spec = None
|
|
154
|
+
|
|
155
|
+
for f in bundle_dir.iterdir():
|
|
156
|
+
name = f.name
|
|
157
|
+
if name.endswith(".json") and not name.endswith(".manual.json"):
|
|
158
|
+
json_path = f
|
|
159
|
+
elif name.endswith(".csv"):
|
|
160
|
+
csv_path = f
|
|
161
|
+
elif name.endswith("_hitmap.png"):
|
|
162
|
+
hitmap_path = f
|
|
163
|
+
elif name.endswith(".svg") and "_hitmap" not in name:
|
|
164
|
+
svg_path = f
|
|
165
|
+
elif (
|
|
166
|
+
name.endswith(".png") and "_hitmap" not in name and "_overview" not in name
|
|
167
|
+
):
|
|
168
|
+
png_path = f
|
|
169
|
+
|
|
170
|
+
# Prefer SVG for display
|
|
171
|
+
if svg_path:
|
|
172
|
+
png_path = svg_path
|
|
173
|
+
|
|
174
|
+
if json_path and json_path.exists():
|
|
175
|
+
with open(json_path) as f:
|
|
176
|
+
bundle_spec = json_module.load(f)
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
json_path,
|
|
180
|
+
csv_path if csv_path and csv_path.exists() else None,
|
|
181
|
+
png_path if png_path and png_path.exists() else None,
|
|
182
|
+
hitmap_path if hitmap_path and hitmap_path.exists() else None,
|
|
183
|
+
bundle_spec,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def resolve_layered_pltz_bundle(bundle_dir: Path) -> Tuple:
|
|
188
|
+
"""
|
|
189
|
+
Resolve paths from a layered FTS bundle.
|
|
190
|
+
|
|
191
|
+
FTS format structure:
|
|
192
|
+
bundle.zip (or bundle.d/)
|
|
193
|
+
canonical/
|
|
194
|
+
spec.json # Main specification
|
|
195
|
+
data.csv # Source data
|
|
196
|
+
encoding.json # Data-to-visual mappings
|
|
197
|
+
theme.json # Visual aesthetics
|
|
198
|
+
artifacts/
|
|
199
|
+
exports/ # PNG, SVG, PDF
|
|
200
|
+
cache/ # geometry_px.json
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
bundle_dir : Path
|
|
205
|
+
Path to bundle directory.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
tuple
|
|
210
|
+
(json_path, csv_path, png_path, hitmap_path, bundle_spec)
|
|
211
|
+
"""
|
|
212
|
+
# Load FTS bundle directly
|
|
213
|
+
bundle_data = {}
|
|
214
|
+
spec_path = bundle_dir / "canonical" / "spec.json"
|
|
215
|
+
if not spec_path.exists():
|
|
216
|
+
spec_path = bundle_dir / "spec.json" # Legacy location
|
|
217
|
+
|
|
218
|
+
if spec_path.exists():
|
|
219
|
+
with open(spec_path) as f:
|
|
220
|
+
bundle_data["spec"] = json_module.load(f)
|
|
221
|
+
|
|
222
|
+
# Try to load encoding and theme
|
|
223
|
+
for fname in ["encoding.json", "theme.json"]:
|
|
224
|
+
fpath = bundle_dir / "canonical" / fname
|
|
225
|
+
if not fpath.exists():
|
|
226
|
+
fpath = bundle_dir / fname
|
|
227
|
+
if fpath.exists():
|
|
228
|
+
with open(fpath) as f:
|
|
229
|
+
bundle_data[fname.replace(".json", "")] = json_module.load(f)
|
|
230
|
+
|
|
231
|
+
csv_path = None
|
|
232
|
+
png_path = None
|
|
233
|
+
hitmap_path = None
|
|
234
|
+
|
|
235
|
+
# Find CSV (check canonical/ first, then root)
|
|
236
|
+
for search_dir in [bundle_dir / "canonical", bundle_dir]:
|
|
237
|
+
for f in search_dir.glob("*.csv"):
|
|
238
|
+
csv_path = f
|
|
239
|
+
break
|
|
240
|
+
if csv_path:
|
|
241
|
+
break
|
|
242
|
+
|
|
243
|
+
# Find exports (check artifacts/exports first, then exports/)
|
|
244
|
+
for exports_dir in [bundle_dir / "artifacts" / "exports", bundle_dir / "exports"]:
|
|
245
|
+
if exports_dir.exists():
|
|
246
|
+
for f in exports_dir.iterdir():
|
|
247
|
+
name = f.name
|
|
248
|
+
if name.endswith("_hitmap.png"):
|
|
249
|
+
hitmap_path = f
|
|
250
|
+
elif name.endswith(".svg") and "_hitmap" not in name:
|
|
251
|
+
png_path = f
|
|
252
|
+
elif (
|
|
253
|
+
name.endswith(".png") and "_hitmap" not in name and png_path is None
|
|
254
|
+
):
|
|
255
|
+
png_path = f
|
|
256
|
+
|
|
257
|
+
# Merge spec with encoding and theme
|
|
258
|
+
bundle_spec = bundle_data.get("spec", {})
|
|
259
|
+
if "encoding" in bundle_data:
|
|
260
|
+
bundle_spec["encoding"] = bundle_data["encoding"]
|
|
261
|
+
if "theme" in bundle_data:
|
|
262
|
+
bundle_spec["theme"] = bundle_data["theme"]
|
|
263
|
+
|
|
264
|
+
if hitmap_path and "hit_regions" in bundle_spec:
|
|
265
|
+
bundle_spec["hit_regions"]["hit_map"] = str(hitmap_path.name)
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
spec_path,
|
|
269
|
+
csv_path if csv_path and csv_path.exists() else None,
|
|
270
|
+
png_path if png_path and png_path.exists() else None,
|
|
271
|
+
hitmap_path if hitmap_path and hitmap_path.exists() else None,
|
|
272
|
+
bundle_spec,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def resolve_stx_bundle(path: Path) -> Tuple:
|
|
277
|
+
"""
|
|
278
|
+
Resolve paths from a .stx bundle (unified FTS format).
|
|
279
|
+
|
|
280
|
+
Parameters
|
|
281
|
+
----------
|
|
282
|
+
path : Path
|
|
283
|
+
Path to .stx bundle (.stx, .stx.d, .zip, or directory)
|
|
284
|
+
|
|
285
|
+
Returns
|
|
286
|
+
-------
|
|
287
|
+
tuple
|
|
288
|
+
(json_path, csv_path, png_path, hitmap_path, bundle_spec, element_info)
|
|
289
|
+
"""
|
|
290
|
+
from scitex.fts import FTS
|
|
291
|
+
|
|
292
|
+
spath = str(path)
|
|
293
|
+
|
|
294
|
+
# Handle ZIP vs directory
|
|
295
|
+
if spath.endswith((".stx", ".zip")) and not spath.endswith(".stx.d"):
|
|
296
|
+
if not path.exists():
|
|
297
|
+
raise FileNotFoundError(f"Bundle not found: {path}")
|
|
298
|
+
temp_dir = tempfile.mkdtemp(prefix="scitex_edit_stx_")
|
|
299
|
+
with zipfile.ZipFile(path, "r") as zf:
|
|
300
|
+
zf.extractall(temp_dir)
|
|
301
|
+
bundle_dir = Path(temp_dir)
|
|
302
|
+
for item in bundle_dir.iterdir():
|
|
303
|
+
if item.is_dir() and str(item).endswith((".stx.d", ".d")):
|
|
304
|
+
bundle_dir = item
|
|
305
|
+
break
|
|
306
|
+
else:
|
|
307
|
+
bundle_dir = Path(path)
|
|
308
|
+
if not bundle_dir.exists():
|
|
309
|
+
raise FileNotFoundError(f"Bundle directory not found: {bundle_dir}")
|
|
310
|
+
|
|
311
|
+
# Load using FTS class
|
|
312
|
+
fts_bundle = FTS(bundle_dir)
|
|
313
|
+
|
|
314
|
+
# Find spec path (canonical/spec.json or spec.json)
|
|
315
|
+
spec_path = bundle_dir / "canonical" / "spec.json"
|
|
316
|
+
if not spec_path.exists():
|
|
317
|
+
spec_path = bundle_dir / "spec.json"
|
|
318
|
+
|
|
319
|
+
# Find exports (artifacts/exports or exports/)
|
|
320
|
+
png_path = None
|
|
321
|
+
hitmap_path = None
|
|
322
|
+
csv_path = None
|
|
323
|
+
for exports_dir in [bundle_dir / "artifacts" / "exports", bundle_dir / "exports"]:
|
|
324
|
+
if exports_dir.exists():
|
|
325
|
+
for f in exports_dir.iterdir():
|
|
326
|
+
name = f.name
|
|
327
|
+
if name.endswith("_hitmap.png"):
|
|
328
|
+
hitmap_path = f
|
|
329
|
+
elif name.endswith(".svg") and "_hitmap" not in name:
|
|
330
|
+
png_path = f
|
|
331
|
+
elif (
|
|
332
|
+
name.endswith(".png") and "_hitmap" not in name and png_path is None
|
|
333
|
+
):
|
|
334
|
+
png_path = f
|
|
335
|
+
|
|
336
|
+
# Find CSV (canonical/data.csv or root)
|
|
337
|
+
for search_dir in [bundle_dir / "canonical", bundle_dir]:
|
|
338
|
+
for f in search_dir.glob("*.csv"):
|
|
339
|
+
csv_path = f
|
|
340
|
+
break
|
|
341
|
+
if csv_path:
|
|
342
|
+
break
|
|
343
|
+
|
|
344
|
+
# Build bundle spec from FTS
|
|
345
|
+
bundle_spec = fts_bundle.to_dict() if hasattr(fts_bundle, "to_dict") else {}
|
|
346
|
+
|
|
347
|
+
# Build element info for editor
|
|
348
|
+
element_info = {
|
|
349
|
+
"elements": getattr(fts_bundle, "elements", []),
|
|
350
|
+
"size_mm": fts_bundle.node.size_mm if fts_bundle.node else None,
|
|
351
|
+
"bundle_dir": str(bundle_dir),
|
|
352
|
+
"bundle_path": str(path),
|
|
353
|
+
"is_directory": bundle_dir.is_dir(),
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
spec_path,
|
|
358
|
+
csv_path if csv_path and csv_path.exists() else None,
|
|
359
|
+
png_path if png_path and png_path.exists() else None,
|
|
360
|
+
hitmap_path if hitmap_path and hitmap_path.exists() else None,
|
|
361
|
+
bundle_spec,
|
|
362
|
+
element_info,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
# EOF
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_fig/_editor/_cui/_editor_launcher.py
|
|
4
|
+
|
|
5
|
+
"""Main edit function for launching Flask visual editor."""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Union
|
|
9
|
+
|
|
10
|
+
from ._backend_detector import detect_best_backend, print_available_backends
|
|
11
|
+
from ._bundle_resolver import (
|
|
12
|
+
resolve_figz_bundle,
|
|
13
|
+
resolve_pltz_bundle,
|
|
14
|
+
)
|
|
15
|
+
from ._path_resolver import resolve_figure_paths
|
|
16
|
+
|
|
17
|
+
__all__ = ["edit"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def edit(
|
|
21
|
+
path: Union[str, Path],
|
|
22
|
+
apply_manual: bool = True,
|
|
23
|
+
port: int = 5050,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Launch interactive Flask editor for figure style/annotation editing.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
path : str or Path
|
|
31
|
+
Path to figure file. Can be:
|
|
32
|
+
- .stx or .stx.d unified element bundle
|
|
33
|
+
- .pltz.d directory bundle (recommended for hitmap selection)
|
|
34
|
+
- .pltz ZIP bundle
|
|
35
|
+
- .figz or .figz.d multi-panel bundle
|
|
36
|
+
- JSON file (figure.json or figure.manual.json)
|
|
37
|
+
- CSV file (figure.csv) - for data-only start
|
|
38
|
+
- PNG file (figure.png)
|
|
39
|
+
apply_manual : bool, optional
|
|
40
|
+
If True, load .manual.json overrides if exists (default: True)
|
|
41
|
+
port : int, optional
|
|
42
|
+
Port number for Flask editor. Default: 5050.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
None
|
|
47
|
+
Editor runs in Flask event loop. Changes saved to .manual.json.
|
|
48
|
+
"""
|
|
49
|
+
path = Path(path)
|
|
50
|
+
spath = str(path)
|
|
51
|
+
parent_str = str(path.parent) if path.is_file() else ""
|
|
52
|
+
|
|
53
|
+
# Panel info for multi-panel figures
|
|
54
|
+
panel_info = None
|
|
55
|
+
|
|
56
|
+
# Resolve paths based on input type
|
|
57
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = (
|
|
58
|
+
_resolve_paths(path, spath, parent_str)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if not json_path.exists():
|
|
62
|
+
raise FileNotFoundError(f"JSON file not found: {json_path}")
|
|
63
|
+
|
|
64
|
+
# Load data
|
|
65
|
+
import scitex as stx
|
|
66
|
+
|
|
67
|
+
metadata = bundle_spec if bundle_spec else stx.io.load(json_path)
|
|
68
|
+
csv_data = None
|
|
69
|
+
if csv_path and csv_path.exists():
|
|
70
|
+
csv_data = stx.io.load(csv_path)
|
|
71
|
+
|
|
72
|
+
# Load manual overrides if exists
|
|
73
|
+
manual_path = json_path.with_suffix(".manual.json")
|
|
74
|
+
manual_overrides = None
|
|
75
|
+
if apply_manual and manual_path.exists():
|
|
76
|
+
manual_data = stx.io.load(manual_path)
|
|
77
|
+
manual_overrides = manual_data.get("overrides", {})
|
|
78
|
+
|
|
79
|
+
# Verify Flask is available
|
|
80
|
+
detect_best_backend()
|
|
81
|
+
|
|
82
|
+
# Print status
|
|
83
|
+
print_available_backends()
|
|
84
|
+
print(f"Launching Flask editor for: {json_path}")
|
|
85
|
+
|
|
86
|
+
# Launch Flask editor
|
|
87
|
+
_launch_flask(
|
|
88
|
+
json_path=json_path,
|
|
89
|
+
metadata=metadata,
|
|
90
|
+
csv_data=csv_data,
|
|
91
|
+
png_path=png_path,
|
|
92
|
+
hitmap_path=hitmap_path,
|
|
93
|
+
manual_overrides=manual_overrides,
|
|
94
|
+
port=port,
|
|
95
|
+
panel_info=panel_info,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _resolve_paths(path: Path, spath: str, parent_str: str) -> tuple:
|
|
100
|
+
"""Resolve paths based on input type."""
|
|
101
|
+
panel_info = None
|
|
102
|
+
hitmap_path = None
|
|
103
|
+
bundle_spec = None
|
|
104
|
+
|
|
105
|
+
# Check if this is a .stx bundle (unified element format)
|
|
106
|
+
if spath.endswith(".stx.d") or spath.endswith(".stx"):
|
|
107
|
+
from ._bundle_resolver import resolve_stx_bundle
|
|
108
|
+
|
|
109
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = (
|
|
110
|
+
resolve_stx_bundle(path)
|
|
111
|
+
)
|
|
112
|
+
# Check if this is a .figz bundle (multi-panel figure)
|
|
113
|
+
elif spath.endswith(".figz.d") or spath.endswith(".figz"):
|
|
114
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = (
|
|
115
|
+
resolve_figz_bundle(path)
|
|
116
|
+
)
|
|
117
|
+
# Check if this is a .pltz bundle
|
|
118
|
+
elif (
|
|
119
|
+
spath.endswith(".pltz.d")
|
|
120
|
+
or spath.endswith(".pltz")
|
|
121
|
+
or parent_str.endswith(".pltz.d")
|
|
122
|
+
):
|
|
123
|
+
bundle_path = path.parent if parent_str.endswith(".pltz.d") else path
|
|
124
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec = resolve_pltz_bundle(
|
|
125
|
+
bundle_path
|
|
126
|
+
)
|
|
127
|
+
# Check if file is inside a .figz.d
|
|
128
|
+
elif parent_str.endswith(".figz.d") or (
|
|
129
|
+
path.parent.parent and str(path.parent.parent).endswith(".figz.d")
|
|
130
|
+
):
|
|
131
|
+
figz_path = (
|
|
132
|
+
path.parent if parent_str.endswith(".figz.d") else path.parent.parent
|
|
133
|
+
)
|
|
134
|
+
json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info = (
|
|
135
|
+
resolve_figz_bundle(figz_path)
|
|
136
|
+
)
|
|
137
|
+
else:
|
|
138
|
+
# Standard file paths
|
|
139
|
+
json_path, csv_path, png_path = resolve_figure_paths(path)
|
|
140
|
+
|
|
141
|
+
return json_path, csv_path, png_path, hitmap_path, bundle_spec, panel_info
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _launch_flask(
|
|
145
|
+
json_path,
|
|
146
|
+
metadata,
|
|
147
|
+
csv_data,
|
|
148
|
+
png_path,
|
|
149
|
+
hitmap_path,
|
|
150
|
+
manual_overrides,
|
|
151
|
+
port,
|
|
152
|
+
panel_info,
|
|
153
|
+
):
|
|
154
|
+
"""Launch Flask web editor."""
|
|
155
|
+
try:
|
|
156
|
+
from .._gui._flask_editor import WebEditor
|
|
157
|
+
|
|
158
|
+
editor = WebEditor(
|
|
159
|
+
json_path=json_path,
|
|
160
|
+
metadata=metadata,
|
|
161
|
+
csv_data=csv_data,
|
|
162
|
+
png_path=png_path,
|
|
163
|
+
hitmap_path=hitmap_path,
|
|
164
|
+
manual_overrides=manual_overrides,
|
|
165
|
+
port=port,
|
|
166
|
+
panel_info=panel_info,
|
|
167
|
+
)
|
|
168
|
+
editor.run()
|
|
169
|
+
except ImportError as e:
|
|
170
|
+
raise ImportError(
|
|
171
|
+
"Flask backend requires Flask. Install with: pip install flask"
|
|
172
|
+
) from e
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# EOF
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: "2025-12-14 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fig/editor/edit/manual_handler.py
|
|
4
|
+
|
|
5
|
+
"""Manual override handling for figure editor."""
|
|
6
|
+
|
|
7
|
+
import hashlib
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
__all__ = ["compute_file_hash", "save_manual_overrides"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def compute_file_hash(path: Path) -> str:
|
|
14
|
+
"""Compute SHA256 hash of file contents."""
|
|
15
|
+
with open(path, "rb") as f:
|
|
16
|
+
return hashlib.sha256(f.read()).hexdigest()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def save_manual_overrides(json_path: Path, overrides: dict) -> Path:
|
|
20
|
+
"""
|
|
21
|
+
Save manual overrides to .manual.json file.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
json_path : Path
|
|
26
|
+
Path to base JSON file
|
|
27
|
+
overrides : dict
|
|
28
|
+
Override settings (styles, annotations, etc.)
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
Path
|
|
33
|
+
Path to saved manual.json file
|
|
34
|
+
"""
|
|
35
|
+
import scitex as stx
|
|
36
|
+
|
|
37
|
+
manual_path = json_path.with_suffix(".manual.json")
|
|
38
|
+
|
|
39
|
+
# Compute hash of base JSON for staleness detection
|
|
40
|
+
base_hash = compute_file_hash(json_path)
|
|
41
|
+
|
|
42
|
+
manual_data = {
|
|
43
|
+
"base_file": json_path.name,
|
|
44
|
+
"base_hash": base_hash,
|
|
45
|
+
"overrides": overrides,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
stx.io.save(manual_data, manual_path)
|
|
49
|
+
return manual_path
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# EOF
|