Skip to content

Commit fddbacb

Browse files
authored
Fix xarray DataArray coord unwrapping in Model.add_coord (#8391)
When xarray Dataset coords are passed directly to pm.Model(coords=...), the DataArray values were stored as tuples of 0-d DataArrays instead of plain values. This broke np.array_equal comparisons and InferenceData export. Fix by extracting .values from any DataArray before tuple() conversion.
1 parent bf8abd5 commit fddbacb

2 files changed

Lines changed: 29 additions & 0 deletions

File tree

pymc/model/core.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import numpy as np
3030
import pytensor
3131
import pytensor.tensor as pt
32+
import xarray as xr
3233

3334
from pytensor.compile import DeepCopyOp, Function, ProfileStats, get_mode, view_op
3435
from pytensor.compile.io import In, Out
@@ -1856,6 +1857,12 @@ def add_coord(
18561857
f"Either `values` or `length` must be specified for the '{name}' dimension."
18571858
)
18581859
if values is not None:
1860+
# xarray DataArrays passed as coord values must be unwrapped.
1861+
# tuple(DataArray) iterates yielding 0-d DataArrays instead of plain values,
1862+
# which breaks np.array_equal comparisons and DataTree export.
1863+
if isinstance(values, xr.DataArray):
1864+
values = values.values
1865+
18591866
# Conversion to a tuple ensures that the coordinate values are immutable.
18601867
# Also unlike numpy arrays the's tuple.index(...) which is handy to work with.
18611868
values = tuple(values)

tests/model/test_core.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import scipy
3232
import scipy.sparse as sps
3333
import scipy.stats as st
34+
import xarray as xr
3435

3536
from pytensor.compile.mode import get_default_mode
3637
from pytensor.compile.sharedvalue import SharedVariable
@@ -873,6 +874,27 @@ def test_multiple_add_coords_with_same_name():
873874
assert len(variables) == 1 and variables[0] is m.dim_lengths["dim1"]
874875

875876

877+
@pytest.mark.parametrize(
878+
"coords_dict",
879+
[
880+
pytest.param({"city": ["nyc", "la", "chi"]}, id="string"),
881+
pytest.param({"year": [2020, 2021, 2022]}, id="int"),
882+
pytest.param(
883+
{"time": np.array(["2020-01-01", "2020-01-02"], dtype="datetime64[D]")},
884+
id="datetime64",
885+
),
886+
],
887+
)
888+
def test_xarray_coord_values_unwrapped(coords_dict):
889+
"""xarray DataArray coord values are unwrapped to plain tuples of values."""
890+
ds = xr.Dataset(coords=coords_dict)
891+
with pm.Model(coords=ds.coords) as m:
892+
key = next(iter(coords_dict))
893+
coord = m.coords[key]
894+
assert isinstance(coord, tuple)
895+
assert not isinstance(coord[0], xr.DataArray)
896+
897+
876898
class TestSetUpdateCoords:
877899
def test_shapeerror_from_set_data_dimensionality(self):
878900
with pm.Model() as pmodel:

0 commit comments

Comments
 (0)