# 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.3 (2026-03-11)
    #> Platform: x86_64-pc-linux-gnu
    #> Running under: Ubuntu 24.04.4 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=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.1.3
    #>  [3] SingleCellExperiment_1.33.2 SummarizedExperiment_1.41.1
    #>  [5] Biobase_2.71.0              GenomicRanges_1.63.2
    #>  [7] Seqinfo_1.1.0               IRanges_2.45.0
    #>  [9] S4Vectors_0.49.2            BiocGenerics_0.57.1
    #> [11] generics_0.1.4              MatrixGenerics_1.23.0
    #> [13] matrixStats_1.5.0           SeuratObject_5.4.0
    #> [15] sp_2.2-1                    BiocStyle_2.39.0
    #>
    #> loaded via a namespace (and not attached):
    #>   [1] RcppAnnoy_0.0.23       splines_4.5.3          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.2.2            rprojroot_2.1.1        globals_0.19.1
    #>  [13] lattice_0.22-9         MASS_7.3-65            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.0           sctransform_0.4.3
    #>  [25] spam_2.11-3            spatstat.sparse_3.1-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_0.10.1
    #>  [40] spatstat.utils_3.2-2   maketools_1.3.2        goftest_1.2-3
    #>  [43] RSpectra_0.16-2        spatstat.random_3.4-5  fitdistrplus_1.2-6
    #>  [46] parallelly_1.47.0      codetools_0.2-20       DelayedArray_0.37.1
    #>  [49] tidyselect_1.2.1       farver_2.1.2           BiocFileCache_3.1.0
    #>  [52] spatstat.explore_3.8-0 jsonlite_2.0.0         progressr_0.19.0
    #>  [55] ggridges_0.5.7         survival_3.8-6         tools_4.5.3
    #>  [58] ica_1.0-3              Rcpp_1.1.1-1           glue_1.8.1
    #>  [61] gridExtra_2.3          SparseArray_1.11.13    xfun_0.57
    #>  [64] here_1.0.2             Rarr_1.99.44           dplyr_1.2.1
    #>  [67] withr_3.0.2            BiocManager_1.30.27    fastmap_1.2.0
    #>  [70] rhdf5filters_1.23.3    digest_0.6.39          R6_2.6.1
    #>  [73] mime_0.13              scattermore_1.2        tensor_1.5.1
    #>  [76] spatstat.data_3.1-9    RSQLite_2.4.6          paws.storage_0.9.0
    #>  [79] R.methodsS3_1.8.2      tidyr_1.3.2            data.table_1.18.2.1
    #>  [82] httr_1.4.8             htmlwidgets_1.6.4      S4Arrays_1.11.1
    #>  [85] uwot_0.2.4             pkgconfig_2.0.3        gtable_0.3.6
    #>  [88] blob_1.3.0             lmtest_0.9-40          S7_0.2.2
    #>  [91] XVector_0.51.0         sys_3.4.3              htmltools_0.5.9
    #>  [94] dotCall64_1.2          scales_1.4.0           png_0.1-9
    #>  [97] spatstat.univar_3.1-7  knitr_1.51             reshape2_1.4.5
    #> [100] nlme_3.1-169           curl_7.1.0             cachem_1.1.0
    #> [103] zoo_1.8-15             rhdf5_2.55.16          stringr_1.6.0
    #> [106] KernSmooth_2.23-26     parallel_4.5.3         miniUI_0.1.2
    #> [109] pillar_1.11.1          grid_4.5.3             vctrs_0.7.3
    #> [112] RANN_2.6.2             promises_1.5.0         dbplyr_2.5.2
    #> [115] xtable_1.8-8           cluster_2.1.8.2        evaluate_1.0.5
    #> [118] cli_3.6.6              compiler_4.5.3         rlang_1.2.0
    #> [121] crayon_1.5.3           paws.common_0.8.9      future.apply_1.20.2
    #> [124] plyr_1.8.9             stringi_1.8.7          viridisLite_0.4.3
    #> [127] deldir_2.0-4           lazyeval_0.2.3         spatstat.geom_3.7-3
    #> [130] Matrix_1.7-5           RcppHNSW_0.6.0         patchwork_1.3.2
    #> [133] bit64_4.8.0            future_1.70.0          ggplot2_4.0.3
    #> [136] Rhdf5lib_1.99.6        shiny_1.13.0           ROCR_1.0-12
    #> [139] igraph_2.3.0           memoise_2.0.1          bslib_0.10.0
    #> [142] bit_4.6.0

## Python

    reticulate::py_config()
    #> python:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/eytStxV2UYTCVzSATNfuC/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/eytStxV2UYTCVzSATNfuC:/github/home/.cache/R/reticulate/uv/cache/archive-v0/eytStxV2UYTCVzSATNfuC
    #> virtualenv:     /github/home/.cache/R/reticulate/uv/cache/archive-v0/eytStxV2UYTCVzSATNfuC/bin/activate_this.py
    #> version:        3.12.13 (main, Apr 14 2026, 14:29:00) [Clang 22.1.3 ]
    #> numpy:          /github/home/.cache/R/reticulate/uv/cache/archive-v0/eytStxV2UYTCVzSATNfuC/lib/python3.12/site-packages/numpy
    #> numpy_version:  2.4.4
    #> scanpy:         /github/home/.cache/R/reticulate/uv/cache/archive-v0/eytStxV2UYTCVzSATNfuC/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.11             anndata==0.12.11
    #> 2   array-api-compat       1.14.0     array-api-compat==1.14.0
    #> 3            certifi    2026.4.22           certifi==2026.4.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.4.1      fast-array-utils==1.4.1
    #> 8          fonttools       4.62.1            fonttools==4.62.1
    #> 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.47.0             llvmlite==0.47.0
    #> 15        matplotlib       3.10.9           matplotlib==3.10.9
    #> 16            mudata        0.3.6                mudata==0.3.6
    #> 17           natsort        8.4.0               natsort==8.4.0
    #> 18          networkx        3.6.1              networkx==3.6.1
    #> 19             numba       0.65.1                numba==0.65.1
    #> 20         numcodecs       0.16.5            numcodecs==0.16.5
    #> 21             numpy        2.4.4                 numpy==2.4.4
    #> 22         packaging         26.2              packaging==26.2
    #> 23            pandas        2.3.3                pandas==2.3.3
    #> 24             patsy        1.0.2                 patsy==1.0.2
    #> 25            pillow       12.2.0               pillow==12.2.0
    #> 26       pynndescent        0.6.0           pynndescent==0.6.0
    #> 27         pyparsing        3.3.2             pyparsing==3.3.2
    #> 28   python-dateutil  2.9.0.post0 python-dateutil==2.9.0.post0
    #> 29              pytz 2026.1.post1           pytz==2026.1.post1
    #> 30            pyyaml        6.0.3                pyyaml==6.0.3
    #> 31            scanpy       1.12.1               scanpy==1.12.1
    #> 32      scikit-learn        1.8.0          scikit-learn==1.8.0
    #> 33             scipy       1.17.1                scipy==1.17.1
    #> 34      scverse-misc        0.0.4          scverse-misc==0.0.4
    #> 35           seaborn       0.13.2              seaborn==0.13.2
    #> 36     session-info2        0.4.1         session-info2==0.4.1
    #> 37               six       1.17.0                  six==1.17.0
    #> 38       statsmodels       0.14.6          statsmodels==0.14.6
    #> 39     threadpoolctl        3.6.0         threadpoolctl==3.6.0
    #> 40              tqdm       4.67.3                 tqdm==4.67.3
    #> 41 typing-extensions       4.15.0    typing-extensions==4.15.0
    #> 42            tzdata       2026.2               tzdata==2026.2
    #> 43        umap-learn       0.5.12           umap-learn==0.5.12
    #> 44              zarr        3.1.6                  zarr==3.1.6