20
GEOGRAPHIC SCRIPTING IN GVSIG HALFWAY BETWEEN USER AND DEVELOPER Geoinformation Research Group, Department of Geography University of Potsdam 21-25 November 2016 Andrea Antonello PART 6: FROM GEO INTO YOUR REPORT

PART 6: FROM GEO INTO YOUR REPORT

Embed Size (px)

Citation preview

Page 1: PART 6: FROM GEO INTO YOUR REPORT

GEOGRAPHIC SCRIPTING IN GVSIGHALFWAY BETWEEN USER AND DEVELOPER

Geoinformation Research Group,Department of Geography

University of Potsdam

21-25 November 2016

Andrea Antonello

PART 6: FROM GEO INTO YOUR REPORT

Page 2: PART 6: FROM GEO INTO YOUR REPORT

REPORTING UTILITIESFrom within gvSIG it is possible also to create charts and documents.Since those functionalities are not completely integrated into thescripting engine, some tricky looking imports are required most of thetime. This should not scare the user that want's to generate simplereports in batch mode.

In the following examples we will see how to produce charts and spreadsheets.libreoffice

Page 3: PART 6: FROM GEO INTO YOUR REPORT

OBJECTIVELet's assume we have to write a report about how min and max averagetemperature changed between 1983 and 2005 in Germany.

We want to create:

a shapefile containing polygons connected to the temperaturesa chart showing the monthly averages of min and maxa spreadsheet with the cleaned up dataset (ex. remove header)

The maps have to be in CRS EPSG:32632.

The necessary data can be found on the page of Surface meteorology andSolar Energy maintained by NASA: https://eosweb.larc.nasa.gov/sse/

Page 4: PART 6: FROM GEO INTO YOUR REPORT

SUMMARY OF THE STEPSBefore we start, let's create a script with the comments of what we aregoing to implement:

# parse temperature data and extract # a list of information: [lat, lon, tempJan, tempFeb,...]

# create the shapefile ## get polygon of Germany ## filter only the data contained in the ## polygon of Germany ## create polygons with attached temperatures ## and write the features into the shapefile

# create a chart of the average temperatures

# insert the parsed data into a spreadsheet

Page 5: PART 6: FROM GEO INTO YOUR REPORT

STEP 1: PARSE TEMPERATURE DATAfrom gvsig import *from gvsig.geom import *

def main(*args):

# parse temperature data and extract # a dictionary {point: temperaturesList} minPath = "/home/hydrologis/data/potsdam_data/22yr_T10MN" dataFile = open(minPath, "r") lines = dataFile.readlines() dataFile.close() data = {} dataStarted = False for line in lines: if dataStarted or line.startswith("-90"): dataStarted = True lineSplit = line.split(" ") lat = float(lineSplit[0]) lon = float(lineSplit[1]) pointLL = createPoint2D(lon, lat) temperatures = [] for i in range(2, len(lineSplit)-1): # last is avg temperatures.append(float(lineSplit[i])) data[pointLL.convertToWKT()] = temperatures print minData

Page 6: PART 6: FROM GEO INTO YOUR REPORT

STEP 1: PARSE TEMPERATURE DATA

def readData(path): dataFile = open(path, "r") lines = dataFile.readlines() dataFile.close() data = {} dataStarted = False for line in lines: if dataStarted or line.startswith("-90"): dataStarted = True lineSplit = line.split(" ") lat = float(lineSplit[0]) lon = float(lineSplit[1]) pointLL = createPoint2D(lon, lat) temperatures = [] for i in range(2, len(lineSplit)-1): # last is avg temperatures.append(float(lineSplit[i])) data[pointLL.convertToWKT()] = temperatures return data

def main(*args): minPath = "/home/hydrologis/data/potsdam_data/22yr_T10MN" maxPath = "/home/hydrologis/data/potsdam_data/22yr_T10MX" minData = readData(minPath) maxData = readData(maxPath)

To read also the max temperatures, let's do some code reuse:

Page 7: PART 6: FROM GEO INTO YOUR REPORT

STEP 2: GET GERMANY

# create the shapefile ## get polygon of Germany countriesPath = "/home/hydrologis/data/potsdam_data/ne_10m_admin_0_countries.shp" epsg = "EPSG:4326" countriesLayer = loadLayer("Shape", shpFile=countriesPath, CRS=epsg) features = countriesLayer.features("NAME='Germany'") if features.getCount() != 1: print "ERROR!" return

for i in features: germanyFeature = i.getCopy()

We can extract the polygon of Germany from a previous exercise:

It is very simple to get the points that are contained in the polygon:

## filter only the data contained in the ## polygon of Germany allPointsWKT= minData.keys() allPoints = map(lambda p: createGeometryFromWKT(p), allPointsWKT) pointsInGermany = filter(lambda p: p.intersects(germanyFeature.GEOMETRY), allPoints) print "Points in Germany are", len(pointsInGermany), "while all are", len(allPoints)

Page 8: PART 6: FROM GEO INTO YOUR REPORT

STEP 3: WRITE THE SHAPEFILE

## create polygons with attached temperatures ## and write the features into the shapefile

# create the transform between the original crs and the required newEpsg = "EPSG:32632" crs = getCRS(epsg) newCrs = getCRS(newEpsg) transform = crs.getCT(newCrs)

# create the new shapefile and set the editing mode schema = createFeatureType() schema.append("min", "DOUBLE", 8) schema.append("max", "DOUBLE", 8) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POLYGON, D2) shape = createShape(schema, prefixname="minmaxtemperatures", CRS=newEpsg) shape.edit()

First prepare the re-projection transformation and the output shapefile

Page 9: PART 6: FROM GEO INTO YOUR REPORT

STEP 3: WRITE THE SHAPEFILE

for point in pointsInGermany: x = point.x y = point.y

# points all represent the lower left corner # create the polygon considering that pts = [[x,y],[x,y+1],[x+1,y+1],[x+1,y],[x,y]] polygon = createPolygon2D(pts) # reproject the polygon polygon.reProject(transform)

# use the point's WKT as key to get the temperature data # from the dictionary minAvg = sum(minData[point.convertToWKT()])/12.0 maxAvg = sum(maxData[point.convertToWKT()])/12.0 shape.append(min=minAvg, max=maxAvg, GEOMETRY=polygon) shape.commit()

Then, in the main loop, reproject, average and write:

Page 10: PART 6: FROM GEO INTO YOUR REPORT

STEP 3: WRITE THE SHAPEFILE

# create an interval legend on the min values intervalLegend = VectorialIntervalLegend(POLYGON) intervalLegend.setStartColor(getColorFromRGB(0,0,255)) intervalLegend.setEndColor(getColorFromRGB(255,0,0)) intervalLegend.setIntervalType(1) store = shape.getFeatureStore() intervals = intervalLegend.calculateIntervals(store, "MIN", 5, POLYGON) intervalLegend.setIntervals(intervals) shape.setLegend(intervalLegend)

newview = currentProject().createView("Germany View") newview.setProjection(getCRS(newEpsg)) newview.addLayer(shape) newview.addLayer(countriesLayer) newview.showWindow()

newview.centerView(shape.fullEnvelope)

Style and load the data. Also load the countries layer to check the result.Since (as we already know) the countries layer will be messy outside the32632 zone, also zoom to the area of Germany:

Page 11: PART 6: FROM GEO INTO YOUR REPORT

INTERMEDIATE CHECKA this point the script, if run, should produce something like this(countries are styled to only show the borders)

Page 12: PART 6: FROM GEO INTO YOUR REPORT

STEP 4: CHART THE DATACharts can be created through the use of the project.

Charting in not exactly integrated in the scripting engine, so it requiresfor the user to import a whole pile of modules.

The following are the ones we will make use of in the example:

jfreechart

from org.jfree.chart import ChartFactoryfrom org.jfree.chart import ChartFramefrom org.jfree.data.xy import XYSeriesCollectionfrom org.jfree.data.xy import XYSeriesfrom org.jfree.chart.plot.PlotOrientation import *

Page 13: PART 6: FROM GEO INTO YOUR REPORT

STEP 4: CHART THE DATALet's pick the first point of the list of points inside Germany:

# create a chart of the average temperatures chartPoint = pointsInGermany[0] minTemperaturesList = minData[chartPoint.convertToWKT()] maxTemperaturesList = maxData[chartPoint.convertToWKT()]

Then create the XY chart series, fill them with the temperature data permonth and add them to a series collection:

dataset = XYSeriesCollection() seriesMin = XYSeries("min") seriesMax = XYSeries("max")

for i in range(0, 12): month = i + 1 seriesMin.add(month, minTemperaturesList[i]) seriesMax.add(month, maxTemperaturesList[i]) dataset.addSeries(seriesMin) dataset.addSeries(seriesMax)

Page 14: PART 6: FROM GEO INTO YOUR REPORT

STEP 4: CHART THE DATAFinally create the chart and display it in a windows:

chart = ChartFactory.createXYLineChart( "Temperatures", # chart title "Months", # x axis label "Degrees", #y axis label dataset, VERTICAL, # orientation True, # include legend True, # tooltips? False # URLs? )

# show the chart in a window frame = ChartFrame("Plot test", chart); frame.pack(); frame.setVisible(True);

Page 15: PART 6: FROM GEO INTO YOUR REPORT

STEP 4: CHART THE DATAThe JFreechart window allows the user to zoom and save the currentchart as image.

Page 16: PART 6: FROM GEO INTO YOUR REPORT

STEP 5: SPREADSHEETSTo create an modify spreadsheets gvSIG makes use of the project.

On its homepage a . In there it is possible to find all the functions that are

used in the next example.

In the same way as for the charting part, also the spreadsheet part needssome dedicated import statements:

jopendocument

section is dedicated to the programmerdocumentation

from java.io import Filefrom org.jopendocument.model import OpenDocumentfrom org.jopendocument.dom.spreadsheet import SpreadSheetfrom org.jopendocument.dom import OOUtils

Page 17: PART 6: FROM GEO INTO YOUR REPORT

STEP 5: SPREADSHEETS

It is simple to set values in the cells by using the column and row as onewould do with a matrix:

# write the header row in both sheets header = ["lat", "lon", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"] for i, value in enumerate(header): minSheet.setValueAt(value, i, 0) maxSheet.setValueAt(value, i, 0)

Once the imports are in place, it is possible to create a new spreadsheetand add two sheets to it for the min and max table values:

# insert the parsed data into a spreadsheet spreadsheetPath = "/home/hydrologis/data/potsdam_data/data_test.ods" # create a spreadsheet spreadSheet = SpreadSheet.create(2, 100, 70000) minSheet = spreadSheet.getSheet(0) minSheet.setName("MIN") maxSheet = spreadSheet.getSheet(1) maxSheet.setName("MAX")

Page 18: PART 6: FROM GEO INTO YOUR REPORT

STEP 5: SPREADSHEETSThen we can loop the ranges of lat and lon in order to have an ordered listof only the values inside Germany: row = 0 for lat in range(-90, 89): for lon in range(-180, 179): p = createPoint2D(lon, lat) if p in pointsInGermany: row += 1 minSheet.setValueAt(lon, 1, row) minSheet.setValueAt(lat, 0, row) maxSheet.setValueAt(lon, 1, row) maxSheet.setValueAt(lat, 0, row) minTemperaturesList = minData[p.convertToWKT()] maxTemperaturesList = maxData[p.convertToWKT()] for i, t in enumerate(minTemperaturesList): col = i + 2 minSheet.setValueAt(t, col, row) maxSheet.setValueAt(maxTemperaturesList[i], col, row)

Finally, save and open the file:

outputFile = File(spreadsheetPath) OOUtils.open(spreadSheet.saveAs(outputFile))

Page 19: PART 6: FROM GEO INTO YOUR REPORT

STEP 5: SPREADSHEETSThe resulting file should look like:

Page 20: PART 6: FROM GEO INTO YOUR REPORT

<license> This work is released under Creative Commons Attribution Share Alike (CC-BY-SA).</license>

<sources> Much of the knowledge needed to create this training material has been produced by the sparkling knights of the <a href="http:www.osgeo.org">Osgeo</a>, <a href="http://tsusiatsoftware.net/">JTS</a>, <a href="http://www.jgrasstools.org">JGrasstools</a> and <a href="http:www.gvsig.org">gvSIG</a> communities. Their websites are filled up with learning material that can be use to grow knowledge beyond the boundaries of this set of tutorials.

Another essential source has been the Wikipedia project.</sources>

<acknowledgments> Particular thanks go to those friends that directly or indirectly helped out in the creation and review of this series of handbooks. Thanks to Antonio Falciano for proofreading the course and Oscar Martinez for the documentation about gvSIG scripting.</acknowledgments>

<footer> This tutorial is brought to you by <a href="http:www.hydrologis.com">HydroloGIS</a>.<footer>