Scanpy: Finding a better home for cluster centroids (i.e. 馃毇_tmp_cluster_pos)

Created on 29 Nov 2019  路  4Comments  路  Source: theislab/scanpy

We have a weird temporary global variable called sc.pl._utils._tmp_cluster_pos. We use it for storing the positions of cluster centroids (actually the centroids of any categorical variable for any sort of embedding). The weird part is that it's set in scatterplot functions (see https://github.com/theislab/scanpy/blob/master/scanpy/plotting/_anndata.py#L468 and https://github.com/theislab/scanpy/blob/master/scanpy/plotting/_tools/scatterplots.py#L809) and used only by sc.pl.paga_compare (https://github.com/theislab/scanpy/blob/master/scanpy/plotting/_tools/paga.py#L119).

First, it's not obvious where paga_compare finds centroids (it was a mystery to me until recently). Second, the current design is error-prone (see a corner case https://github.com/theislab/scanpy/issues/686). Therefore, there should be a better place to store cluster centroids :)

I'm not following the discussion about the future of AnnData, but maybe having something like adata.uns['obs_category_leiden'] and storing colors and centroids in it e.g. adata.uns['obs_category_leiden']['colors'] and adata.uns['obs_category_leiden']['centroids']['X_umap'] would be more structured.

enhancement

Most helpful comment

I just needed to use centroids for some plotting, and found a pretty straightforward solution. This function will add labels to the centroids of each cluster, but uses adjustText so they don't overlap:

def gen_mpl_labels(adata, groupby, exclude=()):
    medians = {}

    for g, g_idx in adata.obs.groupby(groupby).groups.items():
        if g in exclude:
            continue
        medians[g] = np.median(adata[g_idx].obsm["X_umap"], axis=0)

    texts = [plt.text(x=x, y=y, s=k) for k, (x, y) in medians.items()]
    adjust_text(texts, text_from_points=False)

All 4 comments

What if we didn't store it by default, and just computed it on the fly? It doesn't seem like it would be particularly computationally expensive.

Suffering from a similar issue, in my case the on data export is not working at all. Although the positions are stored in sc.pl._utils._tmp_cluster_pos, but https://github.com/theislab/scanpy/blob/master/scanpy/plotting/_anndata.py#L471:L475 is not working and there is no pos.csv created.

I just needed to use centroids for some plotting, and found a pretty straightforward solution. This function will add labels to the centroids of each cluster, but uses adjustText so they don't overlap:

def gen_mpl_labels(adata, groupby, exclude=()):
    medians = {}

    for g, g_idx in adata.obs.groupby(groupby).groups.items():
        if g in exclude:
            continue
        medians[g] = np.median(adata[g_idx].obsm["X_umap"], axis=0)

    texts = [plt.text(x=x, y=y, s=k) for k, (x, y) in medians.items()]
    adjust_text(texts, text_from_points=False)

@ivirshup This should be added to the embedding code

Was this page helpful?
0 / 5 - 0 ratings

Related issues

falexwolf picture falexwolf  路  4Comments

jhu99 picture jhu99  路  6Comments

naity picture naity  路  5Comments

wflynny picture wflynny  路  6Comments

tkisss picture tkisss  路  5Comments