2012-10-05 23:28:47 +02:00
# -*- coding: utf-8 -*-
"""
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
RAlgorithm . py
- - - - - - - - - - - - - - - - - - - - -
Date : August 2012
Copyright : ( C ) 2012 by Victor Olaya
Email : volayaf at gmail dot com
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
"""
__author__ = ' Victor Olaya '
__date__ = ' August 2012 '
__copyright__ = ' (C) 2012, Victor Olaya '
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = ' $Format: % H$ '
2012-09-15 18:25:25 +03:00
import os
from PyQt4 . QtCore import *
from PyQt4 . QtGui import *
from PyQt4 import QtGui , QtCore
2013-06-06 19:41:41 +02:00
from sextante . core . SextanteConfig import SextanteConfig
2012-09-15 18:25:25 +03:00
from sextante . core . GeoAlgorithm import GeoAlgorithm
from sextante . parameters . ParameterRaster import ParameterRaster
from sextante . parameters . ParameterTable import ParameterTable
from sextante . parameters . ParameterVector import ParameterVector
from sextante . parameters . ParameterMultipleInput import ParameterMultipleInput
from sextante . script . WrongScriptException import WrongScriptException
from sextante . outputs . OutputTable import OutputTable
from sextante . outputs . OutputVector import OutputVector
from sextante . outputs . OutputRaster import OutputRaster
from sextante . parameters . ParameterString import ParameterString
from sextante . parameters . ParameterNumber import ParameterNumber
from sextante . parameters . ParameterBoolean import ParameterBoolean
from sextante . parameters . ParameterSelection import ParameterSelection
from sextante . parameters . ParameterTableField import ParameterTableField
from sextante . outputs . OutputHTML import OutputHTML
from sextante . r . RUtils import RUtils
from sextante . core . GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from sextante . core . SextanteLog import SextanteLog
from sextante . core . SextanteUtils import SextanteUtils
import subprocess
from sextante . parameters . ParameterExtent import ParameterExtent
from sextante . parameters . ParameterFile import ParameterFile
from sextante . outputs . OutputFile import OutputFile
from sextante . gui . Help2Html import Help2Html
class RAlgorithm ( GeoAlgorithm ) :
R_CONSOLE_OUTPUT = " R_CONSOLE_OUTPUT "
RPLOTS = " RPLOTS "
def getCopy ( self ) :
newone = RAlgorithm ( self . descriptionFile )
newone . provider = self . provider
return newone
def __init__ ( self , descriptionFile , script = None ) :
GeoAlgorithm . __init__ ( self )
self . script = script
self . descriptionFile = descriptionFile
if script is not None :
self . defineCharacteristicsFromScript ( )
if descriptionFile is not None :
self . defineCharacteristicsFromFile ( )
def getIcon ( self ) :
return QtGui . QIcon ( os . path . dirname ( __file__ ) + " /../images/r.png " )
def defineCharacteristicsFromScript ( self ) :
2013-03-26 14:15:12 +01:00
lines = self . script . split ( " \n " )
2012-09-15 18:25:25 +03:00
self . name = " [Unnamed algorithm] "
self . group = " User R scripts "
2013-03-20 21:50:40 +01:00
self . parseDescription ( iter ( lines ) )
2013-03-26 14:15:12 +01:00
def defineCharacteristicsFromFile ( self ) :
2013-03-20 21:50:40 +01:00
filename = os . path . basename ( self . descriptionFile )
self . name = filename [ : filename . rfind ( " . " ) ] . replace ( " _ " , " " )
2013-03-26 14:15:12 +01:00
self . group = " User R scripts "
2013-03-20 21:50:40 +01:00
with open ( self . descriptionFile , ' r ' ) as f :
lines = [ line . strip ( ) for line in f ]
self . parseDescription ( iter ( lines ) )
2013-03-26 14:15:12 +01:00
def parseDescription ( self , lines ) :
2012-09-15 18:25:25 +03:00
self . script = " "
self . commands = [ ]
self . showPlots = False
self . showConsoleOutput = False
2013-03-10 21:10:53 +01:00
self . useRasterPackage = True
2013-02-23 15:44:44 +01:00
self . passFileNames = False
2012-09-15 18:25:25 +03:00
self . verboseCommands = [ ]
2013-03-26 14:15:12 +01:00
ender = 0
2013-03-20 21:50:40 +01:00
line = lines . next ( ) . strip ( " \n " ) . strip ( " \r " )
2013-03-07 08:49:12 +01:00
while ender < 10 :
2012-09-15 18:25:25 +03:00
if line . startswith ( " ## " ) :
try :
self . processParameterLine ( line )
except Exception :
raise WrongScriptException ( " Could not load R script: " + self . descriptionFile + " . \n Problem with line \" " + line + " \" " )
elif line . startswith ( " > " ) :
self . commands . append ( line [ 1 : ] )
self . verboseCommands . append ( line [ 1 : ] )
if not self . showConsoleOutput :
self . addOutput ( OutputHTML ( RAlgorithm . R_CONSOLE_OUTPUT , " R Console Output " ) )
self . showConsoleOutput = True
else :
2013-03-07 08:49:12 +01:00
if line == ' ' :
ender + = 1
else :
ender = 0
2012-09-15 18:25:25 +03:00
self . commands . append ( line )
self . script + = line + " \n "
2013-03-20 21:50:40 +01:00
try :
line = lines . next ( ) . strip ( " \n " ) . strip ( " \r " )
except :
break
2012-09-15 18:25:25 +03:00
def getVerboseCommands ( self ) :
return self . verboseCommands
def createDescriptiveName ( self , s ) :
return s . replace ( " _ " , " " )
def processParameterLine ( self , line ) :
param = None
out = None
line = line . replace ( " # " , " " ) ;
if line . lower ( ) . strip ( ) . startswith ( " showplots " ) :
self . showPlots = True
self . addOutput ( OutputHTML ( RAlgorithm . RPLOTS , " R Plots " ) ) ;
return
2013-03-15 09:34:12 +01:00
if line . lower ( ) . strip ( ) . startswith ( " dontuserasterpackage " ) :
2013-03-10 21:10:53 +01:00
self . useRasterPackage = False
2013-02-28 22:08:32 +01:00
return
if line . lower ( ) . strip ( ) . startswith ( " passfilenames " ) :
2013-02-23 15:44:44 +01:00
self . passFileNames = True
return
2012-09-15 18:25:25 +03:00
tokens = line . split ( " = " ) ;
desc = self . createDescriptiveName ( tokens [ 0 ] )
if tokens [ 1 ] . lower ( ) . strip ( ) == " group " :
self . group = tokens [ 0 ]
return
2013-02-07 23:30:53 +01:00
if tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " raster " ) :
2012-09-15 18:25:25 +03:00
param = ParameterRaster ( tokens [ 0 ] , desc , False )
elif tokens [ 1 ] . lower ( ) . strip ( ) == " vector " :
param = ParameterVector ( tokens [ 0 ] , desc , ParameterVector . VECTOR_TYPE_ANY )
elif tokens [ 1 ] . lower ( ) . strip ( ) == " table " :
param = ParameterTable ( tokens [ 0 ] , desc , False )
2013-02-07 23:30:53 +01:00
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " multiple raster " ) :
2012-09-15 18:25:25 +03:00
param = ParameterMultipleInput ( tokens [ 0 ] , desc , ParameterMultipleInput . TYPE_RASTER )
param . optional = False
elif tokens [ 1 ] . lower ( ) . strip ( ) == " multiple vector " :
param = ParameterMultipleInput ( tokens [ 0 ] , desc , ParameterMultipleInput . TYPE_VECTOR_ANY )
param . optional = False
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " selection " ) :
options = tokens [ 1 ] . strip ( ) [ len ( " selection " ) : ] . split ( " ; " )
param = ParameterSelection ( tokens [ 0 ] , desc , options ) ;
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " boolean " ) :
default = tokens [ 1 ] . strip ( ) [ len ( " boolean " ) + 1 : ]
param = ParameterBoolean ( tokens [ 0 ] , desc , default )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " number " ) :
try :
default = float ( tokens [ 1 ] . strip ( ) [ len ( " number " ) + 1 : ] )
param = ParameterNumber ( tokens [ 0 ] , desc , default = default )
except :
raise WrongScriptException ( " Could not load R script: " + self . descriptionFile + " . \n Problem with line \" " + line + " \" " )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " field " ) :
field = tokens [ 1 ] . strip ( ) [ len ( " field " ) + 1 : ]
found = False
for p in self . parameters :
if p . name == field :
found = True
break
if found :
param = ParameterTableField ( tokens [ 0 ] , tokens [ 0 ] , field )
elif tokens [ 1 ] . lower ( ) . strip ( ) == " extent " :
param = ParameterExtent ( tokens [ 0 ] , desc )
elif tokens [ 1 ] . lower ( ) . strip ( ) == " file " :
param = ParameterFile ( tokens [ 0 ] , desc , False )
elif tokens [ 1 ] . lower ( ) . strip ( ) == " folder " :
param = ParameterFile ( tokens [ 0 ] , desc , True )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " string " ) :
default = tokens [ 1 ] . strip ( ) [ len ( " string " ) + 1 : ]
param = ParameterString ( tokens [ 0 ] , desc , default )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " output raster " ) :
out = OutputRaster ( )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " output vector " ) :
out = OutputVector ( )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " output table " ) :
out = OutputTable ( )
elif tokens [ 1 ] . lower ( ) . strip ( ) . startswith ( " output file " ) :
out = OutputFile ( )
if param != None :
self . addParameter ( param )
elif out != None :
out . name = tokens [ 0 ]
out . description = tokens [ 0 ]
self . addOutput ( out )
else :
raise WrongScriptException ( " Could not load R script: " + self . descriptionFile + " . \n Problem with line \" " + line + " \" " )
def processAlgorithm ( self , progress ) :
if SextanteUtils . isWindows ( ) :
path = RUtils . RFolder ( )
if path == " " :
raise GeoAlgorithmExecutionException ( " R folder is not configured. \n Please configure it before running R scripts. " )
loglines = [ ]
loglines . append ( " R execution commands " )
loglines + = self . getFullSetOfRCommands ( )
for line in loglines :
progress . setCommand ( line )
SextanteLog . addToLog ( SextanteLog . LOG_INFO , loglines )
RUtils . executeRAlgorithm ( self , progress )
if self . showPlots :
htmlfilename = self . getOutputValue ( RAlgorithm . RPLOTS )
f = open ( htmlfilename , " w " )
f . write ( " <img src= \" " + self . plotsFilename + " \" /> " )
f . close ( )
if self . showConsoleOutput :
htmlfilename = self . getOutputValue ( RAlgorithm . R_CONSOLE_OUTPUT )
2012-10-27 10:59:23 +02:00
f = open ( htmlfilename , " w " )
2012-09-15 18:25:25 +03:00
f . write ( RUtils . getConsoleOutput ( ) )
f . close ( )
def getFullSetOfRCommands ( self ) :
commands = [ ]
commands + = self . getImportCommands ( )
commands + = self . getRCommands ( )
commands + = self . getExportCommands ( )
return commands
def getExportCommands ( self ) :
commands = [ ]
for out in self . outputs :
if isinstance ( out , OutputRaster ) :
value = out . value
value = value . replace ( " \\ " , " / " )
2013-02-26 12:46:28 +01:00
if self . useRasterPackage or self . passFileNames :
2013-02-25 14:47:27 +01:00
commands . append ( " writeRaster( " + out . name + " , \" " + value + " \" , overwrite=TRUE) " )
2013-02-07 23:30:53 +01:00
else :
2013-02-26 12:46:28 +01:00
if not value . endswith ( " tif " ) :
value = value + " .tif "
2013-02-07 23:30:53 +01:00
commands . append ( " writeGDAL( " + out . name + " , \" " + value + " \" ) " )
2012-09-15 18:25:25 +03:00
if isinstance ( out , OutputVector ) :
value = out . value
if not value . endswith ( " shp " ) :
value = value + " .shp "
value = value . replace ( " \\ " , " / " )
filename = os . path . basename ( value )
filename = filename [ : - 4 ]
commands . append ( " writeOGR( " + out . name + " , \" " + value + " \" , \" "
+ filename + " \" , driver= \" ESRI Shapefile \" ) " ) ;
if self . showPlots :
commands . append ( " dev.off() " ) ;
return commands
def getImportCommands ( self ) :
commands = [ ]
2013-07-18 17:16:16 +02:00
2013-02-25 17:25:04 +01:00
# just use main mirror
commands . append ( ' options( " repos " = " http://cran.at.r-project.org/ " ) ' )
2013-07-18 17:16:16 +02:00
# try to install packages if needed
packages = RUtils . getRequiredPackages ( self . script )
packages . extend ( [ ' rgdal ' , ' raster ' ] )
for p in packages :
commands . append (
' tryCatch(find.package( " ' + p +
' " ), error=function(e) install.packages( " ' + p + ' " , dependencies=TRUE)) ' )
commands . append ( ' library( " raster " ) ' )
commands . append ( ' library( " rgdal " ) ' )
2013-03-26 14:15:12 +01:00
2012-09-15 18:25:25 +03:00
for param in self . parameters :
if isinstance ( param , ParameterRaster ) :
value = param . value
value = value . replace ( " \\ " , " / " )
2013-02-23 15:44:44 +01:00
if self . passFileNames :
2013-02-25 14:47:27 +01:00
commands . append ( param . name + " = \" " + value + " \" " )
2013-02-23 15:44:44 +01:00
elif self . useRasterPackage :
2013-02-07 23:30:53 +01:00
commands . append ( param . name + " = " + " brick( \" " + value + " \" ) " )
else :
commands . append ( param . name + " = " + " readGDAL( \" " + value + " \" ) " )
2012-09-15 18:25:25 +03:00
if isinstance ( param , ParameterVector ) :
value = param . getSafeExportedLayer ( )
value = value . replace ( " \\ " , " / " )
filename = os . path . basename ( value )
filename = filename [ : - 4 ]
2012-12-08 22:47:41 +01:00
folder = os . path . dirname ( value )
2013-02-23 15:44:44 +01:00
if self . passFileNames :
2013-02-25 14:47:27 +01:00
commands . append ( param . name + " = \" " + value + " \" " )
2013-02-23 15:44:44 +01:00
else :
commands . append ( param . name + " = readOGR( \" " + folder + " \" ,layer= \" " + filename + " \" ) " )
2012-09-15 18:25:25 +03:00
if isinstance ( param , ParameterTable ) :
2013-02-28 22:08:32 +01:00
value = param . value
2012-09-15 18:25:25 +03:00
if not value . lower ( ) . endswith ( " csv " ) :
raise GeoAlgorithmExecutionException ( " Unsupported input file format. \n " + value )
2013-02-23 15:44:44 +01:00
if self . passFileNames :
2013-02-25 14:47:27 +01:00
commands . append ( param . name + " = \" " + value + " \" " )
2013-02-23 15:44:44 +01:00
else :
commands . append ( param . name + " <- read.csv( \" " + value + " \" , head=TRUE, sep= \" , \" ) " )
elif isinstance ( param , ( ParameterTableField , ParameterString , ParameterFile ) ) :
2012-09-15 18:25:25 +03:00
commands . append ( param . name + " = \" " + param . value + " \" " )
2013-02-23 15:44:44 +01:00
elif isinstance ( param , ( ParameterNumber , ParameterSelection ) ) :
2012-09-15 18:25:25 +03:00
commands . append ( param . name + " = " + str ( param . value ) )
2013-02-23 15:44:44 +01:00
elif isinstance ( param , ParameterBoolean ) :
2012-09-15 18:25:25 +03:00
if param . value :
commands . append ( param . name + " =TRUE " )
else :
commands . append ( param . name + " =FALSE " )
2013-02-23 15:44:44 +01:00
elif isinstance ( param , ParameterMultipleInput ) :
2012-09-15 18:25:25 +03:00
iLayer = 0 ;
if param . datatype == ParameterMultipleInput . TYPE_RASTER :
layers = param . value . split ( " ; " )
for layer in layers :
2013-02-23 15:44:44 +01:00
#if not layer.lower().endswith("asc") and not layer.lower().endswith("tif") and not self.passFileNames:
#raise GeoAlgorithmExecutionException("Unsupported input file format.\n" + layer)
2012-09-15 18:25:25 +03:00
layer = layer . replace ( " \\ " , " / " )
2013-02-23 15:44:44 +01:00
if self . passFileNames :
2013-02-28 22:08:32 +01:00
commands . append ( " tempvar " + str ( iLayer ) + " <- \" " + layer + " \" " )
2013-02-23 15:44:44 +01:00
elif self . useRasterPackage :
2013-02-25 14:47:27 +01:00
commands . append ( " tempvar " + str ( iLayer ) + " <- " + " brick( \" " + layer + " \" ) " )
2013-02-07 23:30:53 +01:00
else :
2013-02-25 14:47:27 +01:00
commands . append ( " tempvar " + str ( iLayer ) + " <- " + " readGDAL( \" " + layer + " \" ) " )
2012-09-15 18:25:25 +03:00
iLayer + = 1
else :
exported = param . getSafeExportedLayers ( )
layers = exported . split ( " ; " )
for layer in layers :
2013-02-23 15:44:44 +01:00
if not layer . lower ( ) . endswith ( " shp " ) and not self . passFileNames :
2012-09-15 18:25:25 +03:00
raise GeoAlgorithmExecutionException ( " Unsupported input file format. \n " + layer )
layer = layer . replace ( " \\ " , " / " )
filename = os . path . basename ( layer )
filename = filename [ : - 4 ]
2013-02-23 15:44:44 +01:00
if self . passFileNames :
2013-02-25 14:47:27 +01:00
commands . append ( " tempvar " + str ( iLayer ) + " <- \" " + layer + " \" " )
2013-02-23 15:44:44 +01:00
else :
2013-02-25 14:47:27 +01:00
commands . append ( " tempvar " + str ( iLayer ) + " <- " + " readOGR( \" " + layer + " \" ,layer= \" " + filename + " \" ) " )
2012-09-15 18:25:25 +03:00
iLayer + = 1
s = " "
s + = param . name
s + = ( " = c( " )
iLayer = 0
for layer in layers :
if iLayer != 0 :
s + = " , "
s + = " tempvar " + str ( iLayer )
iLayer + = 1
s + = " ) \n "
commands . append ( s )
if self . showPlots :
htmlfilename = self . getOutputValue ( RAlgorithm . RPLOTS )
self . plotsFilename = htmlfilename + " .png "
self . plotsFilename = self . plotsFilename . replace ( " \\ " , " / " ) ;
commands . append ( " png( \" " + self . plotsFilename + " \" ) " ) ;
return commands
def getRCommands ( self ) :
return self . commands
def helpFile ( self ) :
2013-03-20 21:50:40 +01:00
helpfile = unicode ( self . descriptionFile ) + " .help "
2012-09-15 18:25:25 +03:00
if os . path . exists ( helpfile ) :
h2h = Help2Html ( )
return h2h . getHtmlFile ( self , helpfile )
else :
return None
def checkBeforeOpeningParametersDialog ( self ) :
2013-07-18 17:16:16 +02:00
msg = RUtils . checkRIsInstalled ( )
if msg is not None :
html = ( " <p>This algorithm requires R to be run. "
" Unfortunately, it seems that R is not installed in your system, or it is not correctly configured to be used from QGIS</p> " )
html + = ' <p><a href= " http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html " >Click here</a> to know more about how to install and configure R to be used with SEXTANTE</p> '
return html
def getPostProcessingErrorMessage ( self , wrongLayers ) :
html = GeoAlgorithm . getPostProcessingErrorMessage ( self , wrongLayers )
msg = RUtils . checkRIsInstalled ( True )
html + = ( " <p>This algorithm requires R to be run. A test to check if R is correctly installed "
" and configured in your system has been performed, with the following result:</p><ul><i> " )
if msg is None :
html + = " GRASS seems to be correctly installed and configured</i></li></ul> "
html + = " <p>The script you have executed needs the following packages:</p><ul> "
packages = RUtils . getRequiredPackages ( self . script )
for p in packages :
html + = ' <li> ' + p + ' </li> '
html + = " </ul><p>Make sure they are installed in your R environment before trying to execute this script.</p> "
2012-09-15 18:25:25 +03:00
else :
2013-07-18 17:16:16 +02:00
html + = msg + " </i></li></ul> "
html + = ' <p><a href= " http://docs.qgis.org/2.0/html/en/docs/user_manual/sextante/3rdParty.html " >Click here</a> to know more about how to install and configure R to be used with SEXTANTE</p> '
2012-09-15 18:25:25 +03:00
2013-07-18 17:16:16 +02:00
return html