Skip to content

Commit 625cfc6

Browse files
committed
Enable assigning obs_names and var_names for mudata (recursive)
1 parent 8b40aee commit 625cfc6

File tree

1 file changed

+80
-10
lines changed

1 file changed

+80
-10
lines changed

src/mudata/_core/mudata.py

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,11 @@ def obs_names_make_unique(self):
14631463
self.update_obs()
14641464

14651465
for k in self.mod:
1466-
self.mod[k].obs_names_make_unique()
1466+
if isinstance(self.mod[k], AnnData):
1467+
self.mod[k].obs_names_make_unique()
1468+
# Only propagate to individual modalities with shared vars
1469+
elif isinstance(self.mod[k], MuData) and getattr(self.mod[k], 'axis', 1) == 1:
1470+
self.mod[k].obs_names_make_unique()
14671471

14681472
# Check if there are observations with the same name in different modalities
14691473
common_obs = []
@@ -1490,13 +1494,44 @@ def obs_names_make_unique(self):
14901494
def obs_names(self) -> pd.Index:
14911495
"""
14921496
Names of variables (alias for `.obs.index`)
1493-
1494-
This property is read-only.
1495-
To be modified, obs_names of individual modalities
1496-
should be changed, and .update_obs() should be called then.
14971497
"""
14981498
return self.obs.index
14991499

1500+
@obs_names.setter
1501+
def obs_names(self, names: Sequence[str]):
1502+
"""
1503+
Set the observation names for all the nested AnnData/MuData objects.
1504+
"""
1505+
if isinstance(names, pd.Index):
1506+
if not isinstance(names.name, str | type(None)):
1507+
raise ValueError(
1508+
f"MuData expects .obs.index.name to be a string or None, "
1509+
f"but you passed a name of type {type(names.name).__name__!r}"
1510+
)
1511+
else:
1512+
names = pd.Index(names)
1513+
if not isinstance(names.name, str | type(None)):
1514+
names.name = None
1515+
1516+
mod_obs_sum = np.sum([a.n_obs for a in self.mod.values()])
1517+
if mod_obs_sum != self.n_obs:
1518+
self.update_obs()
1519+
1520+
if len(names) != self.n_obs:
1521+
raise ValueError(
1522+
f"The length of provided observation names {len(names)} does not match the length {self.shape[0]} of MuData.obs."
1523+
)
1524+
1525+
if self.is_view:
1526+
self._init_as_actual(self.copy())
1527+
1528+
self._obs.index = names
1529+
for mod, a in self.mod.items():
1530+
indices = self.obsmap[mod]
1531+
self.mod[mod].obs_names = names[indices[indices != 0] - 1]
1532+
1533+
self.update_obs()
1534+
15001535
@property
15011536
def var(self) -> pd.DataFrame:
15021537
"""
@@ -1565,7 +1600,11 @@ def var_names_make_unique(self):
15651600
self.update_var()
15661601

15671602
for k in self.mod:
1568-
self.mod[k].var_names_make_unique()
1603+
if isinstance(self.mod[k], AnnData):
1604+
self.mod[k].var_names_make_unique()
1605+
# Only propagate to individual modalities with shared obs
1606+
elif isinstance(self.mod[k], MuData) and getattr(self.mod[k], 'axis', 0) == 0:
1607+
self.mod[k].var_names_make_unique()
15691608

15701609
# Check if there are variables with the same name in different modalities
15711610
common_vars = []
@@ -1592,13 +1631,44 @@ def var_names_make_unique(self):
15921631
def var_names(self) -> pd.Index:
15931632
"""
15941633
Names of variables (alias for `.var.index`)
1595-
1596-
This property is read-only.
1597-
To be modified, var_names of individual modalities
1598-
should be changed, and .update_var() should be called then.
15991634
"""
16001635
return self.var.index
16011636

1637+
@var_names.setter
1638+
def var_names(self, names: Sequence[str]):
1639+
"""
1640+
Set the variable names for all the nested AnnData/MuData objects.
1641+
"""
1642+
if isinstance(names, pd.Index):
1643+
if not isinstance(names.name, str | type(None)):
1644+
raise ValueError(
1645+
f"MuData expects .var.index.name to be a string or None, "
1646+
f"but you passed a name of type {type(names.name).__name__!r}"
1647+
)
1648+
else:
1649+
names = pd.Index(names)
1650+
if not isinstance(names.name, str | type(None)):
1651+
names.name = None
1652+
1653+
mod_var_sum = np.sum([a.n_vars for a in self.mod.values()])
1654+
if mod_var_sum != self.n_vars:
1655+
self.update_var()
1656+
1657+
if len(names) != self.n_vars:
1658+
raise ValueError(
1659+
f"The length of provided variable names {len(names)} does not match the length {self.shape[0]} of MuData.var."
1660+
)
1661+
1662+
if self.is_view:
1663+
self._init_as_actual(self.copy())
1664+
1665+
self._var.index = names
1666+
for mod, a in self.mod.items():
1667+
indices = self.varmap[mod]
1668+
self.mod[mod].var_names = names[indices[indices != 0] - 1]
1669+
1670+
self.update_var()
1671+
16021672
# Multi-dimensional annotations (.obsm and .varm)
16031673

16041674
@property

0 commit comments

Comments
 (0)