Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Release Notes
-------------

### Version 1.4.5 (future)
* Fix: pandas 3 compatibility. Under pandas 3 (mandatory Copy-on-Write) `DataFrame.values` returns a read-only view, so several in-place mutations raised `ValueError: assignment destination is read-only`. `run_palantir` failed in `_differentiation_entropy` (terminal-state identity block, now built with `np.eye(...)`), and `select_branch_cells` failed on its NaN fill of the fate-probability array (now copied before mutation). Compatible with both pandas 2 and 3 ([#180](https://github.com/dpeerlab/Palantir/issues/180)).
* Use `numpy.random.Generator` in place of the legacy global `numpy.random.RandomState` and require
`numpy>=1.17`. Note that since the default PRNG is now [PCG64](https://numpy.org/devdocs/reference/random/bit_generators/pcg64.html) instead of the Mersenne Twister, numerical outputs are expected to differ from
those in previous versions. If exact reproducibility is required, users should pin the relevant prior version.
Expand Down
14 changes: 10 additions & 4 deletions src/palantir/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,11 @@ def _differentiation_entropy(
Q = T[trans_states, :][:, trans_states]
if len(trans_states) == 0:
ent = pd.Series(0, index=terminal_states)
bp = pd.DataFrame(0, index=terminal_states, columns=terminal_states)
bp.values[range(len(terminal_states)), range(len(terminal_states))] = 1
bp = pd.DataFrame(
np.eye(len(terminal_states)),
index=terminal_states,
columns=terminal_states,
)
return ent, bp

# Fundamental matrix solver
Expand Down Expand Up @@ -761,8 +764,11 @@ def _differentiation_entropy(

# Add terminal states
ent = pd.concat([ent, pd.Series(0, index=terminal_states)])
bp = pd.DataFrame(0, index=terminal_states, columns=terminal_states)
bp.values[range(len(terminal_states)), range(len(terminal_states))] = 1
bp = pd.DataFrame(
np.eye(len(terminal_states)),
index=terminal_states,
columns=terminal_states,
)
branch_probs = pd.concat([branch_probs, bp.loc[:, branch_probs.columns]])

return ent, branch_probs
Expand Down
6 changes: 5 additions & 1 deletion src/palantir/presults.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ def cluster_gene_trends(
columns=trends.columns,
)

gt_ad = AnnData(trends.values, dtype=np.float32)
gt_ad = AnnData(trends.values.astype(np.float32))
sc.pp.neighbors(gt_ad, n_neighbors=n_neighbors, use_rep="X")

# Add required kwargs for leiden with igraph backend to avoid FutureWarning
Expand Down Expand Up @@ -604,6 +604,10 @@ def select_branch_cells(
fate_probs, fate_names = _validate_obsm_key(ad, fate_prob_key, as_df=False)
pseudotime = ad.obs[pseudo_time_key].values

# Own the array before the in-place NaN fill: when obsm holds a DataFrame,
# _validate_obsm_key returns a .values view that is read-only under pandas 3
# (mandatory Copy-on-Write).
fate_probs = fate_probs.copy()
fate_probs[np.isnan(fate_probs)] = 1 / fate_probs.shape[1]

idx = np.argsort(pseudotime)
Expand Down
Loading