scitex 2.7.0__py3-none-any.whl → 2.7.3__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/fig/__init__.py +352 -0
- scitex/{vis → fig}/backend/_parser.py +1 -1
- scitex/{vis → fig}/canvas.py +1 -1
- scitex/{vis → fig}/editor/_defaults.py +70 -5
- scitex/fig/editor/_edit.py +751 -0
- scitex/{vis → fig}/editor/_qt_editor.py +181 -1
- scitex/fig/editor/flask_editor/_bbox.py +1276 -0
- scitex/fig/editor/flask_editor/_core.py +624 -0
- scitex/{vis → fig}/editor/flask_editor/_plotter.py +38 -4
- scitex/fig/editor/flask_editor/_renderer.py +739 -0
- scitex/{vis → fig}/editor/flask_editor/templates/__init__.py +1 -1
- scitex/fig/editor/flask_editor/templates/_html.py +834 -0
- scitex/fig/editor/flask_editor/templates/_scripts.py +3136 -0
- scitex/{vis → fig}/editor/flask_editor/templates/_styles.py +625 -18
- scitex/{vis → fig}/io/__init__.py +13 -1
- scitex/fig/io/_bundle.py +973 -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 +10 -26
- scitex/io/_bundle.py +434 -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/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.7.3.dist-info}/METADATA +11 -1
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/RECORD +238 -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/_html.py +0 -513
- scitex/vis/editor/flask_editor/templates/_scripts.py +0 -1261
- /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/__init__.py +0 -0
- /scitex/{vis → fig}/editor/_dearpygui_editor.py +0 -0
- /scitex/{vis → fig}/editor/_flask_editor.py +0 -0
- /scitex/{vis → fig}/editor/_mpl_editor.py +0 -0
- /scitex/{vis → fig}/editor/_tkinter_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.7.3.dist-info}/WHEEL +0 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.0.dist-info → scitex-2.7.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -14,9 +14,14 @@ from functools import wraps
|
|
|
14
14
|
|
|
15
15
|
import matplotlib
|
|
16
16
|
|
|
17
|
+
from scitex import logging
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
17
21
|
from ._AxisWrapperMixins import (
|
|
18
22
|
AdjustmentMixin,
|
|
19
23
|
MatplotlibPlotMixin,
|
|
24
|
+
RawMatplotlibMixin,
|
|
20
25
|
SeabornMixin,
|
|
21
26
|
TrackingMixin,
|
|
22
27
|
UnitAwareMixin,
|
|
@@ -25,7 +30,12 @@ from scitex.plt.styles import apply_plot_defaults, apply_plot_postprocess
|
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
class AxisWrapper(
|
|
28
|
-
MatplotlibPlotMixin,
|
|
33
|
+
MatplotlibPlotMixin,
|
|
34
|
+
SeabornMixin,
|
|
35
|
+
RawMatplotlibMixin,
|
|
36
|
+
AdjustmentMixin,
|
|
37
|
+
TrackingMixin,
|
|
38
|
+
UnitAwareMixin,
|
|
29
39
|
):
|
|
30
40
|
def __init__(self, fig_scitex, axis_mpl, track):
|
|
31
41
|
"""Initialize the AxisWrapper.
|
|
@@ -219,10 +229,8 @@ class AxisWrapper(
|
|
|
219
229
|
kwargs,
|
|
220
230
|
)
|
|
221
231
|
except AttributeError:
|
|
222
|
-
|
|
223
|
-
f"Tracking setup incomplete for AxisWrapper ({__method_name__})."
|
|
224
|
-
UserWarning,
|
|
225
|
-
stacklevel=2,
|
|
232
|
+
logger.warning(
|
|
233
|
+
f"Tracking setup incomplete for AxisWrapper ({__method_name__})."
|
|
226
234
|
)
|
|
227
235
|
except Exception as e:
|
|
228
236
|
# Silently continue if tracking fails to not break plotting
|
|
@@ -240,11 +248,9 @@ class AxisWrapper(
|
|
|
240
248
|
# 2. If not found on instance, try the counterpart type (fallback)
|
|
241
249
|
if hasattr(self._counter_part, name):
|
|
242
250
|
counterpart_attr = getattr(self._counter_part, name)
|
|
243
|
-
|
|
251
|
+
logger.warning(
|
|
244
252
|
f"SciTeX Axis_MplWrapper: '{name}' not directly handled. "
|
|
245
|
-
f"Falling back to underlying '{self._counter_part.__name__}' attribute."
|
|
246
|
-
UserWarning,
|
|
247
|
-
stacklevel=2,
|
|
253
|
+
f"Falling back to underlying '{self._counter_part.__name__}' attribute."
|
|
248
254
|
)
|
|
249
255
|
# If the counterpart attribute is callable (likely a method descriptor)
|
|
250
256
|
if callable(counterpart_attr):
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-13 (ywatanabe)"
|
|
4
|
+
# File: __init__.py - AdjustmentMixin package
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
AdjustmentMixin - Modular axis adjustment mixin for AxisWrapper.
|
|
8
|
+
|
|
9
|
+
This package provides axis adjustment functionality split into logical submodules:
|
|
10
|
+
- _labels: Label rotation and legend positioning
|
|
11
|
+
- _metadata: Axis labels, titles, and scientific metadata
|
|
12
|
+
- _visual: Visual adjustments (ticks, spines, extend, shift)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
__FILE__ = __file__
|
|
18
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
19
|
+
|
|
20
|
+
from ._labels import LabelsMixin
|
|
21
|
+
from ._metadata import MetadataMixin
|
|
22
|
+
from ._visual import VisualAdjustmentMixin
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AdjustmentMixin(LabelsMixin, MetadataMixin, VisualAdjustmentMixin):
|
|
26
|
+
"""Mixin class for matplotlib axis adjustments.
|
|
27
|
+
|
|
28
|
+
Combines multiple specialized mixins:
|
|
29
|
+
- LabelsMixin: Label rotation and legend positioning
|
|
30
|
+
- MetadataMixin: Axis labels, titles, and scientific metadata
|
|
31
|
+
- VisualAdjustmentMixin: Ticks, spines, extend, shift
|
|
32
|
+
"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# EOF
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-13 (ywatanabe)"
|
|
4
|
+
# File: _labels.py - Label rotation and legend handling
|
|
5
|
+
|
|
6
|
+
"""Mixin for label rotation and legend positioning."""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from scitex import logging
|
|
11
|
+
|
|
12
|
+
__FILE__ = __file__
|
|
13
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LabelsMixin:
|
|
19
|
+
"""Mixin for label rotation and legend positioning."""
|
|
20
|
+
|
|
21
|
+
def _get_ax_module(self):
|
|
22
|
+
"""Lazy import ax module to avoid circular imports."""
|
|
23
|
+
from .....plt import ax as ax_module
|
|
24
|
+
return ax_module
|
|
25
|
+
|
|
26
|
+
def rotate_labels(
|
|
27
|
+
self,
|
|
28
|
+
x: float = None,
|
|
29
|
+
y: float = None,
|
|
30
|
+
x_ha: str = None,
|
|
31
|
+
y_ha: str = None,
|
|
32
|
+
x_va: str = None,
|
|
33
|
+
y_va: str = None,
|
|
34
|
+
auto_adjust: bool = True,
|
|
35
|
+
scientific_convention: bool = True,
|
|
36
|
+
tight_layout: bool = False,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Rotate x and y axis labels with automatic positioning.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
x : float or None, optional
|
|
43
|
+
Rotation angle for x-axis labels in degrees.
|
|
44
|
+
y : float or None, optional
|
|
45
|
+
Rotation angle for y-axis labels in degrees.
|
|
46
|
+
x_ha, y_ha : str or None, optional
|
|
47
|
+
Horizontal alignment for x/y-axis labels.
|
|
48
|
+
x_va, y_va : str or None, optional
|
|
49
|
+
Vertical alignment for x/y-axis labels.
|
|
50
|
+
auto_adjust : bool, optional
|
|
51
|
+
Whether to automatically adjust alignment. Default is True.
|
|
52
|
+
scientific_convention : bool, optional
|
|
53
|
+
Whether to follow scientific conventions. Default is True.
|
|
54
|
+
tight_layout : bool, optional
|
|
55
|
+
Whether to apply tight_layout. Default is False.
|
|
56
|
+
"""
|
|
57
|
+
self._axis_mpl = self._get_ax_module().rotate_labels(
|
|
58
|
+
self._axis_mpl,
|
|
59
|
+
x=x,
|
|
60
|
+
y=y,
|
|
61
|
+
x_ha=x_ha,
|
|
62
|
+
y_ha=y_ha,
|
|
63
|
+
x_va=x_va,
|
|
64
|
+
y_va=y_va,
|
|
65
|
+
auto_adjust=auto_adjust,
|
|
66
|
+
scientific_convention=scientific_convention,
|
|
67
|
+
tight_layout=tight_layout,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def legend(
|
|
71
|
+
self, *args, loc: str = "best", check_overlap: bool = False, **kwargs
|
|
72
|
+
) -> None:
|
|
73
|
+
"""Places legend at specified location, with support for outside positions.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
*args : tuple
|
|
78
|
+
Positional arguments (handles, labels) as in matplotlib
|
|
79
|
+
loc : str
|
|
80
|
+
Legend position. Default is "best" (matplotlib auto-placement).
|
|
81
|
+
Special positions:
|
|
82
|
+
- "best": Matplotlib automatic placement
|
|
83
|
+
- "outer": Place outside plot area (right side)
|
|
84
|
+
- "separate": Save legend as a separate figure file
|
|
85
|
+
- upper/lower/center variants: e.g. "upper right out"
|
|
86
|
+
check_overlap : bool
|
|
87
|
+
If True, checks for overlap between legend and data.
|
|
88
|
+
**kwargs : dict
|
|
89
|
+
Additional keyword arguments passed to legend()
|
|
90
|
+
"""
|
|
91
|
+
import matplotlib.pyplot as plt
|
|
92
|
+
|
|
93
|
+
if loc == "outer":
|
|
94
|
+
legend = self._axis_mpl.legend(
|
|
95
|
+
*args, loc="center left", bbox_to_anchor=(1.02, 0.5), **kwargs
|
|
96
|
+
)
|
|
97
|
+
if hasattr(self, "_figure_wrapper") and self._figure_wrapper:
|
|
98
|
+
self._figure_wrapper._fig_mpl.tight_layout()
|
|
99
|
+
self._figure_wrapper._fig_mpl.subplots_adjust(right=0.85)
|
|
100
|
+
return legend
|
|
101
|
+
|
|
102
|
+
elif loc == "separate":
|
|
103
|
+
handles, labels = self._axis_mpl.get_legend_handles_labels()
|
|
104
|
+
if not handles:
|
|
105
|
+
logger.warning("No legend handles found.")
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
fig = self._axis_mpl.get_figure()
|
|
109
|
+
if not hasattr(fig, "_separate_legend_params"):
|
|
110
|
+
fig._separate_legend_params = []
|
|
111
|
+
|
|
112
|
+
figsize = kwargs.pop("figsize", (4, 3))
|
|
113
|
+
dpi = kwargs.pop("dpi", 150)
|
|
114
|
+
frameon = kwargs.pop("frameon", True)
|
|
115
|
+
fancybox = kwargs.pop("fancybox", True)
|
|
116
|
+
shadow = kwargs.pop("shadow", True)
|
|
117
|
+
|
|
118
|
+
axis_id = self._get_axis_id(fig)
|
|
119
|
+
|
|
120
|
+
fig._separate_legend_params.append({
|
|
121
|
+
"axis": self._axis_mpl,
|
|
122
|
+
"axis_id": axis_id,
|
|
123
|
+
"handles": handles,
|
|
124
|
+
"labels": labels,
|
|
125
|
+
"figsize": figsize,
|
|
126
|
+
"dpi": dpi,
|
|
127
|
+
"frameon": frameon,
|
|
128
|
+
"fancybox": fancybox,
|
|
129
|
+
"shadow": shadow,
|
|
130
|
+
"kwargs": kwargs,
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if self._axis_mpl.get_legend():
|
|
134
|
+
self._axis_mpl.get_legend().remove()
|
|
135
|
+
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
outside_positions = {
|
|
139
|
+
"upper right out": ("center left", (1.15, 0.85)),
|
|
140
|
+
"right upper out": ("center left", (1.15, 0.85)),
|
|
141
|
+
"center right out": ("center left", (1.15, 0.5)),
|
|
142
|
+
"right out": ("center left", (1.15, 0.5)),
|
|
143
|
+
"right": ("center left", (1.05, 0.5)),
|
|
144
|
+
"lower right out": ("center left", (1.15, 0.15)),
|
|
145
|
+
"right lower out": ("center left", (1.15, 0.15)),
|
|
146
|
+
"upper left out": ("center right", (-0.25, 0.85)),
|
|
147
|
+
"left upper out": ("center right", (-0.25, 0.85)),
|
|
148
|
+
"center left out": ("center right", (-0.25, 0.5)),
|
|
149
|
+
"left out": ("center right", (-0.25, 0.5)),
|
|
150
|
+
"left": ("center right", (-0.15, 0.5)),
|
|
151
|
+
"lower left out": ("center right", (-0.25, 0.15)),
|
|
152
|
+
"left lower out": ("center right", (-0.25, 0.15)),
|
|
153
|
+
"upper center out": ("lower center", (0.5, 1.25)),
|
|
154
|
+
"upper out": ("lower center", (0.5, 1.25)),
|
|
155
|
+
"lower center out": ("upper center", (0.5, -0.25)),
|
|
156
|
+
"lower out": ("upper center", (0.5, -0.25)),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if loc in outside_positions:
|
|
160
|
+
location, bbox = outside_positions[loc]
|
|
161
|
+
legend_obj = self._axis_mpl.legend(
|
|
162
|
+
*args, loc=location, bbox_to_anchor=bbox, **kwargs
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
legend_obj = self._axis_mpl.legend(*args, loc=loc, **kwargs)
|
|
166
|
+
|
|
167
|
+
if check_overlap and legend_obj is not None:
|
|
168
|
+
self._check_legend_overlap(legend_obj)
|
|
169
|
+
|
|
170
|
+
return legend_obj
|
|
171
|
+
|
|
172
|
+
def _get_axis_id(self, fig):
|
|
173
|
+
"""Get unique axis identifier for separate legend handling."""
|
|
174
|
+
axis_id = None
|
|
175
|
+
|
|
176
|
+
try:
|
|
177
|
+
fig_axes = fig.get_axes()
|
|
178
|
+
for idx, ax in enumerate(fig_axes):
|
|
179
|
+
if ax is self._axis_mpl:
|
|
180
|
+
axis_id = f"ax_{idx:02d}"
|
|
181
|
+
break
|
|
182
|
+
except:
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
if axis_id is None and hasattr(self._axis_mpl, "get_subplotspec"):
|
|
186
|
+
try:
|
|
187
|
+
spec = self._axis_mpl.get_subplotspec()
|
|
188
|
+
if spec is not None:
|
|
189
|
+
gridspec = spec.get_gridspec()
|
|
190
|
+
nrows, ncols = gridspec.get_geometry()
|
|
191
|
+
rowspan = spec.rowspan
|
|
192
|
+
colspan = spec.colspan
|
|
193
|
+
row_start = rowspan.start if hasattr(rowspan, "start") else rowspan
|
|
194
|
+
col_start = colspan.start if hasattr(colspan, "start") else colspan
|
|
195
|
+
flat_idx = row_start * ncols + col_start
|
|
196
|
+
axis_id = f"ax_{flat_idx:02d}"
|
|
197
|
+
except:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
if axis_id is None:
|
|
201
|
+
axis_id = f"ax_{len(fig._separate_legend_params):02d}"
|
|
202
|
+
|
|
203
|
+
return axis_id
|
|
204
|
+
|
|
205
|
+
def _check_legend_overlap(self, legend_obj):
|
|
206
|
+
"""Check if legend overlaps with plotted data and issue warning if needed."""
|
|
207
|
+
import warnings
|
|
208
|
+
import matplotlib.transforms as transforms
|
|
209
|
+
import numpy as np
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
fig = self._axis_mpl.get_figure()
|
|
213
|
+
fig.canvas.draw()
|
|
214
|
+
|
|
215
|
+
legend_bbox = legend_obj.get_window_extent(fig.canvas.get_renderer())
|
|
216
|
+
inv_transform = self._axis_mpl.transData.inverted()
|
|
217
|
+
legend_bbox_data = legend_bbox.transformed(inv_transform)
|
|
218
|
+
|
|
219
|
+
data_bboxes = []
|
|
220
|
+
|
|
221
|
+
for line in self._axis_mpl.get_lines():
|
|
222
|
+
if line.get_visible():
|
|
223
|
+
try:
|
|
224
|
+
data = line.get_xydata()
|
|
225
|
+
if len(data) > 0:
|
|
226
|
+
data_bboxes.append(data)
|
|
227
|
+
except:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
for collection in self._axis_mpl.collections:
|
|
231
|
+
if collection.get_visible():
|
|
232
|
+
try:
|
|
233
|
+
offsets = collection.get_offsets()
|
|
234
|
+
if len(offsets) > 0:
|
|
235
|
+
data_bboxes.append(offsets)
|
|
236
|
+
except:
|
|
237
|
+
pass
|
|
238
|
+
|
|
239
|
+
if data_bboxes:
|
|
240
|
+
all_data = np.vstack(data_bboxes)
|
|
241
|
+
|
|
242
|
+
x_overlap = (all_data[:, 0] >= legend_bbox_data.x0) & (
|
|
243
|
+
all_data[:, 0] <= legend_bbox_data.x1
|
|
244
|
+
)
|
|
245
|
+
y_overlap = (all_data[:, 1] >= legend_bbox_data.y0) & (
|
|
246
|
+
all_data[:, 1] <= legend_bbox_data.y1
|
|
247
|
+
)
|
|
248
|
+
overlap_points = np.sum(x_overlap & y_overlap)
|
|
249
|
+
overlap_pct = (overlap_points / len(all_data)) * 100
|
|
250
|
+
|
|
251
|
+
if overlap_pct > 5:
|
|
252
|
+
logger.warning(
|
|
253
|
+
f"Legend overlaps with {overlap_pct:.1f}% of data points. "
|
|
254
|
+
f"Consider using loc='outer' or loc='separate'."
|
|
255
|
+
)
|
|
256
|
+
return True
|
|
257
|
+
|
|
258
|
+
except Exception:
|
|
259
|
+
pass
|
|
260
|
+
|
|
261
|
+
return False
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# EOF
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-13 (ywatanabe)"
|
|
4
|
+
# File: _metadata.py - Axis metadata and labels
|
|
5
|
+
|
|
6
|
+
"""Mixin for axis labels, titles, and metadata."""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
__FILE__ = __file__
|
|
12
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MetadataMixin:
|
|
16
|
+
"""Mixin for setting axis labels, titles, and metadata."""
|
|
17
|
+
|
|
18
|
+
def _get_ax_module(self):
|
|
19
|
+
"""Lazy import ax module to avoid circular imports."""
|
|
20
|
+
from .....plt import ax as ax_module
|
|
21
|
+
return ax_module
|
|
22
|
+
|
|
23
|
+
def set_xyt(
|
|
24
|
+
self,
|
|
25
|
+
x: Optional[str] = None,
|
|
26
|
+
y: Optional[str] = None,
|
|
27
|
+
t: Optional[str] = None,
|
|
28
|
+
format_labels: bool = True,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Set xlabel, ylabel, and title."""
|
|
31
|
+
self._axis_mpl = self._get_ax_module().set_xyt(
|
|
32
|
+
self._axis_mpl,
|
|
33
|
+
x=x,
|
|
34
|
+
y=y,
|
|
35
|
+
t=t,
|
|
36
|
+
format_labels=format_labels,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def set_xytc(
|
|
40
|
+
self,
|
|
41
|
+
x: Optional[str] = None,
|
|
42
|
+
y: Optional[str] = None,
|
|
43
|
+
t: Optional[str] = None,
|
|
44
|
+
c: Optional[str] = None,
|
|
45
|
+
format_labels: bool = True,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Set xlabel, ylabel, title, and caption for automatic saving.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
x : str, optional
|
|
52
|
+
X-axis label
|
|
53
|
+
y : str, optional
|
|
54
|
+
Y-axis label
|
|
55
|
+
t : str, optional
|
|
56
|
+
Title
|
|
57
|
+
c : str, optional
|
|
58
|
+
Caption to be saved automatically with scitex.io.save()
|
|
59
|
+
format_labels : bool, optional
|
|
60
|
+
Whether to apply automatic formatting, by default True
|
|
61
|
+
"""
|
|
62
|
+
self._axis_mpl = self._get_ax_module().set_xytc(
|
|
63
|
+
self._axis_mpl,
|
|
64
|
+
x=x,
|
|
65
|
+
y=y,
|
|
66
|
+
t=t,
|
|
67
|
+
c=c,
|
|
68
|
+
format_labels=format_labels,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if c is not False and c is not None:
|
|
72
|
+
self._scitex_caption = c
|
|
73
|
+
|
|
74
|
+
def set_supxyt(
|
|
75
|
+
self,
|
|
76
|
+
xlabel: Optional[str] = None,
|
|
77
|
+
ylabel: Optional[str] = None,
|
|
78
|
+
title: Optional[str] = None,
|
|
79
|
+
format_labels: bool = True,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Set figure-level xlabel, ylabel, and title (suptitle)."""
|
|
82
|
+
self._axis_mpl = self._get_ax_module().set_supxyt(
|
|
83
|
+
self._axis_mpl,
|
|
84
|
+
xlabel=xlabel,
|
|
85
|
+
ylabel=ylabel,
|
|
86
|
+
title=title,
|
|
87
|
+
format_labels=format_labels,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def set_supxytc(
|
|
91
|
+
self,
|
|
92
|
+
xlabel: Optional[str] = None,
|
|
93
|
+
ylabel: Optional[str] = None,
|
|
94
|
+
title: Optional[str] = None,
|
|
95
|
+
caption: Optional[str] = None,
|
|
96
|
+
format_labels: bool = True,
|
|
97
|
+
) -> None:
|
|
98
|
+
"""Set figure-level xlabel, ylabel, title, and caption.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
xlabel : str, optional
|
|
103
|
+
Figure-level X-axis label
|
|
104
|
+
ylabel : str, optional
|
|
105
|
+
Figure-level Y-axis label
|
|
106
|
+
title : str, optional
|
|
107
|
+
Figure-level title (suptitle)
|
|
108
|
+
caption : str, optional
|
|
109
|
+
Figure-level caption for automatic saving
|
|
110
|
+
format_labels : bool, optional
|
|
111
|
+
Whether to apply automatic formatting
|
|
112
|
+
"""
|
|
113
|
+
self._axis_mpl = self._get_ax_module().set_supxytc(
|
|
114
|
+
self._axis_mpl,
|
|
115
|
+
xlabel=xlabel,
|
|
116
|
+
ylabel=ylabel,
|
|
117
|
+
title=title,
|
|
118
|
+
caption=caption,
|
|
119
|
+
format_labels=format_labels,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if caption is not False and caption is not None:
|
|
123
|
+
fig = self._axis_mpl.get_figure()
|
|
124
|
+
fig._scitex_main_caption = caption
|
|
125
|
+
|
|
126
|
+
def set_meta(
|
|
127
|
+
self,
|
|
128
|
+
caption=None,
|
|
129
|
+
methods=None,
|
|
130
|
+
stats=None,
|
|
131
|
+
keywords=None,
|
|
132
|
+
experimental_details=None,
|
|
133
|
+
journal_style=None,
|
|
134
|
+
significance=None,
|
|
135
|
+
**kwargs,
|
|
136
|
+
) -> None:
|
|
137
|
+
"""Set comprehensive scientific metadata with YAML export capability.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
caption : str, optional
|
|
142
|
+
Figure caption text
|
|
143
|
+
methods : str, optional
|
|
144
|
+
Experimental methods description
|
|
145
|
+
stats : str, optional
|
|
146
|
+
Statistical analysis details
|
|
147
|
+
keywords : List[str], optional
|
|
148
|
+
Keywords for categorization
|
|
149
|
+
experimental_details : Dict[str, Any], optional
|
|
150
|
+
Structured experimental parameters
|
|
151
|
+
journal_style : str, optional
|
|
152
|
+
Target journal style
|
|
153
|
+
significance : str, optional
|
|
154
|
+
Significance statement
|
|
155
|
+
**kwargs : additional metadata
|
|
156
|
+
"""
|
|
157
|
+
self._axis_mpl = self._get_ax_module().set_meta(
|
|
158
|
+
self._axis_mpl,
|
|
159
|
+
caption=caption,
|
|
160
|
+
methods=methods,
|
|
161
|
+
stats=stats,
|
|
162
|
+
keywords=keywords,
|
|
163
|
+
experimental_details=experimental_details,
|
|
164
|
+
journal_style=journal_style,
|
|
165
|
+
significance=significance,
|
|
166
|
+
**kwargs,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def set_figure_meta(
|
|
170
|
+
self,
|
|
171
|
+
caption=None,
|
|
172
|
+
methods=None,
|
|
173
|
+
stats=None,
|
|
174
|
+
significance=None,
|
|
175
|
+
funding=None,
|
|
176
|
+
conflicts=None,
|
|
177
|
+
data_availability=None,
|
|
178
|
+
**kwargs,
|
|
179
|
+
) -> None:
|
|
180
|
+
"""Set figure-level metadata for multi-panel figures.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
caption : str, optional
|
|
185
|
+
Figure-level caption
|
|
186
|
+
methods : str, optional
|
|
187
|
+
Overall experimental methods
|
|
188
|
+
stats : str, optional
|
|
189
|
+
Overall statistical approach
|
|
190
|
+
significance : str, optional
|
|
191
|
+
Significance and implications
|
|
192
|
+
funding : str, optional
|
|
193
|
+
Funding acknowledgments
|
|
194
|
+
conflicts : str, optional
|
|
195
|
+
Conflict of interest statement
|
|
196
|
+
data_availability : str, optional
|
|
197
|
+
Data availability statement
|
|
198
|
+
**kwargs : additional metadata
|
|
199
|
+
"""
|
|
200
|
+
self._axis_mpl = self._get_ax_module().set_figure_meta(
|
|
201
|
+
self._axis_mpl,
|
|
202
|
+
caption=caption,
|
|
203
|
+
methods=methods,
|
|
204
|
+
stats=stats,
|
|
205
|
+
significance=significance,
|
|
206
|
+
funding=funding,
|
|
207
|
+
conflicts=conflicts,
|
|
208
|
+
data_availability=data_availability,
|
|
209
|
+
**kwargs,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# EOF
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-13 (ywatanabe)"
|
|
4
|
+
# File: _visual.py - Visual adjustments (ticks, spines, position)
|
|
5
|
+
|
|
6
|
+
"""Mixin for visual adjustments including ticks, spines, and positioning."""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from typing import List, Optional, Union
|
|
10
|
+
|
|
11
|
+
__FILE__ = __file__
|
|
12
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class VisualAdjustmentMixin:
|
|
16
|
+
"""Mixin for visual adjustments to axis appearance."""
|
|
17
|
+
|
|
18
|
+
def _get_ax_module(self):
|
|
19
|
+
"""Lazy import ax module to avoid circular imports."""
|
|
20
|
+
from .....plt import ax as ax_module
|
|
21
|
+
return ax_module
|
|
22
|
+
|
|
23
|
+
def set_ticks(
|
|
24
|
+
self,
|
|
25
|
+
xvals: Optional[List[Union[int, float]]] = None,
|
|
26
|
+
xticks: Optional[List[str]] = None,
|
|
27
|
+
yvals: Optional[List[Union[int, float]]] = None,
|
|
28
|
+
yticks: Optional[List[str]] = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Set custom tick positions and labels.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
xvals : list of numbers, optional
|
|
35
|
+
Positions for x-axis ticks
|
|
36
|
+
xticks : list of str, optional
|
|
37
|
+
Labels for x-axis ticks
|
|
38
|
+
yvals : list of numbers, optional
|
|
39
|
+
Positions for y-axis ticks
|
|
40
|
+
yticks : list of str, optional
|
|
41
|
+
Labels for y-axis ticks
|
|
42
|
+
"""
|
|
43
|
+
self._axis_mpl = self._get_ax_module().set_ticks(
|
|
44
|
+
self._axis_mpl,
|
|
45
|
+
xvals=xvals,
|
|
46
|
+
xticks=xticks,
|
|
47
|
+
yvals=yvals,
|
|
48
|
+
yticks=yticks,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def set_n_ticks(self, n_xticks: int = 4, n_yticks: int = 4) -> None:
|
|
52
|
+
"""Set the number of ticks on each axis.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
n_xticks : int, optional
|
|
57
|
+
Number of ticks on x-axis, by default 4
|
|
58
|
+
n_yticks : int, optional
|
|
59
|
+
Number of ticks on y-axis, by default 4
|
|
60
|
+
"""
|
|
61
|
+
self._axis_mpl = self._get_ax_module().set_n_ticks(
|
|
62
|
+
self._axis_mpl, n_xticks=n_xticks, n_yticks=n_yticks
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def hide_spines(
|
|
66
|
+
self,
|
|
67
|
+
top: bool = True,
|
|
68
|
+
bottom: bool = False,
|
|
69
|
+
left: bool = False,
|
|
70
|
+
right: bool = True,
|
|
71
|
+
ticks: bool = False,
|
|
72
|
+
labels: bool = False,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""Hide specific spines and optionally ticks/labels.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
top : bool, optional
|
|
79
|
+
Hide top spine, by default True
|
|
80
|
+
bottom : bool, optional
|
|
81
|
+
Hide bottom spine, by default False
|
|
82
|
+
left : bool, optional
|
|
83
|
+
Hide left spine, by default False
|
|
84
|
+
right : bool, optional
|
|
85
|
+
Hide right spine, by default True
|
|
86
|
+
ticks : bool, optional
|
|
87
|
+
Hide all ticks, by default False
|
|
88
|
+
labels : bool, optional
|
|
89
|
+
Hide all tick labels, by default False
|
|
90
|
+
"""
|
|
91
|
+
self._axis_mpl = self._get_ax_module().hide_spines(
|
|
92
|
+
self._axis_mpl,
|
|
93
|
+
top=top,
|
|
94
|
+
bottom=bottom,
|
|
95
|
+
left=left,
|
|
96
|
+
right=right,
|
|
97
|
+
ticks=ticks,
|
|
98
|
+
labels=labels,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def extend(self, x_ratio: float = 1.0, y_ratio: float = 1.0) -> None:
|
|
102
|
+
"""Extend axis limits by a ratio.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
x_ratio : float, optional
|
|
107
|
+
Ratio to extend x-axis by, by default 1.0
|
|
108
|
+
y_ratio : float, optional
|
|
109
|
+
Ratio to extend y-axis by, by default 1.0
|
|
110
|
+
"""
|
|
111
|
+
self._axis_mpl = self._get_ax_module().extend(
|
|
112
|
+
self._axis_mpl, x_ratio=x_ratio, y_ratio=y_ratio
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def shift(self, dx: float = 0, dy: float = 0) -> None:
|
|
116
|
+
"""Shift axis position.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
dx : float, optional
|
|
121
|
+
Horizontal shift, by default 0
|
|
122
|
+
dy : float, optional
|
|
123
|
+
Vertical shift, by default 0
|
|
124
|
+
"""
|
|
125
|
+
self._axis_mpl = self._get_ax_module().shift(self._axis_mpl, dx=dx, dy=dy)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# EOF
|