2

I would like to run this Python code from R:

>>> import nlmpy 
>>> nlm = nlmpy.mpd(nRow=50, nCol=50, h=0.75) 
>>> nlmpy.exportASCIIGrid("raster.asc", nlm)

Nlmpy is a Python package to build neutral landscape models. The example comes from the website

To run this Python code from R, I 'm trying to use the package rPithon. However, I obtain this error message:

if (pithon.available()) 
{ 
  nRow <- 50 
  nCol <- 50 
  h <- 0.75 

  # this file contains the definition of function concat 
  pithon.load("C:/Users/Anaconda2/Lib/site-packages/nlmpy/nlmpy.py") 
  pithon.call( "mpd", nRow, nCol, h) 

} else { 
  print("Unable to execute python") 
} 

Error in pithon.get("_r_call_return", instance.name = instname) : 
Couldn't retrieve variable: Traceback (most recent call last): 
File "C:/Users/Documents/R/win-library/3.3/rPithon/pythonwrapperscript.py", line 110, in <module> 
reallyReallyLongAndUnnecessaryPrefix.data = json.dumps([eval(reallyReallyLongAndUnnecessaryPrefix.argData)]) 
File "C:\Users\ANACON~1\lib\json\__init__.py", line 244, in dumps 
return _default_encoder.encode(obj) 
File "C:\Users\ANACON~1\lib\json\encoder.py", line 207, in encode 
chunks = self.iterencode(o, _one_shot=True) 
File "C:\Users\ANACON~1\lib\json\encoder.py", line 270, in iterencode 
return _iterencode(o, 0) 
File "C:\Users\ANACON~1\lib\json\encoder.py", line 184, in default 
raise TypeError(repr(o) + " is not JSON serializable") 
TypeError: array([[ 0.36534654,  0.31962481,  0.44229946, ...,  0.11513079, 
0.07156331,  0.00286971], [ 0.41534291,  0.41333479,  0.48118995, ...,  0.19203674, 
0.04192771,  0.03679473], [ 0.5188

Is this error caused by a syntax issue in my code ? I work with the Anaconda 4.2.0 platform for Windows which uses the Python 2.7 version.

Martin Schmelzer
  • 23,283
  • 6
  • 73
  • 98
Nell
  • 559
  • 4
  • 20
  • 3
    The mpd function in python returns a 2D array which is not supported by the JSONEncoder by default. In python, do `import json` `help(json.encoder)` to see more information. Also, this post appears to be related http://stackoverflow.com/questions/22281059/set-object-is-not-json-serializable – jmuhlenkamp Nov 22 '16 at 20:09
  • 3
    How determined are you to use the `rPithon` package? Are you open to use some other approaches which calls Python functions from R? – Ronak Shah Nov 23 '16 at 06:07
  • 3
    Why not call Python script at command line with args using R's `system()`? – Parfait Nov 24 '16 at 00:44
  • Thanks a lot for your answers. I don't know system() or other approaches to call Python functions from R. – Nell Nov 24 '16 at 16:13

2 Answers2

3

I haven't used the nlmpy package hence, I am not sure what would be your expected output. However, this code successfully communicates between R and Python.

There are two files,

nlmpyInR.R

command ="python"
path2script="path_to_your_pythoncode/nlmpyInPython.py"

nRow <-50 
nCol <-50 
h <- 0.75

# Build up args in a vector
args = c(nRow, nCol, h)

# Add path to script as first arg
allArgs = c(path2script, args)

Routput = system2(command, args=allArgs, stdout=TRUE)
#The command would be python nlmpyInPython.py 50 50 0.75

print(paste("The Output is:\n", Routput))

nlmpyInPython.py

import sys
import nlmpy 
#Getting the arguments from the command line call
nRow = sys.argv[1]
nCol = sys.argv[2]
h = sys.argv[3]

nlm = nlmpy.mpd(nRow, nCol, h) 
pyhtonOutput = nlmpy.exportASCIIGrid("raster.asc", nlm)
#Whatever you print will get stored in the R's output variable. 
print pyhtonOutput
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Thanks a lot for your response ! I have a error message when I run the code from R (The code in "nlmpylnPython.py" works in Python): `running command '"python" C:/nlmpyInPython.py 50 50 0.75' had status [1] "Traceback (most recent call last):" [2] " File \"C:/nlmpyInPython.py\", line 14, in " [3] " nlm = nlmpy.mpd(nRow, nCol, h) " [4] " File \"C:\\Users\\ANACON~1\\lib\\site-packages\\nlmpy\\nlmpy.py\", line 523, in mpd"` – Nell Nov 30 '16 at 03:38
  • The rest of the error message is `[5] " mask = np.ones((nRow, nCol)) " [6] " File \"C:\\Users\\ANACON~1\\lib\\site-packages\\numpy\\core\\numeric.py\", line 190, in ones" [7] " a = empty(shape, dtype, order)" [8] "TypeError: an integer is required" attr(,"status") [1] 1` – Nell Nov 30 '16 at 03:38
  • @Nell I had ran on my windows system and it was working fine. The python call seems a bit doubtful. why it is `'"python" C:/nlmpyInPython.py 50 50 0.75'`?Rather shouldn't it be `python C:/nlmpyInPython.py 50 50 0.75` ? Looks like the numbers `50 50 0.75` are going as string. – Ronak Shah Nov 30 '16 at 04:16
  • I have checked that nRow, nCol and h are numbers by using class(nRow) in R. All these arguments are numeric. I've also tested the Python path by running `command="C:/Users/Anaconda2/python.exe"` instead of `command="python"`. I have again the same error message. – Nell Nov 30 '16 at 20:01
  • Can you run `python C:/nlmpyInPython.py 50 50 0.75` from command line and check if it is running properly? – Ronak Shah Dec 01 '16 at 04:37
  • Thanks a lot for your help. Finally, the R script works when I specify `nRow = int(sys.argv.[1])`, `nCol = int(sys.argv.[2])` and `h = float(sys.argv.[3])`. However, I would like to run another function `nlm1 = nlmpy.classifyArray(nlm, [1, 1, 1])` in the Python script but I don't know how to define the list [1, 1, 1] in the arguments of the function `system2()`? Thanks a lot for your time. – Nell Dec 02 '16 at 22:33
  • Maybe you can send the elements of the list separately from R? `a=1`, `b=1` and `c=1` and then in Python use `nlm1 = nlmpy.classifyArray(nlm, [sys.argv[4], sys.argv[5], sys.argv[6]])` ? – Ronak Shah Dec 03 '16 at 02:02
  • Thanks a lot for your help. It's a good idea ! I obtain this error message:`[1] "Traceback (most recent call last):" [2] " File \"C:/nlmpyInPython.py\", line 34, in " [3] " nlm1= nlmpy.classifyArray(nlm, [a, b, c])" [4] " File \"C:\\Users\\ANACON~1\\lib\\site-packages\\nlmpy\\nlmpy.py\", line 233, in classifyArray" [5] " cumulativeProportions = w2cp(weights)"` – Nell Dec 09 '16 at 17:15
  • `[6] " File \"C:\\Users\\ANACON~1\\lib\\site-packages\\nlmpy\\nlmpy.py\", line 169, in w2cp" [7] " w = np.array(weights, dtype=float)" [8] "ValueError: could not convert string to float: function" attr(,"status") [1] 1` – Nell Dec 09 '16 at 17:18
0

The cause of the error that you're getting is hinted at by the "is not JSON serializable" line. Your R code calls the mpd function with certain arguments, and that function itself will execute correctly. The rPithon library will then try to send the return value of the function back to R, and to do this it will try to create a JSON object that describes the return value.

This works well for integers, floating point values, arrays, etc, but not every kind of Python object can be converted to such a JSON representation. And because rPithon can't convert the return value of mpd this way, an error is generated.

You can still use rPithon to call the mpd function though. The following code creates a new Python function that performs two steps: first it calls the mpd function with the specified parameters, and then it exports the result to a file, of which the filename is also an argument. Using rPithon, the new function is then called from R. Because myFunction doesn't return anything, representing the return value in JSON format will not be a problem.

library("rPithon")

pythonCode = paste("import nlmpy.nlmpy as nlmpy",
                   "",
                   "def myFunction(nRow, nCol, h, fileName):",
                   "    nlm = nlmpy.mpd(nRow, nCol, h)",
                   "    nlmpy.exportASCIIGrid(fileName, nlm)", 
                   sep = "\n")
pithon.exec(pythonCode)

nRow <- 50 
nCol <- 50 
h <- 0.75 

pithon.call("myFunction", nRow, nCol, h, "outputraster.asc")

Here, the Python code defined as an R string, and executed using pithon.exec. You could also put that Python code in a separate file and use pithon.load to process the code so that the myFunction function is known.

brm
  • 3,706
  • 1
  • 14
  • 14