Introduction to Vector classes¶
Details about the GRASS GIS vector architecture can be found in the GRASS GIS 8 Programmer’s Manual: GRASS Vector Library.
PyGRASS has two classes for vector maps: Vector and
VectorTopo. As the names suggest, the Vector class is
for vector maps, while VectorTopo opens vector maps with GRASS GIS
topology.
VectorTopo is an extension of the Vector class, so supports all the
Vector class methods, with additions. The classes are part of the
vector
module.
Vector¶
The Vector
class is based on the
Info
class, which provides methods
for accessing basic information about the vector map:
>>> from grass.pygrass.vector import Vector
>>> cens = Vector('census')
>>> cens.is_open()
False
>>> cens.mapset
''
>>> cens.exist()
True
>>> cens.mapset
'PERMANENT'
>>> cens.overwrite
False
VectorTopo¶
The VectorTopo
class allows vector maps to be loaded
along with an accompanying topology. The VectorTopo class interface has all the
same methods as the basic Vector class, but includes many more methods dependent
on the topology rules. Consult each class’s documentation for a list of the
methods to compare what each class can do. Using the VectorTopo class is just
like the Vector class:
>>> from grass.pygrass.vector import VectorTopo
>>> municip = VectorTopo('boundary_municp_sqlite')
>>> municip.is_open()
False
>>> municip.mapset
''
>>> municip.exist() # check if exist, and if True set mapset
True
>>> municip.mapset
'user1'
Working with Vector Maps¶
As the VectorTopo class is so similar to the Vector class, the following examples exclusively demonstrate the VectorTopo class.
To begin using a vector map, it must first be opened:
>>> from grass.pygrass.vector import VectorTopo
>>> municip = VectorTopo('boundary_municp_sqlite')
>>> municip.open(mode='r')
The open()
method supports a number of option arguments (see the
Info
documentation for a complete
list). In particular, the mode argument can take a a value of:
‘r’: read-only mode, vector features are read-only (attribute table is modifiable since are handle by a database);
‘w’: write-only mode, write a new vector map in case of an old vector map all the previous features will be removed/overwritten;
‘rw’: read-write mode, add new/update vector features without removing the existing ones. Add/remove vector layers.
The geometry of a vector map can be read sequentially using the next()
method.
To return to the beginning, use the rewind()
method.
>>> municip.next()
Boundary(v_id=1)
>>> municip.next()
Boundary(v_id=2)
>>> municip.next()
Boundary(v_id=3)
>>> municip.rewind()
>>> municip.next()
Boundary(v_id=1)
If a vector map is opened with the mode w
or rw
, then the user can write
new features to the dataset:
Open a new vector map:
>>> new = VectorTopo('newvect')
>>> new.exist()
False
Define the new columns in the attribute table:
>>> cols = [(u'cat', 'INTEGER PRIMARY KEY'),
... (u'name', 'TEXT')]
Open the vector map in write mode:
>>> new.open('w', tab_name='newvect', tab_cols=cols)
Import the geometry feature class and add two points:
>>> from grass.pygrass.vector.geometry import Point
>>> point0 = Point(636981.336043, 256517.602235)
>>> point1 = Point(637209.083058, 257970.129540)
Write the two points to the map:
>>> new.write(point0, cat=1, attrs=('pub',))
>>> new.write(point1, cat=2, attrs=('resturant',))
Commit the DB changes (attributes):
>>> new.table.conn.commit()
>>> new.table.execute().fetchall()
[(1, u'pub'), (2, u'resturnat')]
Close the vector map:
>>> new.close()
>>> new.exist()
True
Now we can play with the map:
>>> new.open(mode='r')
>>> new.read(1)
Point(636981.336043, 256517.602235)
>>> new.read(2)
Point(637209.083058, 257970.129540)
>>> new.read(1).attrs['name']
u'pub'
>>> new.read(2).attrs['name']
u'resturnat'
>>> new.close()
>>> new.remove()
Note the close()
and remove()
methods above. The close()
method
ensure that the files are properly released by the operating system, and will
also build the topology (if called by the VectorTopo class). Take caution with
the remove()
method; it is used here because this example map was temporary.
Calling this method will completely delete the map and its data from the file
system.
More Features of the VectorTopo Class¶
See the class documentation for a full list of methods, but here are some examples using VectorTopo methods:
Get the number of primitives:
>>> municip.num_primitive_of('line')
0
>>> municip.num_primitive_of('centroid')
3579
>>> municip.num_primitive_of('boundary')
5128
Get the number of different feature types in the vector map:
>>> municip.number_of("areas")
3579
>>> municip.number_of("islands")
2629
>>> municip.number_of("holes")
0
>>> municip.number_of("lines")
8707
>>> municip.number_of("nodes")
4178
>>> municip.number_of("pizza")
Traceback (most recent call last):
...
ValueError: vtype not supported, use one of: 'areas', ..., 'volumes'
Note that the method with raise a ValueError
if a non-supported vtype is
specified.
Accessing Attribute Tables¶
The GRASS philosophy stipulates that vector map features are independent from their attributes, and that a vector map’s attribute table(s) should not be loaded unless explicitly specified, in case they are not needed.
Accessing a vector map’s table(s) requires finding any links to tables, then requesting the table from each of the returned links:
>>> from grass.pygrass.vector import VectorTopo
>>> municip = VectorTopo('census')
>>> municip.open(mode='r')
>>> dblinks = DBlinks(municip.c_mapinfo)
>>> dblinks
DBlinks([Link(1, census, sqlite)])
>>> link = DBlinks[0]
Link(1, census, sqlite)
>>> table = link.table()
Here, DBlinks
is a class that contains
all the links of a vector map. Each link is also a class
(Link
) that contains a specific link’s
parameters. The table()
method of the link class return the linked
table as a table object (Table
).
Geometry Classes¶
The vector package also includes a number of geometry classes,
including Area
,
Boundary
,
Centroid
,
Isle
,
Line
, and
Point
classes. Please consult the
geometry
module for a complete list of methods
for these classes, as there are many. Some basic examples are given
below.
Instantiate a Point object that could be 2 or 3D, default parameters are 0:
>>> pnt = Point()
>>> pnt.x
0.0
>>> pnt.y
0.0
>>> pnt.z
>>> pnt.is2D
True
>>> pnt
Point(0.000000, 0.000000)
>>> pnt.z = 0
>>> pnt.is2D
False
>>> pnt
Point(0.000000, 0.000000, 0.000000)
>>> print(pnt)
POINT(0.000000 0.000000 0.000000)
Create a Boundary and calculate its area:
>>> bound = Boundary(points=[(0, 0), (0, 2), (2, 2), (2, 0),
... (0, 0)])
>>> bound.area()
4.0
Construct a Line feature and find its bounding box:
>>> line = Line([(0, 0), (1, 1), (2, 0), (1, -1)])
>>> line
Line([Point(0.000000, 0.000000),
Point(1.000000, 1.000000),
Point(2.000000, 0.000000),
Point(1.000000, -1.000000)])
>>>bbox = line.bbox()
>>> bbox
Bbox(1.0, -1.0, 2.0, 0.0)
Buffer a Line feature and find the buffer centroid:
>>> line = Line([(0, 0), (0, 2)])
>>> area = line.buffer(10)
>>> area.boundary
Line([Point(-10.000000, 0.000000),...Point(-10.000000, 0.000000)])
>>> area.centroid
Point(0.000000, 0.000000)
More Examples¶
Find all areas larger than 10000m2:
>>> big = [area for area in municip.viter('areas')
... if area.alive() and area.area >= 10000]
The PyGRASS vector methods make complex operations rather easy. Notice the
viter()
method: this returns an iterator object of the vector features, so
the user can choose on which vector features to iterate without loading all the
features into memory.
We can then sort the areas by size:
>>> from operator import methodcaller as method
>>> big.sort(key = method('area'), reverse = True) # sort the list
>>> for area in big[:3]:
... print area, area.area()
Area(3102) 697521857.848
Area(2682) 320224369.66
Area(2552) 298356117.948
Or sort for the number of isles that are contained inside:
>>> big.sort(key = lambda x: x.isles.__len__(), reverse = True)
>>> for area in big[:3]:
... print area, area.isles.__len__()
...
Area(2682) 68
Area(2753) 45
Area(872) 42
Or can list only the areas containing isles:
>>> area_with_isles = [area for area in big if area.isles]
>>> area_with_isles
[Area(...), ..., Area(...)]
Of course is still possible work only with a specific area, with:
>>> from grass.pygrass.vector.geometry import Area
>>> area = Area(v_id=1859, c_mapinfo=municip.c_mapinfo)
>>> area.area()
39486.05401495844
>>> area.bbox() # north, south, east, west
Bbox(175711.718494, 175393.514494, 460344.093986, 460115.281986)
>>> area.isles
Isles([])
Now, find an area with an island inside…
>>> area = Area(v_id=2972, c_mapinfo=municip.c_mapinfo)
>>> area.isles
Isles([Isle(1538), Isle(1542), Isle(1543), ..., Isle(2571)])
>>> isle = area.isles[0]
>>> isle.bbox()
Bbox(199947.296494, 199280.969494, 754920.623987, 754351.812986)