import%20marimo%0A%0A__generated_with%20%3D%20%220.20.4%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20rctd-py%20Tutorial%0A%0A%20%20%20%20**GPU-accelerated%20spatial%20transcriptomics%20deconvolution%20using%20RCTD%20(Robust%20Cell%20Type%20Decomposition).**%0A%0A%20%20%20%20This%20notebook%20demonstrates%20an%20end-to-end%20RCTD%20workflow%20using%20the%20same%20**Slide-seq%20cerebellum**%20dataset%20from%20the%20%5Boriginal%20spacexr%20vignette%5D(https%3A%2F%2Fraw.githack.com%2Fdmcable%2Fspacexr%2Fmaster%2Fvignettes%2Fspatial-transcriptomics.html)%3A%0A%20%20%20%20loading%20real%20single-cell%20reference%20and%20spatial%20data%2C%20building%20a%20%60Reference%60%20object%2C%20running%20RCTD%0A%20%20%20%20in%20all%20three%20modes%20(full%2C%20doublet%2C%20multi)%2C%20and%20interpreting%20the%20results.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Installation%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20pip%20install%20rctd-py%20%20%20%23%20CPU%20(works%20everywhere%3B%20GPU%20auto-detected%20if%20CUDA%20available)%0A%20%20%20%20%60%60%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20io%0A%20%20%20%20import%20time%0A%20%20%20%20import%20urllib.request%0A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20anndata%0A%0A%20%20%20%20from%20rctd%20import%20Reference%2C%20run_rctd%2C%20RCTDConfig%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20RCTDConfig%2C%0A%20%20%20%20%20%20%20%20Reference%2C%0A%20%20%20%20%20%20%20%20anndata%2C%0A%20%20%20%20%20%20%20%20io%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20pd%2C%0A%20%20%20%20%20%20%20%20plt%2C%0A%20%20%20%20%20%20%20%20run_rctd%2C%0A%20%20%20%20%20%20%20%20time%2C%0A%20%20%20%20%20%20%20%20urllib%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Download%20the%20spacexr%20Vignette%20Data%0A%0A%20%20%20%20We%20use%20the%20exact%20same%20cerebellum%20data%20bundled%20with%20the%20R%20%5Bspacexr%5D(https%3A%2F%2Fgithub.com%2Fdmcable%2Fspacexr)%20package%3A%0A%20%20%20%20-%20**Reference**%3A%20475%20single-cell%20RNA-seq%20profiles%20across%2019%20cerebellar%20cell%20types%0A%20%20%20%20-%20**Spatial**%3A%20100%20Slide-seq%20beads%20from%20mouse%20cerebellum%0A%0A%20%20%20%20The%20data%20is%20small%20(~500%20KB)%20and%20downloaded%20directly%20from%20the%20spacexr%20GitHub%20repository.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(io%2C%20pd%2C%20urllib)%3A%0A%20%20%20%20BASE%20%3D%20%22https%3A%2F%2Fraw.githubusercontent.com%2Fdmcable%2Fspacexr%2Fmaster%2Finst%2Fextdata%22%0A%0A%20%20%20%20def%20fetch_csv(url)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Download%20a%20CSV%20from%20URL%20and%20return%20as%20pandas%20DataFrame.%22%22%22%0A%20%20%20%20%20%20%20%20with%20urllib.request.urlopen(url)%20as%20resp%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20pd.read_csv(io.BytesIO(resp.read()))%0A%0A%20%20%20%20%23%20Reference%20data%0A%20%20%20%20ref_dge%20%3D%20fetch_csv(f%22%7BBASE%7D%2FReference%2FVignette%2Fdge.csv%22)%0A%20%20%20%20ref_meta%20%3D%20fetch_csv(f%22%7BBASE%7D%2FReference%2FVignette%2Fmeta_data.csv%22)%0A%20%20%20%20cell_type_dict%20%3D%20fetch_csv(f%22%7BBASE%7D%2FReference%2FVignette%2Fcell_type_dict.csv%22)%0A%0A%20%20%20%20%23%20Spatial%20data%0A%20%20%20%20spatial_dge%20%3D%20fetch_csv(f%22%7BBASE%7D%2FSpatialRNA%2FVignette%2FMappedDGEForR.csv%22)%0A%20%20%20%20bead_locs%20%3D%20fetch_csv(f%22%7BBASE%7D%2FSpatialRNA%2FVignette%2FBeadLocationsForR.csv%22)%0A%0A%20%20%20%20print(%22Downloaded%20all%20files.%22)%0A%20%20%20%20print(f%22Reference%20DGE%3A%20%7Bref_dge.shape%7D%22)%0A%20%20%20%20print(f%22Spatial%20DGE%3A%20%7Bspatial_dge.shape%7D%22)%0A%20%20%20%20print(f%22Bead%20locations%3A%20%7Bbead_locs.shape%7D%22)%0A%20%20%20%20return%20bead_locs%2C%20cell_type_dict%2C%20ref_dge%2C%20ref_meta%2C%20spatial_dge%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%202.%20Prepare%20AnnData%20Objects%0A%0A%20%20%20%20Convert%20the%20spacexr%20CSV%20format%20(genes%20%C3%97%20cells)%20into%20AnnData%20objects%20(cells%20%C3%97%20genes)%0A%20%20%20%20that%20%60rctd-py%60%20expects.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(anndata%2C%20cell_type_dict%2C%20np%2C%20pd%2C%20ref_dge%2C%20ref_meta)%3A%0A%20%20%20%20%23%20---%20Build%20reference%20AnnData%20---%0A%20%20%20%20%23%20dge.csv%3A%20first%20column%20is%20gene%20names%2C%20remaining%20columns%20are%20cell%20barcodes%0A%20%20%20%20gene_names%20%3D%20ref_dge.iloc%5B%3A%2C%200%5D.values%0A%20%20%20%20_counts%20%3D%20ref_dge.iloc%5B%3A%2C%201%3A%5D.values.T.astype(np.float32)%20%20%23%20cells%20%C3%97%20genes%0A%20%20%20%20cell_barcodes%20%3D%20ref_dge.columns%5B1%3A%5D.values%0A%20%20%20%20cluster_to_name%20%3D%20dict(zip(cell_type_dict%5B'Cluster'%5D%2C%20cell_type_dict%5B'Name'%5D))%0A%20%20%20%20%23%20Map%20cluster%20numbers%20to%20cell%20type%20names%0A%20%20%20%20ref_meta_indexed%20%3D%20ref_meta.set_index('barcode')%0A%20%20%20%20cell_types%20%3D%20%5Bcluster_to_name%5Bref_meta_indexed.loc%5Bbc%2C%20'cluster'%5D%5D%20for%20bc%20in%20cell_barcodes%5D%0A%20%20%20%20ref_adata%20%3D%20anndata.AnnData(X%3D_counts%2C%20obs%3Dpd.DataFrame(%7B'cell_type'%3A%20cell_types%7D%2C%20index%3Dcell_barcodes))%0A%20%20%20%20ref_adata.var_names%20%3D%20pd.Index(gene_names)%0A%20%20%20%20print(f'Reference%3A%20%7Bref_adata.n_obs%7D%20cells%20%C3%97%20%7Bref_adata.n_vars%7D%20genes')%0A%20%20%20%20print(f'Cell%20types%20(%7Blen(set(cell_types))%7D)%3A%20%7Bsorted(set(cell_types))%7D')%0A%20%20%20%20return%20(ref_adata%2C)%0A%0A%0A%40app.cell%0Adef%20_(anndata%2C%20bead_locs%2C%20np%2C%20pd%2C%20spatial_dge)%3A%0A%20%20%20%20%23%20---%20Build%20spatial%20AnnData%20---%0A%20%20%20%20%23%20MappedDGEForR.csv%3A%20first%20column%20is%20gene%20names%2C%20remaining%20are%20bead%20barcodes%0A%20%20%20%20sp_gene_names%20%3D%20spatial_dge.iloc%5B%3A%2C%200%5D.values%0A%20%20%20%20sp_counts%20%3D%20spatial_dge.iloc%5B%3A%2C%201%3A%5D.values.T.astype(np.float32)%20%20%23%20beads%20%C3%97%20genes%0A%20%20%20%20sp_barcodes%20%3D%20spatial_dge.columns%5B1%3A%5D.values%0A%0A%20%20%20%20%23%20Bead%20coordinates%0A%20%20%20%20locs%20%3D%20bead_locs.set_index(%22barcodes%22)%0A%0A%20%20%20%20spatial_adata%20%3D%20anndata.AnnData(%0A%20%20%20%20%20%20%20%20X%3Dsp_counts%2C%0A%20%20%20%20%20%20%20%20obs%3Dpd.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%22x%22%3A%20locs.loc%5Bsp_barcodes%2C%20%22xcoord%22%5D.values%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%22y%22%3A%20locs.loc%5Bsp_barcodes%2C%20%22ycoord%22%5D.values%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20index%3Dsp_barcodes%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20)%0A%20%20%20%20spatial_adata.var_names%20%3D%20pd.Index(sp_gene_names)%0A%0A%20%20%20%20print(f%22Spatial%3A%20%7Bspatial_adata.n_obs%7D%20beads%20%C3%97%20%7Bspatial_adata.n_vars%7D%20genes%22)%0A%20%20%20%20return%20(spatial_adata%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20Build%20Reference%0A%0A%20%20%20%20The%20%60Reference%60%20class%20takes%20a%20single-cell%20%60AnnData%60%20object%20and%20computes%20per-type%0A%20%20%20%20expression%20profiles%20(mean%20UMI-normalized%20counts).%20Specify%20the%20%60cell_type_col%60%0A%20%20%20%20parameter%20to%20point%20to%20the%20column%20in%20%60.obs%60%20that%20holds%20cell%20type%20labels.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Reference%2C%20ref_adata)%3A%0A%20%20%20%20reference%20%3D%20Reference(ref_adata%2C%20cell_type_col%3D%22cell_type%22)%0A%20%20%20%20print(f%22Reference%20profiles%3A%20%7Breference.profiles.shape%7D%22)%0A%20%20%20%20print(f%22Cell%20types%3A%20%7Breference.cell_type_names%7D%22)%0A%20%20%20%20return%20(reference%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20Run%20RCTD%0A%0A%20%20%20%20RCTD%20supports%20three%20deconvolution%20modes%3A%0A%0A%20%20%20%20%7C%20Mode%20%7C%20Description%20%7C%20Best%20for%20%7C%0A%20%20%20%20%7C------%7C-------------%7C----------%7C%0A%20%20%20%20%7C%20%60full%60%20%7C%20Estimates%20continuous%20weights%20for%20all%20cell%20types%20simultaneously%20%7C%20Visium%2C%20continuous%20mixtures%20%7C%0A%20%20%20%20%7C%20%60doublet%60%20%7C%20Classifies%20each%20bead%20as%20singlet%20or%20doublet%2C%20assigns%201%E2%80%932%20types%20%7C%20Slide-seq%2C%20sparse%20spatial%20%7C%0A%20%20%20%20%7C%20%60multi%60%20%7C%20Greedy%20forward%20selection%20of%20up%20to%204%20cell%20types%20per%20bead%20%7C%20Xenium%2C%20MERFISH%2C%20dense%20platforms%20%7C%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Doublet%20Mode%20(default%20for%20Slide-seq)%0A%0A%20%20%20%20This%20is%20the%20mode%20used%20in%20the%20original%20spacexr%20vignette.%20It%20classifies%20each%20bead%20as%0A%20%20%20%20a%20singlet%20(one%20dominant%20cell%20type)%20or%20doublet%20(two%20cell%20types).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20rctd%20import%20SPOT_CLASS_NAMES%0A%0A%20%20%20%20class_labels%20%3D%20dict(enumerate(SPOT_CLASS_NAMES))%0A%20%20%20%20return%20(class_labels%2C)%0A%0A%0A%40app.cell%0Adef%20_(RCTDConfig%2C%20class_labels%2C%20np%2C%20reference%2C%20run_rctd%2C%20spatial_adata%2C%20time)%3A%0A%20%20%20%20%23%20Use%20UMI_min%3D1%20for%20this%20small%20tutorial%20dataset%20to%20keep%20all%20beads%0A%20%20%20%20_config%20%3D%20RCTDConfig(UMI_min%3D1%2C%20UMI_min_sigma%3D1)%0A%20%20%20%20_t0%20%3D%20time.time()%0A%20%20%20%20result_doublet%20%3D%20run_rctd(spatial_adata%2C%20reference%2C%20mode%3D'doublet'%2C%20config%3D_config)%0A%20%20%20%20t_doublet%20%3D%20time.time()%20-%20_t0%0A%20%20%20%20print(f'Doublet%20mode%3A%20%7Bt_doublet%3A.1f%7Ds')%0A%20%20%20%20classes%2C%20_counts%20%3D%20np.unique(result_doublet.spot_class%2C%20return_counts%3DTrue)%0A%20%20%20%20for%20cl%2C%20ct%20in%20zip(classes%2C%20_counts)%3A%0A%20%20%20%20%20%20%20%20print(f'%20%20%7Bclass_labels.get(cl%2C%20cl)%7D%3A%20%7Bct%7D')%0A%20%20%20%20return%20result_doublet%2C%20t_doublet%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Full%20Mode%0A%0A%20%20%20%20Estimates%20a%20continuous%20weight%20vector%20over%20all%20cell%20types%20for%20every%20bead.%0A%20%20%20%20Most%20flexible%20%E2%80%94%20recommended%20when%20beads%20may%20contain%20mixtures%20of%20more%20than%20two%20types.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(RCTDConfig%2C%20reference%2C%20run_rctd%2C%20spatial_adata%2C%20time)%3A%0A%20%20%20%20_config%20%3D%20RCTDConfig(UMI_min%3D1%2C%20UMI_min_sigma%3D1)%0A%20%20%20%20_t0%20%3D%20time.time()%0A%20%20%20%20result_full%20%3D%20run_rctd(spatial_adata%2C%20reference%2C%20mode%3D'full'%2C%20config%3D_config)%0A%20%20%20%20t_full%20%3D%20time.time()%20-%20_t0%0A%20%20%20%20print(f'Full%20mode%3A%20%7Bt_full%3A.1f%7Ds')%0A%20%20%20%20print(f'Weights%20shape%3A%20%7Bresult_full.weights.shape%7D')%0A%20%20%20%20print(f'Converged%3A%20%7Bresult_full.converged.sum()%7D%2F%7Blen(result_full.converged)%7D%20beads')%0A%20%20%20%20return%20result_full%2C%20t_full%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Multi%20Mode%0A%0A%20%20%20%20Greedy%20forward%20selection%2C%20adding%20cell%20types%20one%20at%20a%20time%20until%20adding%20another%0A%20%20%20%20no%20longer%20improves%20the%20fit.%20Max%20types%20per%20bead%20controlled%20by%20%60RCTDConfig.MAX_MULTI_TYPES%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(RCTDConfig%2C%20reference%2C%20run_rctd%2C%20spatial_adata%2C%20time)%3A%0A%20%20%20%20_config%20%3D%20RCTDConfig(UMI_min%3D1%2C%20UMI_min_sigma%3D1)%0A%20%20%20%20_t0%20%3D%20time.time()%0A%20%20%20%20result_multi%20%3D%20run_rctd(spatial_adata%2C%20reference%2C%20mode%3D'multi'%2C%20config%3D_config)%0A%20%20%20%20t_multi%20%3D%20time.time()%20-%20_t0%0A%20%20%20%20print(f'Multi%20mode%3A%20%7Bt_multi%3A.1f%7Ds')%0A%20%20%20%20print(f'Types%20per%20bead%3A%20min%3D%7Bresult_multi.n_types.min()%7D%2C%20max%3D%7Bresult_multi.n_types.max()%7D')%0A%20%20%20%20return%20result_multi%2C%20t_multi%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%205.%20Interpreting%20Results%0A%0A%20%20%20%20The%20%60result_full.weights%60%20matrix%20has%20shape%20%60(n_beads%2C%20n_types)%60.%20Each%20row%0A%20%20%20%20sums%20to%201%20and%20represents%20the%20estimated%20cell%20type%20composition%20of%20that%20bead.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20reference%2C%20result_full)%3A%0A%20%20%20%20%23%20Dominant%20cell%20type%20per%20bead%20(full%20mode)%0A%20%20%20%20cell_type_names%20%3D%20reference.cell_type_names%0A%20%20%20%20dominant_idx%20%3D%20np.argmax(result_full.weights%2C%20axis%3D1)%0A%20%20%20%20dominant_names%20%3D%20%5Bcell_type_names%5B_i%5D%20for%20_i%20in%20dominant_idx%5D%0A%20%20%20%20print('Weight%20statistics%20per%20cell%20type%20(full%20mode)%3A')%0A%20%20%20%20%23%20Weight%20statistics%0A%20%20%20%20for%20_i%2C%20name%20in%20enumerate(cell_type_names)%3A%0A%20%20%20%20%20%20%20%20w%20%3D%20result_full.weights%5B%3A%2C%20_i%5D%0A%20%20%20%20%20%20%20%20if%20w.max()%20%3E%200.01%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(f'%20%20%7Bname%3A20s%7D%3A%20mean%3D%7Bw.mean()%3A.3f%7D%2C%20max%3D%7Bw.max()%3A.3f%7D')%0A%20%20%20%20return%20cell_type_names%2C%20dominant_idx%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%206.%20Visualization%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cell_type_names%2C%20plt%2C%20spatial_adata%2C%20t_doublet%2C%20t_full%2C%20t_multi)%3A%0A%20%20%20%20%23%20---%20Plot%201%3A%20Runtime%20comparison%20---%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(6%2C%203))%0A%20%20%20%20modes%20%3D%20%5B'full'%2C%20'doublet'%2C%20'multi'%5D%0A%20%20%20%20times%20%3D%20%5Bt_full%2C%20t_doublet%2C%20t_multi%5D%0A%20%20%20%20colors%20%3D%20%5B'%234C78A8'%2C%20'%23F58518'%2C%20'%2354A24B'%5D%0A%20%20%20%20bars%20%3D%20_ax.barh(modes%2C%20times%2C%20color%3Dcolors%2C%20edgecolor%3D'white'%2C%20height%3D0.5)%0A%20%20%20%20_ax.bar_label(bars%2C%20fmt%3D'%25.1fs'%2C%20padding%3D4%2C%20fontsize%3D10)%0A%20%20%20%20_ax.set_xlabel('Time%20(seconds)')%0A%20%20%20%20n_beads%20%3D%20spatial_adata.n_obs%0A%20%20%20%20n_genes%20%3D%20spatial_adata.n_vars%0A%20%20%20%20n_types%20%3D%20len(cell_type_names)%0A%20%20%20%20_ax.set_title(f'RCTD%20Runtime%20by%20Mode%5Cn(%7Bn_beads%7D%20beads%2C%20%7Bn_genes%7D%20genes%2C%20%7Bn_types%7D%20cell%20types)')%0A%20%20%20%20_ax.set_xlim(0%2C%20max(times)%20*%201.35)%0A%20%20%20%20_ax.spines%5B%5B'top'%2C%20'right'%5D%5D.set_visible(False)%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Spatial%20Maps%0A%0A%20%20%20%20Each%20panel%20shows%20the%20Slide-seq%20beads%20colored%20by%20the%20RCTD%20result%20for%20that%20mode.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20cell_type_names%2C%0A%20%20%20%20class_labels%2C%0A%20%20%20%20dominant_idx%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20result_doublet%2C%0A%20%20%20%20result_multi%2C%0A%20%20%20%20spatial_adata%2C%0A)%3A%0A%20%20%20%20_fig%2C%20axes%20%3D%20plt.subplots(1%2C%203%2C%20figsize%3D(16%2C%205))%0A%20%20%20%20x%20%3D%20spatial_adata.obs%5B'x'%5D.values%0A%20%20%20%20y%20%3D%20spatial_adata.obs%5B'y'%5D.values%0A%20%20%20%20cmap%20%3D%20plt.cm.get_cmap('tab20'%2C%20len(cell_type_names))%0A%20%20%20%20sc%20%3D%20axes%5B0%5D.scatter(x%2C%20y%2C%20c%3Ddominant_idx%2C%20cmap%3Dcmap%2C%20vmin%3D-0.5%2C%20vmax%3Dlen(cell_type_names)%20-%200.5%2C%20s%3D30%2C%20alpha%3D0.9%2C%20edgecolors%3D'none')%0A%20%20%20%20axes%5B0%5D.set_title('Full%20mode%5Cn(dominant%20cell%20type)')%0A%20%20%20%20axes%5B0%5D.set_aspect('equal')%0A%20%20%20%20axes%5B0%5D.set_xlabel('x')%0A%20%20%20%20axes%5B0%5D.set_ylabel('y')%0A%20%20%20%20_class_colors%20%3D%20%7B0%3A%20'%23888888'%2C%201%3A%20'%234C78A8'%2C%202%3A%20'%23F58518'%2C%203%3A%20'%23E45756'%7D%0A%20%20%20%20for%20_cls%2C%20color%20in%20_class_colors.items()%3A%0A%20%20%20%20%20%20%20%20mask%20%3D%20result_doublet.spot_class%20%3D%3D%20_cls%0A%20%20%20%20%20%20%20%20if%20mask.any()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5B1%5D.scatter(x%5Bmask%5D%2C%20y%5Bmask%5D%2C%20c%3Dcolor%2C%20s%3D30%2C%20alpha%3D0.9%2C%20edgecolors%3D'none'%2C%20label%3Dclass_labels%5B_cls%5D)%0A%20%20%20%20axes%5B1%5D.set_title('Doublet%20mode%5Cn(spot%20class)')%0A%20%20%20%20axes%5B1%5D.set_aspect('equal')%0A%20%20%20%20axes%5B1%5D.set_xlabel('x')%0A%20%20%20%20axes%5B1%5D.legend(fontsize%3D8%2C%20markerscale%3D1.2%2C%20loc%3D'upper%20right')%0A%20%20%20%20sc2%20%3D%20axes%5B2%5D.scatter(x%2C%20y%2C%20c%3Dresult_multi.n_types%2C%20cmap%3D'viridis'%2C%20vmin%3D0.5%2C%20vmax%3D4.5%2C%20s%3D30%2C%20alpha%3D0.9%2C%20edgecolors%3D'none')%0A%20%20%20%20axes%5B2%5D.set_title('Multi%20mode%5Cn(%23%20cell%20types%20per%20bead)')%0A%20%20%20%20axes%5B2%5D.set_aspect('equal')%0A%20%20%20%20axes%5B2%5D.set_xlabel('x')%0A%20%20%20%20plt.colorbar(sc2%2C%20ax%3Daxes%5B2%5D%2C%20ticks%3D%5B1%2C%202%2C%203%2C%204%5D%2C%20label%3D'%23%20types')%0A%20%20%20%20plt.suptitle('RCTD%20Spatial%20Deconvolution%20%E2%80%94%20Slide-seq%20Cerebellum'%2C%20fontsize%3D13%2C%20y%3D1.01)%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Weight%20Heatmap%0A%0A%20%20%20%20Full-mode%20weights%20across%20all%20beads%2C%20showing%20the%20estimated%20proportion%20of%20each%20cell%20type.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cell_type_names%2C%20dominant_idx%2C%20np%2C%20plt%2C%20result_full)%3A%0A%20%20%20%20%23%20---%20Plot%203%3A%20Weight%20heatmap%20(full%20mode%2C%20top%20cell%20types)%20---%0A%20%20%20%20%23%20Sort%20beads%20by%20dominant%20type%20for%20cleaner%20visualization%0A%20%20%20%20order%20%3D%20np.lexsort((result_full.weights.max(axis%3D1)%2C%20dominant_idx))%0A%20%20%20%20active_mask%20%3D%20result_full.weights.mean(axis%3D0)%20%3E%200.01%0A%20%20%20%20%23%20Show%20only%20cell%20types%20with%20mean%20weight%20%3E%201%25%0A%20%20%20%20active_names%20%3D%20%5Bcell_type_names%5B_i%5D%20for%20_i%20in%20range(len(cell_type_names))%20if%20active_mask%5B_i%5D%5D%0A%20%20%20%20active_weights%20%3D%20result_full.weights%5Border%5D%5B%3A%2C%20active_mask%5D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(10%2C%205))%0A%20%20%20%20im%20%3D%20_ax.imshow(active_weights.T%2C%20aspect%3D'auto'%2C%20cmap%3D'YlOrRd'%2C%20vmin%3D0%2C%20vmax%3D1)%0A%20%20%20%20_ax.set_yticks(range(len(active_names)))%0A%20%20%20%20_ax.set_yticklabels(active_names%2C%20fontsize%3D9)%0A%20%20%20%20_ax.set_xlabel('Beads%20(sorted%20by%20dominant%20type)')%0A%20%20%20%20_ax.set_title('Full%20Mode%20%E2%80%94%20Cell%20Type%20Weights%20per%20Bead')%0A%20%20%20%20plt.colorbar(im%2C%20ax%3D_ax%2C%20label%3D'Weight'%2C%20shrink%3D0.8)%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Doublet%20Mode%20Details%0A%0A%20%20%20%20For%20each%20bead%20classified%20as%20a%20doublet%2C%20RCTD%20identifies%20the%20two%20most%20likely%0A%20%20%20%20cell%20types%20and%20their%20proportions.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cell_type_names%2C%20class_labels%2C%20result_doublet%2C%20spatial_adata)%3A%0A%20%20%20%20first_names%20%3D%20%5Bcell_type_names%5B_i%5D%20for%20_i%20in%20result_doublet.first_type%5D%0A%20%20%20%20second_names%20%3D%20%5Bcell_type_names%5B_i%5D%20for%20_i%20in%20result_doublet.second_type%5D%0A%20%20%20%20print('Doublet%20mode%20%E2%80%94%20first%2010%20beads%3A')%0A%20%20%20%20print(f%22%7B'Bead'%3A%3C20s%7D%20%7B'Class'%3A%3C22s%7D%20%7B'Type%201'%3A%3C18s%7D%20%7B'Type%202'%3A%3C18s%7D%20%7B'Weight%201'%3A%3E8s%7D%20%7B'Weight%202'%3A%3E8s%7D%22)%0A%20%20%20%20print('-'%20*%2096)%0A%20%20%20%20for%20_i%20in%20range(min(10%2C%20len(first_names)))%3A%0A%20%20%20%20%20%20%20%20_cls%20%3D%20class_labels.get(int(result_doublet.spot_class%5B_i%5D)%2C%20'%3F')%0A%20%20%20%20%20%20%20%20w1%20%3D%20result_doublet.weights_doublet%5B_i%2C%200%5D%0A%20%20%20%20%20%20%20%20w2%20%3D%20result_doublet.weights_doublet%5B_i%2C%201%5D%0A%20%20%20%20%20%20%20%20print(f'%7Bspatial_adata.obs_names%5B_i%5D%3A%3C20s%7D%20%7B_cls%3A%3C22s%7D%20%7Bfirst_names%5B_i%5D%3A%3C18s%7D%20%7Bsecond_names%5B_i%5D%3A%3C18s%7D%20%7Bw1%3A%3E8.3f%7D%20%7Bw2%3A%3E8.3f%7D')%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%207.%20Configuration%0A%0A%20%20%20%20%60RCTDConfig%60%20controls%20all%20algorithm%20hyperparameters%3A%0A%0A%20%20%20%20%7C%20Parameter%20%7C%20Default%20%7C%20Description%20%7C%0A%20%20%20%20%7C-----------%7C---------%7C-------------%7C%0A%20%20%20%20%7C%20%60UMI_min%60%20%7C%20100%20%7C%20Minimum%20UMI%20count%20to%20include%20a%20bead%20%7C%0A%20%20%20%20%7C%20%60N_fit%60%20%7C%201000%20%7C%20Number%20of%20beads%20used%20to%20estimate%20sigma%20%7C%0A%20%20%20%20%7C%20%60MAX_MULTI_TYPES%60%20%7C%204%20%7C%20Max%20cell%20types%20per%20bead%20in%20multi%20mode%20%7C%0A%20%20%20%20%7C%20%60max_iter%60%20%7C%2050%20%7C%20Maximum%20IRWLS%20iterations%20%7C%0A%20%20%20%20%7C%20%60doublet_mode_alpha%60%20%7C%200.01%20%7C%20Regularization%20strength%20in%20doublet%20mode%20%7C%0A%0A%20%20%20%20The%20%60batch_size%60%20argument%20to%20%60run_rctd%60%20controls%20how%20many%20beads%20are%20processed%0A%20%20%20%20per%20GPU%20kernel%20launch.%20Larger%20values%20use%20more%20VRAM%20but%20may%20be%20faster.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(RCTDConfig%2C%20reference%2C%20run_rctd%2C%20spatial_adata)%3A%0A%20%20%20%20%23%20Custom%20configuration%20example%0A%20%20%20%20_config%20%3D%20RCTDConfig(UMI_min%3D100%2C%20N_fit%3D1000%2C%20MAX_MULTI_TYPES%3D4%2C%20max_iter%3D50)%0A%20%20%20%20result%20%3D%20run_rctd(spatial_adata%2C%20reference%2C%20mode%3D'full'%2C%20config%3D_config%2C%20batch_size%3D5000)%0A%20%20%20%20print(f'Custom%20run%3A%20%7Bresult.weights.shape%7D')%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
397d8ebe0ffc8a6a711b94e86b2b7f4a