Skip to content

Commit

Permalink
[BUGFIX][Processing] R scripts do not have enough outputs
Browse files Browse the repository at this point in the history
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 16, 2017
1 parent 126cf5f commit 5bdd038
Showing 1 changed file with 80 additions and 3 deletions.
83 changes: 80 additions & 3 deletions python/plugins/processing/algs/r/RAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,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

Expand All @@ -62,6 +66,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)
Expand Down Expand Up @@ -99,6 +104,7 @@ def parseDescription(self, lines):
self.commands = []
self.showPlots = False
self.showConsoleOutput = False
self.saveOutputValues = False
self.useRasterPackage = True
self.passFileNames = False
self.verboseCommands = []
Expand All @@ -108,7 +114,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('>'):
Expand Down Expand Up @@ -282,8 +288,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

Expand All @@ -301,6 +323,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')
Expand All @@ -312,6 +338,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()
Expand All @@ -322,6 +379,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
Expand All @@ -347,6 +413,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()')
Expand All @@ -371,6 +440,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:
Expand Down Expand Up @@ -489,6 +559,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'
Expand Down

0 comments on commit 5bdd038

Please sign in to comment.