Successfully reported this slideshow.
Upcoming SlideShare
×

PART 4: GEOGRAPHIC SCRIPTING

399 views

Published on

GEOGRAPHIC SCRIPTING IN GVSIG
HALFWAY BETWEEN USER AND DEVELOPER held at the University of Potsdam in 2016 - PART 4: GEOGRAPHIC SCRIPTING

Published in: Engineering
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

PART 4: GEOGRAPHIC SCRIPTING

1. 1. 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 4: GEOGRAPHIC SCRIPTING
2. 2. GEO-SCRIPTING IN GVSIG In gvSIG geographic scripting is done using the Python programming language syntax (the actual engine is called Jython). As proposed when creating a new script, most geo-related operations are done using the gvsig module. Also, a main method needs to be deﬁned, for the script to work: import gvsig def main(*args): # do some scripting here
3. 3. GEO-SCRIPTING IN GVSIG gvSIG imports will be used in several ways throughout the course, mostly because the way one uses imports depends on what he/she is writing... and also in order to make you better understand how things work. Let's see an example of two different ways to handle imports: from gvsig import * from gvsig.geom import * def main(*args): point = createPoint(D2, 30, 10) print "Point: ", point project = currentProject() print "Project name: ", project.name import gvsig from gvsig import geom def main(*args): point = geom.createPoint(geom.D2, 30, 10) print "Point: ", point project = gvsig.currentProject() print "Project name: ", project.name
4. 4. BUILDING GEOMETRIES Geometries can be built through the use of their constructors, which is the usual way to create geometries programmatically: # build 2D geometries by constructor # simple geometries # point point = geom.createPoint(geom.D2, 30, 10) print point # line line = geom.createLine(geom.D2, [(30,10), (10,30), (20,40), (40,40)]) print line.convertToWKT() # but also using points already created line = geom.createLine(geom.D2, [point, (10,30), (20,40), (40,40)]) print line.convertToWKT() # polygon polygon = geom.createPolygon(geom.D2, [[35,10],[10,20],[15,40],[45,45],[35,10]]) print polygon.convertToWKT()
5. 5. BUILDING GEOMETRIES The same applies to the multi-geometries: # multi-geometries # multipoint p1 = geom.createPoint(geom.D2, 10,40) p2 = geom.createPoint(geom.D2, 40,30) p3 = geom.createPoint(geom.D2, 20,20) p4 = geom.createPoint(geom.D2, 30,10) multiPoint = geom.createMultiPoint(points=[p1, p2, p3, p4]) print multiPoint.convertToWKT() # multiline l1 = geom.createLine(geom.D2, [(10,10),(20,20),(10,40)]) l2 = geom.createLine(geom.D2, [(40,40),(30,30),(40,20),(30,10)]) multiline = geom.createMultiLine() multiline.addCurve(l1) multiline.addCurve(l2) # for multipolygons the same approach as with lines can be used
6. 6. BUILDING GEOMETRIES Also the well known text (WKT) representation can be used: # build geometries by wkt # simple g = geom.createGeometryFromWKT("POINT (30 10)") print "POINT: " + g.convertToWKT() g = geom.createGeometryFromWKT("LINESTRING (30 10, 10 30, 20 40, 40 40)") print "LINESTRING: " + g.convertToWKT() g = geom.createGeometryFromWKT("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))") print "POLYGON: " + g.convertToWKT() g = geom.createGeometryFromWKT("POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10), " + "(20 30, 35 35, 30 20, 20 30))") print "POLYGON: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTIPOINT (10 40, 40 30, 20 20, 30 10)") # multi print "MULTIPOINT: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTILINESTRING ((10 10, 20 20, 10 40), " + "(40 40, 30 30, 40 20, 30 10))") print "MULTILINESTRING: " + g.convertToWKT() g = geom.createGeometryFromWKT("MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), " + "((15 5, 40 10, 10 20, 5 10, 15 5)))") print "MULTIPOLYGON: " + g.convertToWKT()
7. 7. BUILDING GEOMETRIES If the geometries are 2D simpliﬁed constructors are available: # for 2D geometries a simpler constructor can be used # point point = geom.createPoint2D(30, 10) print point # as opposed to a 4D point point3DM = geom.createPoint(geom.D3M,30,10,1005,23) print point3DM.convertToWKT() # line line = geom.createLine2D([(30,10), (10,30), (20,40), (40,40)]) print line.convertToWKT() # polygon polygon = geom.createPolygon2D([[35,10],[10,20],[15,40],[45,45],[35,10]]) print polygon.convertToWKT()
8. 8. A TEST SET OF GEOMETRIES TO USE AS REFERENCE To better explain the various functions and predicates we will start by creating a set of geometries on which to apply the operations. You are now able to create the following points, line and polygons: 0 5 0 5 g1 g5 g2 g3 g4 g6
9. 9. BUILDING GEOMETRIES In order to visualize intermediate results we will create a view document (the map view) and make it active. Geometries will be loaded on top of it. Let's create the example dataset, using wildcards for imports in order to have a more readable code: from gvsig import * from gvsig.geom import * def main(*args): # build the example dataset g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))") g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))") g3 = createGeometryFromWKT("POINT (4 1)") g4 = createGeometryFromWKT("POINT (5 4)") g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)") g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))") And now that it is build, how do we check if it is correct?
10. 10. BUILDING GEOMETRIES We can exploit the map view to check geometries: # get the current active view view = currentView() # create an envelope containing our # geometries bbox = createEnvelope([-4,-4],[10,10]) # zoom to the envelope view.centerView(bbox) # get the view's graphics layer and # draw the geometries gr = view.getGraphicsLayer() gr.clearAllGraphics() c1 = getColorFromRGB(255, 0, 0, 128) g1Sym = simplePolygonSymbol(c1) idG1 = gr.addSymbol(g1Sym) gr.addGraphic("g1", g1, idG1, "g1") c2 = getColorFromRGB(255, 255, 0, 128) g2Sym = simplePolygonSymbol(c2) idG2 = gr.addSymbol(g2Sym) gr.addGraphic("g2", g2, idG2, "g2") c3 = getColorFromRGB(0, 255, 0, 128) g3Sym = simplePointSymbol(c3) g3Sym.setSize(10) idG3 = gr.addSymbol(g3Sym) gr.addGraphic("g3", g3, idG3, "g3") c4 = getColorFromRGB(0, 255, 0, 128) g4Sym = simplePointSymbol(c4) g4Sym.setSize(10) idG4 = gr.addSymbol(g4Sym) gr.addGraphic("g4", g4, idG4, "g4") c5 = getColorFromRGB(0, 255, 255, 128) g5Sym = simpleLineSymbol(c5) g5Sym.setLineWidth(3) idG5 = gr.addSymbol(g5Sym) gr.addGraphic("g5", g5, idG5, "g5") c6 = getColorFromRGB(0, 0, 255, 128) g6Sym = simplePolygonSymbol(c6) idG6 = gr.addSymbol(g6Sym) gr.addGraphic("g6", g6, idG6, "g6") # refresh the view view.getMapContext().invalidate()
11. 11. BUILDING GEOMETRIES The graphics layer is a layer that can be used to draw on top of the map layers. If we have the countries layer loaded, and execute the script, we should see some shapes appear near the equator (this is true only if the view has been created with CRS EPSG:4326, which is the default for the new map views) :
12. 12. PREDICATES INTERSECTS Let's see which geometries intersect with g1 and print the result: print g1.intersects(g2) # True print g1.intersects(g3) # True print g1.intersects(g4) # True print g1.intersects(g5) # True print g1.intersects(g6) # True Note that geometries that touch (like g1 and g2) also intersect. TOUCHES Let's see which geometries touch with g1 and print the result: print g1.touches(g2) # True print g1.touches(g3) # False print g1.touches(g4) # True print g1.touches(g5) # False print g1.touches(g6) # False
13. 13. PREDICATES CONTAINS Let's see which geometries are contained in g1 and print the result: print g1.contains(g2) # False print g1.contains(g3) # True print g1.contains(g4) # False print g1.contains(g5) # False print g1.contains(g6) # False Mind that a point on the border is not contained, so only g3 is contained. This can be solved through the covers predicate. COVERS print g1.covers(g2) # False print g1.covers(g3) # True print g1.covers(g4) # True print g1.covers(g5) # False print g1.covers(g6) # False
14. 14. FUNCTIONS: INTERSECTION Let's see which geometries are contained in g1 and print the result: # the intersection of polygons returns a polygon g1_inter_g6 = g1.intersection(g6) print g1_inter_g6 # the intersection of touching polygons returns a line print g1.intersection(g2) # the intersection of a polygon with a point is a point print g1.intersection(g3) # the intersection of a polygon with a line is a point print g1.intersection(g5) # view the intersection of g1 and g6 gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g1, idG, "g") c = getColorFromRGB(0, 0, 255, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g6, idG, "g") c = getColorFromRGB(0, 255, 0, 128) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) gr.addGraphic("g", g1_inter_g6, idG, "g") 0 5 0 5 g1 g5 g2 g3 g4 g6
15. 15. FUNCTIONS: SYMDIFFERENCE What is the resulting geometry of the symdifference (portions not shared) of different geometry types? # the symDifference of intersecting polygons returns a multipolygon g1jts = g1.getJTS() symDiff16 = g1jts.symDifference(g6.getJTS()) print symDiff16 # but the symDifference of touching polygons returns the polygons union print g1jts.symDifference(g2.getJTS()) # the symDifference of a polygon with a contained point returns the original polygon print g1jts.symDifference(g3.getJTS()) # the symDifference of a polygon with a line is a hybrid collection (line + polygon) print g1jts.symDifference(g5.getJTS()) # to get back a gvsig geometry multiPolygon2d = createGeometryFromWKT(symDiff16) print multiPolygon2d 0 5 0 5 g1 g5 g2 g3 g4 g6 Note that the symDifference is not implemented in gvSIG. In that case it is possible to access directly the JTS geometries and use the function on those. Afterwards through the WKT deﬁnition they can be converted back.
16. 16. FUNCTIONS: UNION What is the resulting geometry of the union of different geometry types? # the union of intersecting polygons returns a polygon print g1.union(g6).convertToWKT() # same as the union of touching polygons print g1.union(g2).convertToWKT() # the union of a polygon with a contained point returns the original polygon print g1.union(g3).convertToWKT() # the union of a polygon with a line doesn't result in a valid geometry print g1.union(g5) The following shows the union of polygons g1 and g6: 0 5 0 5 g1 g5 g2 g3 g4 g6
17. 17. FUNCTIONS: DIFFERENCE The difference of geometries obviously depends on the calling object: # this returns g1 minus the overlapping part of g6 print g1.difference(g6).convertToWKT() # while this returns g6 minus the overlapping part of g1 print g6.difference(g1).convertToWKT() # in the case of difference with lines, the result is the original polygon # with additional points in the intersections print g1.difference(g5).convertToWKT() # the difference of polygon and point is the original polygon print g1.difference(g3).convertToWKT() The following shows the difference of polygons g1 and g6: 0 5 0 5 g1 g5 g2 g3 g4 g6
18. 18. JTS GEOMETRIES Some functions are not supported in the gvSIG scripting API. But it is possible to access the underlying JTS geometries. JTS stands for , the most well known spatial predicates and geometry processing library available in the open source panorama. This is how to get back and forth between gvSIG and JTS: Java Topology Suite # create a gvsig geometry polygonGvsig = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))") # get the JTS geometry polygonJTS = polygonGvsig.getJTS() # do some advanced processing... for example get the centroid centroidJTS = polygonJTS.getCentroid(); # print the gvsig geometry print "gvSIG polygon WKT: " + polygonGvsig.convertToWKT() # print the JTS geometry print "JTS polygon WKT: %s" % polygonJTS # get back to a gvsig geometry centroidGvsig = createGeometryFromWKT(centroidJTS) print "gvSIG centroid WKT: " + centroidGvsig.convertToWKT()
19. 19. FUNCTIONS: BUFFER Creating a buffer around a geometry always generates a polygon geometry. The behavior can be tweaked, depending on the geometry type: from com.vividsolutions.jts.operation.buffer import BufferParameters g3jts = g3.getJTS() g5jts = g5.getJTS() # the buffer of a point b1 = g3jts.buffer(1.0) # the buffer of a point with few quandrant segments b2 = g3jts.buffer(1.0, 1) # round end cap style, few points b3 = g5jts.buffer(1.0, 2, BufferParameters.CAP_ROUND) # round end cap style, more points b4 = g5jts.buffer(1.0, 10, BufferParameters.CAP_ROUND) # square end cap style b5 = g5jts.buffer(1.0, -1, BufferParameters.CAP_SQUARE) # flat end cap style b6 = g5jts.buffer(1.0, -1, BufferParameters.CAP_FLAT) geoms = [b1, b2, b3, b4, b5, b6] gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(g.toText()), idG, "g") JTS gives more control about buffering, it just requires us to import the BufferParameters module.
20. 20. FUNCTIONS IN JTS: CONVEXHULL Some functions are not available through the gvSIG API. We saw this already in the buffer functions and symDifference. Another example is the convex hull. So let's try working the JTS way. First, we create the geometries as JTS geometries: # build the example dataset g1 = createGeometryFromWKT("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))").getJTS() g2 = createGeometryFromWKT("POLYGON ((5 0, 5 2, 7 2, 7 0, 5 0))").getJTS() g3 = createGeometryFromWKT("POINT (4 1)").getJTS() g4 = createGeometryFromWKT("POINT (5 4)").getJTS() g5 = createGeometryFromWKT("LINESTRING (1 0, 1 6)").getJTS() g6 = createGeometryFromWKT("POLYGON ((3 3, 3 6, 6 6, 6 3, 3 3))").getJTS() geoms = [g1, g2, g3, g4, g5, g6]
21. 21. FUNCTIONS IN JTS: CONVEXHULL Once we have the geometries, we need to create a collection of geometries, which will require us to import a few classes. from com.vividsolutions.jts.geom import GeometryCollection, GeometryFactory gc = GeometryCollection(geoms, GeometryFactory()) with a GeometryCollection it is very simple to create a convex hull and visualize it: convexHull = gc.convexHull() gr = view.getGraphicsLayer() gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(convexHull.toText()), idG, "g") view.getMapContext().invalidate()
22. 22. FUNCTIONS IN JTS: TRANSFORMATIONS Also for operations of translation, scaling and rotation we can make use of the JTS capabilities. It all boils down to a single class, the AfﬁneTransformation, which we can import as: from com.vividsolutions.jts.geom.util import AffineTransformation as AT import math # used for conversion to radians It has direct methods to access to the different transformations: # create the jts polygon square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))") square = square.getJTS() # this is how affine transformations are created scaleAffineTransformation = AT.scaleInstance(4,4) translationAffineTransformation = AT.translationInstance(2,2) rotationAffineTransformation = AT.rotationInstance(math.radians(45)) shearAffineTransformation = AT.shearInstance(0.75, 0) # this is how transformations are applied to geometries scaledSquare = scaleAffineTransformation.transform(square) print "Original: %s" % square print "Scaled: %s" % scaledSquare
23. 23. FUNCTIONS IN JTS: TRANSFORMATIONSLet's see how all the transformations work: square = createGeometryFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))").getJTS() # scale the square by 4 times squareLarge = AT.scaleInstance(4,4).transform(square) # move it by x, y units squareTranslate = AT.translationInstance(2,2).transform(square) # move it and then rotate it by 45 degrees squareTranslateRotate = AT.rotationInstance(math.radians(45) ).transform(squareTranslate) # realize that the order of things are there for a reason squareRotate = AT.rotationInstance(math.radians(45)).transform(square) squareRotateTranslate = AT.translationInstance(2,2).transform(squareRotate) # rotate around a defined center squareTranslateRotateCenter = AT.rotationInstance(math.radians(45), 2.5, 2.5).transform(squareTranslate) # shear the square squareShear = AT.shearInstance(0.75,0).transform(square) geoms = [square, squareLarge, squareTranslate, squareTranslateRotate, squareRotateTranslate, squareTranslateRotateCenter, squareShear] view = currentView() gr = view.getGraphicsLayer() gr.clearAllGraphics() c = getColorFromRGB(255, 0, 0, 80) gSym = simplePolygonSymbol(c) idG = gr.addSymbol(gSym) for g in geoms: gr.addGraphic("g", createGeometryFromWKT(g), idG, "g") view.mapContext.invalidate()
24. 24. PROJECTIONS Geometries can be reprojected directly using the crs objects. These can be created in several ways. The simplest is through the use of the EPSG code: from gvsig import * from gvsig.geom import * def main(*args): # create the source and destination crs # usign the EPSG codes crs1 = getCRS('EPSG:4326') crs2 = getCRS('EPSG:32632') # get the transformation object transform = crs1.getCT(crs2) # reproject a point from 4326 to 32632 point = createPoint2D(11, 46) print "Original point in lat/long: " + str(point) point.reProject(transform) print "and the reprojected point: " + str(point) # get the WKT representation of the crs object print crs2.getWKT()
25. 25. PROJECTIONS Sometimes it is necessary to modify the crs deﬁnition. If you load the data in a GIS and they do not appear where they should, it might be a problem of the false easting, but also the units might not be right. PROJCS["WGS 84 / UTM zone 32N", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Longitude", EAST], AXIS["Latitude", NORTH], AUTHORITY["EPSG","4326"]], PROJECTION["Transverse_Mercator"], PARAMETER["central_meridian", 9.0], PARAMETER["latitude_of_origin", 0.0], PARAMETER["scale_factor", 0.9996], PARAMETER["false_easting", 500000.0], # sometimes a different false easting is used PARAMETER["false_northing", 0.0], UNIT["m", 1.0], # sometimes millimeters are used, with scale 0.001 AXIS["Easting", EAST], AXIS["Northing", NORTH], AUTHORITY["EPSG","32632"]]
26. 26. PROJECTIONS Converting from WKT to a crs is only an import statement away: from org.gvsig.fmap.crs import CRSFactory factory = CRSFactory.getCRSFactory() prjWkt = """PROJCS["WGS 84 / UTM zone 32N", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Longitude", EAST], AXIS["Latitude", NORTH], AUTHORITY["EPSG","4326"]], PROJECTION["Transverse_Mercator"], PARAMETER["central_meridian", 9.0], PARAMETER["latitude_of_origin", 0.0], PARAMETER["scale_factor", 0.9996], PARAMETER["false_easting", 500000.0], PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["Easting", EAST], AXIS["Northing", NORTH], AUTHORITY["EPSG","32632"]] """ crs2 = factory.get("wkt", prjWkt)
27. 27. CREATING THE FIRST SHAPEFILE When we talk about "writing GIS stuff", we are usually talking about creating a shapeﬁle. Let's see the steps to create our ﬁrst shapeﬁle: # place here the usual imports and main definition # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, CRS="EPSG:4326") # edit the shapefile and add features shape.edit() point1 = createPoint2D(-122.42, 37.78) shape.append(name='San Francisco', GEOMETRY=point1) point2 = createPoint2D(-73.98, 40.47) shape.append(name='New York', GEOMETRY=point2) shape.commit() # add the shapefile as layer to the view currentView().addLayer(shape) # print the path of the shapefile print "path: ", shape.getDataStore().getFullName()
28. 28. CREATING THE FIRST SHAPEFILE Let's see a slightly more complex example: # place here the usual imports and main definition # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("population", "INTEGER", 4) schema.append("lat", "DOUBLE", 8) schema.append("lon", "DOUBLE", 8) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, prefixname="complex", CRS="EPSG:4326") # edit the shapefile and add features shape.edit() point = createPoint2D(-73.98, 40.47) shape.append(name='New York',population=19040000, lat=40.749979064, lon=-73.9800169288, GEOMETRY=point) shape.commit() # add the shapefile as layer to the view currentView().addLayer(shape)
29. 29. CREATING THE FIRST SHAPEFILE Once the scripts are run, you should see the following in the map view:
30. 30. BUILD A VIEW AND LOAD DATALet's start from scratch and go through the whole process again. 1) imports # the most used imports are... from gvsig import * from gvsig.geom import * 2) create the data blueprint # define a working crs epsg = "EPSG:4326" # create the blueprint of the shapefile schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) # create the shapefile shape = createShape(schema, prefixname="simple", CRS=epsg) # edit the shapefile and add a feature shape.edit() x = -122.42 y = 37.78 point = createPoint2D(x, y) shape.append(name='New York', GEOMETRY=point) shape.commit() 3) create some data
31. 31. BUILD A VIEW AND LOAD DATA 3) load an external shapeﬁle into a layer # first add some background shp background = loadLayer("Shape", shpFile="/home/hydrologis/data/natural_earth/ne_10m_admin_0_countries.shp", CRS=epsg) 4) create a new map view with name and crs and load the layers into it # zoom to the feature boxDelta = 0.05 newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta])) 5) zoom to the created feature # create a new view and set its projection newview = currentProject().createView("Example view") newview.setProjection(getCRS(epsg)) newview.addLayer(background) newview.addLayer(shape) newview.showWindow()
32. 32. INVESTIGATING A VECTOR LAYER Let's see how accessing views and layers is done... # define view and layer to investigate viewName = "Example view" layerName = "ne_10m_admin_0_countries" # get the view and layers view = currentProject().getView(viewName) if view is None: print "ERROR: view ", viewName, " is not available in the current project" return layers = view.getLayers() # pick the right layer layerToRead = None print "Iterate through the layers: " for layer in layers: print "tLayer: ", layer.getName() if layer.getName() == layerName: layerToRead = layer
33. 33. INVESTIGATING A VECTOR LAYER ...and what about the layer's schema content? # investigate its schema if layerToRead is not None: schema = layerToRead.getSchema() # show the attributes attrSchema = schema.getAttrNames() print "nnSchema attr: ", attrSchema print "nnFields description" for field in schema: print " Name: ", field.getName(), print " tDataTypeName: ", field.getDataTypeName(), print " tPrecision: ", field.getPrecision(), print " tSize: ", field.getSize() if field.getDataTypeName() == 'Geometry': geomType = field.getGeomType() print " tGeom Name: ", geomType.getName() print " tGeom FullName: ", geomType.getFullName() print " tDimension: ", geomType.getDimension() else: print "ERROR: layer ", layerName, " is not available in view: ", viewName
34. 34. INVESTIGATING A VECTOR LAYER ...and what about the data? # define view and layer to investigate viewName = "Example view" layerName = "ne_10m_admin_0_countries" # get the view view = currentProject().getView(viewName) # get the layer by its name layer = view.getLayer(layerName) # get the features set features = layer.features() print "Features available in layer: ", features.getSize() # loop through the features for feature in features: print feature.getValues()
35. 35. INVESTIGATING A VECTOR LAYER How to access the feature attributes: layer = currentView().getLayer("ne_10m_admin_0_countries") features = layer.features() for feature in features: print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." It is possible to get only the features selected by the user with: features = layer.getSelection()
36. 36. INVESTIGATING A VECTOR LAYER Features can be extracted from a layer by means of ﬁlters and sorted by a given attribute. Extract the population less than 1000 and major than 0, in ascending order: layer = currentView().getLayer("ne_10m_admin_0_countries") features = layer.features("POP_EST < 1000 and POP_EST > 0", sortby="POP_EST", asc=True) for feature in features: print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." And here a simple way to get the country with largest population: features = layer.features(sortby="POP_EST", asc=False) for feature in features: print "The country with most inhabitants is ", feature.NAME , " with ", feature.POP_EST break
37. 37. SELECT FEATURES IN A VECTOR LAYER Features can be selected or deselected in a view/layer using the selection object of the layer. Example: select an print the countries with more than 1E9 inhabitants # select features selection = layer.getSelection() selection.deselectAll() features = layer.features("POP_EST > 1E9") for feature in features: selection.select(feature) print "The country ", feature.NAME , " has ", feature.get("POP_EST"), " inhabitants." selection.deselect(feature) Single features can be removed from the selection through:
38. 38. CREATE A COUNTRIES CENTROIDS LAYER It is no rocket science to apply all we have seen until this point to create a shapeﬁle containing the centroids of the countries. All you need to know is that the geometry has a method that extracts the centroid for you: centroid countriesLayer = currentView().getLayer("ne_10m_admin_0_countries") shpPath = "/home/hydrologis/TMP/centroids.shp" epsg = "EPSG:4326" schema = createFeatureType() schema.append("name", "STRING", 20) schema.append("GEOMETRY", "GEOMETRY") schema.get("GEOMETRY").setGeometryType(POINT, D2) shape = createShape(schema, filename=shpPath, CRS=epsg) shape.edit() countries = countriesLayer.features() for country in countries: geometry = country.GEOMETRY centroid = geometry.centroid() shape.append(name=country.NAME, GEOMETRY=centroid) shape.commit() currentView().addLayer(shape)
39. 39. STYLING YOUR LAYERS Let's see how styling of the different feature/geometries types is done. To do so, we ﬁrst load a layer of each type: point, line, polygon basePath = "/home/hydrologis/data/natural_earth/" countries = basePath + "ne_10m_admin_0_countries.shp" places = basePath + "ne_10m_populated_places.shp" roads = basePath + "ne_10m_roads.shp" # create a new view and set its projection epsg = "EPSG:4326" newview = currentProject().createView("Example view") newview.setProjection(getCRS(epsg)) newview.showWindow() countriesLayer = loadLayer("Shape", shpFile=countries, CRS=epsg) placesLayer = loadLayer("Shape", shpFile=places, CRS=epsg) roadsLayer = loadLayer("Shape", shpFile=roads, CRS=epsg) newview.addLayer(countriesLayer) newview.addLayer(roadsLayer) newview.addLayer(placesLayer)
40. 40. SIMPLE STYLING OF POINTS Styling of shapes is done by creating a symbol and set it in the layer's legend: # get the layer's legend pointsLegend = placesLayer.getLegend() # create and modify the symbol pointSymbol = simplePointSymbol() pointSymbol.setSize(15); pointSymbol.setColor(getColorFromRGB(0,0,255,128)); # blue pointSymbol.setOutlined(True); pointSymbol.setOutlineColor(getColorFromRGB(255,255,0)); # yellow pointSymbol.setOutlineSize(1); # circle = 0; square = 1; cross = 2; diamond = 3; X = 4; triangle = 5; star = 6; vertical line = 7; pointSymbol.setStyle(5); # set symbol to legend and legend to layer pointsLegend.setDefaultSymbol(pointSymbol) placesLayer.setLegend(pointsLegend) # then zoom x = 11 y = 46 boxDelta = 2 newview.centerView(createEnvelope([x-boxDelta,y-boxDelta],[x+boxDelta,y+boxDelta]))
41. 41. SIMPLE STYLING OF LINES Styling of lines is similar to that of points: lineSymbol = simpleLineSymbol() lineSymbol.setLineWidth(2); lineSymbol.setLineColor(getColorFromRGB(128,128,128)); linesLegend = roadsLayer.getLegend() linesLegend.setDefaultSymbol(lineSymbol) roadsLayer.setLegend(linesLegend) While styling of polygons is done in two steps: outline and ﬁll # first create the outline symbol and style it polygonOutlineSymbol = simpleLineSymbol() polygonOutlineSymbol.setLineWidth(2) polygonOutlineSymbol.setLineColor(getColorFromRGB(255,0,0)) # then the fill polygonFillSymbol = simplePolygonSymbol() polygonFillSymbol.setOutline(polygonOutlineSymbol) polygonFillSymbol.setFillColor(getColorFromRGB(255,0,0,70)) polygonLegend = countriesLayer.getLegend() polygonLegend.setDefaultSymbol(polygonFillSymbol) countriesLayer.setLegend(polygonLegend)
42. 42. SIMPLE STYLING OF POLYGONS Once run, the script should create a new view that looks like:
43. 43. HOW TO REUSE CODE? Often pieces of code are repeated for different variables and could be reused. This can be easily done with functions. Functions are deﬁned using the "def" construct. The following is a simple example that shows how one can use a function to set the symbol in the layer's legend, using one line instead of repeating three lines for each layer: def setSymbolInLayer(symbol, layer): legend = layer.getLegend() legend.setDefaultSymbol(symbol) layer.setLegend(legend)
44. 44. SIMPLE STYLING OF POLYGONS It is also possible to style using a color-ramp based on an attribute of the layer. In that case it will be necessary to add one import: from org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl import VectorialIntervalLegend Then, using the interval legend, it is quite straight forward: # create an interval legend intervalLegend = VectorialIntervalLegend(POLYGON) intervalLegend.setStartColor(Color.gray) intervalLegend.setEndColor(Color.red) intervalLegend.setIntervalType(1) # natural = 1, quantile = 2 store = countriesLayer.getFeatureStore() # calculate the intervals using the field name and the desired number of intervals intervals = intervalLegend.calculateIntervals(store, "POP_EST", 5, POLYGON) intervalLegend.setIntervals(intervals) countriesLayer.setLegend(intervalLegend)
45. 45. SIMPLE STYLING OF POLYGONS ...which the should look like a choropleth map:
46. 46. <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>