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
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
scitex/diagram/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# SciTeX Diagram
|
|
2
|
+
|
|
3
|
+
Paper-optimized diagram generation with semantic constraints.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
SciTeX Diagram provides a **semantic layer** above Mermaid/Graphviz that understands paper constraints:
|
|
8
|
+
- Column width (single/double)
|
|
9
|
+
- Reading direction
|
|
10
|
+
- Node emphasis for scientific communication
|
|
11
|
+
- Automatic splitting of large diagrams
|
|
12
|
+
|
|
13
|
+
**Key insight**: LLMs are good at generating *constraints*, not pixel layouts. SciTeX Diagram defines "what this diagram means for a paper" and compiles that to backend-specific layout directives.
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
scitex-diagram.yaml ← Semantic layer (human/LLM readable)
|
|
19
|
+
↓
|
|
20
|
+
Compiler (applies paper constraints)
|
|
21
|
+
↓
|
|
22
|
+
workflow.mmd / workflow.dot ← Backend output
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from scitex.diagram import Diagram
|
|
29
|
+
|
|
30
|
+
# Create programmatically
|
|
31
|
+
d = Diagram(type="workflow", title="Data Pipeline")
|
|
32
|
+
d.add_node("input", "Raw Data", shape="stadium")
|
|
33
|
+
d.add_node("process", "Transform", emphasis="primary")
|
|
34
|
+
d.add_node("output", "Results", shape="stadium")
|
|
35
|
+
d.add_edge("input", "process")
|
|
36
|
+
d.add_edge("process", "output")
|
|
37
|
+
|
|
38
|
+
# Export
|
|
39
|
+
d.to_mermaid("pipeline.mmd")
|
|
40
|
+
d.to_graphviz("pipeline.dot")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## From YAML Specification
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
# workflow.diagram.yaml
|
|
47
|
+
type: workflow
|
|
48
|
+
title: SciTeX Figure Lifecycle
|
|
49
|
+
|
|
50
|
+
paper:
|
|
51
|
+
column: single
|
|
52
|
+
mode: publication # draft | publication
|
|
53
|
+
emphasize: [figz_bundle, editor]
|
|
54
|
+
return_edges: # Hide in publication mode
|
|
55
|
+
- [editor, figz_bundle]
|
|
56
|
+
|
|
57
|
+
layout:
|
|
58
|
+
layer_gap: tight
|
|
59
|
+
layers: # rank=same constraints
|
|
60
|
+
- [python, savefig]
|
|
61
|
+
- [figz_bundle]
|
|
62
|
+
- [editor, ai_review]
|
|
63
|
+
|
|
64
|
+
nodes:
|
|
65
|
+
- id: python
|
|
66
|
+
label: Python
|
|
67
|
+
shape: rounded
|
|
68
|
+
- id: figz_bundle
|
|
69
|
+
label: .figz Bundle
|
|
70
|
+
shape: stadium
|
|
71
|
+
emphasis: primary
|
|
72
|
+
|
|
73
|
+
edges:
|
|
74
|
+
- from: python
|
|
75
|
+
to: savefig
|
|
76
|
+
- from: savefig
|
|
77
|
+
to: figz_bundle
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
d = Diagram.from_yaml("workflow.diagram.yaml")
|
|
82
|
+
d.to_mermaid("workflow.mmd")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Paper Modes
|
|
86
|
+
|
|
87
|
+
### Draft Mode (default)
|
|
88
|
+
- Full arrows and labels
|
|
89
|
+
- Medium spacing
|
|
90
|
+
- All edges visible
|
|
91
|
+
|
|
92
|
+
### Publication Mode
|
|
93
|
+
- Tight spacing (`ranksep=0.3, nodesep=0.2`)
|
|
94
|
+
- Return edges hidden (invisible but constrain layout)
|
|
95
|
+
- No clusters in Graphviz (uses `rank=same` only)
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
paper:
|
|
99
|
+
mode: publication
|
|
100
|
+
return_edges:
|
|
101
|
+
- [editor, figz_bundle] # Will be invisible
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Auto-Split Large Diagrams
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
d = Diagram.from_yaml("large_workflow.yaml")
|
|
108
|
+
|
|
109
|
+
# Split if > 8 nodes per figure
|
|
110
|
+
parts = d.split(max_nodes=8, strategy="by_groups")
|
|
111
|
+
|
|
112
|
+
for i, part in enumerate(parts):
|
|
113
|
+
part.to_mermaid(f"fig_{chr(65+i)}.mmd") # fig_A.mmd, fig_B.mmd
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Split Strategies
|
|
117
|
+
|
|
118
|
+
| Strategy | Description |
|
|
119
|
+
|----------|-------------|
|
|
120
|
+
| `by_groups` | Split by layout.groups (deterministic, paper-friendly) |
|
|
121
|
+
| `by_articulation` | Split at hub nodes (graph-theoretic) |
|
|
122
|
+
|
|
123
|
+
Ghost nodes are automatically added at boundaries with `→` prefix.
|
|
124
|
+
|
|
125
|
+
## Diagram Types
|
|
126
|
+
|
|
127
|
+
| Type | Direction | Use Case |
|
|
128
|
+
|------|-----------|----------|
|
|
129
|
+
| `workflow` | LR | Sequential processes |
|
|
130
|
+
| `decision` | TB | Decision trees |
|
|
131
|
+
| `pipeline` | LR | Data pipelines with stages |
|
|
132
|
+
| `hierarchy` | TB | Tree structures |
|
|
133
|
+
| `comparison` | LR | Side-by-side comparison |
|
|
134
|
+
|
|
135
|
+
## Node Shapes
|
|
136
|
+
|
|
137
|
+
| Shape | Mermaid | Use Case |
|
|
138
|
+
|-------|---------|----------|
|
|
139
|
+
| `box` | `["label"]` | Default |
|
|
140
|
+
| `rounded` | `("label")` | Processes |
|
|
141
|
+
| `stadium` | `(["label"])` | Start/End |
|
|
142
|
+
| `diamond` | `{"label"}` | Decisions |
|
|
143
|
+
| `circle` | `(("label"))` | Events |
|
|
144
|
+
|
|
145
|
+
## Emphasis Levels
|
|
146
|
+
|
|
147
|
+
| Level | Color | Use Case |
|
|
148
|
+
|-------|-------|----------|
|
|
149
|
+
| `normal` | Dark | Default |
|
|
150
|
+
| `primary` | Blue | Key nodes |
|
|
151
|
+
| `success` | Green | Positive outcomes |
|
|
152
|
+
| `warning` | Red | Negative outcomes |
|
|
153
|
+
| `muted` | Gray | Secondary/derived |
|
|
154
|
+
|
|
155
|
+
## Graphviz Output
|
|
156
|
+
|
|
157
|
+
For tightest layouts, use Graphviz:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Render DOT to PNG
|
|
161
|
+
dot -Tpng workflow.dot -o workflow.png
|
|
162
|
+
|
|
163
|
+
# Render DOT to SVG (vector)
|
|
164
|
+
dot -Tsvg workflow.dot -o workflow.svg
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Note: Mermaid doesn't support `rank=same` constraints, so Graphviz produces more compact output.
|
|
168
|
+
|
|
169
|
+
## API Reference
|
|
170
|
+
|
|
171
|
+
### Diagram Class
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
Diagram(type="workflow", title="", column="single")
|
|
175
|
+
Diagram.from_yaml(path)
|
|
176
|
+
Diagram.from_mermaid(path, diagram_type="workflow")
|
|
177
|
+
|
|
178
|
+
diagram.add_node(id, label, shape="box", emphasis="normal")
|
|
179
|
+
diagram.add_edge(source, target, label=None, style="solid")
|
|
180
|
+
diagram.set_group(group_name, node_ids)
|
|
181
|
+
diagram.emphasize(*node_ids)
|
|
182
|
+
|
|
183
|
+
diagram.to_mermaid(path=None) -> str
|
|
184
|
+
diagram.to_graphviz(path=None) -> str
|
|
185
|
+
diagram.to_yaml(path=None) -> str
|
|
186
|
+
diagram.split(max_nodes=12, strategy="by_groups") -> List[Diagram]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Schema Classes
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
DiagramSpec # Complete specification
|
|
193
|
+
PaperConstraints # column, mode, emphasize, return_edges
|
|
194
|
+
LayoutHints # groups, layers, layer_gap, node_gap
|
|
195
|
+
NodeSpec # id, label, shape, emphasis
|
|
196
|
+
EdgeSpec # source, target, label, style
|
|
197
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: 2025-12-15
|
|
4
|
+
# Author: ywatanabe / Claude
|
|
5
|
+
# File: scitex/diagram/__init__.py
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
SciTeX Diagram - Paper-optimized diagram generation.
|
|
9
|
+
|
|
10
|
+
This module provides a semantic layer above Mermaid/Graphviz/D2 that
|
|
11
|
+
understands paper constraints (column width, reading direction, emphasis)
|
|
12
|
+
and compiles to backend formats with appropriate layout hints.
|
|
13
|
+
|
|
14
|
+
Key insight: LLMs are good at generating CONSTRAINTS, not pixel layouts.
|
|
15
|
+
SciTeX Diagram defines "what this diagram means for a paper" and compiles
|
|
16
|
+
that to backend-specific layout directives.
|
|
17
|
+
|
|
18
|
+
Example
|
|
19
|
+
-------
|
|
20
|
+
>>> from scitex.diagram import Diagram
|
|
21
|
+
>>>
|
|
22
|
+
>>> diagram = Diagram.from_yaml("workflow.diagram.yaml")
|
|
23
|
+
>>> diagram.to_mermaid("workflow.mmd")
|
|
24
|
+
>>> diagram.to_graphviz("workflow.dot")
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from scitex.diagram._schema import DiagramSpec, PaperConstraints, LayoutHints, PaperMode
|
|
28
|
+
from scitex.diagram._diagram import Diagram
|
|
29
|
+
from scitex.diagram._compile import compile_to_mermaid, compile_to_graphviz
|
|
30
|
+
from scitex.diagram._presets import WORKFLOW_PRESET, DECISION_PRESET, PIPELINE_PRESET
|
|
31
|
+
from scitex.diagram._split import split_diagram, SplitConfig, SplitStrategy, SplitResult
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"Diagram",
|
|
35
|
+
"DiagramSpec",
|
|
36
|
+
"PaperConstraints",
|
|
37
|
+
"LayoutHints",
|
|
38
|
+
"PaperMode",
|
|
39
|
+
"compile_to_mermaid",
|
|
40
|
+
"compile_to_graphviz",
|
|
41
|
+
"WORKFLOW_PRESET",
|
|
42
|
+
"DECISION_PRESET",
|
|
43
|
+
"PIPELINE_PRESET",
|
|
44
|
+
"split_diagram",
|
|
45
|
+
"SplitConfig",
|
|
46
|
+
"SplitStrategy",
|
|
47
|
+
"SplitResult",
|
|
48
|
+
]
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: 2025-12-15
|
|
4
|
+
# Author: ywatanabe / Claude
|
|
5
|
+
# File: scitex/diagram/_compile.py
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Compilers from DiagramSpec to backend formats (Mermaid, Graphviz).
|
|
9
|
+
|
|
10
|
+
The compiler applies paper constraints to generate backend-specific
|
|
11
|
+
layout directives. This is where domain knowledge about "good paper figures"
|
|
12
|
+
gets encoded.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
from typing import Optional
|
|
17
|
+
from scitex.diagram._schema import (
|
|
18
|
+
DiagramSpec, DiagramType, ColumnLayout, SpacingLevel, PaperMode
|
|
19
|
+
)
|
|
20
|
+
from scitex.diagram._presets import get_preset, DiagramPreset
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def compile_to_mermaid(
|
|
24
|
+
spec: DiagramSpec,
|
|
25
|
+
preset: Optional[DiagramPreset] = None
|
|
26
|
+
) -> str:
|
|
27
|
+
"""
|
|
28
|
+
Compile DiagramSpec to Mermaid format with paper-optimized settings.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
spec : DiagramSpec
|
|
33
|
+
The semantic diagram specification.
|
|
34
|
+
preset : DiagramPreset, optional
|
|
35
|
+
Override preset (default: inferred from spec.type).
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
str
|
|
40
|
+
Mermaid diagram source code.
|
|
41
|
+
"""
|
|
42
|
+
if preset is None:
|
|
43
|
+
preset = get_preset(spec.type.value)
|
|
44
|
+
|
|
45
|
+
lines = []
|
|
46
|
+
|
|
47
|
+
# Theme initialization
|
|
48
|
+
theme_vars = {**preset.mermaid_theme, **spec.theme}
|
|
49
|
+
theme_json = json.dumps({"theme": "base", "themeVariables": theme_vars})
|
|
50
|
+
lines.append(f"%%{{init: {theme_json}}}%%")
|
|
51
|
+
|
|
52
|
+
# Determine direction based on paper constraints
|
|
53
|
+
direction = preset.mermaid_direction
|
|
54
|
+
if spec.paper.reading_direction == "top_to_bottom":
|
|
55
|
+
direction = "TB"
|
|
56
|
+
elif spec.paper.column == ColumnLayout.DOUBLE:
|
|
57
|
+
# Double column prefers vertical to save horizontal space
|
|
58
|
+
direction = "TB"
|
|
59
|
+
|
|
60
|
+
lines.append(f"graph {direction}")
|
|
61
|
+
|
|
62
|
+
# Build node ID to spec mapping
|
|
63
|
+
node_map = {n.id: n for n in spec.nodes}
|
|
64
|
+
|
|
65
|
+
# Generate subgraphs for groups
|
|
66
|
+
indent = " "
|
|
67
|
+
for group_name, group_nodes in spec.layout.groups.items():
|
|
68
|
+
lines.append(f'{indent}subgraph {_sanitize_id(group_name)}["{group_name}"]')
|
|
69
|
+
for node_id in group_nodes:
|
|
70
|
+
if node_id in node_map:
|
|
71
|
+
node = node_map[node_id]
|
|
72
|
+
lines.append(f"{indent}{indent}{_mermaid_node(node, preset)}")
|
|
73
|
+
lines.append(f"{indent}end")
|
|
74
|
+
|
|
75
|
+
# Generate standalone nodes (not in any group)
|
|
76
|
+
grouped_nodes = set()
|
|
77
|
+
for group_nodes in spec.layout.groups.values():
|
|
78
|
+
grouped_nodes.update(group_nodes)
|
|
79
|
+
|
|
80
|
+
for node in spec.nodes:
|
|
81
|
+
if node.id not in grouped_nodes:
|
|
82
|
+
lines.append(f"{indent}{_mermaid_node(node, preset)}")
|
|
83
|
+
|
|
84
|
+
# Generate edges
|
|
85
|
+
for edge in spec.edges:
|
|
86
|
+
edge_str = _mermaid_edge(edge)
|
|
87
|
+
lines.append(f"{indent}{edge_str}")
|
|
88
|
+
|
|
89
|
+
# Generate styles for emphasized nodes
|
|
90
|
+
for node in spec.nodes:
|
|
91
|
+
if node.emphasis != "normal" or node.id in spec.paper.emphasize:
|
|
92
|
+
emphasis = "primary" if node.id in spec.paper.emphasize else node.emphasis
|
|
93
|
+
style = preset.emphasis_styles.get(emphasis, {})
|
|
94
|
+
if style:
|
|
95
|
+
style_parts = [f"{k}:{v}" for k, v in style.items()]
|
|
96
|
+
lines.append(f"{indent}style {_sanitize_id(node.id)} {','.join(style_parts)}")
|
|
97
|
+
|
|
98
|
+
return "\n".join(lines)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def compile_to_graphviz(
|
|
102
|
+
spec: DiagramSpec,
|
|
103
|
+
preset: Optional[DiagramPreset] = None
|
|
104
|
+
) -> str:
|
|
105
|
+
"""
|
|
106
|
+
Compile DiagramSpec to Graphviz DOT format.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
spec : DiagramSpec
|
|
111
|
+
The semantic diagram specification.
|
|
112
|
+
preset : DiagramPreset, optional
|
|
113
|
+
Override preset.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
str
|
|
118
|
+
Graphviz DOT source code.
|
|
119
|
+
"""
|
|
120
|
+
if preset is None:
|
|
121
|
+
preset = get_preset(spec.type.value)
|
|
122
|
+
|
|
123
|
+
is_publication = spec.paper.mode == PaperMode.PUBLICATION
|
|
124
|
+
lines = []
|
|
125
|
+
|
|
126
|
+
# Determine direction
|
|
127
|
+
rankdir = preset.graphviz_rankdir
|
|
128
|
+
if spec.paper.reading_direction == "top_to_bottom":
|
|
129
|
+
rankdir = "TB"
|
|
130
|
+
elif spec.paper.column == ColumnLayout.DOUBLE:
|
|
131
|
+
rankdir = "TB"
|
|
132
|
+
|
|
133
|
+
# Get spacing - publication mode uses tight spacing
|
|
134
|
+
if is_publication:
|
|
135
|
+
spacing = preset.spacing_map.get("tight", {})
|
|
136
|
+
else:
|
|
137
|
+
spacing = preset.spacing_map.get(spec.layout.layer_gap.value, {})
|
|
138
|
+
ranksep = spacing.get("ranksep", preset.graphviz_ranksep)
|
|
139
|
+
nodesep = spacing.get("nodesep", preset.graphviz_nodesep)
|
|
140
|
+
|
|
141
|
+
lines.append("digraph G {")
|
|
142
|
+
lines.append(f" rankdir={rankdir};")
|
|
143
|
+
lines.append(f" ranksep={ranksep};")
|
|
144
|
+
lines.append(f" nodesep={nodesep};")
|
|
145
|
+
lines.append(" splines=ortho;") # Orthogonal edges for cleaner look
|
|
146
|
+
lines.append(' node [fontname="Helvetica", fontsize=10];')
|
|
147
|
+
lines.append(' edge [fontname="Helvetica", fontsize=9];')
|
|
148
|
+
lines.append("")
|
|
149
|
+
|
|
150
|
+
# Node map
|
|
151
|
+
node_map = {n.id: n for n in spec.nodes}
|
|
152
|
+
|
|
153
|
+
# Build return edges set for publication mode
|
|
154
|
+
return_edge_set = set()
|
|
155
|
+
for e in spec.paper.return_edges:
|
|
156
|
+
if len(e) >= 2:
|
|
157
|
+
return_edge_set.add((e[0], e[1]))
|
|
158
|
+
|
|
159
|
+
# Generate subgraphs (without clusters for tighter layout in publication)
|
|
160
|
+
if is_publication and spec.layout.layers:
|
|
161
|
+
# In publication mode with layers, skip clusters - use rank=same instead
|
|
162
|
+
for node in spec.nodes:
|
|
163
|
+
lines.append(f" {_graphviz_node(node, preset, spec.paper.emphasize)}")
|
|
164
|
+
else:
|
|
165
|
+
# Draft mode: use clusters for visual grouping
|
|
166
|
+
cluster_idx = 0
|
|
167
|
+
for group_name, group_nodes in spec.layout.groups.items():
|
|
168
|
+
lines.append(f' subgraph cluster_{cluster_idx} {{')
|
|
169
|
+
lines.append(f' label="{group_name}";')
|
|
170
|
+
for node_id in group_nodes:
|
|
171
|
+
if node_id in node_map:
|
|
172
|
+
node = node_map[node_id]
|
|
173
|
+
lines.append(f" {_graphviz_node(node, preset, spec.paper.emphasize)}")
|
|
174
|
+
lines.append(" }")
|
|
175
|
+
cluster_idx += 1
|
|
176
|
+
|
|
177
|
+
# Standalone nodes
|
|
178
|
+
grouped_nodes = set()
|
|
179
|
+
for group_nodes in spec.layout.groups.values():
|
|
180
|
+
grouped_nodes.update(group_nodes)
|
|
181
|
+
|
|
182
|
+
for node in spec.nodes:
|
|
183
|
+
if node.id not in grouped_nodes:
|
|
184
|
+
lines.append(f" {_graphviz_node(node, preset, spec.paper.emphasize)}")
|
|
185
|
+
|
|
186
|
+
lines.append("")
|
|
187
|
+
|
|
188
|
+
# Rank constraints from layers (CRITICAL for minimizing whitespace)
|
|
189
|
+
for layer in spec.layout.layers:
|
|
190
|
+
if layer:
|
|
191
|
+
node_ids = "; ".join(_sanitize_id(n) for n in layer)
|
|
192
|
+
lines.append(f" {{ rank=same; {node_ids}; }}")
|
|
193
|
+
|
|
194
|
+
lines.append("")
|
|
195
|
+
|
|
196
|
+
# Edges - handle return edges in publication mode
|
|
197
|
+
for edge in spec.edges:
|
|
198
|
+
edge_key = (edge.source, edge.target)
|
|
199
|
+
if is_publication and edge_key in return_edge_set:
|
|
200
|
+
# Make return edges invisible in publication mode
|
|
201
|
+
lines.append(f" {_graphviz_edge_with_style(edge, invisible=True)}")
|
|
202
|
+
else:
|
|
203
|
+
lines.append(f" {_graphviz_edge(edge)}")
|
|
204
|
+
|
|
205
|
+
lines.append("}")
|
|
206
|
+
|
|
207
|
+
return "\n".join(lines)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _sanitize_id(s: str) -> str:
|
|
211
|
+
"""Make string safe for use as node ID."""
|
|
212
|
+
import re
|
|
213
|
+
# Remove or replace problematic characters for Mermaid/Graphviz
|
|
214
|
+
s = re.sub(r'[^\w]', '_', s) # Replace non-word chars with _
|
|
215
|
+
s = re.sub(r'_+', '_', s) # Collapse multiple underscores
|
|
216
|
+
s = s.strip('_') # Remove leading/trailing underscores
|
|
217
|
+
return s or "node"
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _mermaid_node(node, preset: DiagramPreset) -> str:
|
|
221
|
+
"""Generate Mermaid node definition."""
|
|
222
|
+
shape_template = preset.mermaid_shapes.get(node.shape, '["__LABEL__"]')
|
|
223
|
+
shape_str = shape_template.replace("__LABEL__", node.label)
|
|
224
|
+
return f"{_sanitize_id(node.id)}{shape_str}"
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _mermaid_edge(edge) -> str:
|
|
228
|
+
"""Generate Mermaid edge definition."""
|
|
229
|
+
arrow = "-->" if edge.arrow == "normal" else "---"
|
|
230
|
+
if edge.style == "dashed":
|
|
231
|
+
arrow = "-.->" if edge.arrow == "normal" else "-.-"
|
|
232
|
+
elif edge.style == "dotted":
|
|
233
|
+
arrow = "..>" if edge.arrow == "normal" else "..."
|
|
234
|
+
|
|
235
|
+
src = _sanitize_id(edge.source)
|
|
236
|
+
tgt = _sanitize_id(edge.target)
|
|
237
|
+
|
|
238
|
+
if edge.label:
|
|
239
|
+
return f'{src} {arrow}|"{edge.label}"| {tgt}'
|
|
240
|
+
return f"{src} {arrow} {tgt}"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _graphviz_node(node, preset: DiagramPreset, emphasize: list) -> str:
|
|
244
|
+
"""Generate Graphviz node definition."""
|
|
245
|
+
shape = preset.graphviz_shapes.get(node.shape, "box")
|
|
246
|
+
|
|
247
|
+
# Get emphasis style
|
|
248
|
+
emphasis_key = "primary" if node.id in emphasize else node.emphasis
|
|
249
|
+
style = preset.emphasis_styles.get(emphasis_key, {})
|
|
250
|
+
|
|
251
|
+
attrs = [f'label="{node.label}"', f'shape={shape}']
|
|
252
|
+
|
|
253
|
+
# Collect style values (filled, rounded, etc.) - combine with comma
|
|
254
|
+
styles = []
|
|
255
|
+
if style.get("fill"):
|
|
256
|
+
attrs.append(f'fillcolor="{style["fill"]}"')
|
|
257
|
+
styles.append("filled")
|
|
258
|
+
if style.get("stroke"):
|
|
259
|
+
attrs.append(f'color="{style["stroke"]}"')
|
|
260
|
+
if node.shape == "rounded":
|
|
261
|
+
styles.append("rounded")
|
|
262
|
+
|
|
263
|
+
# Output style once with comma-separated values
|
|
264
|
+
if styles:
|
|
265
|
+
attrs.append(f'style="{",".join(styles)}"')
|
|
266
|
+
|
|
267
|
+
return f'{_sanitize_id(node.id)} [{", ".join(attrs)}];'
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _graphviz_edge(edge) -> str:
|
|
271
|
+
"""Generate Graphviz edge definition."""
|
|
272
|
+
src = _sanitize_id(edge.source)
|
|
273
|
+
tgt = _sanitize_id(edge.target)
|
|
274
|
+
|
|
275
|
+
attrs = []
|
|
276
|
+
if edge.label:
|
|
277
|
+
attrs.append(f'label="{edge.label}"')
|
|
278
|
+
if edge.style == "dashed":
|
|
279
|
+
attrs.append("style=dashed")
|
|
280
|
+
elif edge.style == "dotted":
|
|
281
|
+
attrs.append("style=dotted")
|
|
282
|
+
if edge.arrow == "none":
|
|
283
|
+
attrs.append("arrowhead=none")
|
|
284
|
+
|
|
285
|
+
if attrs:
|
|
286
|
+
return f'{src} -> {tgt} [{", ".join(attrs)}];'
|
|
287
|
+
return f"{src} -> {tgt};"
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _graphviz_edge_with_style(edge, invisible: bool = False) -> str:
|
|
291
|
+
"""Generate Graphviz edge with optional invisible style."""
|
|
292
|
+
src = _sanitize_id(edge.source)
|
|
293
|
+
tgt = _sanitize_id(edge.target)
|
|
294
|
+
|
|
295
|
+
attrs = []
|
|
296
|
+
if invisible:
|
|
297
|
+
attrs.append("style=invis")
|
|
298
|
+
# Invisible edges still constrain layout
|
|
299
|
+
attrs.append("constraint=true")
|
|
300
|
+
else:
|
|
301
|
+
if edge.label:
|
|
302
|
+
attrs.append(f'label="{edge.label}"')
|
|
303
|
+
if edge.style == "dashed":
|
|
304
|
+
attrs.append("style=dashed")
|
|
305
|
+
elif edge.style == "dotted":
|
|
306
|
+
attrs.append("style=dotted")
|
|
307
|
+
if edge.arrow == "none":
|
|
308
|
+
attrs.append("arrowhead=none")
|
|
309
|
+
|
|
310
|
+
if attrs:
|
|
311
|
+
return f'{src} -> {tgt} [{", ".join(attrs)}];'
|
|
312
|
+
return f"{src} -> {tgt};"
|