# Python Integration with anndataR

# Introduction

anndataR works with Python `AnnData` objects through reticulate. You can load Python objects, apply Python functions to them, and convert them to `Seurat` or `SingleCellExperiment` objects.

    message(
      "Python packages scanpy and mudata are required to run this vignette. Code chunks will not be evaluated."
    )

## Prerequisites

This vignette requires Python with the scanpy and mudata packages installed. If these are not available, the code chunks will not be evaluated but the examples remain visible.

# Basic Integration with scanpy

Install required Python packages if needed:

    reticulate::py_require("scanpy")

    library(anndataR)
    library(reticulate)
    sc <- import("scanpy")

Load a dataset directly from scanpy:

    adata <- sc$datasets$pbmc3k_processed()
    adata
    #> ReticulateAnnData object with n_obs × n_vars = 2638 × 1838
    #>     obs: 'n_genes', 'percent_mito', 'n_counts', 'louvain'
    #>     var: 'n_cells'
    #>     uns: 'draw_graph', 'louvain', 'louvain_colors', 'neighbors', 'pca', 'rank_genes_groups'
    #>     obsm: 'X_pca', 'X_tsne', 'X_umap', 'X_draw_graph_fr'
    #>     varm: 'PCs'
    #>     obsp: 'distances', 'connectivities'

Apply scanpy functions directly:

    sc$pp$filter_cells(adata, min_genes = 200L)
    sc$pp$normalize_total(adata, target_sum = 1e4)
    sc$pp$log1p(adata)

# Conversion to R objects

Convert to `SingleCellExperiment` (see `vignette("usage_singlecellexperiment")`):

    sce_obj <- adata$as_SingleCellExperiment()
    sce_obj
    #> class: SingleCellExperiment
    #> dim: 1838 538
    #> metadata(7): draw_graph louvain ... rank_genes_groups log1p
    #> assays(1): X
    #> rownames(1838): TNFRSF4 CPSF3L ... S100B PRMT2
    #> rowData names(1): n_cells
    #> colnames(538): AAACATTGAGCTAC-1 AAACATTGATCAGC-1 ... TTTCGAACTCTCAT-1
    #>   TTTCTACTGAGGCA-1
    #> colData names(4): n_genes percent_mito n_counts louvain
    #> reducedDimNames(4): X_pca X_tsne X_umap X_draw_graph_fr
    #> mainExpName: NULL
    #> altExpNames(0):

Convert to `Seurat` (see `vignette("usage_seurat")`):

    seurat_obj <- adata$as_Seurat()
    #> Warning: No "counts" or "data" layer found in `names(layers_mapping)`, this may lead to
    #> unexpected results when using the resulting <Seurat> object.
    #> Warning: Data is of class matrix. Coercing to dgCMatrix.
    seurat_obj
    #> An object of class Seurat
    #> 1838 features across 538 samples within 1 assay
    #> Active assay: RNA (1838 features, 0 variable features)
    #>  1 layer present: X
    #>  4 dimensional reductions calculated: X_pca, X_tsne, X_umap, X_draw_graph_fr

# Multi-modal data with mudata

Install required Python packages if needed:

    reticulate::py_install("mudata")

    md <- import("mudata")

Load a `MuData` object from file:

    cache <- BiocFileCache::BiocFileCache(ask = FALSE)
    h5mu_file <- BiocFileCache::bfcrpath(
      cache,
      "https://github.com/gtca/h5xx-datasets/raw/b1177ac8877c89d8bb355b072164384b4e9cc81d/datasets/minipbcite.h5mu"
    )
    #> adding rname 'https://github.com/gtca/h5xx-datasets/raw/b1177ac8877c89d8bb355b072164384b4e9cc81d/datasets/minipbcite.h5mu'

    mdata <- md$read_h5mu(h5mu_file)

Access individual modalities and convert them:

    rna_mod <- mdata$mod[["rna"]]

    rna_seurat <- rna_mod$as_Seurat()
    #> Warning: No "counts" or "data" layer found in `names(layers_mapping)`, this may lead to
    #> unexpected results when using the resulting <Seurat> object.
    #> Warning: Data is of class matrix. Coercing to dgCMatrix.
    print(rna_seurat)
    #> An object of class Seurat
    #> 27 features across 411 samples within 1 assay
    #> Active assay: RNA (27 features, 0 variable features)
    #>  1 layer present: X
    #>  2 dimensional reductions calculated: X_pca, X_umap

    rna_sce <- rna_mod$as_SingleCellExperiment()
    print(rna_sce)
    #> class: SingleCellExperiment
    #> dim: 27 411
    #> metadata(8): celltype_colors hvg ... rank_genes_groups umap
    #> assays(1): X
    #> rownames(27): NKG7 KLRC2 ... MS4A1 KLF4
    #> rowData names(13): gene_ids feature_types ... mean std
    #> colnames(411): CAGCCAGGTCTCGACG-1 TTCTTCCTCTCGGTAA-1 ...
    #>   GACTCTCCAGCTCTGG-1 GAAATGACAAGCACCC-1
    #> colData names(6): n_genes_by_counts total_counts ... leiden celltype
    #> reducedDimNames(2): X_pca X_umap
    #> mainExpName: NULL
    #> altExpNames(0):

# Session info

## R

    sessionInfo()
    #> R version 4.5.2 (2025-10-31)
    #> Platform: x86_64-pc-linux-gnu
    #> Running under: Ubuntu 24.04.3 LTS
    #>
    #> Matrix products: default
    #> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
    #> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
    #>
    #> locale:
    #>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
    #>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C
    #>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
    #>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
    #>  [9] LC_ADDRESS=C               LC_TELEPHONE=C
    #> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
    #>
    #> time zone: Etc/UTC
    #> tzcode source: system (glibc)
    #>
    #> attached base packages:
    #> [1] stats4    stats     graphics  grDevices utils     datasets  methods
    #> [8] base
    #>
    #> other attached packages:
    #>  [1] reticulate_1.44.0           anndataR_1.0.0
    #>  [3] SingleCellExperiment_1.33.0 SummarizedExperiment_1.41.0
    #>  [5] Biobase_2.71.0              GenomicRanges_1.63.0
    #>  [7] Seqinfo_1.1.0               IRanges_2.45.0
    #>  [9] S4Vectors_0.49.0            BiocGenerics_0.57.0
    #> [11] generics_0.1.4              MatrixGenerics_1.23.0
    #> [13] matrixStats_1.5.0           SeuratObject_5.2.0
    #> [15] sp_2.2-0                    BiocStyle_2.39.0
    #>
    #> loaded via a namespace (and not attached):
    #>   [1] RColorBrewer_1.1-3     sys_3.4.3              jsonlite_2.0.0
    #>   [4] magrittr_2.0.4         spatstat.utils_3.2-0   farver_2.1.2
    #>   [7] rmarkdown_2.30         vctrs_0.6.5            ROCR_1.0-11
    #>  [10] memoise_2.0.1          spatstat.explore_3.5-3 htmltools_0.5.8.1
    #>  [13] S4Arrays_1.11.0        curl_7.0.0             Rhdf5lib_1.33.0
    #>  [16] SparseArray_1.11.1     rhdf5_2.55.7           sass_0.4.10
    #>  [19] sctransform_0.4.2      parallelly_1.45.1      KernSmooth_2.23-26
    #>  [22] bslib_0.9.0            htmlwidgets_1.6.4      ica_1.0-3
    #>  [25] httr2_1.2.1            plyr_1.8.9             plotly_4.11.0
    #>  [28] zoo_1.8-14             cachem_1.1.0           buildtools_1.0.0
    #>  [31] igraph_2.2.1           mime_0.13              lifecycle_1.0.4
    #>  [34] pkgconfig_2.0.3        Matrix_1.7-4           R6_2.6.1
    #>  [37] fastmap_1.2.0          fitdistrplus_1.2-4     future_1.67.0
    #>  [40] shiny_1.11.1           digest_0.6.37          patchwork_1.3.2
    #>  [43] rprojroot_2.1.1        Seurat_5.3.1           tensor_1.5.1
    #>  [46] RSpectra_0.16-2        irlba_2.3.5.1          RSQLite_2.4.4
    #>  [49] filelock_1.0.3         progressr_0.18.0       spatstat.sparse_3.1-0
    #>  [52] httr_1.4.7             polyclip_1.10-7        abind_1.4-8
    #>  [55] compiler_4.5.2         here_1.0.2             bit64_4.6.0-1
    #>  [58] withr_3.0.2            S7_0.2.0               DBI_1.2.3
    #>  [61] fastDummies_1.7.5      MASS_7.3-65            rappdirs_0.3.3
    #>  [64] DelayedArray_0.37.0    tools_4.5.2            lmtest_0.9-40
    #>  [67] otel_0.2.0             httpuv_1.6.16          future.apply_1.20.0
    #>  [70] goftest_1.2-3          glue_1.8.0             nlme_3.1-168
    #>  [73] rhdf5filters_1.23.0    promises_1.5.0         grid_4.5.2
    #>  [76] Rtsne_0.17             cluster_2.1.8.1        reshape2_1.4.4
    #>  [79] gtable_0.3.6           spatstat.data_3.1-9    tidyr_1.3.1
    #>  [82] data.table_1.17.8      XVector_0.51.0         spatstat.geom_3.6-0
    #>  [85] RcppAnnoy_0.0.22       ggrepel_0.9.6          RANN_2.6.2
    #>  [88] pillar_1.11.1          stringr_1.6.0          spam_2.11-1
    #>  [91] RcppHNSW_0.6.0         later_1.4.4            splines_4.5.2
    #>  [94] dplyr_1.1.4            BiocFileCache_3.1.0    lattice_0.22-7
    #>  [97] bit_4.6.0              deldir_2.0-4           survival_3.8-3
    #> [100] tidyselect_1.2.1       maketools_1.3.2        miniUI_0.1.2
    #> [103] pbapply_1.7-4          knitr_1.50             gridExtra_2.3
    #> [106] scattermore_1.2        xfun_0.54              stringi_1.8.7
    #> [109] lazyeval_0.2.2         yaml_2.3.10            evaluate_1.0.5
    #> [112] codetools_0.2-20       tibble_3.3.0           BiocManager_1.30.26
    #> [115] cli_3.6.5              uwot_0.2.4             xtable_1.8-4
    #> [118] jquerylib_0.1.4        Rcpp_1.1.0             spatstat.random_3.4-2
    #> [121] globals_0.18.0         dbplyr_2.5.1           png_0.1-8
    #> [124] spatstat.univar_3.1-4  parallel_4.5.2         blob_1.2.4
    #> [127] ggplot2_4.0.0          dotCall64_1.2          listenv_0.10.0
    #> [130] viridisLite_0.4.2      scales_1.4.0           ggridges_0.5.7
    #> [133] purrr_1.2.0            rlang_1.1.6            cowplot_1.2.0

## Python

    reticulate::py_config()
    #> python:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2/bin/python
    #> libpython:      /github/home/.cache/R/reticulate/uv/python/cpython-3.12.12-linux-x86_64-gnu/lib/libpython3.12.so
    #> pythonhome:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2:/github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2
    #> virtualenv:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2/bin/activate_this.py
    #> version:        3.12.12 (main, Oct 28 2025, 12:10:49) [Clang 20.1.4 ]
    #> numpy:          /github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2/lib/python3.12/site-packages/numpy
    #> numpy_version:  2.3.4
    #> scanpy:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2/lib/python3.12/site-packages/scanpy
    #>
    #> NOTE: Python version was forced by py_require()

    reticulate::py_list_packages()
    #> Warning in system2(python, args, stdout = TRUE): running command
    #> ''/github/home/.cache/R/reticulate/uv/cache/archive-v0/LiRQXgyOXXv5a9PgzcYO2/bin/python'
    #> -m pip freeze' had status 1 and error message 'Function not implemented'
    #> [1] package     version     requirement
    #> <0 rows> (or 0-length row.names)