03 Geographic scripting in uDig - halfway between user and developer

Embed Size (px)

Citation preview

  • nvironmental ngineeringydroloGISHydroloGIS S.r.l. - Via Siemens, 19 - 39100 Bolzano www.hydrologis.com

    Open Source GIS

    Geographic scripting in uDig - halfwaybetween user and developer

    Geoinformation Research Group, Department of GeographyUniversity of Potsdam

    March 2013

    The scripting consoleTutor: Andrea Antonello

  • The Geoscript editor

    Scritping is one of the powerful things in GIS. Non developers have the

    possibility to create great automatisations through it.

    uDig's scripting console is based on the groovy java scripting language.

    The geoscript geographic scripting engine can be used from within uDig.

    http://groovy.codehaus.org/http://www.geoscript.org

  • Open the console

    Two icons can be used to open the scripting editor: one for creating a new

    empty script and one to open an existing script.

  • Let's create a new one. The user will be prompted to save the new script to

    file and an empty editor is opened.

    There are a few tool inside the editor, needed to start and stop scripts, or set

    the heap memory allowed to be used by a script or enable logging.

  • Script away, with command completion and syntax coloring

    Inside the editor some basic command completion is available. For geoscript

    objects, as for example the widely use Geometry:

  • but also for methods, as for example the fromWKT, a handy way to create

    geometries on the fly:

  • The base language: be Groovy!

    In order to be able exploit 100% the console and scripting engine, it is

    mandatory to get a good insight of the base language that can be used in the

    console.

    Before we start with the geo part, we will investigate a bit groovy.

    Let's create a new script to do so. We should find ourself in front of a nice

    empty editor.

  • Writing strings

    To run your first script, simply write the following in the editor

    // write a stringprintln "This is a string"

    and push the play button.

    The result should be the following inside the console window:

    Process started: 2013-02-10 18:02:03

    This is a string

    Process finished: 2013-02-10 18:02:04

    The script simply prints the string in the console. It also gives information

    about the start and end timestamps of the script execution.

    Note that the editor executes only the selected text inside the editor. If

    nothing is selected, all of it is used.

  • Also more complex strings can be used, by surrounding text with triple

    quotes:

    // write a complex stringprintln """Inside triple quotes

    you can

    do almost anything. It is kind of an advanced string!"""

    Select only the second part and see if it is executed properly.

  • Variables

    // define variables

    // a stringdef name = "Luis"// a numberdef age = 25

    /* * insert the variables into a string template * through the use of ${} */def myTemplate1 = "Hi, my name is ${name} and I'm ${age}."println myTemplate1

    // strings and numbers can also be concatenated through the + signdef myTemplate2 = "Hi, my name is " + name + " and I'm " + age + "."println myTemplate2

  • Lists

    // working with lists

    // create a list of stringsdef list = ["Merano", "Bolzano", "Trento"];println list;

    // how to access the elements?println "The elements start at position 0: " + list[0]

    // how to add an element to the list?list

  • Lists magic - part 1

    // lists magic - part 1

    def list = ["Merano", "Bolzano", "Trento"];// to loop over a list the default 'it' can be usedlist.each { println it}

    // ...or your very own variable...list.each{ myVar -> println "This a town: " + myVar}

    // ...or you can use an index, toolist.eachWithIndex{myVar, i -> println "${myVar} is town N.${i}"}

  • Lists magic - part 2

    // lists magic - part 2

    def list = ["Merano", "Bolzano", "Trento"];println "This is the original list: " + list

    // lists can be sortedlist.sort();println "This is the sorted list: " + list

    // and reverse sorteddef revList = list.reverse();

    // note that while sort changes the original list, reverse makes a copyprintln "This is list after the sorting: " + listprintln "This is reverse list: " + revListprintln "This is list after the reverse sorting: " + list

  • Lists magic - part 3

    // lists magic - part 3

    // concatenate list def abc = ["a", "b", "c"]def cde = ["c", "d", "e"]def newabcde = abc + cdeprintln newabcde

    // through 'join' the list can be concatenated to one single stringprintln newabcde.join(",")println newabcde.join(" | ")

    // if we are talking about numbers, some functions applydef nums = [1.0, 2, 3.5]println nums.max()println nums.min()println nums.sum()

  • Lists magic - part 4

    // lists magic - part 4

    // modify each element of the list with collectdef abc = ["a", "b", "c"]println "Original abc: " + abcabc = abc.collect{ it += " is a letter"}println "Modified abc: " + abc

    // flatten nested listsdef abc = ["a", "b", "c"]def cde = ["c", "d", "e"]abc

  • Maps (Hash)

    Groovy speaking a Map is a container of key and value pairs.

    // working with maps

    // create a map// key1:value1, key2:value2, ...def townsProvinceMap = [merano:"BZ", bolzano:"BZ", trento:"TN"]println townsProvinceMap

    // ways of accessing the values of a map

    // implicitprintln townsProvinceMap.merano// the "array" wayprintln townsProvinceMap["merano"]// through the "getter"println townsProvinceMap.get("merano")

    // ways to add an element// implicittownsProvinceMap.lagundo = "BZ"println townsProvinceMap// through the put methodtownsProvinceMap.put("Postdam", "BR")println townsProvinceMap

  • Maps magic

    // maps magic

    def townsProvinceMap = [merano:"BZ", bolzano:"BZ", trento:"TN"]// iterate the thing with the default value...townsProvinceMap.each{ println it}

    // ...or with key and value separated...townsProvinceMap.each{ println "${it.key} is in province of ${it.value}"}

    // ...or with own varstownsProvinceMap.each{key, value -> println "${key} is in province of ${value}"}

  • Ranges

    Range can be seen at first as a sequence, but there is much more behind it.

    // working with ranges

    // create a rangedef range = 1..3

    // do some iterationsrange.each{ println it}range.each{ println "what?"}

    // and what about dates?def now = new Date();def nextWeek = now + 7;(now..nextWeek).each{ println it}

    // since ranges have a from, to and size...println "A range from " + range.from + " to " + range.to + " of size " + range.size()// ...you can use them in for loops...for (i in 1..3){ println "step number: ${i}"}// ...which ovbiously could be done like the following(1..3).each{ println "closure step number: ${it}"}

  • Groovy: working with files & filesystem

    Groovy allows to access the OS-environment and read the filesystem.

    // working with the filesystem

    // get system infoSystem.env.each{ println it}// get the home folderdef userHome = System.getenv("HOME")println userHome

    // list a folder's contentdef home = new File(userHome)println "The contents of " + home.absolutePath + " are:"home.eachFile{ file -> println "\t" + file}// list only foldersprintln "...of which folders:"home.eachDir{ dir -> println "\t" + dir}// list only filesprintln "...of which files:"home.eachFile{ file -> if(file.isFile()) println "\t" + file}// recursive list contentprintln "Recursive folders content:"home.eachDirRecurse{ dir -> println "\t" + dir}

  • Reading Files

    // reading files

    // start with creating a new file to be read afterwardsdef newFile = new File(System.getenv("HOME") + "/testFileToBeRemoved.txt");

    // one way to writ text to filenewFile.write("""A new header.A new testline.A second testline.""")

    // read the file line by linenewFile.eachLine{ line, index -> println "line " + index + ". " + line }

    // read the file into a string variabledef content = newFile.textprintln content

  • Writing Files

    // writing files

    def file = new File(System.getenv("HOME") + "/testFileToBeRemoved.txt");println file.text// append some contentfile

  • Reading CSV Files

    // read values from a csv file

    // create a sample csv filedef file = new File(System.getenv("HOME") + "/sample.csv");file.write("""# id, lat, lon, elev1, 11.0, 46.0, 250

    2, 11.1, 46.1, 2513, 11.2, 46.2, 252""")

    println file.text

    // read the csv valuesdef recordsList = []file.eachLine{ if(it.trim().length() == 0) { println "Empty line hit." } else if(it.startsWith("#")) { println "Comment line hit." } else { def lineSplit = it.split(",") println "Values: ${lineSplit[0]}, ${lineSplit[1]}, ${lineSplit[2]}, ${lineSplit[3]}" }}

  • Groovy: Data structures for complex scripts

    // working with data structures

    // create a data structureclass Record { def id def lat def lon def elev public String toString(){ "Values: [${id}, ${lat}, ${lon}, ${elev}]" }}

    // read the csv into a list of recordsdef file = new File(System.getenv("HOME") + "/sample.csv");def recordsList = []file.eachLine{ if(it.trim().length() > 0 && !it.startsWith("#")) { def lineSplit = it.split(",") def record = new Record() record.id = lineSplit[0] record.lat = lineSplit[1] record.lon = lineSplit[2] record.elev = lineSplit[3] recordsList

  • Groovy: most important conditions and loops

    If-then-else:

    def x = falsedef y = false

    if ( x ) { x = false} else { y = true}

    Ternary operator:

    def y = 5def x = (y > 1) ? "worked" : "failed"

    While loop:

    def x = 0def y = 5

    while ( y-- > 0 ) { x++}

  • For loop:

    for (int i = 0; i < 5; i++) { ...}

    def x = 0for ( i in 0..9 ) { x += i}

    x = 0for ( i in [0, 1, 2, 3, 4] ) { x += i}

    Loop with closures:

    def stringList = [ "java", "perl", "python", "ruby", "c#", "cobol", "groovy", "jython", "smalltalk", "prolog", "m", "yacc" ];

    stringList.each() { print " ${it}"}

  • This work is released under Creative Commons Attribution ShareAlike (CC-BY-SA)

    Much of the knowledge needed to create this training material hasbeen produced by the sparkling knights of the GeoTools, JTS,Geoscript and uDig community. Their community websites are full oflearning material that can be use to grow knowledge beyond theboundaries of this set of tutorials.

    The Groovy examples base on the great documentation available onGroovy's homepage.

    Another essential source has been the Wikipedia community effort.

    Particular thanks go to those friends that directly or indirectly helpedout in the creation and review of this series of handbooks.

    This tutorial is brought to you by HydroloGIS.

    http://en.wikipedia.org/wiki/Share-alikehttp://www.hydrologis.com/

    Geographic scripting in uDig - halfway between user and developerThe Geoscript editorOpen the consoleScript away, with command completion and syntax coloring

    The base language: be Groovy!Writing stringsVariablesListsLists magic - part 1Lists magic - part 2Lists magic - part 3Lists magic - part 4Maps (Hash)Maps magicRanges

    Groovy: working with files & filesystemReading FilesWriting FilesReading CSV Files

    Groovy: Data structures for complex scriptsGroovy: most important conditions and loops