# 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:

    # TEMP(anndata<0.13.0): anndataR does not yet support Python anndata >= 0.13.0
    reticulate::py_require("scanpy>=1.10")
    reticulate::py_require("anndata<0.13.0")

    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.6.1 (2026-06-24)
    #> Platform: x86_64-pc-linux-gnu
    #> Running under: Ubuntu 26.04 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.32.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=en_US.UTF-8
    #>  [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.46.0           anndataR_1.2.1
    #>  [3] SingleCellExperiment_1.34.0 SummarizedExperiment_1.42.0
    #>  [5] Biobase_2.72.0              GenomicRanges_1.64.0
    #>  [7] Seqinfo_1.2.0               IRanges_2.46.0
    #>  [9] S4Vectors_0.50.1            BiocGenerics_0.58.1
    #> [11] generics_0.1.4              MatrixGenerics_1.24.0
    #> [13] matrixStats_1.5.0           SeuratObject_5.4.0
    #> [15] sp_2.2-3                    BiocStyle_2.40.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.5         spatstat.utils_3.2-4   farver_2.1.2
    #>   [7] rmarkdown_2.31         vctrs_0.7.3            ROCR_1.0-12
    #>  [10] memoise_2.0.1          spatstat.explore_3.8-1 htmltools_0.5.9
    #>  [13] S4Arrays_1.12.0        curl_7.1.0             Rhdf5lib_2.0.0
    #>  [16] SparseArray_1.12.2     rhdf5_2.56.0           sass_0.4.10
    #>  [19] sctransform_0.4.3      parallelly_1.48.0      KernSmooth_2.23-26
    #>  [22] bslib_0.11.0           htmlwidgets_1.6.4      ica_1.0-3
    #>  [25] httr2_1.3.0            plyr_1.8.9             plotly_4.12.1
    #>  [28] zoo_1.8-15             cachem_1.1.0           buildtools_1.0.0
    #>  [31] igraph_2.3.3           mime_0.13              lifecycle_1.0.5
    #>  [34] pkgconfig_2.0.3        Matrix_1.7-6           R6_2.6.1
    #>  [37] fastmap_1.2.0          fitdistrplus_1.2-6     future_1.75.0
    #>  [40] shiny_1.14.0           digest_0.6.39          paws.storage_0.10.0
    #>  [43] patchwork_1.3.2        rprojroot_2.1.1        Seurat_5.5.1
    #>  [46] tensor_1.5.1           RSpectra_0.16-2        irlba_2.3.7
    #>  [49] RSQLite_3.53.3         filelock_1.0.3         Rarr_2.0.1
    #>  [52] progressr_1.0.0        spatstat.sparse_3.2-0  httr_1.4.8
    #>  [55] polyclip_1.10-7        abind_1.4-8            compiler_4.6.1
    #>  [58] here_1.0.2             bit64_4.8.2            withr_3.0.3
    #>  [61] S7_0.2.2               DBI_1.3.0              fastDummies_1.7.6
    #>  [64] R.utils_2.13.0         MASS_7.3-66            rappdirs_0.3.4
    #>  [67] DelayedArray_0.38.2    tools_4.6.1            lmtest_0.9-40
    #>  [70] otel_0.2.0             httpuv_1.6.17          future.apply_1.20.2
    #>  [73] goftest_1.2-3          R.oo_1.27.1            glue_1.8.1
    #>  [76] nlme_3.1-170           rhdf5filters_1.24.0    promises_1.5.0
    #>  [79] grid_4.6.1             Rtsne_0.17             cluster_2.1.8.2
    #>  [82] reshape2_1.4.5         gtable_0.3.6           spatstat.data_3.1-9
    #>  [85] R.methodsS3_1.8.2      tidyr_1.3.2            data.table_1.18.4
    #>  [88] XVector_0.52.0         spatstat.geom_3.8-2    RcppAnnoy_0.0.23
    #>  [91] ggrepel_0.9.8          RANN_2.6.2             pillar_1.11.1
    #>  [94] stringr_1.6.0          spam_2.11-4            RcppHNSW_0.7.0
    #>  [97] later_1.4.8            splines_4.6.1          dplyr_1.2.1
    #> [100] BiocFileCache_3.2.0    lattice_0.22-9         bit_4.6.0
    #> [103] survival_3.8-9         deldir_2.0-4           paws.common_0.8.10
    #> [106] tidyselect_1.2.1       maketools_1.3.2        miniUI_0.1.2
    #> [109] pbapply_1.7-4          knitr_1.51             gridExtra_2.3.1
    #> [112] scattermore_1.2        xfun_0.60              stringi_1.8.7
    #> [115] yaml_2.3.12            evaluate_1.0.5         codetools_0.2-20
    #> [118] tibble_3.3.1           BiocManager_1.30.27    cli_3.6.6
    #> [121] uwot_0.2.4             xtable_1.8-8           jquerylib_0.1.4
    #> [124] Rcpp_1.1.2             spatstat.random_3.5-0  globals_0.19.1
    #> [127] dbplyr_2.6.0           png_0.1-9              spatstat.univar_3.2-0
    #> [130] parallel_4.6.1         blob_1.3.0             ggplot2_4.0.3
    #> [133] dotCall64_1.2          listenv_1.0.0          viridisLite_0.4.3
    #> [136] scales_1.4.0           ggridges_0.5.7         crayon_1.5.3
    #> [139] purrr_1.2.2            rlang_1.3.0            cowplot_1.2.0

## Python

    reticulate::py_config()
    #> python:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB/bin/python
    #> libpython:      /github/home/.cache/R/reticulate/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/libpython3.12.so
    #> pythonhome:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB:/github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB
    #> virtualenv:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB/bin/activate_this.py
    #> version:        3.12.13 (main, Jul 18 2026, 17:02:19) [Clang 22.1.3 ]
    #> numpy:          /github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB/lib/python3.12/site-packages/numpy
    #> numpy_version:  2.4.6
    #> scanpy:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/tdOcbSwI0k7LtLfB/lib/python3.12/site-packages/scanpy
    #>
    #> NOTE: Python version was forced by py_require()

    reticulate::py_list_packages()
    #>              package      version                  requirement
    #> 1            anndata      0.12.19             anndata==0.12.19
    #> 2   array-api-compat       1.15.0     array-api-compat==1.15.0
    #> 3            certifi    2026.7.22           certifi==2026.7.22
    #> 4          contourpy        1.3.3             contourpy==1.3.3
    #> 5             cycler       0.12.1               cycler==0.12.1
    #> 6             donfig  0.8.1.post1          donfig==0.8.1.post1
    #> 7   fast-array-utils          1.5        fast-array-utils==1.5
    #> 8          fonttools       4.63.0            fonttools==4.63.0
    #> 9      google-crc32c        1.8.0         google-crc32c==1.8.0
    #> 10              h5py       3.16.0                 h5py==3.16.0
    #> 11            joblib        1.5.3                joblib==1.5.3
    #> 12        kiwisolver        1.5.0            kiwisolver==1.5.0
    #> 13   legacy-api-wrap          1.5         legacy-api-wrap==1.5
    #> 14          llvmlite       0.48.0             llvmlite==0.48.0
    #> 15        matplotlib       3.11.1           matplotlib==3.11.1
    #> 16            mudata       0.3.10               mudata==0.3.10
    #> 17          narwhals       2.24.0             narwhals==2.24.0
    #> 18           natsort        8.4.0               natsort==8.4.0
    #> 19          networkx        3.6.1              networkx==3.6.1
    #> 20             numba       0.66.0                numba==0.66.0
    #> 21         numcodecs       0.16.5            numcodecs==0.16.5
    #> 22             numpy        2.4.6                 numpy==2.4.6
    #> 23         packaging         26.2              packaging==26.2
    #> 24            pandas        2.3.3                pandas==2.3.3
    #> 25             patsy        1.0.2                 patsy==1.0.2
    #> 26            pillow       12.3.0               pillow==12.3.0
    #> 27       pynndescent        0.6.0           pynndescent==0.6.0
    #> 28         pyparsing        3.3.2             pyparsing==3.3.2
    #> 29   python-dateutil  2.9.0.post0 python-dateutil==2.9.0.post0
    #> 30              pytz 2026.3.post1           pytz==2026.3.post1
    #> 31            pyyaml        6.0.3                pyyaml==6.0.3
    #> 32            scanpy       1.12.3               scanpy==1.12.3
    #> 33      scikit-learn        1.9.0          scikit-learn==1.9.0
    #> 34             scipy       1.18.0                scipy==1.18.0
    #> 35      scverse-misc        0.1.1          scverse-misc==0.1.1
    #> 36           seaborn       0.13.2              seaborn==0.13.2
    #> 37     session-info2        0.4.1         session-info2==0.4.1
    #> 38               six       1.17.0                  six==1.17.0
    #> 39       statsmodels       0.14.6          statsmodels==0.14.6
    #> 40     threadpoolctl        3.6.0         threadpoolctl==3.6.0
    #> 41              tqdm       4.70.0                 tqdm==4.70.0
    #> 42 typing-extensions       4.16.0    typing-extensions==4.16.0
    #> 43            tzdata       2026.3               tzdata==2026.3
    #> 44        umap-learn       0.5.12           umap-learn==0.5.12
    #> 45              zarr        3.2.1                  zarr==3.2.1