Skip to content

Commit

Permalink
Merge pull request #4571 from rldhont/release-2_18-processing-rscript…
Browse files Browse the repository at this point in the history
…s-outputs

[BUGFIX][Processing] R scripts do not have enough outputs
  • Loading branch information
rldhont committed May 17, 2017
2 parents bb7f95f + 5bdd038 commit 70a25d6
Showing 1 changed file with 80 additions and 3 deletions.
83 changes: 80 additions & 3 deletions python/plugins/processing/algs/r/RAlgorithm.py
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 70a25d6

Please sign in to comment.