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,182 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: 2025-12-15
|
|
4
|
+
# Author: ywatanabe / Claude
|
|
5
|
+
# File: scitex/diagram/_schema.py
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Schema definitions for SciTeX Diagram.
|
|
9
|
+
|
|
10
|
+
The schema defines paper-specific constraints that Mermaid/Graphviz don't know:
|
|
11
|
+
- Paper layout (single/double column, max width)
|
|
12
|
+
- Reading direction preferences
|
|
13
|
+
- Node emphasis for scientific communication
|
|
14
|
+
- Semantic layer grouping
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from typing import List, Dict, Optional, Literal
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DiagramType(Enum):
|
|
23
|
+
"""Semantic type of diagram - affects layout strategy."""
|
|
24
|
+
WORKFLOW = "workflow" # Sequential process, prefer LR/TB flow
|
|
25
|
+
DECISION = "decision" # Decision tree, prefer TB with branches
|
|
26
|
+
PIPELINE = "pipeline" # Data pipeline, strict LR with stages
|
|
27
|
+
HIERARCHY = "hierarchy" # Tree structure, TB with levels
|
|
28
|
+
COMPARISON = "comparison" # Side-by-side, two columns
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ColumnLayout(Enum):
|
|
32
|
+
"""Paper column layout."""
|
|
33
|
+
SINGLE = "single" # Full width (~170mm)
|
|
34
|
+
DOUBLE = "double" # Half width (~85mm)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class SpacingLevel(Enum):
|
|
38
|
+
"""Abstract spacing levels - mapped to backend-specific values."""
|
|
39
|
+
TIGHT = "tight" # Publication: minimal whitespace
|
|
40
|
+
COMPACT = "compact"
|
|
41
|
+
MEDIUM = "medium"
|
|
42
|
+
LARGE = "large"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class PaperMode(Enum):
|
|
46
|
+
"""Paper mode affects layout density and edge visibility."""
|
|
47
|
+
DRAFT = "draft" # Full arrows, visible bidirectional, medium spacing
|
|
48
|
+
PUBLICATION = "publication" # Compact, return edges hidden/dotted
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class PaperConstraints:
|
|
53
|
+
"""Paper-specific constraints that affect layout."""
|
|
54
|
+
column: ColumnLayout = ColumnLayout.SINGLE
|
|
55
|
+
max_width_mm: int = 170
|
|
56
|
+
reading_direction: Literal["left_to_right", "top_to_bottom"] = "left_to_right"
|
|
57
|
+
mode: PaperMode = PaperMode.DRAFT # draft: full details, publication: compact
|
|
58
|
+
emphasize: List[str] = field(default_factory=list) # Node IDs to highlight
|
|
59
|
+
|
|
60
|
+
# Scientific communication hints
|
|
61
|
+
main_flow: List[str] = field(default_factory=list) # Critical path nodes
|
|
62
|
+
secondary_flow: List[str] = field(default_factory=list) # Supporting elements
|
|
63
|
+
return_edges: List[tuple] = field(default_factory=list) # Edges to hide in publication
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class LayoutHints:
|
|
68
|
+
"""Abstract layout hints - compiled to backend directives."""
|
|
69
|
+
layers: List[List[str]] = field(default_factory=list) # Nodes grouped by rank
|
|
70
|
+
alignment: Dict[str, str] = field(default_factory=dict) # Node alignment hints
|
|
71
|
+
layer_gap: SpacingLevel = SpacingLevel.MEDIUM
|
|
72
|
+
node_gap: SpacingLevel = SpacingLevel.MEDIUM
|
|
73
|
+
|
|
74
|
+
# Subgraph organization
|
|
75
|
+
groups: Dict[str, List[str]] = field(default_factory=dict) # Named groups
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class NodeSpec:
|
|
80
|
+
"""Specification for a single node."""
|
|
81
|
+
id: str
|
|
82
|
+
label: str
|
|
83
|
+
shape: Literal["box", "rounded", "diamond", "circle", "stadium"] = "box"
|
|
84
|
+
emphasis: Literal["normal", "primary", "success", "warning", "muted"] = "normal"
|
|
85
|
+
|
|
86
|
+
def short_label(self, max_chars: int = 20) -> str:
|
|
87
|
+
"""Return truncated label for compact layouts."""
|
|
88
|
+
if len(self.label) <= max_chars:
|
|
89
|
+
return self.label
|
|
90
|
+
return self.label[:max_chars-3] + "..."
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class EdgeSpec:
|
|
95
|
+
"""Specification for an edge between nodes."""
|
|
96
|
+
source: str
|
|
97
|
+
target: str
|
|
98
|
+
label: Optional[str] = None
|
|
99
|
+
style: Literal["solid", "dashed", "dotted"] = "solid"
|
|
100
|
+
arrow: Literal["normal", "none", "open"] = "normal"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class DiagramSpec:
|
|
105
|
+
"""Complete diagram specification - the semantic layer."""
|
|
106
|
+
|
|
107
|
+
# Metadata
|
|
108
|
+
type: DiagramType = DiagramType.WORKFLOW
|
|
109
|
+
title: str = ""
|
|
110
|
+
|
|
111
|
+
# Paper constraints
|
|
112
|
+
paper: PaperConstraints = field(default_factory=PaperConstraints)
|
|
113
|
+
|
|
114
|
+
# Layout hints
|
|
115
|
+
layout: LayoutHints = field(default_factory=LayoutHints)
|
|
116
|
+
|
|
117
|
+
# Content
|
|
118
|
+
nodes: List[NodeSpec] = field(default_factory=list)
|
|
119
|
+
edges: List[EdgeSpec] = field(default_factory=list)
|
|
120
|
+
|
|
121
|
+
# Theme
|
|
122
|
+
theme: Dict[str, str] = field(default_factory=dict)
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
def from_dict(cls, data: dict) -> "DiagramSpec":
|
|
126
|
+
"""Create DiagramSpec from dictionary (parsed YAML)."""
|
|
127
|
+
spec = cls()
|
|
128
|
+
|
|
129
|
+
# Parse type
|
|
130
|
+
if "type" in data:
|
|
131
|
+
spec.type = DiagramType(data["type"])
|
|
132
|
+
|
|
133
|
+
spec.title = data.get("title", "")
|
|
134
|
+
|
|
135
|
+
# Parse paper constraints
|
|
136
|
+
if "paper" in data:
|
|
137
|
+
p = data["paper"]
|
|
138
|
+
spec.paper = PaperConstraints(
|
|
139
|
+
column=ColumnLayout(p.get("column", "single")),
|
|
140
|
+
max_width_mm=p.get("max_width_mm", 170),
|
|
141
|
+
reading_direction=p.get("reading_direction", "left_to_right"),
|
|
142
|
+
mode=PaperMode(p.get("mode", "draft")),
|
|
143
|
+
emphasize=p.get("emphasize", []),
|
|
144
|
+
main_flow=p.get("main_flow", []),
|
|
145
|
+
secondary_flow=p.get("secondary_flow", []),
|
|
146
|
+
return_edges=[tuple(e) for e in p.get("return_edges", [])],
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Parse layout hints
|
|
150
|
+
if "layout" in data:
|
|
151
|
+
lt = data["layout"]
|
|
152
|
+
spec.layout = LayoutHints(
|
|
153
|
+
layers=lt.get("layers", []),
|
|
154
|
+
alignment=lt.get("alignment", {}),
|
|
155
|
+
layer_gap=SpacingLevel(lt.get("layer_gap", "medium")),
|
|
156
|
+
node_gap=SpacingLevel(lt.get("node_gap", "medium")),
|
|
157
|
+
groups=lt.get("groups", {}),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Parse nodes
|
|
161
|
+
for n in data.get("nodes", []):
|
|
162
|
+
spec.nodes.append(NodeSpec(
|
|
163
|
+
id=n["id"],
|
|
164
|
+
label=n.get("label", n["id"]),
|
|
165
|
+
shape=n.get("shape", "box"),
|
|
166
|
+
emphasis=n.get("emphasis", "normal"),
|
|
167
|
+
))
|
|
168
|
+
|
|
169
|
+
# Parse edges
|
|
170
|
+
for e in data.get("edges", []):
|
|
171
|
+
spec.edges.append(EdgeSpec(
|
|
172
|
+
source=e["from"] if "from" in e else e["source"],
|
|
173
|
+
target=e["to"] if "to" in e else e["target"],
|
|
174
|
+
label=e.get("label"),
|
|
175
|
+
style=e.get("style", "solid"),
|
|
176
|
+
arrow=e.get("arrow", "normal"),
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
# Theme
|
|
180
|
+
spec.theme = data.get("theme", {})
|
|
181
|
+
|
|
182
|
+
return spec
|
scitex/diagram/_split.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: 2025-12-15
|
|
4
|
+
# Author: ywatanabe / Claude
|
|
5
|
+
# File: scitex/diagram/_split.py
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Auto-split large diagrams into multiple figures.
|
|
9
|
+
|
|
10
|
+
Strategies:
|
|
11
|
+
- by_groups: Split by existing layout.groups (deterministic, paper-friendly)
|
|
12
|
+
- by_articulation: Split at hub nodes (graph-theoretic)
|
|
13
|
+
|
|
14
|
+
The split preserves "ghost nodes" at boundaries for visual continuity.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import List, Dict, Set, Optional, Tuple
|
|
19
|
+
from copy import deepcopy
|
|
20
|
+
from enum import Enum
|
|
21
|
+
|
|
22
|
+
from scitex.diagram._schema import DiagramSpec, NodeSpec, EdgeSpec
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SplitStrategy(Enum):
|
|
26
|
+
BY_GROUPS = "by_groups" # Split by layout.groups
|
|
27
|
+
BY_ARTICULATION = "by_articulation" # Split at hub nodes
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class SplitConfig:
|
|
32
|
+
"""Configuration for auto-splitting."""
|
|
33
|
+
enabled: bool = False
|
|
34
|
+
max_nodes: int = 12 # Split if more nodes than this
|
|
35
|
+
strategy: SplitStrategy = SplitStrategy.BY_GROUPS
|
|
36
|
+
keep_hubs: bool = True # Show hub nodes in both parts
|
|
37
|
+
ghost_style: str = "muted" # Style for ghost nodes
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class SplitResult:
|
|
42
|
+
"""Result of splitting a diagram."""
|
|
43
|
+
figures: List[DiagramSpec]
|
|
44
|
+
labels: List[str] # Figure labels (A, B, C, ...)
|
|
45
|
+
cut_nodes: Set[str] # Nodes that appear in multiple figures
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def split_diagram(
|
|
49
|
+
spec: DiagramSpec,
|
|
50
|
+
config: Optional[SplitConfig] = None,
|
|
51
|
+
group_assignments: Optional[List[List[str]]] = None,
|
|
52
|
+
) -> SplitResult:
|
|
53
|
+
"""
|
|
54
|
+
Split a diagram into multiple figures.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
spec : DiagramSpec
|
|
59
|
+
Original diagram specification.
|
|
60
|
+
config : SplitConfig, optional
|
|
61
|
+
Split configuration.
|
|
62
|
+
group_assignments : List[List[str]], optional
|
|
63
|
+
Manual group assignments for splitting.
|
|
64
|
+
If provided, overrides automatic detection.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
SplitResult
|
|
69
|
+
List of split diagram specifications.
|
|
70
|
+
"""
|
|
71
|
+
if config is None:
|
|
72
|
+
config = SplitConfig(enabled=True)
|
|
73
|
+
|
|
74
|
+
# Check if split is needed
|
|
75
|
+
if not config.enabled or len(spec.nodes) <= config.max_nodes:
|
|
76
|
+
return SplitResult(figures=[spec], labels=[""], cut_nodes=set())
|
|
77
|
+
|
|
78
|
+
# Determine groups to split by
|
|
79
|
+
if group_assignments:
|
|
80
|
+
groups = group_assignments
|
|
81
|
+
elif config.strategy == SplitStrategy.BY_GROUPS:
|
|
82
|
+
groups = _split_by_groups(spec, max_nodes=config.max_nodes)
|
|
83
|
+
else: # BY_ARTICULATION
|
|
84
|
+
groups = _split_by_articulation(spec)
|
|
85
|
+
|
|
86
|
+
# Create split figures
|
|
87
|
+
figures = []
|
|
88
|
+
labels = []
|
|
89
|
+
cut_nodes = set()
|
|
90
|
+
|
|
91
|
+
for i, group_nodes in enumerate(groups):
|
|
92
|
+
fig, cuts = _create_split_figure(spec, group_nodes, config)
|
|
93
|
+
figures.append(fig)
|
|
94
|
+
labels.append(chr(ord('A') + i))
|
|
95
|
+
cut_nodes.update(cuts)
|
|
96
|
+
|
|
97
|
+
return SplitResult(figures=figures, labels=labels, cut_nodes=cut_nodes)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _split_by_groups(spec: DiagramSpec, max_nodes: int = 12) -> List[List[str]]:
|
|
101
|
+
"""
|
|
102
|
+
Split by existing layout.groups using greedy packing.
|
|
103
|
+
|
|
104
|
+
Packs groups into figures until max_nodes is exceeded,
|
|
105
|
+
then starts a new figure.
|
|
106
|
+
|
|
107
|
+
Returns list of node ID lists, one per split figure.
|
|
108
|
+
"""
|
|
109
|
+
if not spec.layout.groups:
|
|
110
|
+
# No groups defined - try to split in half
|
|
111
|
+
node_ids = [n.id for n in spec.nodes]
|
|
112
|
+
mid = len(node_ids) // 2
|
|
113
|
+
return [node_ids[:mid], node_ids[mid:]]
|
|
114
|
+
|
|
115
|
+
# Group keys in order
|
|
116
|
+
group_names = list(spec.layout.groups.keys())
|
|
117
|
+
|
|
118
|
+
# Greedy packing: add groups until max_nodes exceeded
|
|
119
|
+
figures = []
|
|
120
|
+
current_figure = []
|
|
121
|
+
current_count = 0
|
|
122
|
+
|
|
123
|
+
for group_name in group_names:
|
|
124
|
+
group_nodes = spec.layout.groups[group_name]
|
|
125
|
+
group_size = len(group_nodes)
|
|
126
|
+
|
|
127
|
+
# If adding this group exceeds max and we have something, start new figure
|
|
128
|
+
if current_count + group_size > max_nodes and current_figure:
|
|
129
|
+
figures.append(current_figure)
|
|
130
|
+
current_figure = []
|
|
131
|
+
current_count = 0
|
|
132
|
+
|
|
133
|
+
# Add group to current figure
|
|
134
|
+
current_figure.extend(group_nodes)
|
|
135
|
+
current_count += group_size
|
|
136
|
+
|
|
137
|
+
# Don't forget the last figure
|
|
138
|
+
if current_figure:
|
|
139
|
+
figures.append(current_figure)
|
|
140
|
+
|
|
141
|
+
# Add ungrouped nodes to first figure
|
|
142
|
+
grouped = set()
|
|
143
|
+
for fig in figures:
|
|
144
|
+
grouped.update(fig)
|
|
145
|
+
for n in spec.nodes:
|
|
146
|
+
if n.id not in grouped:
|
|
147
|
+
if figures:
|
|
148
|
+
figures[0].append(n.id)
|
|
149
|
+
else:
|
|
150
|
+
figures.append([n.id])
|
|
151
|
+
|
|
152
|
+
# Ensure at least 2 figures if we have enough nodes
|
|
153
|
+
if len(figures) == 1 and len(figures[0]) > max_nodes:
|
|
154
|
+
# Force split in half
|
|
155
|
+
nodes = figures[0]
|
|
156
|
+
mid = len(nodes) // 2
|
|
157
|
+
figures = [nodes[:mid], nodes[mid:]]
|
|
158
|
+
|
|
159
|
+
return figures
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _split_by_articulation(spec: DiagramSpec) -> List[List[str]]:
|
|
163
|
+
"""
|
|
164
|
+
Split at articulation points (hub nodes).
|
|
165
|
+
|
|
166
|
+
This finds nodes that, if removed, would disconnect the graph.
|
|
167
|
+
These are natural split points for large diagrams.
|
|
168
|
+
"""
|
|
169
|
+
# Build adjacency
|
|
170
|
+
adj: Dict[str, Set[str]] = {n.id: set() for n in spec.nodes}
|
|
171
|
+
for e in spec.edges:
|
|
172
|
+
adj[e.source].add(e.target)
|
|
173
|
+
adj[e.target].add(e.source)
|
|
174
|
+
|
|
175
|
+
# Find node with most connections (hub)
|
|
176
|
+
hub = max(adj.keys(), key=lambda x: len(adj[x]))
|
|
177
|
+
|
|
178
|
+
# BFS from first node, stopping at hub
|
|
179
|
+
visited = {hub} # Block the hub
|
|
180
|
+
node_ids = [n.id for n in spec.nodes if n.id != hub]
|
|
181
|
+
|
|
182
|
+
if not node_ids:
|
|
183
|
+
return [[hub]]
|
|
184
|
+
|
|
185
|
+
# Find components when hub is removed
|
|
186
|
+
components = []
|
|
187
|
+
for start in node_ids:
|
|
188
|
+
if start in visited:
|
|
189
|
+
continue
|
|
190
|
+
component = []
|
|
191
|
+
queue = [start]
|
|
192
|
+
while queue:
|
|
193
|
+
curr = queue.pop(0)
|
|
194
|
+
if curr in visited:
|
|
195
|
+
continue
|
|
196
|
+
visited.add(curr)
|
|
197
|
+
component.append(curr)
|
|
198
|
+
for neighbor in adj[curr]:
|
|
199
|
+
if neighbor not in visited:
|
|
200
|
+
queue.append(neighbor)
|
|
201
|
+
if component:
|
|
202
|
+
components.append(component)
|
|
203
|
+
|
|
204
|
+
# Add hub to each component (as ghost)
|
|
205
|
+
for comp in components:
|
|
206
|
+
comp.append(hub)
|
|
207
|
+
|
|
208
|
+
return components if components else [[n.id for n in spec.nodes]]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _create_split_figure(
|
|
212
|
+
spec: DiagramSpec,
|
|
213
|
+
node_ids: List[str],
|
|
214
|
+
config: SplitConfig,
|
|
215
|
+
) -> Tuple[DiagramSpec, Set[str]]:
|
|
216
|
+
"""
|
|
217
|
+
Create a split figure containing specified nodes.
|
|
218
|
+
|
|
219
|
+
Returns (figure_spec, ghost_node_ids).
|
|
220
|
+
"""
|
|
221
|
+
node_id_set = set(node_ids)
|
|
222
|
+
|
|
223
|
+
# Find edges that cross the boundary
|
|
224
|
+
boundary_nodes = set()
|
|
225
|
+
for edge in spec.edges:
|
|
226
|
+
src_in = edge.source in node_id_set
|
|
227
|
+
tgt_in = edge.target in node_id_set
|
|
228
|
+
if src_in and not tgt_in:
|
|
229
|
+
if config.keep_hubs:
|
|
230
|
+
boundary_nodes.add(edge.target)
|
|
231
|
+
elif tgt_in and not src_in:
|
|
232
|
+
if config.keep_hubs:
|
|
233
|
+
boundary_nodes.add(edge.source)
|
|
234
|
+
|
|
235
|
+
# Create new spec
|
|
236
|
+
new_spec = DiagramSpec(
|
|
237
|
+
type=spec.type,
|
|
238
|
+
title=spec.title,
|
|
239
|
+
paper=deepcopy(spec.paper),
|
|
240
|
+
layout=deepcopy(spec.layout),
|
|
241
|
+
theme=dict(spec.theme),
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Filter nodes
|
|
245
|
+
node_map = {n.id: n for n in spec.nodes}
|
|
246
|
+
for node_id in node_ids:
|
|
247
|
+
if node_id in node_map:
|
|
248
|
+
new_spec.nodes.append(deepcopy(node_map[node_id]))
|
|
249
|
+
|
|
250
|
+
# Add ghost nodes (boundary nodes not in this split)
|
|
251
|
+
for ghost_id in boundary_nodes:
|
|
252
|
+
if ghost_id in node_map and ghost_id not in node_id_set:
|
|
253
|
+
ghost = deepcopy(node_map[ghost_id])
|
|
254
|
+
ghost.emphasis = config.ghost_style
|
|
255
|
+
ghost.label = f"→ {ghost.label}" # Mark as continuation
|
|
256
|
+
new_spec.nodes.append(ghost)
|
|
257
|
+
|
|
258
|
+
# Filter edges
|
|
259
|
+
all_ids = node_id_set | boundary_nodes
|
|
260
|
+
for edge in spec.edges:
|
|
261
|
+
if edge.source in all_ids and edge.target in all_ids:
|
|
262
|
+
new_spec.edges.append(deepcopy(edge))
|
|
263
|
+
|
|
264
|
+
# Filter groups
|
|
265
|
+
new_spec.layout.groups = {}
|
|
266
|
+
for group_name, group_nodes in spec.layout.groups.items():
|
|
267
|
+
filtered = [n for n in group_nodes if n in all_ids]
|
|
268
|
+
if filtered:
|
|
269
|
+
new_spec.layout.groups[group_name] = filtered
|
|
270
|
+
|
|
271
|
+
# Filter layers
|
|
272
|
+
new_spec.layout.layers = []
|
|
273
|
+
for layer in spec.layout.layers:
|
|
274
|
+
filtered = [n for n in layer if n in all_ids]
|
|
275
|
+
if filtered:
|
|
276
|
+
new_spec.layout.layers.append(filtered)
|
|
277
|
+
|
|
278
|
+
return new_spec, boundary_nodes
|
scitex/dict/_pop_keys.py
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Timestamp: "2025-11-10 22:40:16 (ywatanabe)"
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
import numpy as np
|
|
7
|
-
|
|
8
|
-
|
|
9
5
|
def pop_keys(keys_list, keys_to_pop):
|
|
10
6
|
"""Remove specified keys from a list of keys.
|
|
11
7
|
|
|
@@ -28,9 +24,7 @@ def pop_keys(keys_list, keys_to_pop):
|
|
|
28
24
|
>>> pop_keys(keys_list, keys_to_pop)
|
|
29
25
|
['a', 'c', 'e', 'bde']
|
|
30
26
|
"""
|
|
31
|
-
|
|
32
|
-
keys_remainded_list = list(np.array(keys_list)[list(indi_to_remain)])
|
|
33
|
-
return keys_remainded_list
|
|
27
|
+
return [k for k in keys_list if k not in keys_to_pop]
|
|
34
28
|
|
|
35
29
|
|
|
36
30
|
# EOF
|
scitex/dsp/__init__.py
CHANGED
|
@@ -3,20 +3,23 @@
|
|
|
3
3
|
|
|
4
4
|
import warnings
|
|
5
5
|
|
|
6
|
+
# Import example, params, norm, reference, filt, and add_noise modules as submodules
|
|
7
|
+
from . import add_noise, example, filt, norm, params, reference
|
|
8
|
+
|
|
6
9
|
# Core imports that should always work
|
|
7
10
|
from ._crop import crop
|
|
8
11
|
from ._demo_sig import demo_sig
|
|
9
12
|
from ._detect_ripples import (
|
|
10
|
-
detect_ripples,
|
|
11
|
-
_preprocess,
|
|
12
|
-
_find_events,
|
|
13
|
-
_drop_ripples_at_edges,
|
|
14
13
|
_calc_relative_peak_position,
|
|
14
|
+
_drop_ripples_at_edges,
|
|
15
|
+
_find_events,
|
|
16
|
+
_preprocess,
|
|
15
17
|
_sort_columns,
|
|
18
|
+
detect_ripples,
|
|
16
19
|
)
|
|
17
20
|
from ._ensure_3d import ensure_3d
|
|
18
21
|
from ._hilbert import hilbert
|
|
19
|
-
from ._modulation_index import
|
|
22
|
+
from ._modulation_index import _reshape, modulation_index
|
|
20
23
|
from ._pac import pac
|
|
21
24
|
from ._psd import band_powers, psd
|
|
22
25
|
from ._resample import resample
|
|
@@ -24,16 +27,12 @@ from ._time import time
|
|
|
24
27
|
from ._transform import to_segments, to_sktime_df
|
|
25
28
|
from ._wavelet import wavelet
|
|
26
29
|
|
|
27
|
-
# Import example and params modules as submodules
|
|
28
|
-
from . import example
|
|
29
|
-
from . import params
|
|
30
|
-
|
|
31
30
|
# Try to import audio-related functions that require PortAudio
|
|
32
31
|
try:
|
|
33
32
|
from ._listen import list_and_select_device
|
|
34
33
|
|
|
35
34
|
_audio_available = True
|
|
36
|
-
except (ImportError, OSError)
|
|
35
|
+
except (ImportError, OSError):
|
|
37
36
|
warnings.warn(
|
|
38
37
|
"Audio functionality unavailable: PortAudio library not found. "
|
|
39
38
|
"Install PortAudio to use audio features (e.g., sudo apt-get install portaudio19-dev)",
|
|
@@ -62,17 +61,23 @@ __all__ = [
|
|
|
62
61
|
"_preprocess",
|
|
63
62
|
"_reshape",
|
|
64
63
|
"_sort_columns",
|
|
64
|
+
"add_noise",
|
|
65
65
|
"band_powers",
|
|
66
66
|
"crop",
|
|
67
67
|
"demo_sig",
|
|
68
68
|
"detect_ripples",
|
|
69
69
|
"ensure_3d",
|
|
70
|
+
"example",
|
|
71
|
+
"filt",
|
|
70
72
|
"get_eeg_pos",
|
|
71
73
|
"hilbert",
|
|
72
74
|
"list_and_select_device",
|
|
73
75
|
"modulation_index",
|
|
76
|
+
"norm",
|
|
74
77
|
"pac",
|
|
78
|
+
"params",
|
|
75
79
|
"psd",
|
|
80
|
+
"reference",
|
|
76
81
|
"resample",
|
|
77
82
|
"time",
|
|
78
83
|
"to_segments",
|
scitex/dsp/add_noise.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Time-stamp: "ywatanabe (2024-11-02 23:09:49)"
|
|
4
3
|
# File: ./scitex_repo/src/scitex/dsp/add_noise.py
|
|
5
4
|
|
|
6
5
|
import torch
|
|
6
|
+
|
|
7
7
|
from scitex.decorators import signal_fn
|
|
8
8
|
|
|
9
9
|
|
|
@@ -50,9 +50,11 @@ def pink(x, amp=1.0, dim=-1):
|
|
|
50
50
|
|
|
51
51
|
@signal_fn
|
|
52
52
|
def brown(x, amp=1.0, dim=-1):
|
|
53
|
+
from scitex.dsp import norm
|
|
54
|
+
|
|
53
55
|
noise = _uniform(x.shape, amp=amp)
|
|
54
56
|
noise = torch.cumsum(noise, dim=dim)
|
|
55
|
-
noise =
|
|
57
|
+
noise = norm.minmax(noise, amp=amp, dim=dim)
|
|
56
58
|
return x + noise.to(x.device)
|
|
57
59
|
|
|
58
60
|
|
|
@@ -60,6 +62,7 @@ if __name__ == "__main__":
|
|
|
60
62
|
import sys
|
|
61
63
|
|
|
62
64
|
import matplotlib.pyplot as plt
|
|
65
|
+
|
|
63
66
|
import scitex
|
|
64
67
|
|
|
65
68
|
# Start
|
scitex/dsp/example.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Time-stamp: "2024-04-06 01:36:18 (ywatanabe)"
|
|
4
3
|
|
|
5
4
|
import matplotlib
|
|
@@ -9,6 +8,17 @@ import matplotlib.pyplot as plt
|
|
|
9
8
|
import pandas as pd
|
|
10
9
|
import scitex
|
|
11
10
|
|
|
11
|
+
import scitex
|
|
12
|
+
|
|
13
|
+
# Module-level constants (defaults for example functions)
|
|
14
|
+
TGT_FS = 512
|
|
15
|
+
LOW_HZ = 20
|
|
16
|
+
HIGH_HZ = 50
|
|
17
|
+
SIGMA = 10
|
|
18
|
+
|
|
19
|
+
# Default color cycle
|
|
20
|
+
CC = {"blue": "#1f77b4", "red": "#d62728", "green": "#2ca02c"}
|
|
21
|
+
|
|
12
22
|
|
|
13
23
|
# Functions
|
|
14
24
|
def calc_norm_resample_filt_hilbert(xx, tt, fs, sig_type, verbose=True):
|
|
@@ -17,18 +27,19 @@ def calc_norm_resample_filt_hilbert(xx, tt, fs, sig_type, verbose=True):
|
|
|
17
27
|
if sig_type == "tensorpac":
|
|
18
28
|
xx = xx[:, :, 0]
|
|
19
29
|
|
|
20
|
-
sigs[
|
|
30
|
+
sigs["orig"] = (xx, tt, fs)
|
|
21
31
|
|
|
22
32
|
# Normalization
|
|
23
33
|
sigs["z_normed"] = (scitex.dsp.norm.z(xx), tt, fs)
|
|
24
34
|
sigs["minmax_normed"] = (scitex.dsp.norm.minmax(xx), tt, fs)
|
|
25
35
|
|
|
26
36
|
# Resampling
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
37
|
+
resampled_xx = scitex.dsp.resample(xx, fs, TGT_FS)
|
|
38
|
+
# Create proper time vector for resampled signal
|
|
39
|
+
import numpy as np
|
|
40
|
+
|
|
41
|
+
resampled_tt = np.linspace(tt[0], tt[-1], resampled_xx.shape[-1])
|
|
42
|
+
sigs["resampled"] = (resampled_xx, resampled_tt, TGT_FS)
|
|
32
43
|
|
|
33
44
|
# Noise injection
|
|
34
45
|
sigs["gaussian_noise_added"] = (scitex.dsp.add_noise.gauss(xx), tt, fs)
|
|
@@ -36,15 +47,16 @@ def calc_norm_resample_filt_hilbert(xx, tt, fs, sig_type, verbose=True):
|
|
|
36
47
|
sigs["pink_noise_added"] = (scitex.dsp.add_noise.pink(xx), tt, fs)
|
|
37
48
|
sigs["brown_noise_added"] = (scitex.dsp.add_noise.brown(xx), tt, fs)
|
|
38
49
|
|
|
39
|
-
# Filtering
|
|
50
|
+
# Filtering (bands format is [[low_hz, high_hz]])
|
|
51
|
+
bands = [[LOW_HZ, HIGH_HZ]]
|
|
40
52
|
sigs[f"bandpass_filted ({LOW_HZ} - {HIGH_HZ} Hz)"] = (
|
|
41
|
-
scitex.dsp.filt.bandpass(xx, fs,
|
|
53
|
+
scitex.dsp.filt.bandpass(xx, fs, bands),
|
|
42
54
|
tt,
|
|
43
55
|
fs,
|
|
44
56
|
)
|
|
45
57
|
|
|
46
58
|
sigs[f"bandstop_filted ({LOW_HZ} - {HIGH_HZ} Hz)"] = (
|
|
47
|
-
scitex.dsp.filt.bandstop(xx, fs,
|
|
59
|
+
scitex.dsp.filt.bandstop(xx, fs, bands),
|
|
48
60
|
tt,
|
|
49
61
|
fs,
|
|
50
62
|
)
|
|
@@ -88,18 +100,19 @@ def plot_signals(plt, sigs, sig_type):
|
|
|
88
100
|
# if sig_type == "tensorpac":
|
|
89
101
|
# xx = xx[:, :, 0]
|
|
90
102
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
# Handle potential shape mismatches from filter operations
|
|
104
|
+
signal = xx[i_batch, i_ch]
|
|
105
|
+
if hasattr(signal, "squeeze"):
|
|
106
|
+
signal = signal.squeeze()
|
|
107
|
+
if hasattr(signal, "numpy"):
|
|
108
|
+
signal = signal.numpy()
|
|
109
|
+
|
|
110
|
+
ax.plot(
|
|
111
|
+
tt,
|
|
112
|
+
signal,
|
|
113
|
+
label=col,
|
|
114
|
+
c=CC["red"] if col == "hilbert_amp" else CC["blue"],
|
|
115
|
+
)
|
|
103
116
|
|
|
104
117
|
# Adjustments
|
|
105
118
|
ax.legend(loc="upper left")
|