diff --git a/CHANGES.md b/CHANGES.md index 5c466d6..91c6ffb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,11 @@ ## [Upcoming release](https://github.com/open2c/bioframe/compare/v0.8.0...HEAD) +Bug fixes: + +- `assign_view(..., drop_unassigned=True)` now drops only intervals that fall outside the view, + instead of also dropping rows that contain NaNs in unrelated columns. + ## v0.8.0 Date: 2025-04-08 diff --git a/src/bioframe/ops.py b/src/bioframe/ops.py index 934603d..82cab56 100644 --- a/src/bioframe/ops.py +++ b/src/bioframe/ops.py @@ -1893,7 +1893,9 @@ def assign_view( out_df.rename(columns={view_name_col + "_view": df_view_col}, inplace=True) if drop_unassigned: - out_df = out_df.iloc[pd.isna(out_df).any(axis=1).values == 0, :] + # only drop intervals that weren't assigned to a view region, not rows + # that happen to contain NaNs in other columns + out_df = out_df[pd.notna(out_df[df_view_col]).values] out_df.reset_index(inplace=True, drop=True) return_cols = [*list(df.columns), df_view_col] diff --git a/tests/test_ops.py b/tests/test_ops.py index 66c0fd2..f0f662d 100644 --- a/tests/test_ops.py +++ b/tests/test_ops.py @@ -2289,3 +2289,24 @@ def test_sort_bedframe(): assert ( df.dtypes == bioframe.sort_bedframe(df, view_df, view_name_col="fruit").dtypes ).all() + + +def test_assign_view_drop_unassigned_keeps_nan_in_other_columns(): + # drop_unassigned should only drop intervals that fall outside the view, not + # intervals that merely contain NaNs in unrelated columns (e.g. cooler bins with + # missing weights). See open2c/bioframe#160. + view_df = bioframe.make_viewframe([("chr1", 0, 100, "region1")]) + df = pd.DataFrame( + { + "chrom": ["chr1", "chr1", "chr2"], + "start": [10, 30, 10], + "end": [20, 40, 20], + "value": [np.nan, 5.0, 7.0], + } + ) + result = bioframe.assign_view(df, view_df, drop_unassigned=True) + + # chr2:10-20 is outside the view and dropped; chr1:10-20 is assigned and kept + # even though its `value` is NaN. + assert list(zip(result["chrom"], result["start"])) == [("chr1", 10), ("chr1", 30)] + assert pd.isna(result.loc[0, "value"])