Thanks to reticulate is it possible to embed a Python session within an R session. The Earth Engine Python 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.
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:
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 <lambda>
#> 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:
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
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
type(1)
#> <class 'int'>
R
class(1)
#> [1] "numeric"
But why does this matter? Let’s explain with an example:
Python
ee.Initialize()
and_bitwise = ee.Number(32).bitwiseAnd(100)
and_bitwise.getInfo()
#> 32
R
and_bitwise = ee$Number(32)$bitwiseAnd(100) #caution: silent error
and_bitwise$getInfo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
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:
and_bitwise = ee$Number(32L)$bitwiseAnd(100L)
and_bitwise$getInfo()
#> [1] 32
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 which is saved in milliseconds since the UNIX epoch.
Python
my_date = ee.Date('1990-01-01')
my_date.getInfo()
#> {'type': 'Date', 'value': 631152000000} # greater than 2 billion
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
.
# 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
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)
:
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:
library(rgee)
ee_Initialize()
ee_list <- ee$List(1:10)
ee_list$'repeat'(10,2)$getInfo()
#> 10 10