Skip to content

Commit 2eaa318

Browse files
committed
fix dataframe dtype conversion for empty df with non-default index
closes #145
1 parent 8f195de commit 2eaa318

4 files changed

Lines changed: 41 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,23 @@ and this project adheres to [Semantic Versioning][].
88
[keep a changelog]: https://keepachangelog.com/en/1.1.0/
99
[semantic versioning]: https://semver.org/spec/v2.0.0.html
1010

11-
## [0.3.8] (Unreleased)
11+
## [0.4.0] (unreleased)
12+
13+
### Changed
14+
15+
- `update()` no longer automatically pulls obs/var columns from individual modalities by default. Set `mudata.set_options(pull_on_update=true)`
16+
to restore the old behavior. Use `pull_obs/pull_var` and `push_obs/push_var` for more flexibility.
17+
- The settings API has changed. Use e.g. `mudata.settings.pull_on_update = True` instead of `mudata.set_options(pull_on_update=True)` and use
18+
`mudata.settings.override` as context manager for local settings overrides.
19+
20+
## [0.3.8]
1221

1322
### Fixed
1423

1524
- `obs_vector` and `var_vector` once again return Pandas Series objects when appropriate. This fixes
1625
applying `sc.pl.umap` on a MuData object.
26+
- `update` with `pull_on_update != None` works again when run on a MuData object where all modalities have empty `.obs` / `.var` but the global
27+
`.obs` or `.var` is not empty.
1728

1829
## [0.3.7]
1930

@@ -169,6 +180,7 @@ To copy the annotations explicitly, you will need to use `pull_obs()` and/or `pu
169180

170181
Initial `mudata` release with `MuData`, previously a part of the `muon` framework.
171182

183+
[0.4.0]: https://github.com/scverse/mudata/releases/tag/v0.4.0
172184
[0.3.8]: https://github.com/scverse/mudata/releases/tag/v0.3.8
173185
[0.3.7]: https://github.com/scverse/mudata/releases/tag/v0.3.7
174186
[0.3.6]: https://github.com/scverse/mudata/releases/tag/v0.3.6

src/mudata/_core/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,4 @@ def try_convert_dataframe_to_numpy_dtypes(df: pd.DataFrame | Mapping[str, pd.Ser
144144
new_cols = {}
145145
for colname, col in df.items():
146146
new_cols[colname] = try_convert_series_to_numpy_dtype(col)
147-
return pd.DataFrame(new_cols)
147+
return pd.DataFrame(new_cols, index=df.index)

tests/test_pandas_utils.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ def test_try_convert_series_to_numpy_dtype(numpy_dtype, nullable_dtype):
3333

3434

3535
def test_try_convert_dataframe_to_numpy_dtypes():
36-
series = pd.Series(np.arange(10))
36+
idx = pd.Index(np.arange(10)[::-1].astype(str))
37+
series = pd.Series(np.arange(10), index=idx)
3738
df = pd.DataFrame({"numpy": series})
3839

3940
series = series.astype(pd.Int64Dtype())
@@ -45,3 +46,11 @@ def test_try_convert_dataframe_to_numpy_dtypes():
4546
df = try_convert_dataframe_to_numpy_dtypes(df)
4647
assert df["numpy"].dtype == df["nullable"].dtype == np.int64
4748
assert df["nullable_noconvert"].dtype == pd.Int64Dtype()
49+
assert (df.index == idx).all()
50+
51+
52+
def test_try_convert_empty_dataframe_to_numpy_dtypes():
53+
idx = pd.Index(np.arange(10)[::-1].astype(str))
54+
df = pd.DataFrame(index=idx)
55+
df = try_convert_dataframe_to_numpy_dtypes(df)
56+
assert (df.index == idx).all()

tests/test_update.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ def test_update_simple(self, mdata: MuData, axis: Axis):
176176
getattr(mdata, f"{attr}_names")[: mdata["mod1"].shape[axis]] == getattr(mdata["mod1"], f"{attr}_names")
177177
).all()
178178

179+
def test_update_simple_empty_modalities(self, modalities: Mapping[str, AnnData], axis: Axis):
180+
for mod in modalities.values():
181+
mod.obs = pd.DataFrame(index=mod.obs_names)
182+
mod.var = pd.DataFrame(index=mod.var_names)
183+
mdata = MuData(modalities)
184+
185+
old_obsnames = mdata.obs_names
186+
old_varnames = mdata.var_names
187+
188+
mdata.obs["test"] = True
189+
del mdata._obshash
190+
del mdata._varhash
191+
mdata.update() # https://github.com/scverse/mudata/issues/145
192+
193+
assert (old_obsnames == mdata.obs_names).all()
194+
assert (old_varnames == mdata.var_names).all()
195+
179196
def test_update_add_modality(self, rng: np.random.Generator, modalities: Mapping[str, AnnData], axis: Axis):
180197
modnames = list(modalities.keys())
181198
mdata = add_mdata_global_columns(

0 commit comments

Comments
 (0)