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

## Python

    reticulate::py_config()
    #> python:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/6UXcEXugf8xCE42e/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/6UXcEXugf8xCE42e:/github/home/.cache/R/reticulate/uv/cache/archive-v0/6UXcEXugf8xCE42e
    #> virtualenv:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/6UXcEXugf8xCE42e/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/6UXcEXugf8xCE42e/lib/python3.12/site-packages/numpy
    #> numpy_version:  2.4.6
    #> scanpy:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/6UXcEXugf8xCE42e/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.2                 pytz==2026.2
    #> 31            pyyaml       6.0.3                pyyaml==6.0.3
    #> 32            scanpy      1.12.2               scanpy==1.12.2
    #> 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.69.0                 tqdm==4.69.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