Skip to content
Permalink
Browse files
[BUGFIX][Processing] R scripts do not have enough outputs
R scripts in processing only supports Vector, Raster and Table.
This commit adds fix the file output and adds directory, number and string outputs.
  • Loading branch information
rldhont committed May 12, 2017
1 parent 512f5d5 commit b830eab
Showing 1 changed file with 80 additions and 3 deletions.
@@ -51,7 +51,11 @@
from processing.core.outputs import OutputRaster
from processing.core.outputs import OutputHTML
from processing.core.outputs import OutputFile
from processing.core.outputs import OutputDirectory
from processing.core.outputs import OutputString
from processing.core.outputs import OutputNumber
from processing.tools.system import isWindows
from processing.tools.system import setTempOutput
from processing.script.WrongScriptException import WrongScriptException
from RUtils import RUtils

@@ -60,6 +64,7 @@ class RAlgorithm(GeoAlgorithm):

R_CONSOLE_OUTPUT = 'R_CONSOLE_OUTPUT'
RPLOTS = 'RPLOTS'
R_OUTPUT_VALUES = 'R_OUTPUT_VALUES'

def getCopy(self):
newone = RAlgorithm(self.descriptionFile)
@@ -97,6 +102,7 @@ def parseDescription(self, lines):
self.commands = []
self.showPlots = False
self.showConsoleOutput = False
self.saveOutputValues = False
self.useRasterPackage = True
self.passFileNames = False
self.verboseCommands = []
@@ -106,7 +112,7 @@ def parseDescription(self, lines):
if line.startswith('##'):
try:
self.processParameterLine(line)
except Exception:
except Exception as e:
raise WrongScriptException(
self.tr('Could not load R script: %s.\n Problem with line %s' % (self.descriptionFile, line)))
elif line.startswith('>'):
@@ -269,8 +275,24 @@ def processOutputParameterToken(self, token):
out = OutputVector()
elif token.lower().strip().startswith('table'):
out = OutputTable()
elif token.lower().strip().startswith('file'):
out = OutputFile()
else:
if token.lower().strip().startswith('file'):
out = OutputFile()
ext = token.strip()[len('file') + 1:]
if ext:
out.ext = ext
elif token.lower().strip().startswith('directory'):
out = OutputDirectory()
elif token.lower().strip().startswith('number'):
out = OutputNumber()
elif token.lower().strip().startswith('string'):
out = OutputString()

if not self.saveOutputValues and out:
outVal = OutputFile(RAlgorithm.R_OUTPUT_VALUES, self.tr('R Output values'), ext='txt')
outVal.hidden = True
self.addOutput(outVal)
self.saveOutputValues = True

return out

@@ -288,6 +310,10 @@ def processAlgorithm(self, progress):
progress.setCommand(line)
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
RUtils.executeRAlgorithm(self, progress)
if self.saveOutputValues:
with open(self.getOutputValue(RAlgorithm.R_OUTPUT_VALUES), 'r') as f:
lines = [line.strip() for line in f]
self.parseOutputValues(iter(lines))
if self.showPlots:
htmlfilename = self.getOutputValue(RAlgorithm.RPLOTS)
f = open(htmlfilename, 'w')
@@ -299,6 +325,37 @@ def processAlgorithm(self, progress):
f.write(RUtils.getConsoleOutput())
f.close()

def parseOutputValues(self, lines):
if not self.saveOutputValues:
return

out = None
ender = 0
line = lines.next().strip('\n').strip('\r')
while ender < 10:
if line.startswith('##'):
name = line.replace('#', '')
out = self.getOutputFromName(name)
else:
if line == '':
ender += 1
else:
ender = 0
if out:
if isinstance(out, OutputNumber):
out.setValue(float(line) if '.' in line else int(line))
elif isinstance(out, OutputString):
if not out.value:
out.setValue(line)
else:
out.value += '\n\r' + line
else:
out.setValue(line)
try:
line = lines.next().strip('\n').strip('\r')
except:
break

def getFullSetOfRCommands(self):
commands = []
commands += self.getImportCommands()
@@ -309,6 +366,15 @@ def getFullSetOfRCommands(self):

def getExportCommands(self):
commands = []

# Output Values
outputDataFile = None
if self.saveOutputValues:
outputDataFile = self.getOutputValue(RAlgorithm.R_OUTPUT_VALUES)
if not outputDataFile:
setTempOutput(self.getOutputFromName(RAlgorithm.R_OUTPUT_VALUES), self)
outputDataFile = self.getOutputValue(RAlgorithm.R_OUTPUT_VALUES)

for out in self.outputs:
if isinstance(out, OutputRaster):
value = out.value
@@ -334,6 +400,9 @@ def getExportCommands(self):
value = out.value
value = value.replace('\\', '/')
commands.append('write.csv(' + out.name + ',"' + value + '")')
elif out.name != RAlgorithm.R_OUTPUT_VALUES:
commands.append('cat("##' + out.name + '",file="' + outputDataFile + '",sep="\n",append=TRUE)')
commands.append('cat(' + out.name + ',file="' + outputDataFile + '",sep="\n",append=TRUE)')

if self.showPlots:
commands.append('dev.off()')
@@ -358,6 +427,7 @@ def getImportCommands(self):
commands.append('library("raster")')
commands.append('library("rgdal")')

# Add parameters
for param in self.parameters:
if isinstance(param, ParameterRaster):
if param.value is None:
@@ -476,6 +546,13 @@ def getImportCommands(self):
s += ')\n'
commands.append(s)

# Set outputs
for out in self.outputs:
if isinstance(out, OutputFile) or isinstance(out, OutputDirectory):
if not out.value:
setTempOutput(out, self)
commands.append(out.name + ' = "' + out.value + '"')

if self.showPlots:
htmlfilename = self.getOutputValue(RAlgorithm.RPLOTS)
self.plotsFilename = htmlfilename + '.png'

0 comments on commit b830eab

Please sign in to comment.