scitex 2.8.1__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/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/edit/panel_loader.py +1 -1
- scitex/fig/io/_bundle.py +7 -7
- 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 -32
- 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} +168 -97
- scitex/io/bundle/_nested.py +713 -0
- scitex/io/bundle/_types.py +74 -0
- scitex/io/{_zip_bundle.py → bundle/_zip.py} +93 -45
- 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/_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/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/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/_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.8.1.dist-info → scitex-2.10.0.dist-info}/METADATA +364 -181
- {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/RECORD +412 -97
- 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.8.1.dist-info → scitex-2.10.0.dist-info}/WHEEL +0 -0
- {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -76,6 +76,8 @@ from ._export_as_csv_formatters import (
|
|
|
76
76
|
_format_eventplot,
|
|
77
77
|
_format_fill,
|
|
78
78
|
_format_fill_between,
|
|
79
|
+
_format_stackplot,
|
|
80
|
+
_format_pcolormesh,
|
|
79
81
|
_format_hexbin,
|
|
80
82
|
_format_hist,
|
|
81
83
|
_format_hist2d,
|
|
@@ -147,6 +149,9 @@ _FORMATTER_REGISTRY = {
|
|
|
147
149
|
"eventplot": _format_eventplot,
|
|
148
150
|
"fill": _format_fill,
|
|
149
151
|
"fill_between": _format_fill_between,
|
|
152
|
+
"stackplot": _format_stackplot,
|
|
153
|
+
"pcolormesh": _format_pcolormesh,
|
|
154
|
+
"pcolor": _format_pcolormesh,
|
|
150
155
|
"hexbin": _format_hexbin,
|
|
151
156
|
"hist": _format_hist,
|
|
152
157
|
"hist2d": _format_hist2d,
|
|
@@ -337,6 +342,12 @@ def format_record(record, record_index=0):
|
|
|
337
342
|
return _format_fill(id, tracked_dict, kwargs)
|
|
338
343
|
elif method == "fill_between":
|
|
339
344
|
return _format_fill_between(id, tracked_dict, kwargs)
|
|
345
|
+
elif method == "stackplot":
|
|
346
|
+
return _format_stackplot(id, tracked_dict, kwargs)
|
|
347
|
+
elif method == "pcolormesh":
|
|
348
|
+
return _format_pcolormesh(id, tracked_dict, kwargs)
|
|
349
|
+
elif method == "pcolor":
|
|
350
|
+
return _format_pcolormesh(id, tracked_dict, kwargs)
|
|
340
351
|
elif method == "hexbin":
|
|
341
352
|
return _format_hexbin(id, tracked_dict, kwargs)
|
|
342
353
|
elif method == "hist2d":
|
|
@@ -24,6 +24,8 @@ from ._format_errorbar import _format_errorbar
|
|
|
24
24
|
from ._format_eventplot import _format_eventplot
|
|
25
25
|
from ._format_fill import _format_fill
|
|
26
26
|
from ._format_fill_between import _format_fill_between
|
|
27
|
+
from ._format_stackplot import _format_stackplot
|
|
28
|
+
from ._format_pcolormesh import _format_pcolormesh
|
|
27
29
|
from ._format_hexbin import _format_hexbin
|
|
28
30
|
from ._format_hist2d import _format_hist2d
|
|
29
31
|
from ._format_imshow import _format_imshow
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-21 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
from scitex.plt.utils._csv_column_naming import get_csv_column_name
|
|
10
|
+
from ._format_plot import _parse_tracking_id
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _format_pcolormesh(id, tracked_dict, kwargs):
|
|
14
|
+
"""Format data from a pcolormesh call.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
id (str): Identifier for the plot
|
|
18
|
+
tracked_dict (dict): Dictionary containing tracked data
|
|
19
|
+
kwargs (dict): Keyword arguments passed to pcolormesh
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
pd.DataFrame: Formatted data from pcolormesh (x, y, value columns)
|
|
23
|
+
"""
|
|
24
|
+
if not tracked_dict or not isinstance(tracked_dict, dict):
|
|
25
|
+
return pd.DataFrame()
|
|
26
|
+
|
|
27
|
+
# Parse tracking ID to get axes position and trace ID
|
|
28
|
+
ax_row, ax_col, trace_id = _parse_tracking_id(id)
|
|
29
|
+
|
|
30
|
+
args = tracked_dict.get("args", ())
|
|
31
|
+
|
|
32
|
+
if len(args) == 0:
|
|
33
|
+
return pd.DataFrame()
|
|
34
|
+
|
|
35
|
+
# pcolormesh can be called as:
|
|
36
|
+
# pcolormesh(C) - just color values
|
|
37
|
+
# pcolormesh(X, Y, C) - with coordinates
|
|
38
|
+
if len(args) == 1:
|
|
39
|
+
# Just C provided
|
|
40
|
+
C = np.asarray(args[0])
|
|
41
|
+
rows, cols = C.shape
|
|
42
|
+
Y, X = np.meshgrid(range(rows), range(cols), indexing="ij")
|
|
43
|
+
elif len(args) >= 3:
|
|
44
|
+
# X, Y, C provided
|
|
45
|
+
X = np.asarray(args[0])
|
|
46
|
+
Y = np.asarray(args[1])
|
|
47
|
+
C = np.asarray(args[2])
|
|
48
|
+
else:
|
|
49
|
+
return pd.DataFrame()
|
|
50
|
+
|
|
51
|
+
# Get column names
|
|
52
|
+
col_x = get_csv_column_name("x", ax_row, ax_col, trace_id=trace_id)
|
|
53
|
+
col_y = get_csv_column_name("y", ax_row, ax_col, trace_id=trace_id)
|
|
54
|
+
col_value = get_csv_column_name("value", ax_row, ax_col, trace_id=trace_id)
|
|
55
|
+
|
|
56
|
+
# Flatten for CSV format
|
|
57
|
+
df = pd.DataFrame({
|
|
58
|
+
col_x: X.flatten(),
|
|
59
|
+
col_y: Y.flatten(),
|
|
60
|
+
col_value: C.flatten(),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return df
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# EOF
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-21 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
from scitex.plt.utils._csv_column_naming import get_csv_column_name
|
|
10
|
+
from ._format_plot import _parse_tracking_id
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _format_stackplot(id, tracked_dict, kwargs):
|
|
14
|
+
"""Format data from a stackplot call.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
id (str): Identifier for the plot
|
|
18
|
+
tracked_dict (dict): Dictionary containing tracked data
|
|
19
|
+
kwargs (dict): Keyword arguments passed to stackplot
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
pd.DataFrame: Formatted data from stackplot (x and multiple y columns)
|
|
23
|
+
"""
|
|
24
|
+
if not tracked_dict or not isinstance(tracked_dict, dict):
|
|
25
|
+
return pd.DataFrame()
|
|
26
|
+
|
|
27
|
+
# Parse tracking ID to get axes position and trace ID
|
|
28
|
+
ax_row, ax_col, trace_id = _parse_tracking_id(id)
|
|
29
|
+
|
|
30
|
+
args = tracked_dict.get("args", ())
|
|
31
|
+
|
|
32
|
+
# stackplot(x, y1, y2, y3, ...) or stackplot(x, [y1, y2, y3], ...)
|
|
33
|
+
if len(args) < 2:
|
|
34
|
+
return pd.DataFrame()
|
|
35
|
+
|
|
36
|
+
x = np.asarray(args[0])
|
|
37
|
+
col_x = get_csv_column_name("x", ax_row, ax_col, trace_id=trace_id)
|
|
38
|
+
data = {col_x: x}
|
|
39
|
+
|
|
40
|
+
# Get labels from kwargs if available
|
|
41
|
+
labels = kwargs.get("labels", [])
|
|
42
|
+
|
|
43
|
+
# Handle remaining args as y arrays
|
|
44
|
+
y_arrays = args[1:]
|
|
45
|
+
|
|
46
|
+
# If first y arg is a 2D array, treat rows as separate series
|
|
47
|
+
if len(y_arrays) == 1 and hasattr(y_arrays[0], "ndim"):
|
|
48
|
+
y_data = np.asarray(y_arrays[0])
|
|
49
|
+
if y_data.ndim == 2:
|
|
50
|
+
y_arrays = [y_data[i] for i in range(y_data.shape[0])]
|
|
51
|
+
|
|
52
|
+
for i, y in enumerate(y_arrays):
|
|
53
|
+
y = np.asarray(y)
|
|
54
|
+
# Use label if available, otherwise use index
|
|
55
|
+
label = labels[i] if i < len(labels) else f"y{i:02d}"
|
|
56
|
+
col_y = get_csv_column_name(label, ax_row, ax_col, trace_id=trace_id)
|
|
57
|
+
data[col_y] = y
|
|
58
|
+
|
|
59
|
+
return pd.DataFrame(data)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# EOF
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-05-18 22:05:10 (ywatanabe)"
|
|
4
|
+
# File: /data/gpfs/projects/punim2354/ywatanabe/scitex_repo/src/scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py
|
|
5
|
+
# ----------------------------------------
|
|
6
|
+
import os
|
|
7
|
+
__FILE__ = __file__
|
|
8
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
9
|
+
# ----------------------------------------
|
|
10
|
+
|
|
11
|
+
import unittest
|
|
12
|
+
import numpy as np
|
|
13
|
+
import pandas as pd
|
|
14
|
+
|
|
15
|
+
# Import formatters directly
|
|
16
|
+
from ._format_plot import _format_plot
|
|
17
|
+
from ._format_plot_kde import _format_plot_kde
|
|
18
|
+
from ._format_plot_ecdf import _format_plot_ecdf
|
|
19
|
+
from ._format_plot_heatmap import _format_plot_heatmap
|
|
20
|
+
from ._format_plot_violin import _format_plot_violin
|
|
21
|
+
from ._format_plot_shaded_line import _format_plot_shaded_line
|
|
22
|
+
from ._format_plot_scatter_hist import _format_plot_scatter_hist
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FormattersTest(unittest.TestCase):
|
|
26
|
+
"""Test the formatter functions."""
|
|
27
|
+
|
|
28
|
+
def test_format_plot_kde(self):
|
|
29
|
+
"""Test _format_plot_kde function."""
|
|
30
|
+
# Test case 1: Normal input
|
|
31
|
+
tracked_dict = {
|
|
32
|
+
'x': np.linspace(-3, 3, 100),
|
|
33
|
+
'kde': np.exp(-np.linspace(-3, 3, 100)**2/2),
|
|
34
|
+
'n': 500
|
|
35
|
+
}
|
|
36
|
+
id = 'test_kde'
|
|
37
|
+
df = _format_plot_kde(id, tracked_dict, {})
|
|
38
|
+
|
|
39
|
+
# Verify columns
|
|
40
|
+
self.assertIn(f"{id}_kde_x", df.columns)
|
|
41
|
+
self.assertIn(f"{id}_kde_density", df.columns)
|
|
42
|
+
self.assertIn(f"{id}_kde_n", df.columns)
|
|
43
|
+
|
|
44
|
+
# Test case 2: Empty tracked_dict
|
|
45
|
+
df = _format_plot_kde(id, {}, {})
|
|
46
|
+
self.assertTrue(df.empty)
|
|
47
|
+
|
|
48
|
+
# Test case 3: Missing 'x' key
|
|
49
|
+
tracked_dict = {'kde': np.exp(-np.linspace(-3, 3, 100)**2/2)}
|
|
50
|
+
df = _format_plot_kde(id, tracked_dict, {})
|
|
51
|
+
self.assertTrue(df.empty)
|
|
52
|
+
|
|
53
|
+
def test_format_plot(self):
|
|
54
|
+
"""Test _format_plot function."""
|
|
55
|
+
# Test case 1: Normal input
|
|
56
|
+
tracked_dict = {
|
|
57
|
+
'plot_df': pd.DataFrame({
|
|
58
|
+
'x': np.linspace(0, 10, 100),
|
|
59
|
+
'y': np.sin(np.linspace(0, 10, 100))
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
id = 'test_plot'
|
|
63
|
+
df = _format_plot(id, tracked_dict, {})
|
|
64
|
+
|
|
65
|
+
# Verify it returned the DataFrame with added prefix
|
|
66
|
+
self.assertFalse(df.empty)
|
|
67
|
+
|
|
68
|
+
# Test case 2: Empty tracked_dict
|
|
69
|
+
df = _format_plot(id, {}, {})
|
|
70
|
+
self.assertTrue(df.empty)
|
|
71
|
+
|
|
72
|
+
def test_format_plot_ecdf(self):
|
|
73
|
+
"""Test _format_plot_ecdf function."""
|
|
74
|
+
# Test case 1: Normal input
|
|
75
|
+
tracked_dict = {
|
|
76
|
+
'ecdf_df': pd.DataFrame({
|
|
77
|
+
'x': np.linspace(-3, 3, 100),
|
|
78
|
+
'ecdf': np.linspace(0, 1, 100)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
id = 'test_ecdf'
|
|
82
|
+
df = _format_plot_ecdf(id, tracked_dict, {})
|
|
83
|
+
|
|
84
|
+
# Verify it returned the DataFrame
|
|
85
|
+
self.assertFalse(df.empty)
|
|
86
|
+
|
|
87
|
+
# Test case 2: Empty tracked_dict
|
|
88
|
+
df = _format_plot_ecdf(id, {}, {})
|
|
89
|
+
self.assertTrue(df.empty)
|
|
90
|
+
|
|
91
|
+
def test_format_plot_heatmap(self):
|
|
92
|
+
"""Test _format_plot_heatmap function."""
|
|
93
|
+
# Test case 1: Normal input with labels
|
|
94
|
+
data = np.random.rand(3, 4)
|
|
95
|
+
x_labels = ['A', 'B', 'C']
|
|
96
|
+
y_labels = ['W', 'X', 'Y', 'Z']
|
|
97
|
+
|
|
98
|
+
tracked_dict = {
|
|
99
|
+
'data': data,
|
|
100
|
+
'x_labels': x_labels,
|
|
101
|
+
'y_labels': y_labels
|
|
102
|
+
}
|
|
103
|
+
id = 'test_heatmap'
|
|
104
|
+
df = _format_plot_heatmap(id, tracked_dict, {})
|
|
105
|
+
|
|
106
|
+
# Verify it returned the DataFrame with the expected shape
|
|
107
|
+
self.assertFalse(df.empty)
|
|
108
|
+
self.assertEqual(df.shape[0], 12) # 3 rows * 4 columns = 12 cells
|
|
109
|
+
# We should have 5 columns: row, col, value, row_label, col_label
|
|
110
|
+
self.assertEqual(df.shape[1], 5)
|
|
111
|
+
|
|
112
|
+
# Test case 2: No labels
|
|
113
|
+
tracked_dict = {'data': data}
|
|
114
|
+
df = _format_plot_heatmap(id, tracked_dict, {})
|
|
115
|
+
self.assertFalse(df.empty)
|
|
116
|
+
|
|
117
|
+
# Test case 3: Empty tracked_dict
|
|
118
|
+
df = _format_plot_heatmap(id, {}, {})
|
|
119
|
+
self.assertTrue(df.empty)
|
|
120
|
+
|
|
121
|
+
def test_format_plot_violin(self):
|
|
122
|
+
"""Test _format_plot_violin function."""
|
|
123
|
+
# Test case 1: List data
|
|
124
|
+
data = [np.random.normal(0, 1, 100), np.random.normal(2, 1, 100)]
|
|
125
|
+
labels = ['Group A', 'Group B']
|
|
126
|
+
|
|
127
|
+
tracked_dict = {
|
|
128
|
+
'data': data,
|
|
129
|
+
'labels': labels
|
|
130
|
+
}
|
|
131
|
+
id = 'test_violin'
|
|
132
|
+
df = _format_plot_violin(id, tracked_dict, {})
|
|
133
|
+
|
|
134
|
+
# Verify it returned the DataFrame
|
|
135
|
+
self.assertFalse(df.empty)
|
|
136
|
+
|
|
137
|
+
# Test case 2: DataFrame data
|
|
138
|
+
data_df = pd.DataFrame({
|
|
139
|
+
'values': np.concatenate([np.random.normal(0, 1, 100), np.random.normal(2, 1, 100)]),
|
|
140
|
+
'group': ['A'] * 100 + ['B'] * 100
|
|
141
|
+
})
|
|
142
|
+
tracked_dict = {
|
|
143
|
+
'data': data_df,
|
|
144
|
+
'x': 'group',
|
|
145
|
+
'y': 'values'
|
|
146
|
+
}
|
|
147
|
+
df = _format_plot_violin(id, tracked_dict, {})
|
|
148
|
+
self.assertFalse(df.empty)
|
|
149
|
+
|
|
150
|
+
# Test case 3: Empty tracked_dict
|
|
151
|
+
df = _format_plot_violin(id, {}, {})
|
|
152
|
+
self.assertTrue(df.empty)
|
|
153
|
+
|
|
154
|
+
def test_format_plot_shaded_line(self):
|
|
155
|
+
"""Test _format_plot_shaded_line function."""
|
|
156
|
+
# Test case 1: Normal input
|
|
157
|
+
tracked_dict = {
|
|
158
|
+
'plot_df': pd.DataFrame({
|
|
159
|
+
'x': np.linspace(0, 10, 100),
|
|
160
|
+
'y_lower': np.sin(np.linspace(0, 10, 100)) - 0.2,
|
|
161
|
+
'y_middle': np.sin(np.linspace(0, 10, 100)),
|
|
162
|
+
'y_upper': np.sin(np.linspace(0, 10, 100)) + 0.2
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
id = 'test_shaded'
|
|
166
|
+
df = _format_plot_shaded_line(id, tracked_dict, {})
|
|
167
|
+
|
|
168
|
+
# Verify it returned the DataFrame
|
|
169
|
+
self.assertFalse(df.empty)
|
|
170
|
+
|
|
171
|
+
# Test case 2: Empty tracked_dict
|
|
172
|
+
df = _format_plot_shaded_line(id, {}, {})
|
|
173
|
+
self.assertTrue(df.empty)
|
|
174
|
+
|
|
175
|
+
def test_format_plot_scatter_hist(self):
|
|
176
|
+
"""Test _format_plot_scatter_hist function."""
|
|
177
|
+
# Test case 1: Normal input
|
|
178
|
+
tracked_dict = {
|
|
179
|
+
'x': np.random.normal(0, 1, 100),
|
|
180
|
+
'y': np.random.normal(0, 1, 100),
|
|
181
|
+
'hist_x': np.random.rand(10),
|
|
182
|
+
'hist_y': np.random.rand(10),
|
|
183
|
+
'bin_edges_x': np.linspace(-3, 3, 11),
|
|
184
|
+
'bin_edges_y': np.linspace(-3, 3, 11)
|
|
185
|
+
}
|
|
186
|
+
id = 'test_scatter_hist'
|
|
187
|
+
df = _format_plot_scatter_hist(id, tracked_dict, {})
|
|
188
|
+
|
|
189
|
+
# Verify it returned the DataFrame with expected columns
|
|
190
|
+
self.assertFalse(df.empty)
|
|
191
|
+
self.assertTrue(any(col.startswith(f"{id}_scatter_hist_x") for col in df.columns))
|
|
192
|
+
self.assertTrue(any(col.startswith(f"{id}_scatter_hist_y") for col in df.columns))
|
|
193
|
+
|
|
194
|
+
# Test case 2: Missing keys
|
|
195
|
+
tracked_dict = {
|
|
196
|
+
'x': np.random.normal(0, 1, 100),
|
|
197
|
+
'y': np.random.normal(0, 1, 100)
|
|
198
|
+
}
|
|
199
|
+
df = _format_plot_scatter_hist(id, tracked_dict, {})
|
|
200
|
+
self.assertFalse(df.empty) # Should still work with just x,y
|
|
201
|
+
|
|
202
|
+
# Test case 3: Empty tracked_dict
|
|
203
|
+
df = _format_plot_scatter_hist(id, {}, {})
|
|
204
|
+
self.assertTrue(df.empty)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
if __name__ == '__main__':
|
|
208
|
+
unittest.main()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Font configuration for matplotlib figures."""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import matplotlib as mpl
|
|
7
|
+
import matplotlib.font_manager as fm
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def configure_arial_font():
|
|
11
|
+
"""Configure Arial font for matplotlib if available.
|
|
12
|
+
|
|
13
|
+
Returns
|
|
14
|
+
-------
|
|
15
|
+
bool
|
|
16
|
+
True if Arial was successfully configured, False otherwise.
|
|
17
|
+
"""
|
|
18
|
+
arial_enabled = False
|
|
19
|
+
|
|
20
|
+
# Try to find Arial
|
|
21
|
+
try:
|
|
22
|
+
fm.findfont("Arial", fallback_to_default=False)
|
|
23
|
+
arial_enabled = True
|
|
24
|
+
except Exception:
|
|
25
|
+
# Search for Arial font files and register them
|
|
26
|
+
arial_paths = [
|
|
27
|
+
f
|
|
28
|
+
for f in fm.findSystemFonts()
|
|
29
|
+
if os.path.basename(f).lower().startswith("arial")
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
if arial_paths:
|
|
33
|
+
for path in arial_paths:
|
|
34
|
+
try:
|
|
35
|
+
fm.fontManager.addfont(path)
|
|
36
|
+
except Exception:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
# Verify Arial is now available
|
|
40
|
+
try:
|
|
41
|
+
fm.findfont("Arial", fallback_to_default=False)
|
|
42
|
+
arial_enabled = True
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
# Configure matplotlib to use Arial if available
|
|
47
|
+
if arial_enabled:
|
|
48
|
+
mpl.rcParams["font.family"] = "Arial"
|
|
49
|
+
mpl.rcParams["font.sans-serif"] = [
|
|
50
|
+
"Arial",
|
|
51
|
+
"Helvetica",
|
|
52
|
+
"DejaVu Sans",
|
|
53
|
+
"Liberation Sans",
|
|
54
|
+
]
|
|
55
|
+
else:
|
|
56
|
+
# Warn about missing Arial
|
|
57
|
+
from scitex import logging as _logging
|
|
58
|
+
|
|
59
|
+
_logger = _logging.getLogger(__name__)
|
|
60
|
+
_logger.warning(
|
|
61
|
+
"Arial font not found. Using fallback fonts (Helvetica/DejaVu Sans). "
|
|
62
|
+
"For publication figures with Arial: sudo apt-get install ttf-mscorefonts-installer && fc-cache -fv"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return arial_enabled
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Configure fonts at module import
|
|
69
|
+
_arial_enabled = configure_arial_font()
|
|
70
|
+
|
|
71
|
+
# EOF
|