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,279 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_export.py
|
|
4
|
+
|
|
5
|
+
"""Main LaTeX export orchestration for FTS bundles."""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, List, Optional, Union
|
|
10
|
+
|
|
11
|
+
from ._figure_exporter import FigureExportOptions, export_figure_to_latex, generate_figure_preamble
|
|
12
|
+
from ._stats_formatter import FormattedStat, format_stat_note, format_stats_for_latex
|
|
13
|
+
from ._table_exporter import TableExportOptions, export_table_to_latex, generate_table_preamble
|
|
14
|
+
from ._validator import LaTeXError, ValidationResult, validate_latex
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from scitex.fts import FTS
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class LaTeXExportOptions:
|
|
22
|
+
"""Options for LaTeX export.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
validate: Whether to validate output
|
|
26
|
+
validation_level: Validation level ("syntax", "semantic", "compile")
|
|
27
|
+
include_preamble: Include required packages in output
|
|
28
|
+
figure_options: Options for figure export
|
|
29
|
+
table_options: Options for table export
|
|
30
|
+
output_path: Where to save the .tex file
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
validate: bool = True
|
|
34
|
+
validation_level: str = "syntax"
|
|
35
|
+
include_preamble: bool = False
|
|
36
|
+
figure_options: Optional[FigureExportOptions] = None
|
|
37
|
+
table_options: Optional[TableExportOptions] = None
|
|
38
|
+
output_path: Optional[Path] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class LaTeXResult:
|
|
43
|
+
"""Result of LaTeX export.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
latex_code: Generated LaTeX code
|
|
47
|
+
preamble: Required preamble packages
|
|
48
|
+
validation: Validation result
|
|
49
|
+
output_path: Path where file was saved (if applicable)
|
|
50
|
+
stats: Formatted statistics (if applicable)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
latex_code: str
|
|
54
|
+
preamble: str = ""
|
|
55
|
+
validation: Optional[ValidationResult] = None
|
|
56
|
+
output_path: Optional[Path] = None
|
|
57
|
+
stats: List[FormattedStat] = field(default_factory=list)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def is_valid(self) -> bool:
|
|
61
|
+
"""Check if export is valid."""
|
|
62
|
+
return self.validation is None or self.validation.is_valid
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def errors(self) -> List[LaTeXError]:
|
|
66
|
+
"""Get validation errors."""
|
|
67
|
+
if self.validation:
|
|
68
|
+
return self.validation.errors
|
|
69
|
+
return []
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def warnings(self) -> List[LaTeXError]:
|
|
73
|
+
"""Get validation warnings."""
|
|
74
|
+
if self.validation:
|
|
75
|
+
return self.validation.warnings
|
|
76
|
+
return []
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def export_to_latex(
|
|
80
|
+
bundle: "FTS",
|
|
81
|
+
options: Optional[LaTeXExportOptions] = None,
|
|
82
|
+
) -> LaTeXResult:
|
|
83
|
+
"""Export an FTS bundle to LaTeX.
|
|
84
|
+
|
|
85
|
+
Automatically detects bundle type and uses appropriate exporter.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
bundle: FTS bundle
|
|
89
|
+
options: Export options
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
LaTeXResult with code, validation, and metadata
|
|
93
|
+
"""
|
|
94
|
+
if options is None:
|
|
95
|
+
options = LaTeXExportOptions()
|
|
96
|
+
|
|
97
|
+
node_type = bundle.node.type
|
|
98
|
+
latex_code = ""
|
|
99
|
+
preamble_parts = []
|
|
100
|
+
stats = []
|
|
101
|
+
|
|
102
|
+
# Export based on type
|
|
103
|
+
if node_type in ("figure", "plot", "image"):
|
|
104
|
+
latex_code = export_figure_to_latex(
|
|
105
|
+
bundle,
|
|
106
|
+
options=options.figure_options,
|
|
107
|
+
)
|
|
108
|
+
preamble_parts.append(generate_figure_preamble())
|
|
109
|
+
|
|
110
|
+
elif node_type == "table":
|
|
111
|
+
table_opts = options.table_options or TableExportOptions()
|
|
112
|
+
latex_code = export_table_to_latex(
|
|
113
|
+
bundle,
|
|
114
|
+
options=table_opts,
|
|
115
|
+
)
|
|
116
|
+
preamble_parts.append(
|
|
117
|
+
generate_table_preamble(
|
|
118
|
+
use_booktabs=table_opts.use_booktabs,
|
|
119
|
+
use_siunitx=table_opts.use_siunitx,
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
elif node_type == "stats":
|
|
124
|
+
# Stats-only bundle - format as paragraph or inline
|
|
125
|
+
if bundle.stats:
|
|
126
|
+
stats = format_stats_for_latex(bundle.stats.to_dict())
|
|
127
|
+
latex_code = _format_stats_only(stats)
|
|
128
|
+
|
|
129
|
+
else:
|
|
130
|
+
raise ValueError(f"Unsupported node type for LaTeX export: {node_type}")
|
|
131
|
+
|
|
132
|
+
# Format statistics if available (for figures/tables with stats)
|
|
133
|
+
if bundle.stats and node_type != "stats":
|
|
134
|
+
stats = format_stats_for_latex(bundle.stats.to_dict())
|
|
135
|
+
if stats:
|
|
136
|
+
note = format_stat_note(stats)
|
|
137
|
+
if note:
|
|
138
|
+
latex_code += "\n\n" + note
|
|
139
|
+
|
|
140
|
+
# Combine preamble
|
|
141
|
+
preamble = "\n\n".join(preamble_parts)
|
|
142
|
+
|
|
143
|
+
# Validate if requested
|
|
144
|
+
validation = None
|
|
145
|
+
if options.validate:
|
|
146
|
+
validation = validate_latex(latex_code, level=options.validation_level)
|
|
147
|
+
|
|
148
|
+
# Create result
|
|
149
|
+
result = LaTeXResult(
|
|
150
|
+
latex_code=latex_code,
|
|
151
|
+
preamble=preamble,
|
|
152
|
+
validation=validation,
|
|
153
|
+
stats=stats,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Save to file if path specified
|
|
157
|
+
output_path = options.output_path
|
|
158
|
+
if output_path is None:
|
|
159
|
+
# Default to exports directory
|
|
160
|
+
exports_dir = bundle.path / "exports"
|
|
161
|
+
exports_dir.mkdir(exist_ok=True)
|
|
162
|
+
output_path = exports_dir / f"{bundle.node.id}.tex"
|
|
163
|
+
|
|
164
|
+
if output_path:
|
|
165
|
+
_save_latex(latex_code, output_path, preamble if options.include_preamble else None)
|
|
166
|
+
result.output_path = output_path
|
|
167
|
+
|
|
168
|
+
return result
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _format_stats_only(stats: List[FormattedStat]) -> str:
|
|
172
|
+
"""Format stats-only bundle as LaTeX.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
stats: Formatted statistics
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
LaTeX code
|
|
179
|
+
"""
|
|
180
|
+
if not stats:
|
|
181
|
+
return "% No statistics to report"
|
|
182
|
+
|
|
183
|
+
lines = ["% Statistical Results", ""]
|
|
184
|
+
for stat in stats:
|
|
185
|
+
lines.append(f"% {stat.test_type}")
|
|
186
|
+
lines.append(stat.full_report)
|
|
187
|
+
lines.append("")
|
|
188
|
+
|
|
189
|
+
return "\n".join(lines)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _save_latex(
|
|
193
|
+
latex_code: str,
|
|
194
|
+
output_path: Path,
|
|
195
|
+
preamble: Optional[str] = None,
|
|
196
|
+
) -> None:
|
|
197
|
+
"""Save LaTeX code to file.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
latex_code: LaTeX code
|
|
201
|
+
output_path: Output path
|
|
202
|
+
preamble: Optional preamble to prepend
|
|
203
|
+
"""
|
|
204
|
+
output_path = Path(output_path)
|
|
205
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
206
|
+
|
|
207
|
+
content = []
|
|
208
|
+
if preamble:
|
|
209
|
+
content.append(preamble)
|
|
210
|
+
content.append("")
|
|
211
|
+
|
|
212
|
+
content.append(latex_code)
|
|
213
|
+
|
|
214
|
+
output_path.write_text("\n".join(content), encoding="utf-8")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def export_multiple(
|
|
218
|
+
bundles: List["FTS"],
|
|
219
|
+
output_path: Path,
|
|
220
|
+
options: Optional[LaTeXExportOptions] = None,
|
|
221
|
+
) -> LaTeXResult:
|
|
222
|
+
"""Export multiple bundles to a single LaTeX file.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
bundles: List of FTS bundles
|
|
226
|
+
output_path: Output path
|
|
227
|
+
options: Export options
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
Combined LaTeXResult
|
|
231
|
+
"""
|
|
232
|
+
if options is None:
|
|
233
|
+
options = LaTeXExportOptions()
|
|
234
|
+
|
|
235
|
+
all_code = []
|
|
236
|
+
all_preamble = set()
|
|
237
|
+
all_stats = []
|
|
238
|
+
all_errors = []
|
|
239
|
+
all_warnings = []
|
|
240
|
+
|
|
241
|
+
for bundle in bundles:
|
|
242
|
+
result = export_to_latex(bundle, options)
|
|
243
|
+
all_code.append(result.latex_code)
|
|
244
|
+
if result.preamble:
|
|
245
|
+
all_preamble.add(result.preamble)
|
|
246
|
+
all_stats.extend(result.stats)
|
|
247
|
+
all_errors.extend(result.errors)
|
|
248
|
+
all_warnings.extend(result.warnings)
|
|
249
|
+
|
|
250
|
+
combined_code = "\n\n".join(all_code)
|
|
251
|
+
combined_preamble = "\n\n".join(sorted(all_preamble))
|
|
252
|
+
|
|
253
|
+
# Save combined file
|
|
254
|
+
_save_latex(combined_code, output_path, combined_preamble if options.include_preamble else None)
|
|
255
|
+
|
|
256
|
+
# Create combined validation result
|
|
257
|
+
combined_validation = ValidationResult()
|
|
258
|
+
for error in all_errors:
|
|
259
|
+
combined_validation.add_error(error)
|
|
260
|
+
for warning in all_warnings:
|
|
261
|
+
combined_validation.add_error(warning)
|
|
262
|
+
|
|
263
|
+
return LaTeXResult(
|
|
264
|
+
latex_code=combined_code,
|
|
265
|
+
preamble=combined_preamble,
|
|
266
|
+
validation=combined_validation,
|
|
267
|
+
output_path=output_path,
|
|
268
|
+
stats=all_stats,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
__all__ = [
|
|
273
|
+
"LaTeXExportOptions",
|
|
274
|
+
"LaTeXResult",
|
|
275
|
+
"export_to_latex",
|
|
276
|
+
"export_multiple",
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
# EOF
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_figure_exporter.py
|
|
4
|
+
|
|
5
|
+
"""Export FTS figures to LaTeX using includegraphics."""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import TYPE_CHECKING, Optional
|
|
10
|
+
|
|
11
|
+
from ._utils import escape_latex_minimal, sanitize_label
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from scitex.fts import FTS
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class FigureExportOptions:
|
|
19
|
+
"""Options for figure LaTeX export.
|
|
20
|
+
|
|
21
|
+
Attributes:
|
|
22
|
+
width_mm: Figure width in mm (from node.size_mm if not specified)
|
|
23
|
+
placement: Float placement specifier (htbp, t, b, h, p, H)
|
|
24
|
+
centering: Whether to center the figure
|
|
25
|
+
include_caption: Whether to include caption
|
|
26
|
+
include_label: Whether to include label
|
|
27
|
+
pdf_path: Override path to PDF file
|
|
28
|
+
relative_path: Whether to use relative paths
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
width_mm: Optional[float] = None
|
|
32
|
+
placement: str = "htbp"
|
|
33
|
+
centering: bool = True
|
|
34
|
+
include_caption: bool = True
|
|
35
|
+
include_label: bool = True
|
|
36
|
+
pdf_path: Optional[str] = None
|
|
37
|
+
relative_path: bool = True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def export_figure_to_latex(
|
|
41
|
+
bundle: "FTS",
|
|
42
|
+
options: Optional[FigureExportOptions] = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Export a figure/plot bundle to LaTeX.
|
|
45
|
+
|
|
46
|
+
Generates a figure environment with includegraphics pointing to
|
|
47
|
+
a pre-rendered PDF file.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
bundle: FTS bundle of type 'figure' or 'plot'
|
|
51
|
+
options: Export options
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
LaTeX code string
|
|
55
|
+
"""
|
|
56
|
+
if options is None:
|
|
57
|
+
options = FigureExportOptions()
|
|
58
|
+
|
|
59
|
+
node = bundle.node
|
|
60
|
+
node_type = node.type
|
|
61
|
+
|
|
62
|
+
# Validate type
|
|
63
|
+
if node_type not in ("figure", "plot", "image"):
|
|
64
|
+
raise ValueError(f"Cannot export node type '{node_type}' as figure. Expected 'figure', 'plot', or 'image'.")
|
|
65
|
+
|
|
66
|
+
# Get width
|
|
67
|
+
width_mm = options.width_mm
|
|
68
|
+
if width_mm is None and node.size_mm:
|
|
69
|
+
width_mm = node.size_mm.width
|
|
70
|
+
if width_mm is None:
|
|
71
|
+
width_mm = 80 # Default width
|
|
72
|
+
|
|
73
|
+
# Get PDF path
|
|
74
|
+
if options.pdf_path:
|
|
75
|
+
pdf_path = options.pdf_path
|
|
76
|
+
else:
|
|
77
|
+
# Look for existing PDF export
|
|
78
|
+
pdf_path = _find_pdf_export(bundle, options.relative_path)
|
|
79
|
+
|
|
80
|
+
# Get caption
|
|
81
|
+
caption = node.name or ""
|
|
82
|
+
|
|
83
|
+
# Get label
|
|
84
|
+
label = sanitize_label(node.id)
|
|
85
|
+
label_prefix = "fig" if node_type in ("figure", "plot") else "img"
|
|
86
|
+
|
|
87
|
+
# Build LaTeX
|
|
88
|
+
lines = []
|
|
89
|
+
lines.append(f"\\begin{{figure}}[{options.placement}]")
|
|
90
|
+
|
|
91
|
+
if options.centering:
|
|
92
|
+
lines.append(" \\centering")
|
|
93
|
+
|
|
94
|
+
lines.append(f" \\includegraphics[width={width_mm}mm]{{{pdf_path}}}")
|
|
95
|
+
|
|
96
|
+
if options.include_caption and caption:
|
|
97
|
+
escaped_caption = escape_latex_minimal(caption)
|
|
98
|
+
lines.append(f" \\caption{{{escaped_caption}}}")
|
|
99
|
+
|
|
100
|
+
if options.include_label:
|
|
101
|
+
lines.append(f" \\label{{{label_prefix}:{label}}}")
|
|
102
|
+
|
|
103
|
+
lines.append("\\end{figure}")
|
|
104
|
+
|
|
105
|
+
return "\n".join(lines)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _find_pdf_export(bundle: "FTS", relative: bool = True) -> str:
|
|
109
|
+
"""Find the PDF export path for a bundle.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
bundle: FTS bundle
|
|
113
|
+
relative: Return relative path
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Path string for includegraphics
|
|
117
|
+
"""
|
|
118
|
+
# Check exports directory
|
|
119
|
+
exports_dir = bundle.path / "exports"
|
|
120
|
+
if exports_dir.exists():
|
|
121
|
+
# Look for PDF files
|
|
122
|
+
pdf_files = list(exports_dir.glob("*.pdf"))
|
|
123
|
+
if pdf_files:
|
|
124
|
+
pdf_path = pdf_files[0]
|
|
125
|
+
if relative:
|
|
126
|
+
# Return path relative to exports/
|
|
127
|
+
return f"exports/{pdf_path.name}"
|
|
128
|
+
return str(pdf_path)
|
|
129
|
+
|
|
130
|
+
# No PDF found - generate a placeholder path
|
|
131
|
+
bundle_name = bundle.path.stem
|
|
132
|
+
return f"exports/{bundle_name}.pdf"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def generate_figure_preamble() -> str:
|
|
136
|
+
"""Generate required LaTeX preamble for figures.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Preamble code with required packages
|
|
140
|
+
"""
|
|
141
|
+
return """% Required packages for figure export
|
|
142
|
+
\\usepackage{graphicx}
|
|
143
|
+
\\usepackage{float} % For [H] placement specifier
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
__all__ = [
|
|
148
|
+
"FigureExportOptions",
|
|
149
|
+
"export_figure_to_latex",
|
|
150
|
+
"generate_figure_preamble",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
# EOF
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_stats_formatter.py
|
|
4
|
+
|
|
5
|
+
"""Format statistical results for LaTeX output."""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from ._utils import format_effect_size, format_p_value, format_statistic, significance_stars
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class FormattedStat:
|
|
15
|
+
"""A formatted statistical result.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
test_type: Type of test (t-test, anova, etc.)
|
|
19
|
+
statistic: Formatted test statistic (e.g., "$t(48) = 2.31$")
|
|
20
|
+
p_value: Formatted p-value (e.g., ".023")
|
|
21
|
+
effect_size: Formatted effect size if available
|
|
22
|
+
stars: Significance stars
|
|
23
|
+
full_report: Complete inline report
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
test_type: str
|
|
27
|
+
statistic: str
|
|
28
|
+
p_value: str
|
|
29
|
+
effect_size: Optional[str] = None
|
|
30
|
+
stars: str = ""
|
|
31
|
+
full_report: str = ""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def format_stats_for_latex(stats_dict: Dict[str, Any]) -> List[FormattedStat]:
|
|
35
|
+
"""Format stats.json contents for LaTeX.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
stats_dict: Dictionary from stats.json
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
List of FormattedStat objects
|
|
42
|
+
"""
|
|
43
|
+
results = []
|
|
44
|
+
|
|
45
|
+
analyses = stats_dict.get("analyses", [])
|
|
46
|
+
for analysis in analyses:
|
|
47
|
+
formatted = _format_analysis(analysis)
|
|
48
|
+
if formatted:
|
|
49
|
+
results.append(formatted)
|
|
50
|
+
|
|
51
|
+
return results
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _format_analysis(analysis: Dict[str, Any]) -> Optional[FormattedStat]:
|
|
55
|
+
"""Format a single analysis result.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
analysis: Single analysis dictionary
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
FormattedStat or None if cannot format
|
|
62
|
+
"""
|
|
63
|
+
method = analysis.get("method", {})
|
|
64
|
+
result = analysis.get("results", {})
|
|
65
|
+
|
|
66
|
+
if not result:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
# Extract test info
|
|
70
|
+
test_name = method.get("name", "test")
|
|
71
|
+
variant = method.get("variant", "")
|
|
72
|
+
|
|
73
|
+
# Format statistic
|
|
74
|
+
stat_name = result.get("statistic_name", "t")
|
|
75
|
+
stat_value = result.get("statistic")
|
|
76
|
+
df = result.get("df")
|
|
77
|
+
|
|
78
|
+
if stat_value is None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
statistic_str = format_statistic(stat_name, stat_value, df)
|
|
82
|
+
|
|
83
|
+
# Format p-value
|
|
84
|
+
p = result.get("p_value")
|
|
85
|
+
p_str = format_p_value(p) if p is not None else "---"
|
|
86
|
+
stars = significance_stars(p) if p is not None else ""
|
|
87
|
+
|
|
88
|
+
# Format effect size
|
|
89
|
+
effect = result.get("effect_size")
|
|
90
|
+
effect_str = None
|
|
91
|
+
if effect:
|
|
92
|
+
es_name = effect.get("name", "d")
|
|
93
|
+
es_value = effect.get("value")
|
|
94
|
+
ci_lower = effect.get("ci_lower")
|
|
95
|
+
ci_upper = effect.get("ci_upper")
|
|
96
|
+
if es_value is not None:
|
|
97
|
+
effect_str = format_effect_size(es_name, es_value, ci_lower, ci_upper)
|
|
98
|
+
|
|
99
|
+
# Build full report
|
|
100
|
+
full_parts = [statistic_str, f"$p = {p_str}$"]
|
|
101
|
+
if effect_str:
|
|
102
|
+
full_parts.append(effect_str)
|
|
103
|
+
full_report = ", ".join(full_parts)
|
|
104
|
+
|
|
105
|
+
# Determine test type label
|
|
106
|
+
test_type = _get_test_type_label(test_name, variant)
|
|
107
|
+
|
|
108
|
+
return FormattedStat(
|
|
109
|
+
test_type=test_type,
|
|
110
|
+
statistic=statistic_str,
|
|
111
|
+
p_value=p_str,
|
|
112
|
+
effect_size=effect_str,
|
|
113
|
+
stars=stars,
|
|
114
|
+
full_report=full_report,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _get_test_type_label(name: str, variant: str = "") -> str:
|
|
119
|
+
"""Get human-readable test type label.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
name: Test method name
|
|
123
|
+
variant: Test variant
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Human-readable label
|
|
127
|
+
"""
|
|
128
|
+
labels = {
|
|
129
|
+
"t_test": "t-test",
|
|
130
|
+
"t-test": "t-test",
|
|
131
|
+
"ttest": "t-test",
|
|
132
|
+
"anova": "ANOVA",
|
|
133
|
+
"one_way_anova": "one-way ANOVA",
|
|
134
|
+
"two_way_anova": "two-way ANOVA",
|
|
135
|
+
"repeated_measures_anova": "repeated-measures ANOVA",
|
|
136
|
+
"chi_squared": "chi-squared test",
|
|
137
|
+
"chi2": "chi-squared test",
|
|
138
|
+
"fisher_exact": "Fisher's exact test",
|
|
139
|
+
"mann_whitney": "Mann-Whitney U test",
|
|
140
|
+
"wilcoxon": "Wilcoxon signed-rank test",
|
|
141
|
+
"kruskal_wallis": "Kruskal-Wallis test",
|
|
142
|
+
"friedman": "Friedman test",
|
|
143
|
+
"correlation": "correlation",
|
|
144
|
+
"pearson": "Pearson correlation",
|
|
145
|
+
"spearman": "Spearman correlation",
|
|
146
|
+
"regression": "regression",
|
|
147
|
+
"linear_regression": "linear regression",
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
base = labels.get(name.lower(), name)
|
|
151
|
+
|
|
152
|
+
if variant:
|
|
153
|
+
variant_labels = {
|
|
154
|
+
"independent": "independent-samples",
|
|
155
|
+
"paired": "paired-samples",
|
|
156
|
+
"one_sample": "one-sample",
|
|
157
|
+
"two_sample": "two-sample",
|
|
158
|
+
"welch": "Welch's",
|
|
159
|
+
}
|
|
160
|
+
variant_str = variant_labels.get(variant.lower(), variant)
|
|
161
|
+
return f"{variant_str} {base}"
|
|
162
|
+
|
|
163
|
+
return base
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def format_inline_stat(
|
|
167
|
+
statistic_name: str,
|
|
168
|
+
statistic_value: float,
|
|
169
|
+
p_value: float,
|
|
170
|
+
df: Optional[float] = None,
|
|
171
|
+
effect_name: Optional[str] = None,
|
|
172
|
+
effect_value: Optional[float] = None,
|
|
173
|
+
include_stars: bool = True,
|
|
174
|
+
) -> str:
|
|
175
|
+
"""Format a statistical result for inline reporting.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
statistic_name: Name of test statistic (t, F, chi2, etc.)
|
|
179
|
+
statistic_value: Value of test statistic
|
|
180
|
+
p_value: P-value
|
|
181
|
+
df: Degrees of freedom
|
|
182
|
+
effect_name: Effect size name
|
|
183
|
+
effect_value: Effect size value
|
|
184
|
+
include_stars: Include significance stars
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
LaTeX formatted inline report
|
|
188
|
+
"""
|
|
189
|
+
parts = []
|
|
190
|
+
|
|
191
|
+
# Statistic
|
|
192
|
+
stat_str = format_statistic(statistic_name, statistic_value, df)
|
|
193
|
+
parts.append(stat_str)
|
|
194
|
+
|
|
195
|
+
# P-value
|
|
196
|
+
p_str = format_p_value(p_value)
|
|
197
|
+
parts.append(f"$p = {p_str}$")
|
|
198
|
+
|
|
199
|
+
# Effect size
|
|
200
|
+
if effect_name and effect_value is not None:
|
|
201
|
+
es_str = format_effect_size(effect_name, effect_value)
|
|
202
|
+
parts.append(es_str)
|
|
203
|
+
|
|
204
|
+
result = ", ".join(parts)
|
|
205
|
+
|
|
206
|
+
# Add stars
|
|
207
|
+
if include_stars:
|
|
208
|
+
stars = significance_stars(p_value)
|
|
209
|
+
if stars:
|
|
210
|
+
result += f" {stars}"
|
|
211
|
+
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def format_stat_note(stats: List[FormattedStat]) -> str:
|
|
216
|
+
"""Generate a table note explaining significance levels.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
stats: List of formatted statistics
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
LaTeX note string
|
|
223
|
+
"""
|
|
224
|
+
has_stars = any(s.stars for s in stats)
|
|
225
|
+
|
|
226
|
+
if not has_stars:
|
|
227
|
+
return ""
|
|
228
|
+
|
|
229
|
+
# Check which levels are used
|
|
230
|
+
max_stars = max((len(s.stars) for s in stats if s.stars), default=0)
|
|
231
|
+
|
|
232
|
+
note_parts = []
|
|
233
|
+
if max_stars >= 1:
|
|
234
|
+
note_parts.append("$^{*}p < .05$")
|
|
235
|
+
if max_stars >= 2:
|
|
236
|
+
note_parts.append("$^{**}p < .01$")
|
|
237
|
+
if max_stars >= 3:
|
|
238
|
+
note_parts.append("$^{***}p < .001$")
|
|
239
|
+
|
|
240
|
+
if note_parts:
|
|
241
|
+
return "\\textit{Note.} " + ", ".join(note_parts) + "."
|
|
242
|
+
|
|
243
|
+
return ""
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def format_stats_paragraph(stats: List[FormattedStat]) -> str:
|
|
247
|
+
"""Generate a results paragraph from formatted stats.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
stats: List of formatted statistics
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
LaTeX paragraph summarizing results
|
|
254
|
+
"""
|
|
255
|
+
if not stats:
|
|
256
|
+
return ""
|
|
257
|
+
|
|
258
|
+
lines = []
|
|
259
|
+
for stat in stats:
|
|
260
|
+
line = f"The {stat.test_type} revealed {stat.full_report}."
|
|
261
|
+
lines.append(line)
|
|
262
|
+
|
|
263
|
+
return " ".join(lines)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
__all__ = [
|
|
267
|
+
"FormattedStat",
|
|
268
|
+
"format_stats_for_latex",
|
|
269
|
+
"format_inline_stat",
|
|
270
|
+
"format_stat_note",
|
|
271
|
+
"format_stats_paragraph",
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
# EOF
|