Search code examples
rarcpyreticulate

Arcpy map algebra from reticulate


I'm trying to use arcpy from R via reticulate. For the most part, it works really well. However, I'm running into some issues when trying to do raster algebra. Consider the following code:

library(reticulate)
use_python("C:/Python27/ArcGISx6410.2")

arcpy = import("arcpy")
arcpy$CheckOutExtension("Spatial")

arcpy$management$CreateRandomRaster("in_memory", 
  "randrast", "NORMAL 3.0", "0 0 500 500", 50)

randrast = arcpy$sa$Raster("in_memory/randrast")

doublerast = randrast + randrast 

Error in randrast + randrast : non-numeric argument to binary operator

It seems that even though reticulate recognizes that the rasters are Python objects ("python.builtin.Raster" "python.builtin.object"), it doesn't know to use Python's + operator rather than R's. I tried importing arcpy with convert = FALSE but the error is the same.

I can get around this by defining Python functions to mimic the basic arithmetic operators.

tmp = tempfile(fileext = ".py")
cat("def add(x, y):\n  return x + y\n", file = tmp)

source_python(tmp)

doublerast = add(randrast, randrast)

But obviously this is gets pretty cumbersome for more complex statements.

Does anyone know of a way to force reticulate to use Python's arithmetic operators for Python objects, rather than R's?


Solution

  • One option is to define my own operators for Python objects using the operator module:

    `%py+%` = function(e1, e2) {
      op = import("operator")
      op$add(e1, e2)
    }
    
    doublerast = randrast %py+% randrast 
    

    Or, alternatively, use S3 classes to overload the arithmetic operators (as is done for TensorFlow) to support python.builtin.object, e.g.

    `+.python.builtin.object` = function(e1, e2) {
      op = import("operator")
      op$add(e1, e2)
    }
    

    But I worry that order of operations might not function as expected.