scitex 2.7.0__py3-none-any.whl → 2.8.1__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 +6 -2
- scitex/__version__.py +1 -1
- scitex/audio/README.md +52 -0
- scitex/audio/__init__.py +384 -0
- scitex/audio/__main__.py +129 -0
- scitex/audio/_tts.py +334 -0
- scitex/audio/engines/__init__.py +44 -0
- scitex/audio/engines/base.py +275 -0
- scitex/audio/engines/elevenlabs_engine.py +143 -0
- scitex/audio/engines/gtts_engine.py +162 -0
- scitex/audio/engines/pyttsx3_engine.py +131 -0
- scitex/audio/mcp_server.py +757 -0
- scitex/bridge/_helpers.py +1 -1
- scitex/bridge/_plt_vis.py +1 -1
- scitex/bridge/_stats_vis.py +1 -1
- scitex/dev/plt/__init__.py +272 -0
- scitex/dev/plt/plot_mpl_axhline.py +28 -0
- scitex/dev/plt/plot_mpl_axhspan.py +28 -0
- scitex/dev/plt/plot_mpl_axvline.py +28 -0
- scitex/dev/plt/plot_mpl_axvspan.py +28 -0
- scitex/dev/plt/plot_mpl_bar.py +29 -0
- scitex/dev/plt/plot_mpl_barh.py +29 -0
- scitex/dev/plt/plot_mpl_boxplot.py +28 -0
- scitex/dev/plt/plot_mpl_contour.py +31 -0
- scitex/dev/plt/plot_mpl_contourf.py +31 -0
- scitex/dev/plt/plot_mpl_errorbar.py +30 -0
- scitex/dev/plt/plot_mpl_eventplot.py +28 -0
- scitex/dev/plt/plot_mpl_fill.py +30 -0
- scitex/dev/plt/plot_mpl_fill_between.py +31 -0
- scitex/dev/plt/plot_mpl_hexbin.py +28 -0
- scitex/dev/plt/plot_mpl_hist.py +28 -0
- scitex/dev/plt/plot_mpl_hist2d.py +28 -0
- scitex/dev/plt/plot_mpl_imshow.py +29 -0
- scitex/dev/plt/plot_mpl_pcolormesh.py +31 -0
- scitex/dev/plt/plot_mpl_pie.py +29 -0
- scitex/dev/plt/plot_mpl_plot.py +29 -0
- scitex/dev/plt/plot_mpl_quiver.py +31 -0
- scitex/dev/plt/plot_mpl_scatter.py +28 -0
- scitex/dev/plt/plot_mpl_stackplot.py +31 -0
- scitex/dev/plt/plot_mpl_stem.py +29 -0
- scitex/dev/plt/plot_mpl_step.py +29 -0
- scitex/dev/plt/plot_mpl_violinplot.py +28 -0
- scitex/dev/plt/plot_sns_barplot.py +29 -0
- scitex/dev/plt/plot_sns_boxplot.py +29 -0
- scitex/dev/plt/plot_sns_heatmap.py +28 -0
- scitex/dev/plt/plot_sns_histplot.py +29 -0
- scitex/dev/plt/plot_sns_kdeplot.py +29 -0
- scitex/dev/plt/plot_sns_lineplot.py +31 -0
- scitex/dev/plt/plot_sns_scatterplot.py +29 -0
- scitex/dev/plt/plot_sns_stripplot.py +29 -0
- scitex/dev/plt/plot_sns_swarmplot.py +29 -0
- scitex/dev/plt/plot_sns_violinplot.py +29 -0
- scitex/dev/plt/plot_stx_bar.py +29 -0
- scitex/dev/plt/plot_stx_barh.py +29 -0
- scitex/dev/plt/plot_stx_box.py +28 -0
- scitex/dev/plt/plot_stx_boxplot.py +28 -0
- scitex/dev/plt/plot_stx_conf_mat.py +28 -0
- scitex/dev/plt/plot_stx_contour.py +31 -0
- scitex/dev/plt/plot_stx_ecdf.py +28 -0
- scitex/dev/plt/plot_stx_errorbar.py +30 -0
- scitex/dev/plt/plot_stx_fill_between.py +31 -0
- scitex/dev/plt/plot_stx_fillv.py +28 -0
- scitex/dev/plt/plot_stx_heatmap.py +28 -0
- scitex/dev/plt/plot_stx_image.py +28 -0
- scitex/dev/plt/plot_stx_imshow.py +28 -0
- scitex/dev/plt/plot_stx_joyplot.py +28 -0
- scitex/dev/plt/plot_stx_kde.py +28 -0
- scitex/dev/plt/plot_stx_line.py +28 -0
- scitex/dev/plt/plot_stx_mean_ci.py +28 -0
- scitex/dev/plt/plot_stx_mean_std.py +28 -0
- scitex/dev/plt/plot_stx_median_iqr.py +28 -0
- scitex/dev/plt/plot_stx_raster.py +28 -0
- scitex/dev/plt/plot_stx_rectangle.py +28 -0
- scitex/dev/plt/plot_stx_scatter.py +29 -0
- scitex/dev/plt/plot_stx_shaded_line.py +29 -0
- scitex/dev/plt/plot_stx_violin.py +28 -0
- scitex/dev/plt/plot_stx_violinplot.py +28 -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/fig/__init__.py +352 -0
- scitex/{vis → fig}/backend/_parser.py +1 -1
- scitex/{vis → fig}/canvas.py +1 -1
- scitex/{vis → fig}/editor/__init__.py +5 -2
- scitex/{vis → fig}/editor/_dearpygui_editor.py +1 -1
- scitex/{vis → fig}/editor/_defaults.py +70 -5
- scitex/{vis → fig}/editor/_mpl_editor.py +1 -1
- scitex/{vis → fig}/editor/_qt_editor.py +182 -2
- scitex/{vis → 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 +1299 -0
- scitex/fig/editor/flask_editor/_core.py +1429 -0
- scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
- scitex/fig/editor/flask_editor/_renderer.py +813 -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 +123 -0
- scitex/fig/editor/flask_editor/templates/_html.py +852 -0
- scitex/fig/editor/flask_editor/templates/_scripts.py +4933 -0
- scitex/fig/editor/flask_editor/templates/_styles.py +1658 -0
- scitex/{vis → fig}/io/__init__.py +13 -1
- scitex/fig/io/_bundle.py +1058 -0
- scitex/{vis → fig}/io/_canvas.py +1 -1
- scitex/{vis → fig}/io/_data.py +1 -1
- scitex/{vis → fig}/io/_export.py +1 -1
- scitex/{vis → fig}/io/_load.py +1 -1
- scitex/{vis → fig}/io/_panel.py +1 -1
- scitex/{vis → fig}/io/_save.py +1 -1
- scitex/{vis → fig}/model/__init__.py +1 -1
- scitex/{vis → fig}/model/_annotations.py +1 -1
- scitex/{vis → fig}/model/_axes.py +1 -1
- scitex/{vis → fig}/model/_figure.py +1 -1
- scitex/{vis → fig}/model/_guides.py +1 -1
- scitex/{vis → fig}/model/_plot.py +1 -1
- scitex/{vis → fig}/model/_styles.py +1 -1
- scitex/{vis → fig}/utils/__init__.py +1 -1
- scitex/io/__init__.py +22 -26
- scitex/io/_bundle.py +493 -0
- scitex/io/_flush.py +5 -2
- scitex/io/_load.py +98 -0
- scitex/io/_load_modules/_H5Explorer.py +5 -2
- scitex/io/_load_modules/_canvas.py +2 -2
- scitex/io/_load_modules/_image.py +3 -4
- scitex/io/_load_modules/_txt.py +4 -2
- scitex/io/_metadata.py +34 -324
- scitex/io/_metadata_modules/__init__.py +46 -0
- scitex/io/_metadata_modules/_embed.py +70 -0
- scitex/io/_metadata_modules/_read.py +64 -0
- scitex/io/_metadata_modules/_utils.py +79 -0
- scitex/io/_metadata_modules/embed_metadata_jpeg.py +74 -0
- scitex/io/_metadata_modules/embed_metadata_pdf.py +53 -0
- scitex/io/_metadata_modules/embed_metadata_png.py +26 -0
- scitex/io/_metadata_modules/embed_metadata_svg.py +62 -0
- scitex/io/_metadata_modules/read_metadata_jpeg.py +57 -0
- scitex/io/_metadata_modules/read_metadata_pdf.py +51 -0
- scitex/io/_metadata_modules/read_metadata_png.py +39 -0
- scitex/io/_metadata_modules/read_metadata_svg.py +44 -0
- scitex/io/_qr_utils.py +5 -3
- scitex/io/_save.py +548 -30
- scitex/io/_save_modules/_canvas.py +3 -3
- scitex/io/_save_modules/_image.py +5 -9
- scitex/io/_save_modules/_tex.py +7 -4
- scitex/io/_zip_bundle.py +439 -0
- scitex/io/utils/h5_to_zarr.py +11 -9
- scitex/msword/__init__.py +255 -0
- scitex/msword/profiles.py +357 -0
- scitex/msword/reader.py +753 -0
- scitex/msword/utils.py +289 -0
- scitex/msword/writer.py +362 -0
- scitex/plt/__init__.py +5 -2
- scitex/plt/_subplots/_AxesWrapper.py +6 -6
- scitex/plt/_subplots/_AxisWrapper.py +15 -9
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +36 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +264 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +213 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +128 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +59 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +34 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +593 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +654 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +527 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +321 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +33 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +152 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +600 -0
- scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +79 -5
- scitex/plt/_subplots/_FigWrapper.py +6 -6
- scitex/plt/_subplots/_SubplotsWrapper.py +28 -18
- scitex/plt/_subplots/_export_as_csv.py +35 -5
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +8 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +10 -21
- scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +18 -7
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +28 -12
- scitex/plt/_subplots/_export_as_csv_formatters/_format_matshow.py +10 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_imshow.py +13 -1
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +12 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +10 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_quiver.py +10 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +18 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +44 -36
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +14 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_streamplot.py +11 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +84 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +85 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_conf_mat.py +14 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_contour.py +54 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_ecdf.py +14 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +120 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_heatmap.py +16 -6
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_image.py +29 -19
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_imshow.py +63 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_joyplot.py +22 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_ci.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_mean_std.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_median_iqr.py +18 -14
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_raster.py +10 -2
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +51 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter_hist.py +18 -9
- scitex/plt/ax/_plot/_stx_ecdf.py +4 -2
- scitex/plt/gallery/_generate.py +421 -14
- scitex/plt/io/__init__.py +53 -0
- scitex/plt/io/_bundle.py +490 -0
- scitex/plt/io/_layered_bundle.py +1343 -0
- scitex/plt/styles/SCITEX_STYLE.yaml +26 -0
- scitex/plt/styles/__init__.py +14 -0
- scitex/plt/styles/presets.py +78 -0
- scitex/plt/utils/__init__.py +13 -1
- scitex/plt/utils/_collect_figure_metadata.py +10 -14
- scitex/plt/utils/_configure_mpl.py +6 -18
- scitex/plt/utils/_crop.py +32 -14
- scitex/plt/utils/_csv_column_naming.py +54 -0
- scitex/plt/utils/_figure_mm.py +116 -1
- scitex/plt/utils/_hitmap.py +1643 -0
- scitex/plt/utils/metadata/__init__.py +25 -0
- scitex/plt/utils/metadata/_core.py +9 -10
- scitex/plt/utils/metadata/_dimensions.py +6 -3
- scitex/plt/utils/metadata/_editable_export.py +405 -0
- scitex/plt/utils/metadata/_geometry_extraction.py +570 -0
- scitex/schema/__init__.py +109 -16
- scitex/schema/_canvas.py +1 -1
- scitex/schema/_plot.py +1015 -0
- scitex/schema/_stats.py +2 -2
- scitex/stats/__init__.py +117 -0
- scitex/stats/io/__init__.py +29 -0
- scitex/stats/io/_bundle.py +156 -0
- scitex/tex/__init__.py +4 -0
- scitex/tex/_export.py +890 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/METADATA +11 -1
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/RECORD +294 -170
- scitex/io/memo.md +0 -2827
- scitex/plt/REQUESTS.md +0 -191
- scitex/plt/_subplots/TODO.md +0 -53
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +0 -559
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +0 -1609
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +0 -447
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_between.json +0 -110
- scitex/plt/templates/research-master/scitex/vis/gallery/area/fill_betweenx.json +0 -88
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fill_between.json +0 -103
- scitex/plt/templates/research-master/scitex/vis/gallery/area/stx_fillv.json +0 -106
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/bar.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/barh.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/boxplot.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_bar.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_barh.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_box.json +0 -83
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_boxplot.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violin.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/stx_violinplot.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/categorical/violinplot.json +0 -91
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contour.json +0 -97
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/contourf.json +0 -98
- scitex/plt/templates/research-master/scitex/vis/gallery/contour/stx_contour.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist.json +0 -101
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/hist2d.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_ecdf.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_joyplot.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/distribution/stx_kde.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/imshow.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/matshow.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_conf_mat.json +0 -83
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_heatmap.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_image.json +0 -121
- scitex/plt/templates/research-master/scitex/vis/gallery/grid/stx_imshow.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/line/plot.json +0 -110
- scitex/plt/templates/research-master/scitex/vis/gallery/line/step.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_line.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/line/stx_shaded_line.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/hexbin.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/scatter.json +0 -95
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stem.json +0 -92
- scitex/plt/templates/research-master/scitex/vis/gallery/scatter/stx_scatter.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/special/pie.json +0 -94
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_raster.json +0 -109
- scitex/plt/templates/research-master/scitex/vis/gallery/special/stx_rectangle.json +0 -108
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/errorbar.json +0 -93
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_errorbar.json +0 -84
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_ci.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_mean_std.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/statistical/stx_median_iqr.json +0 -96
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/quiver.json +0 -99
- scitex/plt/templates/research-master/scitex/vis/gallery/vector/streamplot.json +0 -100
- scitex/vis/__init__.py +0 -177
- scitex/vis/editor/_edit.py +0 -390
- scitex/vis/editor/flask_editor/_bbox.py +0 -529
- scitex/vis/editor/flask_editor/_core.py +0 -168
- scitex/vis/editor/flask_editor/_renderer.py +0 -393
- scitex/vis/editor/flask_editor/templates/__init__.py +0 -33
- scitex/vis/editor/flask_editor/templates/_html.py +0 -513
- scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
- scitex/vis/editor/flask_editor/templates/_styles.py +0 -739
- /scitex/{vis → fig}/README.md +0 -0
- /scitex/{vis → fig}/backend/__init__.py +0 -0
- /scitex/{vis → fig}/backend/_export.py +0 -0
- /scitex/{vis → fig}/backend/_render.py +0 -0
- /scitex/{vis → fig}/docs/CANVAS_ARCHITECTURE.md +0 -0
- /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
- /scitex/{vis → fig}/editor/flask_editor/__init__.py +0 -0
- /scitex/{vis → fig}/editor/flask_editor/_utils.py +0 -0
- /scitex/{vis → fig}/io/_directory.py +0 -0
- /scitex/{vis → fig}/model/_plot_types.py +0 -0
- /scitex/{vis → fig}/utils/_defaults.py +0 -0
- /scitex/{vis → fig}/utils/_validate.py +0 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/WHEEL +0 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.0.dist-info → scitex-2.8.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -102,3 +102,29 @@ behavior:
|
|
|
102
102
|
hide_right_spine: true # Hide right spine
|
|
103
103
|
grid: false # Show grid
|
|
104
104
|
|
|
105
|
+
# =============================================================================
|
|
106
|
+
# THEME / COLOR MODE
|
|
107
|
+
# =============================================================================
|
|
108
|
+
# Dark mode uses eye-friendly colors optimized for dark backgrounds
|
|
109
|
+
# Light mode uses standard black on white (default matplotlib behavior)
|
|
110
|
+
theme:
|
|
111
|
+
mode: "light" # "light" or "dark"
|
|
112
|
+
|
|
113
|
+
# Dark mode color palette (eye-friendly, reduced strain)
|
|
114
|
+
dark:
|
|
115
|
+
background: "transparent" # Figure background (transparent by default)
|
|
116
|
+
axes_bg: "#1a1a2e" # Axes background (deep navy-black)
|
|
117
|
+
text: "#e8e8e8" # Text, labels, titles (soft white)
|
|
118
|
+
spine: "#4a4a5a" # Axis spines (muted gray)
|
|
119
|
+
tick: "#e8e8e8" # Tick marks and labels
|
|
120
|
+
grid: "#3a3a4a" # Grid lines (subtle)
|
|
121
|
+
|
|
122
|
+
# Light mode color palette (publication standard)
|
|
123
|
+
light:
|
|
124
|
+
background: "transparent" # Figure background
|
|
125
|
+
axes_bg: "white" # Axes background
|
|
126
|
+
text: "black" # Text, labels, titles
|
|
127
|
+
spine: "black" # Axis spines
|
|
128
|
+
tick: "black" # Tick marks and labels
|
|
129
|
+
grid: "#cccccc" # Grid lines
|
|
130
|
+
|
scitex/plt/styles/__init__.py
CHANGED
|
@@ -37,6 +37,13 @@ from .presets import (
|
|
|
37
37
|
set_style,
|
|
38
38
|
get_style,
|
|
39
39
|
resolve_style_value,
|
|
40
|
+
# DPI utilities
|
|
41
|
+
get_default_dpi,
|
|
42
|
+
get_display_dpi,
|
|
43
|
+
get_preview_dpi,
|
|
44
|
+
DPI_SAVE,
|
|
45
|
+
DPI_DISPLAY,
|
|
46
|
+
DPI_PREVIEW,
|
|
40
47
|
)
|
|
41
48
|
|
|
42
49
|
__all__ = [
|
|
@@ -51,6 +58,13 @@ __all__ = [
|
|
|
51
58
|
"set_style",
|
|
52
59
|
"get_style",
|
|
53
60
|
"resolve_style_value",
|
|
61
|
+
# DPI utilities
|
|
62
|
+
"get_default_dpi",
|
|
63
|
+
"get_display_dpi",
|
|
64
|
+
"get_preview_dpi",
|
|
65
|
+
"DPI_SAVE",
|
|
66
|
+
"DPI_DISPLAY",
|
|
67
|
+
"DPI_PREVIEW",
|
|
54
68
|
]
|
|
55
69
|
|
|
56
70
|
|
scitex/plt/styles/presets.py
CHANGED
|
@@ -40,6 +40,13 @@ __all__ = [
|
|
|
40
40
|
"set_style",
|
|
41
41
|
"get_style",
|
|
42
42
|
"resolve_style_value",
|
|
43
|
+
# DPI utilities
|
|
44
|
+
"get_default_dpi",
|
|
45
|
+
"get_display_dpi",
|
|
46
|
+
"get_preview_dpi",
|
|
47
|
+
"DPI_SAVE",
|
|
48
|
+
"DPI_DISPLAY",
|
|
49
|
+
"DPI_PREVIEW",
|
|
43
50
|
]
|
|
44
51
|
|
|
45
52
|
from pathlib import Path
|
|
@@ -79,6 +86,77 @@ def resolve_style_value(
|
|
|
79
86
|
return _get_config().resolve(key, direct_val, default, type)
|
|
80
87
|
|
|
81
88
|
|
|
89
|
+
# =============================================================================
|
|
90
|
+
# DPI Resolution - Central Source of Truth
|
|
91
|
+
# =============================================================================
|
|
92
|
+
#
|
|
93
|
+
# DPI Priority Chain:
|
|
94
|
+
# 1. Bundle's geometry_px.json (highest - existing figure's actual DPI)
|
|
95
|
+
# 2. User override / session setting
|
|
96
|
+
# 3. SCITEX_STYLE.yaml output.dpi (project default)
|
|
97
|
+
# 4. Hardcoded fallback (only if config missing)
|
|
98
|
+
#
|
|
99
|
+
# Usage:
|
|
100
|
+
# from scitex.plt.styles import get_default_dpi, DPI_SAVE
|
|
101
|
+
#
|
|
102
|
+
# # For saving figures (publication quality)
|
|
103
|
+
# fig.savefig("out.png", dpi=get_default_dpi())
|
|
104
|
+
#
|
|
105
|
+
# # For display/preview (lower resolution)
|
|
106
|
+
# fig.savefig("preview.png", dpi=get_display_dpi())
|
|
107
|
+
#
|
|
108
|
+
# # When loading from bundle, use bundle's DPI:
|
|
109
|
+
# dpi = bundle.get("geometry", {}).get("dpi") or get_default_dpi()
|
|
110
|
+
#
|
|
111
|
+
|
|
112
|
+
# Fallback values (only used if config unavailable)
|
|
113
|
+
_FALLBACK_DPI_SAVE = 300
|
|
114
|
+
_FALLBACK_DPI_DISPLAY = 100
|
|
115
|
+
_FALLBACK_DPI_PREVIEW = 150
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_default_dpi() -> int:
|
|
119
|
+
"""Get default DPI for saving/publication from config.
|
|
120
|
+
|
|
121
|
+
Priority: SCITEX_STYLE.yaml → env var → fallback 300
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
int: DPI value for publication-quality output
|
|
125
|
+
"""
|
|
126
|
+
return int(resolve_style_value("output.dpi", None, _FALLBACK_DPI_SAVE, int))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_display_dpi() -> int:
|
|
130
|
+
"""Get DPI for screen display (lower resolution for speed).
|
|
131
|
+
|
|
132
|
+
Returns approximately 1/3 of save DPI, minimum 100.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
int: DPI value for screen display
|
|
136
|
+
"""
|
|
137
|
+
save_dpi = get_default_dpi()
|
|
138
|
+
return max(_FALLBACK_DPI_DISPLAY, save_dpi // 3)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def get_preview_dpi() -> int:
|
|
142
|
+
"""Get DPI for editor previews and thumbnails.
|
|
143
|
+
|
|
144
|
+
Returns 1/2 of save DPI, clamped between 100-200.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
int: DPI value for previews
|
|
148
|
+
"""
|
|
149
|
+
save_dpi = get_default_dpi()
|
|
150
|
+
return max(_FALLBACK_DPI_DISPLAY, min(200, save_dpi // 2))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# Module-level constants (evaluated at import time)
|
|
154
|
+
# Use functions for dynamic resolution, constants for static defaults
|
|
155
|
+
DPI_SAVE = _FALLBACK_DPI_SAVE # Use get_default_dpi() for dynamic
|
|
156
|
+
DPI_DISPLAY = _FALLBACK_DPI_DISPLAY
|
|
157
|
+
DPI_PREVIEW = _FALLBACK_DPI_PREVIEW
|
|
158
|
+
|
|
159
|
+
|
|
82
160
|
def load_style(path: Optional[Union[str, Path]] = None) -> Dict[str, Any]:
|
|
83
161
|
"""Load style from YAML as subplots kwargs."""
|
|
84
162
|
cfg = _get_config(Path(path) if path else None)
|
scitex/plt/utils/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ from ._calc_nice_ticks import calc_nice_ticks
|
|
|
6
6
|
from ._close import close
|
|
7
7
|
from ._colorbar import add_shared_colorbar, colorbar
|
|
8
8
|
from ._configure_mpl import configure_mpl
|
|
9
|
-
from ._figure_mm import apply_style_mm, create_figure_ax_mm
|
|
9
|
+
from ._figure_mm import apply_style_mm, create_figure_ax_mm, THEME_COLORS, _apply_theme_colors
|
|
10
10
|
from ._histogram_utils import HistogramBinManager, histogram_bin_manager
|
|
11
11
|
from ._im2grid import im2grid
|
|
12
12
|
from ._is_valid_axis import assert_valid_axis, is_valid_axis
|
|
@@ -48,6 +48,13 @@ from ._csv_column_naming import (
|
|
|
48
48
|
parse_csv_column_name,
|
|
49
49
|
sanitize_trace_id,
|
|
50
50
|
)
|
|
51
|
+
from ._hitmap import (
|
|
52
|
+
extract_path_data,
|
|
53
|
+
generate_hitmap_id_colors,
|
|
54
|
+
get_all_artists,
|
|
55
|
+
query_hitmap_neighborhood,
|
|
56
|
+
save_hitmap_png,
|
|
57
|
+
)
|
|
51
58
|
|
|
52
59
|
__all__ = [
|
|
53
60
|
"HistogramBinManager",
|
|
@@ -79,6 +86,9 @@ __all__ = [
|
|
|
79
86
|
"cross_ref",
|
|
80
87
|
"enhance_scitex_save_with_captions",
|
|
81
88
|
"export_captions",
|
|
89
|
+
"extract_path_data",
|
|
90
|
+
"generate_hitmap_id_colors",
|
|
91
|
+
"get_all_artists",
|
|
82
92
|
"get_csv_column_name",
|
|
83
93
|
"get_csv_column_prefix",
|
|
84
94
|
"get_dimension_info",
|
|
@@ -94,8 +104,10 @@ __all__ = [
|
|
|
94
104
|
"parse_csv_column_name",
|
|
95
105
|
"print_dimension_info",
|
|
96
106
|
"pt_to_mm",
|
|
107
|
+
"query_hitmap_neighborhood",
|
|
97
108
|
"quick_caption",
|
|
98
109
|
"sanitize_trace_id",
|
|
110
|
+
"save_hitmap_png",
|
|
99
111
|
"save_with_caption",
|
|
100
112
|
"verify_csv_json_consistency",
|
|
101
113
|
"view_dimensions",
|
|
@@ -15,6 +15,10 @@ __FILE__ = __file__
|
|
|
15
15
|
|
|
16
16
|
from typing import Dict, Optional, Union, List
|
|
17
17
|
|
|
18
|
+
from scitex import logging
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
18
22
|
# Precision settings for JSON output
|
|
19
23
|
PRECISION = {
|
|
20
24
|
"mm": 2, # Millimeters: 0.01mm precision (10 microns)
|
|
@@ -205,8 +209,7 @@ def _collect_single_axes_metadata(fig, ax, ax_index: int) -> dict:
|
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
except Exception as e:
|
|
208
|
-
|
|
209
|
-
warnings.warn(f"Could not extract dimension info for axes {ax_index}: {e}")
|
|
212
|
+
logger.warning(f"Could not extract dimension info for axes {ax_index}: {e}")
|
|
210
213
|
|
|
211
214
|
# Extract axes labels and units
|
|
212
215
|
# X-axis - using matplotlib terminology (xaxis)
|
|
@@ -444,8 +447,7 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
|
|
|
444
447
|
if "axes_bbox_mm" in dim_info:
|
|
445
448
|
metadata["axes_bbox_mm"] = dim_info["axes_bbox_mm"]
|
|
446
449
|
except Exception as e:
|
|
447
|
-
|
|
448
|
-
warnings.warn(f"Could not extract figure dimension info: {e}")
|
|
450
|
+
logger.warning(f"Could not extract figure dimension info: {e}")
|
|
449
451
|
|
|
450
452
|
# Collect per-axes metadata
|
|
451
453
|
if all_axes:
|
|
@@ -461,8 +463,7 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
|
|
|
461
463
|
ax_metadata["grid_position"] = {"row": row, "col": col}
|
|
462
464
|
metadata["axes"][ax_key] = ax_metadata
|
|
463
465
|
except Exception as e:
|
|
464
|
-
|
|
465
|
-
warnings.warn(f"Could not extract metadata for {ax_key}: {e}")
|
|
466
|
+
logger.warning(f"Could not extract metadata for {ax_key}: {e}")
|
|
466
467
|
|
|
467
468
|
# Add scitex-specific metadata if axes was tagged
|
|
468
469
|
scitex_meta = None
|
|
@@ -542,11 +543,8 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
|
|
|
542
543
|
f"For {requested_font}: sudo apt-get install ttf-mscorefonts-installer && fc-cache -fv"
|
|
543
544
|
)
|
|
544
545
|
except ImportError:
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
warnings.warn(
|
|
548
|
-
f"Font mismatch: Requested '{requested_font}' but using '{actual_font}'",
|
|
549
|
-
UserWarning,
|
|
546
|
+
logger.warning(
|
|
547
|
+
f"Font mismatch: Requested '{requested_font}' but using '{actual_font}'"
|
|
550
548
|
)
|
|
551
549
|
else:
|
|
552
550
|
# If no style section, add font info to runtime section
|
|
@@ -688,9 +686,7 @@ def collect_figure_metadata(fig, ax=None) -> Dict:
|
|
|
688
686
|
|
|
689
687
|
except Exception as e:
|
|
690
688
|
# If Phase 1 extraction fails, continue without it
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
warnings.warn(f"Could not extract Phase 1 metadata: {e}")
|
|
689
|
+
logger.warning(f"Could not extract Phase 1 metadata: {e}")
|
|
694
690
|
|
|
695
691
|
# Apply precision rounding to all numeric values
|
|
696
692
|
metadata = _round_metadata(metadata)
|
|
@@ -318,25 +318,13 @@ def configure_mpl(
|
|
|
318
318
|
)
|
|
319
319
|
|
|
320
320
|
# Warn user about missing Arial using scitex.logging
|
|
321
|
-
|
|
322
|
-
from scitex.logging import getLogger
|
|
321
|
+
from scitex import logging as _logging
|
|
323
322
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
except ImportError:
|
|
330
|
-
# Fallback to warnings if scitex.logging not available
|
|
331
|
-
import warnings
|
|
332
|
-
|
|
333
|
-
warnings.warn(
|
|
334
|
-
"Arial font not found on system. Using fallback fonts (Helvetica/DejaVu Sans). "
|
|
335
|
-
"For publication-quality figures with Arial, install Microsoft Core Fonts: "
|
|
336
|
-
"sudo apt-get install ttf-mscorefonts-installer && fc-cache -fv",
|
|
337
|
-
UserWarning,
|
|
338
|
-
stacklevel=2,
|
|
339
|
-
)
|
|
323
|
+
_logger = _logging.getLogger(__name__)
|
|
324
|
+
_logger.warning(
|
|
325
|
+
"Arial font not found. Using fallback fonts (Helvetica/DejaVu Sans). "
|
|
326
|
+
"For publication figures with Arial: sudo apt-get install ttf-mscorefonts-installer && fc-cache -fv"
|
|
327
|
+
)
|
|
340
328
|
|
|
341
329
|
# Suppress matplotlib's own font warnings
|
|
342
330
|
import logging
|
scitex/plt/utils/_crop.py
CHANGED
|
@@ -97,6 +97,7 @@ def crop(
|
|
|
97
97
|
overwrite: bool = False,
|
|
98
98
|
verbose: bool = False,
|
|
99
99
|
return_offset: bool = False,
|
|
100
|
+
crop_box: Optional[Tuple[int, int, int, int]] = None,
|
|
100
101
|
) -> str:
|
|
101
102
|
"""
|
|
102
103
|
Crop a figure image to its content area with a specified margin.
|
|
@@ -113,7 +114,8 @@ def crop(
|
|
|
113
114
|
Path to save the cropped image. If None and overwrite=True,
|
|
114
115
|
overwrites the input. If None and overwrite=False, adds '_cropped' suffix.
|
|
115
116
|
margin : int, optional
|
|
116
|
-
Margin in pixels to add around the content area (default: 12, ~1mm at 300 DPI)
|
|
117
|
+
Margin in pixels to add around the content area (default: 12, ~1mm at 300 DPI).
|
|
118
|
+
Only used when crop_box is None (auto-detection mode).
|
|
117
119
|
overwrite : bool, optional
|
|
118
120
|
Whether to overwrite the input file (default: False)
|
|
119
121
|
verbose : bool, optional
|
|
@@ -121,6 +123,10 @@ def crop(
|
|
|
121
123
|
return_offset : bool, optional
|
|
122
124
|
If True, also return the crop offset (left, upper) for metadata adjustment.
|
|
123
125
|
Default is False.
|
|
126
|
+
crop_box : tuple, optional
|
|
127
|
+
Explicit crop coordinates (left, upper, right, lower). If provided,
|
|
128
|
+
skips auto-detection and uses these exact coordinates for cropping.
|
|
129
|
+
This is useful for applying the same crop to multiple images (e.g., hitmap).
|
|
124
130
|
|
|
125
131
|
Returns
|
|
126
132
|
-------
|
|
@@ -144,6 +150,11 @@ def crop(
|
|
|
144
150
|
|
|
145
151
|
>>> # Or crop in place
|
|
146
152
|
>>> stx.plt.crop("figure.png", overwrite=True)
|
|
153
|
+
|
|
154
|
+
>>> # Apply explicit crop coordinates (e.g., for hitmap)
|
|
155
|
+
>>> _, offset = stx.plt.crop("figure.png", return_offset=True)
|
|
156
|
+
>>> crop_box = (offset['left'], offset['upper'], offset['right'], offset['lower'])
|
|
157
|
+
>>> stx.plt.crop("hitmap.png", crop_box=crop_box)
|
|
147
158
|
"""
|
|
148
159
|
# Determine output path
|
|
149
160
|
if output_path is None:
|
|
@@ -164,19 +175,26 @@ def crop(
|
|
|
164
175
|
if "dpi" in img.info:
|
|
165
176
|
print(f"Original DPI: {img.info['dpi']}")
|
|
166
177
|
|
|
167
|
-
#
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
f"
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
# Use explicit crop_box if provided, otherwise auto-detect
|
|
179
|
+
if crop_box is not None:
|
|
180
|
+
# Use explicit crop coordinates (no margin adjustment - use as-is)
|
|
181
|
+
left, upper, right, lower = crop_box
|
|
182
|
+
if verbose:
|
|
183
|
+
print(f"Using explicit crop_box: left={left}, upper={upper}, right={right}, lower={lower}")
|
|
184
|
+
else:
|
|
185
|
+
# Find the content area (returns left, upper, right, lower)
|
|
186
|
+
left, upper, right, lower = find_content_area(input_path)
|
|
187
|
+
|
|
188
|
+
if verbose:
|
|
189
|
+
print(
|
|
190
|
+
f"Content area detected at: left={left}, upper={upper}, right={right}, lower={lower}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Calculate the coordinates with margin, clamping to the image boundaries
|
|
194
|
+
left = max(left - margin, 0)
|
|
195
|
+
upper = max(upper - margin, 0)
|
|
196
|
+
right = min(right + margin, img.width)
|
|
197
|
+
lower = min(lower + margin, img.height)
|
|
180
198
|
|
|
181
199
|
if verbose:
|
|
182
200
|
print(f"Cropping to: left={left}, upper={upper}, right={right}, lower={lower}")
|
|
@@ -40,6 +40,7 @@ __all__ = [
|
|
|
40
40
|
"get_csv_column_prefix",
|
|
41
41
|
"parse_csv_column_name",
|
|
42
42
|
"sanitize_trace_id",
|
|
43
|
+
"get_unique_trace_id",
|
|
43
44
|
]
|
|
44
45
|
|
|
45
46
|
|
|
@@ -91,6 +92,59 @@ def sanitize_trace_id(trace_id: str) -> str:
|
|
|
91
92
|
return sanitized if sanitized else "unnamed"
|
|
92
93
|
|
|
93
94
|
|
|
95
|
+
def get_unique_trace_id(trace_id: str, existing_ids: set) -> str:
|
|
96
|
+
"""Get unique trace ID, adding suffix if collision detected.
|
|
97
|
+
|
|
98
|
+
This function ensures trace IDs remain unique even when multiple traces
|
|
99
|
+
have IDs that sanitize to the same value (e.g., "A" and "a" both become "a").
|
|
100
|
+
When a collision is detected, suffixes are added: a -> a-1 -> a-2, etc.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
trace_id : str
|
|
105
|
+
Raw trace identifier
|
|
106
|
+
existing_ids : set
|
|
107
|
+
Set of already-used trace IDs (will be modified in-place)
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
str
|
|
112
|
+
Unique sanitized trace ID
|
|
113
|
+
|
|
114
|
+
Examples
|
|
115
|
+
--------
|
|
116
|
+
>>> ids = set()
|
|
117
|
+
>>> get_unique_trace_id("A", ids)
|
|
118
|
+
'a'
|
|
119
|
+
>>> ids
|
|
120
|
+
{'a'}
|
|
121
|
+
>>> get_unique_trace_id("a", ids) # collision!
|
|
122
|
+
'a-1'
|
|
123
|
+
>>> ids
|
|
124
|
+
{'a', 'a-1'}
|
|
125
|
+
>>> get_unique_trace_id("A ", ids) # another collision!
|
|
126
|
+
'a-2'
|
|
127
|
+
>>> ids
|
|
128
|
+
{'a', 'a-1', 'a-2'}
|
|
129
|
+
>>> get_unique_trace_id("B", ids) # no collision
|
|
130
|
+
'b'
|
|
131
|
+
"""
|
|
132
|
+
base_id = sanitize_trace_id(trace_id)
|
|
133
|
+
|
|
134
|
+
if base_id not in existing_ids:
|
|
135
|
+
existing_ids.add(base_id)
|
|
136
|
+
return base_id
|
|
137
|
+
|
|
138
|
+
# Find unique suffix
|
|
139
|
+
counter = 1
|
|
140
|
+
while f"{base_id}-{counter}" in existing_ids:
|
|
141
|
+
counter += 1
|
|
142
|
+
|
|
143
|
+
unique_id = f"{base_id}-{counter}"
|
|
144
|
+
existing_ids.add(unique_id)
|
|
145
|
+
return unique_id
|
|
146
|
+
|
|
147
|
+
|
|
94
148
|
def get_csv_column_prefix(
|
|
95
149
|
ax_row: int = 0, ax_col: int = 0, trace_id: str = None, trace_index: int = None
|
|
96
150
|
) -> str:
|
scitex/plt/utils/_figure_mm.py
CHANGED
|
@@ -10,11 +10,13 @@ This module provides functions to create matplotlib figures and axes with
|
|
|
10
10
|
precise millimeter-based control over dimensions, margins, and styling.
|
|
11
11
|
This is particularly useful for creating publication-quality figures that
|
|
12
12
|
need to meet specific size requirements (e.g., Nature, Science journals).
|
|
13
|
+
|
|
14
|
+
Supports dark/light theme modes for eye-friendly visualization.
|
|
13
15
|
"""
|
|
14
16
|
|
|
15
17
|
__FILE__ = __file__
|
|
16
18
|
|
|
17
|
-
from typing import Dict, Optional, Tuple, TYPE_CHECKING
|
|
19
|
+
from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
import matplotlib.pyplot as plt
|
|
20
22
|
from matplotlib.axes import Axes
|
|
@@ -22,6 +24,111 @@ from matplotlib.figure import Figure
|
|
|
22
24
|
|
|
23
25
|
from ._units import mm_to_inch, mm_to_pt
|
|
24
26
|
|
|
27
|
+
# Default theme color palettes
|
|
28
|
+
# Both modes use transparent background by default for flexibility
|
|
29
|
+
# Dark mode: all text elements (labels, ticks, spines) use same soft white color
|
|
30
|
+
# Light mode: all text elements use black
|
|
31
|
+
THEME_COLORS = {
|
|
32
|
+
"dark": {
|
|
33
|
+
"background": "transparent", # Transparent for overlay on dark backgrounds
|
|
34
|
+
"axes_bg": "transparent", # Transparent axes background
|
|
35
|
+
"text": "#e8e8e8", # Soft white (reduced strain)
|
|
36
|
+
"spine": "#e8e8e8", # Same as text (like black in light mode)
|
|
37
|
+
"tick": "#e8e8e8", # Same as text
|
|
38
|
+
"grid": "#3a3a4a", # Subtle grid
|
|
39
|
+
},
|
|
40
|
+
"light": {
|
|
41
|
+
"background": "transparent", # Transparent for overlay on light backgrounds
|
|
42
|
+
"axes_bg": "transparent", # Transparent axes background
|
|
43
|
+
"text": "black", # Black text
|
|
44
|
+
"spine": "black", # Black spines
|
|
45
|
+
"tick": "black", # Black ticks
|
|
46
|
+
"grid": "#cccccc", # Light gray grid
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _apply_theme_colors(
|
|
52
|
+
ax: Axes,
|
|
53
|
+
theme: str = "light",
|
|
54
|
+
custom_colors: Optional[Dict[str, str]] = None
|
|
55
|
+
) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Apply theme colors to axes for dark/light mode support.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
ax : matplotlib.axes.Axes
|
|
62
|
+
Target axes to apply theme to
|
|
63
|
+
theme : str
|
|
64
|
+
Color theme: "light" or "dark" (default: "light")
|
|
65
|
+
custom_colors : dict, optional
|
|
66
|
+
Custom color overrides. Keys: background, axes_bg, text, spine, tick, grid
|
|
67
|
+
|
|
68
|
+
Examples
|
|
69
|
+
--------
|
|
70
|
+
>>> fig, ax = plt.subplots()
|
|
71
|
+
>>> _apply_theme_colors(ax, theme="dark") # Eye-friendly dark mode
|
|
72
|
+
"""
|
|
73
|
+
# Get base theme colors
|
|
74
|
+
colors = THEME_COLORS.get(theme, THEME_COLORS["light"]).copy()
|
|
75
|
+
|
|
76
|
+
# Apply custom overrides
|
|
77
|
+
if custom_colors:
|
|
78
|
+
colors.update(custom_colors)
|
|
79
|
+
|
|
80
|
+
# Apply axes background
|
|
81
|
+
if colors["axes_bg"] != "transparent":
|
|
82
|
+
ax.set_facecolor(colors["axes_bg"])
|
|
83
|
+
ax.patch.set_alpha(1.0)
|
|
84
|
+
else:
|
|
85
|
+
ax.patch.set_alpha(0.0)
|
|
86
|
+
|
|
87
|
+
# Apply figure background if accessible
|
|
88
|
+
fig = ax.get_figure()
|
|
89
|
+
if fig is not None:
|
|
90
|
+
if colors["background"] != "transparent":
|
|
91
|
+
fig.patch.set_facecolor(colors["background"])
|
|
92
|
+
fig.patch.set_alpha(1.0)
|
|
93
|
+
else:
|
|
94
|
+
fig.patch.set_alpha(0.0)
|
|
95
|
+
|
|
96
|
+
# Apply text colors (labels, titles)
|
|
97
|
+
ax.xaxis.label.set_color(colors["text"])
|
|
98
|
+
ax.yaxis.label.set_color(colors["text"])
|
|
99
|
+
ax.title.set_color(colors["text"])
|
|
100
|
+
|
|
101
|
+
# Apply spine colors
|
|
102
|
+
for spine in ax.spines.values():
|
|
103
|
+
spine.set_color(colors["spine"])
|
|
104
|
+
|
|
105
|
+
# Apply tick colors (both marks and labels)
|
|
106
|
+
ax.tick_params(colors=colors["tick"], which="both")
|
|
107
|
+
for label in ax.get_xticklabels() + ax.get_yticklabels():
|
|
108
|
+
label.set_color(colors["tick"])
|
|
109
|
+
|
|
110
|
+
# Apply legend colors if legend exists
|
|
111
|
+
legend = ax.get_legend()
|
|
112
|
+
if legend is not None:
|
|
113
|
+
# Legend text color
|
|
114
|
+
for text in legend.get_texts():
|
|
115
|
+
text.set_color(colors["text"])
|
|
116
|
+
# Legend title if present
|
|
117
|
+
title = legend.get_title()
|
|
118
|
+
if title:
|
|
119
|
+
title.set_color(colors["text"])
|
|
120
|
+
# Legend frame
|
|
121
|
+
frame = legend.get_frame()
|
|
122
|
+
if frame:
|
|
123
|
+
if colors["axes_bg"] != "transparent":
|
|
124
|
+
frame.set_facecolor(colors["axes_bg"])
|
|
125
|
+
frame.set_edgecolor(colors["spine"])
|
|
126
|
+
|
|
127
|
+
# Store theme in axes metadata for reference
|
|
128
|
+
if hasattr(ax, "_scitex_metadata"):
|
|
129
|
+
ax._scitex_metadata["theme"] = theme
|
|
130
|
+
ax._scitex_metadata["theme_colors"] = colors
|
|
131
|
+
|
|
25
132
|
if TYPE_CHECKING:
|
|
26
133
|
from scitex.plt._subplots._FigWrapper import FigWrapper
|
|
27
134
|
from scitex.plt._subplots._AxisWrapper import AxisWrapper
|
|
@@ -197,6 +304,8 @@ def apply_style_mm(ax: Axes, style: Dict) -> float:
|
|
|
197
304
|
- 'axis_font_size_pt' (float): Axis label font size in points (default: 8)
|
|
198
305
|
- 'tick_font_size_pt' (float): Tick label font size in points (default: 7)
|
|
199
306
|
- 'n_ticks' (int): Number of ticks on each axis (default: 4)
|
|
307
|
+
- 'theme' (str): Color theme "light" or "dark" (default: "light")
|
|
308
|
+
- 'theme_colors' (dict): Custom theme color overrides
|
|
200
309
|
|
|
201
310
|
Returns
|
|
202
311
|
-------
|
|
@@ -213,6 +322,7 @@ def apply_style_mm(ax: Axes, style: Dict) -> float:
|
|
|
213
322
|
... 'tick_thickness_mm': 0.2,
|
|
214
323
|
... 'axis_font_size_pt': 7,
|
|
215
324
|
... 'tick_font_size_pt': 7,
|
|
325
|
+
... 'theme': 'dark', # Enable dark mode
|
|
216
326
|
... }
|
|
217
327
|
>>> trace_lw = apply_style_mm(ax, style)
|
|
218
328
|
>>> ax.plot(x, y, lw=trace_lw)
|
|
@@ -224,6 +334,11 @@ def apply_style_mm(ax: Axes, style: Dict) -> float:
|
|
|
224
334
|
- The returned trace linewidth should be used when plotting to maintain
|
|
225
335
|
consistent styling across all plot elements
|
|
226
336
|
"""
|
|
337
|
+
# Apply theme colors (dark/light mode)
|
|
338
|
+
theme = style.get("theme", "light")
|
|
339
|
+
theme_colors = style.get("theme_colors", None)
|
|
340
|
+
_apply_theme_colors(ax, theme, theme_colors)
|
|
341
|
+
|
|
227
342
|
# Convert spine thickness from mm to points
|
|
228
343
|
axis_lw_pt = mm_to_pt(style.get("axis_thickness_mm", 0.2))
|
|
229
344
|
for spine in ax.spines.values():
|