<jupyter_start><jupyter_text>Using Python in R with `reticulate`In this tutorial, we will demonstrate how to perform basic Python operations in R using the library `reticulate`. This includes converting between R and Python dataframe objects and running python functions. Since `scvi-tools` is written in Python, such an interface is necessary to take advantage of these models within the R environment.  Import Libraries<jupyter_code>library(reticulate)
library(anndata)
library(sceasy)

library(Seurat)
library(SeuratData)<jupyter_output>Attaching SeuratObject

Registered S3 method overwritten by 'cli':
  method     from         
  print.boxx spatstat.geom

Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used”
Warning message in if (is.na(desc)) {:
“the condition has length > 1 and only the first element will be used[...]<jupyter_text>Operating between Python and R First, we will create a dummy list, and convert between R and Python. Note that R is 1-indexed while Python is 0-indexed, so when retrieiving elements the user should be conscious of what kind of object they are operating on.<jupyter_code>lst <- list(1, 2, 3)
print(lst)
print(typeof(lst))<jupyter_output>[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[1] "list"<jupyter_text>We will convert this R list to a Python list via a function provided by the `reticulate` library called `r_to_py()`. This works for various fundamental R types like vectors, lists, arrays, data frames, functions, and primitives. Any python object will have `typeof(obj)` as `environment`. To see the Python type, we can call `class(obj)` instead.<jupyter_code>py_lst <- r_to_py(lst)
print(py_lst)
print(typeof(py_lst))
print(class(py_lst))<jupyter_output>[1.0, 2.0, 3.0]
[1] "environment"
[1] "python.builtin.list"   "python.builtin.object"<jupyter_text>We can call instance functions of a Python object by replacing the usual dot notation with `$` instead. So something like `lst.append(5)` would become `lst$append(5)`.<jupyter_code>py_lst$append(5)
print(py_lst)<jupyter_output><empty_output><jupyter_text>Note, arguments passed into these functions can either be Python or R objects. R objects passed in as arguments will automatically converted to the corresponding Python type via the `r_to_py()` function. However, this can sometimes result in unexpected results. For example, `0` in R will be automatically inferred as a float, which can result in an error when trying to pop an element below. We workaround this by explictly casting the R term to an integer with `as.integer(0)` or using the `0L` syntax, which results in the proper type conversion.<jupyter_code># This will fail.
py_lst$pop(0)
py_lst$pop(0L)
print(py_lst)<jupyter_output><empty_output><jupyter_text>Finally, we will convert back into an R list with the function `py_to_r()` which executes the inverse of `r_to_py()`.<jupyter_code>lst <- py_to_r(py_lst)
print(lst)<jupyter_output>[1] 2 3 5<jupyter_text>Import Python libraries Now, we load the scanpy library via reticulate using the `import()` function. The `convert` boolean argument determines whether the output of Python functions is automatically converted to an R object equivalent via the `py_to_r()` function. Here, we set it to `FALSE` intentionally since often times we would like to retain the Python format for further manipulation in Python (e.g. with scanpy). Additionally, this keeps data type conversion more explicit, avoiding type confusion.<jupyter_code>sc <- import('scanpy', convert = FALSE)<jupyter_output><empty_output><jupyter_text>Load Dataset with SeuratData<jupyter_code>data("pbmc3k")
pbmc <- pbmc3k
pbmc<jupyter_output><empty_output><jupyter_text>In order to make use of `scvi-tools`, we use a third-party library called `sceasy` to convert the SeuratObject into an AnnData object, the primary format used by `scanpy` and `scvi-tools`.<jupyter_code>adata <- convertFormat(pbmc, from="seurat", to="anndata", main_layer="counts", drop_single_values=FALSE)
adata<jupyter_output><empty_output><jupyter_text>We can access the AnnData fields in the same way we call instance functions, with the `$` syntax.<jupyter_code>adata$obs$head()
class(adata$obs)
head(py_to_r(adata$obs))<jupyter_output><empty_output><jupyter_text>Above, we loaded the `anndata` R library. It is important to know when dealing with a Python AnnData object and an R AnnDataR6 Object. We can distinguish these by using the `class()` method, then using the `py_to_r(), r_to_py()` functions to interoperate between the two. Generally, it is recommended to use the R AnnDataR6 object to manipulate fields.<jupyter_code>class(adata)
class(py_to_r(adata))
# Convert adata object to R AnnDataR6 object.
adata <- py_to_r(adata)<jupyter_output><empty_output><jupyter_text>We can set fields in the AnnData object using the `$` syntax. Here, we run CPM normalization using scanpy and save it to a new layer in the AnnData object. For the sake of demonstration, we do not use the inplace update option that scanpy provides. Note, this only works well if using the AnnDataR6 object.<jupyter_code>X_norm <- sc$pp$normalize_total(adata, target_sum = 1e+09, inplace = FALSE)["X"]
adata$layers["X_norm"] <- X_norm
head(as.data.frame(adata$layers["X_norm"]))<jupyter_output><empty_output><jupyter_text>Now you should be comfortable interoperating between R and Python. Once you configure your AnnData object to contain all the necessary fields for your model of choice, you can intialize and train with the AnnData object. Visit our tutorials page for examples of running `scvi-tools` in R.  Session Info<jupyter_code>sI <- sessionInfo()
sI$loadedOnly <- NULL
print(sI, locale=FALSE)<jupyter_output>R version 4.0.3 (2020-10-10)
Platform: x86_64-conda-linux-gnu (64-bit)
Running under: Ubuntu 16.04.6 LTS

Matrix products: default
BLAS/LAPACK: /data/yosef2/users/jhong/miniconda3/envs/r_tutorial/lib/libopenblasp-r0.3.12.so

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] stxBrain.SeuratData_0.1.1 pbmc3k.SeuratData_3.1.4  
[3] ifnb.SeuratData_3.0.0     SeuratData_0.2.1         
[5] SeuratObject_4.0.2        Seurat_4.0.4             
[7] sceasy_0.0.6              anndata_0.7.5.3          
[9] reticulate_1.22
{'fraction_non_alphanumeric': 0.09016393442622951, 'fraction_numerical': 0.016681046879493816, 'mean_word_length': 5.277075812274369, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '463432', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2253, 'n_tokens_neox': 2162, 'n_words': 844, 'path': 'python_in_R.ipynb', 'repo_name': 'YosefLab/scvi_tutorials', 'size': '6954'}