Upload
andrea-antonello
View
211
Download
2
Embed Size (px)
Citation preview
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
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
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/
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
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
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:
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)
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
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:
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:
INTERMEDIATE CHECKA this point the script, if run, should produce something like this(countries are styled to only show the borders)
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 *
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)
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);
STEP 4: CHART THE DATAThe JFreechart window allows the user to zoom and save the currentchart as image.
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
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")
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))
STEP 5: SPREADSHEETSThe resulting file should look like:
<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>