xarray-plotly 0.0.16__tar.gz → 0.0.17__tar.gz
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.
- xarray_plotly-0.0.17/.release-please-manifest.json +3 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/CHANGELOG.md +7 -0
- {xarray_plotly-0.0.16/xarray_plotly.egg-info → xarray_plotly-0.0.17}/PKG-INFO +1 -1
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/tests/test_accessor.py +4 -4
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/tests/test_figures.py +157 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/__init__.py +2 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/accessor.py +60 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/figures.py +77 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/plotting.py +49 -8
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17/xarray_plotly.egg-info}/PKG-INFO +1 -1
- xarray_plotly-0.0.16/.release-please-manifest.json +0 -3
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/dependabot.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/ci.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/dependabot-auto-merge.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/docs.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/latest-deps.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/pr-title.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/publish.yaml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.github/workflows/release.yaml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.gitignore +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.pre-commit-config.yaml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.readthedocs.yaml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/.release-please-config.json +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/CONTRIBUTING.md +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/LICENSE +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/README.md +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/api.md +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/combining.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/datasets.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/dimensions.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/fast_bar.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/figure.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/kwargs.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/manipulation.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/examples/plot-types.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/getting-started.ipynb +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/docs/index.md +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/mkdocs.yml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/pyproject.toml +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/setup.cfg +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/tests/__init__.py +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/tests/test_common.py +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/tests/test_config.py +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/common.py +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/config.py +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly/py.typed +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly.egg-info/SOURCES.txt +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly.egg-info/dependency_links.txt +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly.egg-info/requires.txt +0 -0
- {xarray_plotly-0.0.16 → xarray_plotly-0.0.17}/xarray_plotly.egg-info/top_level.txt +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.17](https://github.com/FBumann/xarray_plotly/compare/v0.0.16...v0.0.17) (2026-06-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **plotting:** shared axis labels for faceted plots ([#84](https://github.com/FBumann/xarray_plotly/issues/84)) ([5a3bef8](https://github.com/FBumann/xarray_plotly/commit/5a3bef863ce07dd1a1f69d79ece116c059782025))
|
|
9
|
+
|
|
3
10
|
## [0.0.16](https://github.com/FBumann/xarray_plotly/compare/v0.0.15...v0.0.16) (2026-06-03)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -443,8 +443,8 @@ class TestImshowFaceting:
|
|
|
443
443
|
assert len(fig.data) == 3
|
|
444
444
|
yaxes = [k for k in fig.layout if k.startswith("yaxis")]
|
|
445
445
|
assert len(yaxes) == 3
|
|
446
|
-
|
|
447
|
-
assert
|
|
446
|
+
facet_titles = {a.text for a in fig.layout.annotations if "=" in (a.text or "")}
|
|
447
|
+
assert facet_titles == {"scenario=a", "scenario=b", "scenario=c"}
|
|
448
448
|
|
|
449
449
|
@requires_imshow_facet_row
|
|
450
450
|
def test_imshow_facet_row_auto_4d(self) -> None:
|
|
@@ -452,8 +452,8 @@ class TestImshowFaceting:
|
|
|
452
452
|
fig = self.da_4d.plotly.imshow()
|
|
453
453
|
# 2 facet columns (scenario) x 3 facet rows (year)
|
|
454
454
|
assert len(fig.data) == 6
|
|
455
|
-
|
|
456
|
-
assert
|
|
455
|
+
facet_titles = {a.text for a in fig.layout.annotations if "=" in (a.text or "")}
|
|
456
|
+
assert facet_titles == {
|
|
457
457
|
"scenario=low",
|
|
458
458
|
"scenario=high",
|
|
459
459
|
"year=2020",
|
|
@@ -12,6 +12,7 @@ import xarray as xr
|
|
|
12
12
|
from xarray_plotly import (
|
|
13
13
|
add_secondary_y,
|
|
14
14
|
overlay,
|
|
15
|
+
share_axis_labels,
|
|
15
16
|
simplify_facet_titles,
|
|
16
17
|
subplots,
|
|
17
18
|
xpx,
|
|
@@ -989,3 +990,159 @@ class TestSimplifyFacetTitles:
|
|
|
989
990
|
def test_kwarg_invalid_raises(self) -> None:
|
|
990
991
|
with pytest.raises(ValueError, match="facet_titles must be"):
|
|
991
992
|
xpx(self.da).line(facet_col="country", facet_titles="bogus") # type: ignore[arg-type]
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
def _axis_titles(fig: go.Figure, letter: str) -> list[str]:
|
|
996
|
+
"""Collect non-empty axis title texts for one axis direction."""
|
|
997
|
+
return [
|
|
998
|
+
fig.layout[k].title.text
|
|
999
|
+
for k in fig.layout
|
|
1000
|
+
if k.startswith(f"{letter}axis") and fig.layout[k].title.text
|
|
1001
|
+
]
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
def _shared_label_annotations(fig: go.Figure) -> list[go.layout.Annotation]:
|
|
1005
|
+
"""Collect annotations positioned like shared axis labels (centered bottom/left)."""
|
|
1006
|
+
return [
|
|
1007
|
+
a
|
|
1008
|
+
for a in fig.layout.annotations
|
|
1009
|
+
if a.xref == "paper" and a.yref == "paper" and (a.x, a.y) in {(0.5, 0), (0, 0.5)}
|
|
1010
|
+
]
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
class TestShareAxisLabels:
|
|
1014
|
+
"""Tests for the share_axis_labels helper and the `shared_axis_labels` kwarg."""
|
|
1015
|
+
|
|
1016
|
+
@pytest.fixture(autouse=True)
|
|
1017
|
+
def setup(self) -> None:
|
|
1018
|
+
self.da = xr.DataArray(
|
|
1019
|
+
np.random.rand(10, 2, 3),
|
|
1020
|
+
dims=["time", "scenario", "country"],
|
|
1021
|
+
coords={"scenario": ["low", "high"], "country": ["US", "CN", "BR"]},
|
|
1022
|
+
name="value",
|
|
1023
|
+
)
|
|
1024
|
+
|
|
1025
|
+
def test_matches_plotly_builtin_spec(self) -> None:
|
|
1026
|
+
"""Shared labels must be identical to make_subplots(x_title=, y_title=) output."""
|
|
1027
|
+
import json
|
|
1028
|
+
|
|
1029
|
+
from plotly.subplots import make_subplots
|
|
1030
|
+
|
|
1031
|
+
def canonical(annotations: list[go.layout.Annotation]) -> set[str]:
|
|
1032
|
+
return {json.dumps(a.to_plotly_json(), sort_keys=True) for a in annotations}
|
|
1033
|
+
|
|
1034
|
+
reference = make_subplots(rows=2, cols=2, x_title="value", y_title="value")
|
|
1035
|
+
ref_specs = canonical(list(reference.layout.annotations))
|
|
1036
|
+
|
|
1037
|
+
fig = xpx(self.da).line(color=None, facet_col="scenario", facet_row="country")
|
|
1038
|
+
# Rename both labels to "value" so the comparison covers all other fields
|
|
1039
|
+
for ann in _shared_label_annotations(fig):
|
|
1040
|
+
ann.text = "value"
|
|
1041
|
+
assert canonical(_shared_label_annotations(fig)) == ref_specs
|
|
1042
|
+
|
|
1043
|
+
def test_helper_facet_col_shares_x_label(self) -> None:
|
|
1044
|
+
fig = xpx(self.da.isel(scenario=0, drop=True)).line(
|
|
1045
|
+
color=None, facet_col="country", shared_axis_labels=False
|
|
1046
|
+
)
|
|
1047
|
+
assert len(_axis_titles(fig, "x")) == 3 # repeated per column
|
|
1048
|
+
|
|
1049
|
+
share_axis_labels(fig)
|
|
1050
|
+
|
|
1051
|
+
assert _axis_titles(fig, "x") == []
|
|
1052
|
+
labels = _shared_label_annotations(fig)
|
|
1053
|
+
assert [a.text for a in labels] == ["time"]
|
|
1054
|
+
# y title was never repeated, so it stays a regular axis title
|
|
1055
|
+
assert _axis_titles(fig, "y") == ["value"]
|
|
1056
|
+
|
|
1057
|
+
def test_helper_facet_row_shares_y_label(self) -> None:
|
|
1058
|
+
fig = xpx(self.da.isel(scenario=0, drop=True)).line(
|
|
1059
|
+
color=None, facet_row="country", shared_axis_labels=False
|
|
1060
|
+
)
|
|
1061
|
+
assert len(_axis_titles(fig, "y")) == 3 # repeated per row
|
|
1062
|
+
|
|
1063
|
+
share_axis_labels(fig)
|
|
1064
|
+
|
|
1065
|
+
assert _axis_titles(fig, "y") == []
|
|
1066
|
+
labels = _shared_label_annotations(fig)
|
|
1067
|
+
assert [a.text for a in labels] == ["value"]
|
|
1068
|
+
assert _axis_titles(fig, "x") == ["time"]
|
|
1069
|
+
|
|
1070
|
+
def test_helper_facet_grid_shares_both(self) -> None:
|
|
1071
|
+
fig = xpx(self.da).line(
|
|
1072
|
+
color=None, facet_col="scenario", facet_row="country", shared_axis_labels=False
|
|
1073
|
+
)
|
|
1074
|
+
share_axis_labels(fig)
|
|
1075
|
+
|
|
1076
|
+
assert _axis_titles(fig, "x") == []
|
|
1077
|
+
assert _axis_titles(fig, "y") == []
|
|
1078
|
+
labels = {a.text for a in _shared_label_annotations(fig)}
|
|
1079
|
+
assert labels == {"time", "value"}
|
|
1080
|
+
|
|
1081
|
+
def test_helper_no_facets_is_noop(self) -> None:
|
|
1082
|
+
fig = xpx(self.da.isel(scenario=0, country=0, drop=True)).line()
|
|
1083
|
+
before = fig.to_plotly_json()
|
|
1084
|
+
share_axis_labels(fig)
|
|
1085
|
+
assert fig.to_plotly_json() == before
|
|
1086
|
+
|
|
1087
|
+
def test_helper_idempotent(self) -> None:
|
|
1088
|
+
fig = xpx(self.da).line(color=None, facet_col="scenario", facet_row="country")
|
|
1089
|
+
share_axis_labels(fig)
|
|
1090
|
+
n_annotations = len(fig.layout.annotations)
|
|
1091
|
+
share_axis_labels(fig)
|
|
1092
|
+
assert len(fig.layout.annotations) == n_annotations
|
|
1093
|
+
|
|
1094
|
+
def test_helper_preserves_facet_titles(self) -> None:
|
|
1095
|
+
fig = xpx(self.da).line(color=None, facet_col="scenario", facet_row="country")
|
|
1096
|
+
share_axis_labels(fig)
|
|
1097
|
+
texts = [a.text for a in fig.layout.annotations]
|
|
1098
|
+
assert "scenario=low" in texts
|
|
1099
|
+
assert "scenario=high" in texts
|
|
1100
|
+
|
|
1101
|
+
def test_helper_different_titles_untouched(self) -> None:
|
|
1102
|
+
"""Figures whose subplots have different axis titles are not collapsed."""
|
|
1103
|
+
da1 = xr.DataArray(np.random.rand(5), dims=["time"], name="temperature")
|
|
1104
|
+
da2 = xr.DataArray(np.random.rand(5), dims=["distance"], name="pressure")
|
|
1105
|
+
fig = subplots(xpx(da1).line(), xpx(da2).line(), cols=2)
|
|
1106
|
+
before_x = _axis_titles(fig, "x")
|
|
1107
|
+
before_y = _axis_titles(fig, "y")
|
|
1108
|
+
|
|
1109
|
+
share_axis_labels(fig)
|
|
1110
|
+
|
|
1111
|
+
assert _axis_titles(fig, "x") == before_x
|
|
1112
|
+
assert _axis_titles(fig, "y") == before_y
|
|
1113
|
+
assert _shared_label_annotations(fig) == []
|
|
1114
|
+
|
|
1115
|
+
def test_helper_secondary_y_untouched(self) -> None:
|
|
1116
|
+
"""Identical titles on a primary and overlaying secondary y axis stay separate."""
|
|
1117
|
+
da = xr.DataArray(np.random.rand(5), dims=["time"], name="value")
|
|
1118
|
+
base = xpx(da).line()
|
|
1119
|
+
secondary = xpx(da).line()
|
|
1120
|
+
fig = add_secondary_y(base, secondary)
|
|
1121
|
+
before_y = _axis_titles(fig, "y")
|
|
1122
|
+
|
|
1123
|
+
share_axis_labels(fig)
|
|
1124
|
+
|
|
1125
|
+
assert _axis_titles(fig, "y") == before_y
|
|
1126
|
+
|
|
1127
|
+
def test_kwarg_shares_by_default(self) -> None:
|
|
1128
|
+
fig = xpx(self.da).line(color=None, facet_col="scenario", facet_row="country")
|
|
1129
|
+
assert _axis_titles(fig, "x") == []
|
|
1130
|
+
assert _axis_titles(fig, "y") == []
|
|
1131
|
+
assert {a.text for a in _shared_label_annotations(fig)} == {"time", "value"}
|
|
1132
|
+
|
|
1133
|
+
def test_kwarg_opt_out(self) -> None:
|
|
1134
|
+
fig = xpx(self.da).line(
|
|
1135
|
+
color=None, facet_col="scenario", facet_row="country", shared_axis_labels=False
|
|
1136
|
+
)
|
|
1137
|
+
assert len(_axis_titles(fig, "x")) > 1
|
|
1138
|
+
assert len(_axis_titles(fig, "y")) > 1
|
|
1139
|
+
assert _shared_label_annotations(fig) == []
|
|
1140
|
+
|
|
1141
|
+
def test_kwarg_on_imshow(self) -> None:
|
|
1142
|
+
da = xr.DataArray(
|
|
1143
|
+
np.random.rand(4, 5, 2, 3),
|
|
1144
|
+
dims=["lat", "lon", "scenario", "year"],
|
|
1145
|
+
name="temperature",
|
|
1146
|
+
)
|
|
1147
|
+
fig = da.plotly.imshow()
|
|
1148
|
+
assert {a.text for a in _shared_label_annotations(fig)} == {"lat", "lon"}
|
|
@@ -56,6 +56,7 @@ from xarray_plotly.common import SLOT_ORDERS, Colors, auto
|
|
|
56
56
|
from xarray_plotly.figures import (
|
|
57
57
|
add_secondary_y,
|
|
58
58
|
overlay,
|
|
59
|
+
share_axis_labels,
|
|
59
60
|
simplify_facet_titles,
|
|
60
61
|
subplots,
|
|
61
62
|
update_traces,
|
|
@@ -68,6 +69,7 @@ __all__ = [
|
|
|
68
69
|
"auto",
|
|
69
70
|
"config",
|
|
70
71
|
"overlay",
|
|
72
|
+
"share_axis_labels",
|
|
71
73
|
"simplify_facet_titles",
|
|
72
74
|
"subplots",
|
|
73
75
|
"update_traces",
|
|
@@ -55,6 +55,7 @@ class DataArrayPlotlyAccessor:
|
|
|
55
55
|
animation_frame: SlotValue = auto,
|
|
56
56
|
colors: Colors = None,
|
|
57
57
|
facet_titles: FacetTitlesMode = "default",
|
|
58
|
+
shared_axis_labels: bool = True,
|
|
58
59
|
**px_kwargs: Any,
|
|
59
60
|
) -> go.Figure:
|
|
60
61
|
"""Create an interactive line plot.
|
|
@@ -70,6 +71,8 @@ class DataArrayPlotlyAccessor:
|
|
|
70
71
|
facet_row: Dimension for subplot rows. Default: sixth dimension.
|
|
71
72
|
animation_frame: Dimension for animation. Default: seventh dimension.
|
|
72
73
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
74
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
75
|
+
plots are replaced with a single shared, centered label per axis.
|
|
73
76
|
**px_kwargs: Additional arguments passed to `plotly.express.line()`.
|
|
74
77
|
|
|
75
78
|
Returns:
|
|
@@ -86,6 +89,7 @@ class DataArrayPlotlyAccessor:
|
|
|
86
89
|
animation_frame=animation_frame,
|
|
87
90
|
colors=colors,
|
|
88
91
|
facet_titles=facet_titles,
|
|
92
|
+
shared_axis_labels=shared_axis_labels,
|
|
89
93
|
**px_kwargs,
|
|
90
94
|
)
|
|
91
95
|
|
|
@@ -100,6 +104,7 @@ class DataArrayPlotlyAccessor:
|
|
|
100
104
|
animation_frame: SlotValue = auto,
|
|
101
105
|
colors: Colors = None,
|
|
102
106
|
facet_titles: FacetTitlesMode = "default",
|
|
107
|
+
shared_axis_labels: bool = True,
|
|
103
108
|
**px_kwargs: Any,
|
|
104
109
|
) -> go.Figure:
|
|
105
110
|
"""Create an interactive bar chart.
|
|
@@ -114,6 +119,8 @@ class DataArrayPlotlyAccessor:
|
|
|
114
119
|
facet_row: Dimension for subplot rows. Default: fifth dimension.
|
|
115
120
|
animation_frame: Dimension for animation. Default: sixth dimension.
|
|
116
121
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
122
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
123
|
+
plots are replaced with a single shared, centered label per axis.
|
|
117
124
|
**px_kwargs: Additional arguments passed to `plotly.express.bar()`.
|
|
118
125
|
|
|
119
126
|
Returns:
|
|
@@ -129,6 +136,7 @@ class DataArrayPlotlyAccessor:
|
|
|
129
136
|
animation_frame=animation_frame,
|
|
130
137
|
colors=colors,
|
|
131
138
|
facet_titles=facet_titles,
|
|
139
|
+
shared_axis_labels=shared_axis_labels,
|
|
132
140
|
**px_kwargs,
|
|
133
141
|
)
|
|
134
142
|
|
|
@@ -143,6 +151,7 @@ class DataArrayPlotlyAccessor:
|
|
|
143
151
|
animation_frame: SlotValue = auto,
|
|
144
152
|
colors: Colors = None,
|
|
145
153
|
facet_titles: FacetTitlesMode = "default",
|
|
154
|
+
shared_axis_labels: bool = True,
|
|
146
155
|
**px_kwargs: Any,
|
|
147
156
|
) -> go.Figure:
|
|
148
157
|
"""Create an interactive stacked area chart.
|
|
@@ -157,6 +166,8 @@ class DataArrayPlotlyAccessor:
|
|
|
157
166
|
facet_row: Dimension for subplot rows. Default: fifth dimension.
|
|
158
167
|
animation_frame: Dimension for animation. Default: sixth dimension.
|
|
159
168
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
169
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
170
|
+
plots are replaced with a single shared, centered label per axis.
|
|
160
171
|
**px_kwargs: Additional arguments passed to `plotly.express.area()`.
|
|
161
172
|
|
|
162
173
|
Returns:
|
|
@@ -172,6 +183,7 @@ class DataArrayPlotlyAccessor:
|
|
|
172
183
|
animation_frame=animation_frame,
|
|
173
184
|
colors=colors,
|
|
174
185
|
facet_titles=facet_titles,
|
|
186
|
+
shared_axis_labels=shared_axis_labels,
|
|
175
187
|
**px_kwargs,
|
|
176
188
|
)
|
|
177
189
|
|
|
@@ -185,6 +197,7 @@ class DataArrayPlotlyAccessor:
|
|
|
185
197
|
animation_frame: SlotValue = auto,
|
|
186
198
|
colors: Colors = None,
|
|
187
199
|
facet_titles: FacetTitlesMode = "default",
|
|
200
|
+
shared_axis_labels: bool = True,
|
|
188
201
|
**px_kwargs: Any,
|
|
189
202
|
) -> go.Figure:
|
|
190
203
|
"""Create a bar-like chart using stacked areas for better performance.
|
|
@@ -198,6 +211,8 @@ class DataArrayPlotlyAccessor:
|
|
|
198
211
|
facet_row: Dimension for subplot rows. Default: fourth dimension.
|
|
199
212
|
animation_frame: Dimension for animation. Default: fifth dimension.
|
|
200
213
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
214
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
215
|
+
plots are replaced with a single shared, centered label per axis.
|
|
201
216
|
**px_kwargs: Additional arguments passed to `plotly.express.area()`.
|
|
202
217
|
|
|
203
218
|
Returns:
|
|
@@ -212,6 +227,7 @@ class DataArrayPlotlyAccessor:
|
|
|
212
227
|
animation_frame=animation_frame,
|
|
213
228
|
colors=colors,
|
|
214
229
|
facet_titles=facet_titles,
|
|
230
|
+
shared_axis_labels=shared_axis_labels,
|
|
215
231
|
**px_kwargs,
|
|
216
232
|
)
|
|
217
233
|
|
|
@@ -227,6 +243,7 @@ class DataArrayPlotlyAccessor:
|
|
|
227
243
|
animation_frame: SlotValue = auto,
|
|
228
244
|
colors: Colors = None,
|
|
229
245
|
facet_titles: FacetTitlesMode = "default",
|
|
246
|
+
shared_axis_labels: bool = True,
|
|
230
247
|
**px_kwargs: Any,
|
|
231
248
|
) -> go.Figure:
|
|
232
249
|
"""Create an interactive scatter plot.
|
|
@@ -246,6 +263,8 @@ class DataArrayPlotlyAccessor:
|
|
|
246
263
|
facet_row: Dimension for subplot rows. Default: fifth dimension.
|
|
247
264
|
animation_frame: Dimension for animation. Default: sixth dimension.
|
|
248
265
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
266
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
267
|
+
plots are replaced with a single shared, centered label per axis.
|
|
249
268
|
**px_kwargs: Additional arguments passed to `plotly.express.scatter()`.
|
|
250
269
|
|
|
251
270
|
Returns:
|
|
@@ -262,6 +281,7 @@ class DataArrayPlotlyAccessor:
|
|
|
262
281
|
animation_frame=animation_frame,
|
|
263
282
|
colors=colors,
|
|
264
283
|
facet_titles=facet_titles,
|
|
284
|
+
shared_axis_labels=shared_axis_labels,
|
|
265
285
|
**px_kwargs,
|
|
266
286
|
)
|
|
267
287
|
|
|
@@ -275,6 +295,7 @@ class DataArrayPlotlyAccessor:
|
|
|
275
295
|
animation_frame: SlotValue = None,
|
|
276
296
|
colors: Colors = None,
|
|
277
297
|
facet_titles: FacetTitlesMode = "default",
|
|
298
|
+
shared_axis_labels: bool = True,
|
|
278
299
|
**px_kwargs: Any,
|
|
279
300
|
) -> go.Figure:
|
|
280
301
|
"""Create an interactive box plot.
|
|
@@ -291,6 +312,8 @@ class DataArrayPlotlyAccessor:
|
|
|
291
312
|
facet_row: Dimension for subplot rows. Default: None (aggregated).
|
|
292
313
|
animation_frame: Dimension for animation. Default: None (aggregated).
|
|
293
314
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
315
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
316
|
+
plots are replaced with a single shared, centered label per axis.
|
|
294
317
|
**px_kwargs: Additional arguments passed to `plotly.express.box()`.
|
|
295
318
|
|
|
296
319
|
Returns:
|
|
@@ -305,6 +328,7 @@ class DataArrayPlotlyAccessor:
|
|
|
305
328
|
animation_frame=animation_frame,
|
|
306
329
|
colors=colors,
|
|
307
330
|
facet_titles=facet_titles,
|
|
331
|
+
shared_axis_labels=shared_axis_labels,
|
|
308
332
|
**px_kwargs,
|
|
309
333
|
)
|
|
310
334
|
|
|
@@ -319,6 +343,7 @@ class DataArrayPlotlyAccessor:
|
|
|
319
343
|
robust: bool = False,
|
|
320
344
|
colors: Colors = None,
|
|
321
345
|
facet_titles: FacetTitlesMode = "default",
|
|
346
|
+
shared_axis_labels: bool = True,
|
|
322
347
|
**px_kwargs: Any,
|
|
323
348
|
) -> go.Figure:
|
|
324
349
|
"""Create an interactive heatmap image.
|
|
@@ -340,6 +365,8 @@ class DataArrayPlotlyAccessor:
|
|
|
340
365
|
animation_frame: Dimension for animation. Default: fifth dimension.
|
|
341
366
|
robust: If True, use 2nd/98th percentiles for color bounds (handles outliers).
|
|
342
367
|
colors: Color scale name (e.g., "Viridis", "RdBu"). See module docs.
|
|
368
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
369
|
+
plots are replaced with a single shared, centered label per axis.
|
|
343
370
|
**px_kwargs: Additional arguments passed to `plotly.express.imshow()`.
|
|
344
371
|
Use `zmin` and `zmax` to manually set color scale bounds.
|
|
345
372
|
|
|
@@ -356,6 +383,7 @@ class DataArrayPlotlyAccessor:
|
|
|
356
383
|
robust=robust,
|
|
357
384
|
colors=colors,
|
|
358
385
|
facet_titles=facet_titles,
|
|
386
|
+
shared_axis_labels=shared_axis_labels,
|
|
359
387
|
**px_kwargs,
|
|
360
388
|
)
|
|
361
389
|
|
|
@@ -368,6 +396,7 @@ class DataArrayPlotlyAccessor:
|
|
|
368
396
|
facet_row: SlotValue = auto,
|
|
369
397
|
colors: Colors = None,
|
|
370
398
|
facet_titles: FacetTitlesMode = "default",
|
|
399
|
+
shared_axis_labels: bool = True,
|
|
371
400
|
**px_kwargs: Any,
|
|
372
401
|
) -> go.Figure:
|
|
373
402
|
"""Create an interactive pie chart.
|
|
@@ -380,6 +409,8 @@ class DataArrayPlotlyAccessor:
|
|
|
380
409
|
facet_col: Dimension for subplot columns. Default: second dimension.
|
|
381
410
|
facet_row: Dimension for subplot rows. Default: third dimension.
|
|
382
411
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
412
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
413
|
+
plots are replaced with a single shared, centered label per axis.
|
|
383
414
|
**px_kwargs: Additional arguments passed to `plotly.express.pie()`.
|
|
384
415
|
|
|
385
416
|
Returns:
|
|
@@ -393,6 +424,7 @@ class DataArrayPlotlyAccessor:
|
|
|
393
424
|
facet_row=facet_row,
|
|
394
425
|
colors=colors,
|
|
395
426
|
facet_titles=facet_titles,
|
|
427
|
+
shared_axis_labels=shared_axis_labels,
|
|
396
428
|
**px_kwargs,
|
|
397
429
|
)
|
|
398
430
|
|
|
@@ -474,6 +506,7 @@ class DatasetPlotlyAccessor:
|
|
|
474
506
|
animation_frame: SlotValue = auto,
|
|
475
507
|
colors: Colors = None,
|
|
476
508
|
facet_titles: FacetTitlesMode = "default",
|
|
509
|
+
shared_axis_labels: bool = True,
|
|
477
510
|
**px_kwargs: Any,
|
|
478
511
|
) -> go.Figure:
|
|
479
512
|
"""Create an interactive line plot.
|
|
@@ -488,6 +521,8 @@ class DatasetPlotlyAccessor:
|
|
|
488
521
|
facet_row: Dimension for subplot rows.
|
|
489
522
|
animation_frame: Dimension for animation.
|
|
490
523
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
524
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
525
|
+
plots are replaced with a single shared, centered label per axis.
|
|
491
526
|
**px_kwargs: Additional arguments passed to `plotly.express.line()`.
|
|
492
527
|
|
|
493
528
|
Returns:
|
|
@@ -505,6 +540,7 @@ class DatasetPlotlyAccessor:
|
|
|
505
540
|
animation_frame=animation_frame,
|
|
506
541
|
colors=colors,
|
|
507
542
|
facet_titles=facet_titles,
|
|
543
|
+
shared_axis_labels=shared_axis_labels,
|
|
508
544
|
**px_kwargs,
|
|
509
545
|
)
|
|
510
546
|
|
|
@@ -520,6 +556,7 @@ class DatasetPlotlyAccessor:
|
|
|
520
556
|
animation_frame: SlotValue = auto,
|
|
521
557
|
colors: Colors = None,
|
|
522
558
|
facet_titles: FacetTitlesMode = "default",
|
|
559
|
+
shared_axis_labels: bool = True,
|
|
523
560
|
**px_kwargs: Any,
|
|
524
561
|
) -> go.Figure:
|
|
525
562
|
"""Create an interactive bar chart.
|
|
@@ -533,6 +570,8 @@ class DatasetPlotlyAccessor:
|
|
|
533
570
|
facet_row: Dimension for subplot rows.
|
|
534
571
|
animation_frame: Dimension for animation.
|
|
535
572
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
573
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
574
|
+
plots are replaced with a single shared, centered label per axis.
|
|
536
575
|
**px_kwargs: Additional arguments passed to `plotly.express.bar()`.
|
|
537
576
|
|
|
538
577
|
Returns:
|
|
@@ -549,6 +588,7 @@ class DatasetPlotlyAccessor:
|
|
|
549
588
|
animation_frame=animation_frame,
|
|
550
589
|
colors=colors,
|
|
551
590
|
facet_titles=facet_titles,
|
|
591
|
+
shared_axis_labels=shared_axis_labels,
|
|
552
592
|
**px_kwargs,
|
|
553
593
|
)
|
|
554
594
|
|
|
@@ -564,6 +604,7 @@ class DatasetPlotlyAccessor:
|
|
|
564
604
|
animation_frame: SlotValue = auto,
|
|
565
605
|
colors: Colors = None,
|
|
566
606
|
facet_titles: FacetTitlesMode = "default",
|
|
607
|
+
shared_axis_labels: bool = True,
|
|
567
608
|
**px_kwargs: Any,
|
|
568
609
|
) -> go.Figure:
|
|
569
610
|
"""Create an interactive stacked area chart.
|
|
@@ -577,6 +618,8 @@ class DatasetPlotlyAccessor:
|
|
|
577
618
|
facet_row: Dimension for subplot rows.
|
|
578
619
|
animation_frame: Dimension for animation.
|
|
579
620
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
621
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
622
|
+
plots are replaced with a single shared, centered label per axis.
|
|
580
623
|
**px_kwargs: Additional arguments passed to `plotly.express.area()`.
|
|
581
624
|
|
|
582
625
|
Returns:
|
|
@@ -593,6 +636,7 @@ class DatasetPlotlyAccessor:
|
|
|
593
636
|
animation_frame=animation_frame,
|
|
594
637
|
colors=colors,
|
|
595
638
|
facet_titles=facet_titles,
|
|
639
|
+
shared_axis_labels=shared_axis_labels,
|
|
596
640
|
**px_kwargs,
|
|
597
641
|
)
|
|
598
642
|
|
|
@@ -607,6 +651,7 @@ class DatasetPlotlyAccessor:
|
|
|
607
651
|
animation_frame: SlotValue = auto,
|
|
608
652
|
colors: Colors = None,
|
|
609
653
|
facet_titles: FacetTitlesMode = "default",
|
|
654
|
+
shared_axis_labels: bool = True,
|
|
610
655
|
**px_kwargs: Any,
|
|
611
656
|
) -> go.Figure:
|
|
612
657
|
"""Create a bar-like chart using stacked areas for better performance.
|
|
@@ -619,6 +664,8 @@ class DatasetPlotlyAccessor:
|
|
|
619
664
|
facet_row: Dimension for subplot rows.
|
|
620
665
|
animation_frame: Dimension for animation.
|
|
621
666
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
667
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
668
|
+
plots are replaced with a single shared, centered label per axis.
|
|
622
669
|
**px_kwargs: Additional arguments passed to `plotly.express.area()`.
|
|
623
670
|
|
|
624
671
|
Returns:
|
|
@@ -634,6 +681,7 @@ class DatasetPlotlyAccessor:
|
|
|
634
681
|
animation_frame=animation_frame,
|
|
635
682
|
colors=colors,
|
|
636
683
|
facet_titles=facet_titles,
|
|
684
|
+
shared_axis_labels=shared_axis_labels,
|
|
637
685
|
**px_kwargs,
|
|
638
686
|
)
|
|
639
687
|
|
|
@@ -650,6 +698,7 @@ class DatasetPlotlyAccessor:
|
|
|
650
698
|
animation_frame: SlotValue = auto,
|
|
651
699
|
colors: Colors = None,
|
|
652
700
|
facet_titles: FacetTitlesMode = "default",
|
|
701
|
+
shared_axis_labels: bool = True,
|
|
653
702
|
**px_kwargs: Any,
|
|
654
703
|
) -> go.Figure:
|
|
655
704
|
"""Create an interactive scatter plot.
|
|
@@ -664,6 +713,8 @@ class DatasetPlotlyAccessor:
|
|
|
664
713
|
facet_row: Dimension for subplot rows.
|
|
665
714
|
animation_frame: Dimension for animation.
|
|
666
715
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
716
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
717
|
+
plots are replaced with a single shared, centered label per axis.
|
|
667
718
|
**px_kwargs: Additional arguments passed to `plotly.express.scatter()`.
|
|
668
719
|
|
|
669
720
|
Returns:
|
|
@@ -681,6 +732,7 @@ class DatasetPlotlyAccessor:
|
|
|
681
732
|
animation_frame=animation_frame,
|
|
682
733
|
colors=colors,
|
|
683
734
|
facet_titles=facet_titles,
|
|
735
|
+
shared_axis_labels=shared_axis_labels,
|
|
684
736
|
**px_kwargs,
|
|
685
737
|
)
|
|
686
738
|
|
|
@@ -695,6 +747,7 @@ class DatasetPlotlyAccessor:
|
|
|
695
747
|
animation_frame: SlotValue = None,
|
|
696
748
|
colors: Colors = None,
|
|
697
749
|
facet_titles: FacetTitlesMode = "default",
|
|
750
|
+
shared_axis_labels: bool = True,
|
|
698
751
|
**px_kwargs: Any,
|
|
699
752
|
) -> go.Figure:
|
|
700
753
|
"""Create an interactive box plot.
|
|
@@ -707,6 +760,8 @@ class DatasetPlotlyAccessor:
|
|
|
707
760
|
facet_row: Dimension for subplot rows.
|
|
708
761
|
animation_frame: Dimension for animation.
|
|
709
762
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
763
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
764
|
+
plots are replaced with a single shared, centered label per axis.
|
|
710
765
|
**px_kwargs: Additional arguments passed to `plotly.express.box()`.
|
|
711
766
|
|
|
712
767
|
Returns:
|
|
@@ -722,6 +777,7 @@ class DatasetPlotlyAccessor:
|
|
|
722
777
|
animation_frame=animation_frame,
|
|
723
778
|
colors=colors,
|
|
724
779
|
facet_titles=facet_titles,
|
|
780
|
+
shared_axis_labels=shared_axis_labels,
|
|
725
781
|
**px_kwargs,
|
|
726
782
|
)
|
|
727
783
|
|
|
@@ -735,6 +791,7 @@ class DatasetPlotlyAccessor:
|
|
|
735
791
|
facet_row: SlotValue = auto,
|
|
736
792
|
colors: Colors = None,
|
|
737
793
|
facet_titles: FacetTitlesMode = "default",
|
|
794
|
+
shared_axis_labels: bool = True,
|
|
738
795
|
**px_kwargs: Any,
|
|
739
796
|
) -> go.Figure:
|
|
740
797
|
"""Create an interactive pie chart.
|
|
@@ -746,6 +803,8 @@ class DatasetPlotlyAccessor:
|
|
|
746
803
|
facet_col: Dimension for subplot columns.
|
|
747
804
|
facet_row: Dimension for subplot rows.
|
|
748
805
|
colors: Color specification (scale name, list, or dict). See module docs.
|
|
806
|
+
shared_axis_labels: If True (default), repeated axis titles on faceted
|
|
807
|
+
plots are replaced with a single shared, centered label per axis.
|
|
749
808
|
**px_kwargs: Additional arguments passed to `plotly.express.pie()`.
|
|
750
809
|
|
|
751
810
|
Returns:
|
|
@@ -760,5 +819,6 @@ class DatasetPlotlyAccessor:
|
|
|
760
819
|
facet_row=facet_row,
|
|
761
820
|
colors=colors,
|
|
762
821
|
facet_titles=facet_titles,
|
|
822
|
+
shared_axis_labels=shared_axis_labels,
|
|
763
823
|
**px_kwargs,
|
|
764
824
|
)
|
|
@@ -971,3 +971,80 @@ def simplify_facet_titles(
|
|
|
971
971
|
if text and _FACET_TITLE_PREFIX_RE.match(text):
|
|
972
972
|
ann.text = text.split("=", 1)[1]
|
|
973
973
|
return fig
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
# Matches cartesian axis layout keys like "xaxis", "xaxis2", "yaxis12".
|
|
977
|
+
_AXIS_KEY_RE = re.compile(r"([xy])axis\d*$")
|
|
978
|
+
|
|
979
|
+
# Annotation specs identical to plotly's built-in shared subplot titles,
|
|
980
|
+
# i.e. what `make_subplots(x_title=..., y_title=...)` produces. Kept in
|
|
981
|
+
# sync with plotly via a test against make_subplots output.
|
|
982
|
+
_SHARED_LABEL_SPECS: dict[str, dict[str, Any]] = {
|
|
983
|
+
"x": {
|
|
984
|
+
"x": 0.5,
|
|
985
|
+
"y": 0,
|
|
986
|
+
"xref": "paper",
|
|
987
|
+
"yref": "paper",
|
|
988
|
+
"xanchor": "center",
|
|
989
|
+
"yanchor": "top",
|
|
990
|
+
"yshift": -30,
|
|
991
|
+
"showarrow": False,
|
|
992
|
+
"font": {"size": 16},
|
|
993
|
+
},
|
|
994
|
+
"y": {
|
|
995
|
+
"x": 0,
|
|
996
|
+
"y": 0.5,
|
|
997
|
+
"xref": "paper",
|
|
998
|
+
"yref": "paper",
|
|
999
|
+
"xanchor": "right",
|
|
1000
|
+
"yanchor": "middle",
|
|
1001
|
+
"xshift": -40,
|
|
1002
|
+
"textangle": -90,
|
|
1003
|
+
"showarrow": False,
|
|
1004
|
+
"font": {"size": 16},
|
|
1005
|
+
},
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
def share_axis_labels(fig: go.Figure) -> go.Figure:
|
|
1010
|
+
"""Replace repeated facet axis titles with a single shared label per axis.
|
|
1011
|
+
|
|
1012
|
+
Plotly Express repeats the x-axis title under every facet column and the
|
|
1013
|
+
y-axis title beside every facet row. This helper removes the repeated
|
|
1014
|
+
titles and adds one centered label per axis instead, styled exactly like
|
|
1015
|
+
plotly's built-in shared titles (``make_subplots(x_title=..., y_title=...)``),
|
|
1016
|
+
which Plotly Express does not expose for faceted figures.
|
|
1017
|
+
|
|
1018
|
+
Titles are only collapsed when they are repeated and identical, so
|
|
1019
|
+
figures without facets, figures combined from differently-labeled
|
|
1020
|
+
subplots, and secondary-y figures are returned unchanged.
|
|
1021
|
+
|
|
1022
|
+
Args:
|
|
1023
|
+
fig: A Plotly figure (mutated in place).
|
|
1024
|
+
|
|
1025
|
+
Returns:
|
|
1026
|
+
The (possibly mutated) figure, for chaining.
|
|
1027
|
+
|
|
1028
|
+
Example:
|
|
1029
|
+
>>> import plotly.express as px
|
|
1030
|
+
>>> from xarray_plotly import share_axis_labels
|
|
1031
|
+
>>> fig = px.line(df, x="year", y="gdp", facet_col="country", facet_row="metric")
|
|
1032
|
+
>>> share_axis_labels(fig) # one "year" below, one "gdp" at the left
|
|
1033
|
+
"""
|
|
1034
|
+
axes_by_letter: dict[str, list[Any]] = {"x": [], "y": []}
|
|
1035
|
+
for key in fig.layout:
|
|
1036
|
+
match = _AXIS_KEY_RE.match(key)
|
|
1037
|
+
# Overlaying axes (secondary y) share their domain with the axis
|
|
1038
|
+
# they overlay; their titles are independent, not facet repetition.
|
|
1039
|
+
if match and not fig.layout[key].overlaying:
|
|
1040
|
+
axes_by_letter[match.group(1)].append(fig.layout[key])
|
|
1041
|
+
|
|
1042
|
+
for letter, axes in axes_by_letter.items():
|
|
1043
|
+
titles = [axis.title.text for axis in axes if axis.title.text]
|
|
1044
|
+
# Only collapse titles that are actually repeated and identical
|
|
1045
|
+
if len(titles) < 2 or len(set(titles)) != 1:
|
|
1046
|
+
continue
|
|
1047
|
+
for axis in axes:
|
|
1048
|
+
axis.title.text = None
|
|
1049
|
+
fig.add_annotation(text=titles[0], **_SHARED_LABEL_SPECS[letter])
|
|
1050
|
+
return fig
|
|
@@ -26,6 +26,7 @@ from xarray_plotly.common import (
|
|
|
26
26
|
)
|
|
27
27
|
from xarray_plotly.figures import (
|
|
28
28
|
_iter_all_traces,
|
|
29
|
+
share_axis_labels,
|
|
29
30
|
simplify_facet_titles,
|
|
30
31
|
)
|
|
31
32
|
|
|
@@ -34,6 +35,14 @@ if TYPE_CHECKING:
|
|
|
34
35
|
from xarray import DataArray
|
|
35
36
|
|
|
36
37
|
|
|
38
|
+
def _finalize(fig: go.Figure, facet_titles: FacetTitlesMode, shared_axis_labels: bool) -> go.Figure:
|
|
39
|
+
"""Apply facet post-processing shared by all plot functions."""
|
|
40
|
+
simplify_facet_titles(fig, facet_titles)
|
|
41
|
+
if shared_axis_labels:
|
|
42
|
+
share_axis_labels(fig)
|
|
43
|
+
return fig
|
|
44
|
+
|
|
45
|
+
|
|
37
46
|
def line(
|
|
38
47
|
darray: DataArray,
|
|
39
48
|
*,
|
|
@@ -46,6 +55,7 @@ def line(
|
|
|
46
55
|
animation_frame: SlotValue = auto,
|
|
47
56
|
colors: Colors = None,
|
|
48
57
|
facet_titles: FacetTitlesMode = "default",
|
|
58
|
+
shared_axis_labels: bool = True,
|
|
49
59
|
**px_kwargs: Any,
|
|
50
60
|
) -> go.Figure:
|
|
51
61
|
"""
|
|
@@ -79,6 +89,9 @@ def line(
|
|
|
79
89
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
80
90
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
81
91
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
92
|
+
shared_axis_labels
|
|
93
|
+
If True (default), repeated axis titles on faceted plots are
|
|
94
|
+
replaced with a single shared, centered label per axis.
|
|
82
95
|
**px_kwargs
|
|
83
96
|
Additional arguments passed to `plotly.express.line()`.
|
|
84
97
|
|
|
@@ -116,7 +129,7 @@ def line(
|
|
|
116
129
|
labels=labels,
|
|
117
130
|
**px_kwargs,
|
|
118
131
|
)
|
|
119
|
-
return
|
|
132
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
120
133
|
|
|
121
134
|
|
|
122
135
|
def bar(
|
|
@@ -130,6 +143,7 @@ def bar(
|
|
|
130
143
|
animation_frame: SlotValue = auto,
|
|
131
144
|
colors: Colors = None,
|
|
132
145
|
facet_titles: FacetTitlesMode = "default",
|
|
146
|
+
shared_axis_labels: bool = True,
|
|
133
147
|
**px_kwargs: Any,
|
|
134
148
|
) -> go.Figure:
|
|
135
149
|
"""
|
|
@@ -161,6 +175,9 @@ def bar(
|
|
|
161
175
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
162
176
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
163
177
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
178
|
+
shared_axis_labels
|
|
179
|
+
If True (default), repeated axis titles on faceted plots are
|
|
180
|
+
replaced with a single shared, centered label per axis.
|
|
164
181
|
**px_kwargs
|
|
165
182
|
Additional arguments passed to `plotly.express.bar()`.
|
|
166
183
|
|
|
@@ -196,7 +213,7 @@ def bar(
|
|
|
196
213
|
labels=labels,
|
|
197
214
|
**px_kwargs,
|
|
198
215
|
)
|
|
199
|
-
return
|
|
216
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
200
217
|
|
|
201
218
|
|
|
202
219
|
def _classify_trace_sign(y_values: npt.ArrayLike) -> str:
|
|
@@ -293,6 +310,7 @@ def fast_bar(
|
|
|
293
310
|
animation_frame: SlotValue = auto,
|
|
294
311
|
colors: Colors = None,
|
|
295
312
|
facet_titles: FacetTitlesMode = "default",
|
|
313
|
+
shared_axis_labels: bool = True,
|
|
296
314
|
**px_kwargs: Any,
|
|
297
315
|
) -> go.Figure:
|
|
298
316
|
"""
|
|
@@ -330,6 +348,9 @@ def fast_bar(
|
|
|
330
348
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
331
349
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
332
350
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
351
|
+
shared_axis_labels
|
|
352
|
+
If True (default), repeated axis titles on faceted plots are
|
|
353
|
+
replaced with a single shared, centered label per axis.
|
|
333
354
|
**px_kwargs
|
|
334
355
|
Additional arguments passed to `plotly.express.area()`.
|
|
335
356
|
|
|
@@ -367,7 +388,7 @@ def fast_bar(
|
|
|
367
388
|
|
|
368
389
|
_style_traces_as_bars(fig)
|
|
369
390
|
|
|
370
|
-
return
|
|
391
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
371
392
|
|
|
372
393
|
|
|
373
394
|
def area(
|
|
@@ -381,6 +402,7 @@ def area(
|
|
|
381
402
|
animation_frame: SlotValue = auto,
|
|
382
403
|
colors: Colors = None,
|
|
383
404
|
facet_titles: FacetTitlesMode = "default",
|
|
405
|
+
shared_axis_labels: bool = True,
|
|
384
406
|
**px_kwargs: Any,
|
|
385
407
|
) -> go.Figure:
|
|
386
408
|
"""
|
|
@@ -412,6 +434,9 @@ def area(
|
|
|
412
434
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
413
435
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
414
436
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
437
|
+
shared_axis_labels
|
|
438
|
+
If True (default), repeated axis titles on faceted plots are
|
|
439
|
+
replaced with a single shared, centered label per axis.
|
|
415
440
|
**px_kwargs
|
|
416
441
|
Additional arguments passed to `plotly.express.area()`.
|
|
417
442
|
|
|
@@ -447,7 +472,7 @@ def area(
|
|
|
447
472
|
labels=labels,
|
|
448
473
|
**px_kwargs,
|
|
449
474
|
)
|
|
450
|
-
return
|
|
475
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
451
476
|
|
|
452
477
|
|
|
453
478
|
def box(
|
|
@@ -460,6 +485,7 @@ def box(
|
|
|
460
485
|
animation_frame: SlotValue = None,
|
|
461
486
|
colors: Colors = None,
|
|
462
487
|
facet_titles: FacetTitlesMode = "default",
|
|
488
|
+
shared_axis_labels: bool = True,
|
|
463
489
|
**px_kwargs: Any,
|
|
464
490
|
) -> go.Figure:
|
|
465
491
|
"""
|
|
@@ -491,6 +517,9 @@ def box(
|
|
|
491
517
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
492
518
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
493
519
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
520
|
+
shared_axis_labels
|
|
521
|
+
If True (default), repeated axis titles on faceted plots are
|
|
522
|
+
replaced with a single shared, centered label per axis.
|
|
494
523
|
**px_kwargs
|
|
495
524
|
Additional arguments passed to `plotly.express.box()`.
|
|
496
525
|
|
|
@@ -525,7 +554,7 @@ def box(
|
|
|
525
554
|
labels=labels,
|
|
526
555
|
**px_kwargs,
|
|
527
556
|
)
|
|
528
|
-
return
|
|
557
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
529
558
|
|
|
530
559
|
|
|
531
560
|
def scatter(
|
|
@@ -540,6 +569,7 @@ def scatter(
|
|
|
540
569
|
animation_frame: SlotValue = auto,
|
|
541
570
|
colors: Colors = None,
|
|
542
571
|
facet_titles: FacetTitlesMode = "default",
|
|
572
|
+
shared_axis_labels: bool = True,
|
|
543
573
|
**px_kwargs: Any,
|
|
544
574
|
) -> go.Figure:
|
|
545
575
|
"""
|
|
@@ -578,6 +608,9 @@ def scatter(
|
|
|
578
608
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
579
609
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
580
610
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
611
|
+
shared_axis_labels
|
|
612
|
+
If True (default), repeated axis titles on faceted plots are
|
|
613
|
+
replaced with a single shared, centered label per axis.
|
|
581
614
|
**px_kwargs
|
|
582
615
|
Additional arguments passed to `plotly.express.scatter()`.
|
|
583
616
|
|
|
@@ -625,7 +658,7 @@ def scatter(
|
|
|
625
658
|
labels=labels,
|
|
626
659
|
**px_kwargs,
|
|
627
660
|
)
|
|
628
|
-
return
|
|
661
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
629
662
|
|
|
630
663
|
|
|
631
664
|
def _imshow_supports_facet_row() -> bool:
|
|
@@ -647,6 +680,7 @@ def imshow(
|
|
|
647
680
|
robust: bool = False,
|
|
648
681
|
colors: Colors = None,
|
|
649
682
|
facet_titles: FacetTitlesMode = "default",
|
|
683
|
+
shared_axis_labels: bool = True,
|
|
650
684
|
**px_kwargs: Any,
|
|
651
685
|
) -> go.Figure:
|
|
652
686
|
"""
|
|
@@ -689,6 +723,9 @@ def imshow(
|
|
|
689
723
|
continuous scale (e.g., "Viridis", "RdBu"). Lists and dicts
|
|
690
724
|
are not applicable for heatmaps.
|
|
691
725
|
Explicit color_continuous_scale in px_kwargs takes precedence.
|
|
726
|
+
shared_axis_labels
|
|
727
|
+
If True (default), repeated axis titles on faceted plots are
|
|
728
|
+
replaced with a single shared, centered label per axis.
|
|
692
729
|
**px_kwargs
|
|
693
730
|
Additional arguments passed to `plotly.express.imshow()`.
|
|
694
731
|
Use `zmin` and `zmax` to manually set color scale bounds.
|
|
@@ -752,7 +789,7 @@ def imshow(
|
|
|
752
789
|
**facet_row_kwargs,
|
|
753
790
|
**px_kwargs,
|
|
754
791
|
)
|
|
755
|
-
return
|
|
792
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
756
793
|
|
|
757
794
|
|
|
758
795
|
def pie(
|
|
@@ -764,6 +801,7 @@ def pie(
|
|
|
764
801
|
facet_row: SlotValue = auto,
|
|
765
802
|
colors: Colors = None,
|
|
766
803
|
facet_titles: FacetTitlesMode = "default",
|
|
804
|
+
shared_axis_labels: bool = True,
|
|
767
805
|
**px_kwargs: Any,
|
|
768
806
|
) -> go.Figure:
|
|
769
807
|
"""
|
|
@@ -790,6 +828,9 @@ def pie(
|
|
|
790
828
|
- A list of colors (e.g., ["red", "blue", "green"])
|
|
791
829
|
- A dict mapping values to colors (e.g., {"A": "red", "B": "blue"})
|
|
792
830
|
Explicit color_* kwargs in px_kwargs take precedence.
|
|
831
|
+
shared_axis_labels
|
|
832
|
+
If True (default), repeated axis titles on faceted plots are
|
|
833
|
+
replaced with a single shared, centered label per axis.
|
|
793
834
|
**px_kwargs
|
|
794
835
|
Additional arguments passed to `plotly.express.pie()`.
|
|
795
836
|
|
|
@@ -823,4 +864,4 @@ def pie(
|
|
|
823
864
|
labels=labels,
|
|
824
865
|
**px_kwargs,
|
|
825
866
|
)
|
|
826
|
-
return
|
|
867
|
+
return _finalize(fig, facet_titles, shared_axis_labels)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|