--- title: "Considerations" output: html_document: toc: true toc_float: collapsed: false smooth_scroll: false toc_depth: 2 vignette: > %\VignetteIndexEntry{2. Considerations} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} --- Thanks to **reticulate** is it possible to embed a Python session within an R session. The **[Earth Engine Python API](https://pypi.org/project/earthengine-api/)** and **rgee** share the **same modules, classes, functions, and methods**. In other words, the logic of the syntax is the same and just as fast (just change **.** by a **$**). Notwithstanding, differences in the language design of R and Python might cause some problems in specific scenarios. We identify **four** bug-potential cases. Each of them is explained in-depth below. ```{r, setup, include=FALSE} knitr::opts_chunk$set( comment = '', fig.width = 6, fig.height = 6 ) ``` ### **1. The map message error:** This issue happens when the **map** method is used while: (1) running a reticulate version lower than < 1.14 (please update it!); or (2) leading with **ee$List** objects. For instance: ``` r library(rgee) ee$Initialize() mylist = ee$List$sequence(10) mylist$map(function(x) ee$Number(x)$add(1)) #> Error in py_call_impl(callable, dots$args, dots$keywords): RuntimeError: Evaluation error: argument "x" is missing, with no default. #> #> Detailed traceback: #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/apifunction.py", line 205, in #> return lambda *args, **kwargs: func.call(*args, **kwargs) # pylint: disable=unnecessary-lambda #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/function.py", line 67, in call #> return self.apply(self.nameArgs(args, kwargs)) #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/function.py", line 80, in apply #> result = computedobject.ComputedObject(self, self.promoteArgs(named_args)) #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/function.py", line 107, in promoteArgs #> promoted_args[name] = Function._promoter(args[name], spec['type']) #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/__init__.py", line 242, in _Promote #> return CustomFunction.create(arg, 'Object', ['Object'] * args_count) #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/customfunction.py", line 121, in create #> return CustomFunction(signature, func) #> File "/home/aybarpc01/.virtualenvs/r-reticulate/lib/python3.7/site-packages/ee/customfunction.py", line 47, in __init__ #> self._body = body(*variables) #> File "/home/aybarpc01/R/x86_64-pc-linux-gnu-library/3.6/reticulate/python/rpytools/call.py", line 21, in python_function #> raise RuntimeError(res[kErrorKey]) ``` The code before is perfectly valid but `rgee` will produce an error. This problem should be easily solved by adding the function **ee_utils_pyfunc**. It will permit to wrap R functions before to send it to `reticulate`. Let’s see: ``` r library(rgee) ee$Initialize() mylist = ee$List$sequence(0,10) mynewlist = mylist$map( ee_utils_pyfunc( function(x) ee$Number(x)$add(1) ) ) mynewlist$getInfo() #> [1] 1 2 3 4 5 6 7 8 9 10 11 ``` ### **2. Do not forget the L** By default, when you define a number in R it will produce a **double precision** value. This does not happen in Python because, by default it will create an **int** value. **Python** ``` python type(1) #> ``` **R** ``` r class(1) #> [1] "numeric" ``` But why does this matter? Let's explain with an example: **Python** ``` python ee.Initialize() and_bitwise = ee.Number(32).bitwiseAnd(100) and_bitwise.getInfo() #> 32 ``` **R** ``` r and_bitwise = ee$Number(32)$bitwiseAnd(100) #caution: silent error and_bitwise$getInfo() Traceback (most recent call last): File "", line 1, in File "/home/aybarpc01/.local/lib/python3.7/site-packages/ee/computedobject.py", line 95, in getInfo return data.computeValue(self) File "/home/aybarpc01/.local/lib/python3.7/site-packages/ee/data.py", line 490, in computeValue return send_('/value', ({'json': obj.serialize(), 'json_format': 'v2'})) File "/home/aybarpc01/.local/lib/python3.7/site-packages/ee/data.py", line 1186, in send_ raise ee_exception.EEException(json_content['error']['message']) ee.ee_exception.EEException: Number.bitwiseAnd: Bitwise operands must be integer only. ``` Users need to take into consideration that most of the arguments of the Earth Engine methods are strict to admit only **integer values**. The creation of integers in R is quite simple; you just need to add the letter **L** to the end of the specific number or employ the function `as.integer`. The **correct code** in R would be: ``` r and_bitwise = ee$Number(32L)$bitwiseAnd(100L) and_bitwise$getInfo() #> [1] 32 ``` ### **3. Be careful with ee$Date** This problem also appears due to differences between the design of R and Python as programming languages. Currently, R only supports integer data type of 32 bits. Such integers can only count up to about 2 billion. Unfortunately, this range is insufficient to deal with [Google Earth Engine timestamp](https://developers.google.com/earth-engine/glossary/) which is saved in milliseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). **Python** ``` python my_date = ee.Date('1990-01-01') my_date.getInfo() #> {'type': 'Date', 'value': 631152000000} # greater than 2 billion ``` **R** ``` r my_date <- ee$Date('1990-01-01') my_date$getInfo() #> $type #> [1] "Date" #> #> $value #> [1] -208192512 ``` The problems with `ee$Date` just appear in the last mile (Python to R or vice-versa, `reticulate`), and they should not be too severe if treated with care. `rgee` implements two functions to deal with Earth Engine dates: `eedate_to_rdate` and `rdate_to_eedate`. ``` r # Era5 dataset era_img <- ee$ImageCollection("ECMWF/ERA5/DAILY")$ filterDate("2019-01-01", "2019-12-31")$ first() # Extracting init date ee_date <- era_img$get('system:time_start') ee_date$getInfo() # Silent error #> [1] 112573440 eedate_to_rdate(ee_date = ee_date, timestamp = TRUE) #> [1] 1.546301e+12 ``` ### **4. Take into consideration reserved words in R** A reserved word is a word that cannot be used as an identifier, such as the name of a variable or a function. According with `?reserved`, the reserved words in R's parser are: `if`, `else`, **`repeat`**, `while`, `function`, `for`, `in`, `next`, `break`, `TRUE`, `FALSE`, `NULL`, `Inf`, `NaN`, `NA`, `NA_integer_`, `NA_real_`, `NA_complex_`, `NA_character_`. Of these words, the only one that is part of the Earth Engine API is **repeat**. We can find **repeat** as a method for an Earth Engine List object. See **[`ee$List$repeat(value, count)`](https://developers.google.com/earth-engine/apidocs/ee-list-repeat)**: ``` r library(rgee) ee_Initialize() ee_list <- ee$List(1:10) ee_list$repeat(10,2)$getInfo() #> Error: unexpected 'repeat' in "ee_list$repeat" ``` To avoid this error use backticks/quotation marks: ``` r library(rgee) ee_Initialize() ee_list <- ee$List(1:10) ee_list$'repeat'(10,2)$getInfo() #> 10 10 ```