Spatial feature count
Suppose you have two vectors: one that contains points associated with surveyed sites, and another made of areas that represent fields or different regions of survey. You want to know how many sites are in each area and draw a map that brings this information.
Here are some result maps made with the tool d.vect.chart
described in this page:
If your sites are classified into different types or classes (based on period or size), you might want also to know what distribution different classes have for each of your survey areas.
With GRASS
This is a shell script for GRASS that calls v.what.vect
to know
which points fall into each area. Counts for each area are written to a
new column "count". This attribute can be used as input for
d.vect.chart (bar chart).
You can you also provide a column name for the points vector, that contains a classification attribute. This way more columns are created, to be used for creating pie-charts. When you use pie-charts, the "count" column can be used to generate different sizes of graphics proportional to the total number of points in each area.
This script is quite slow. If someone with enough skills (not me) wants
to write a better module, I think significant parts of code from
v.qcount
can be useful. It would be good to have such a feature
included by default in GRASS, with an efficient and fast code.
To run the script, cd into the directory that contains the script from
the GRASS prompt and call it (it's useful to
chmod 755 v.count.points.sh
).
#!/bin/sh
#
############################################################################
#
# MODULE: v.count.points
#
# AUTHOR(S): Stefano Costa steko@iosa.it
#
# PURPOSE: generate summary statistics for point features
# COPYRIGHT: (C) 2007 by the GRASS Development Team
#
# This program is free software under the GNU General Public
# License (>=v2). Read the file COPYING that comes with GRASS
# for details.
#
##
#############################################################################
#
#
#%Module
#% description: count the number of point features from vector A that are within areas from vector B
#%End
#%option
#% key: points
#% type: string
#% gisprompt: old,vector,vector
#% description: points vector to be counted for each area
#% required : yes
#%end
#%option
#% key: polygon
#% type: string
#% description: polygon vector
#% gisprompt: old,vector,vector
#% required : yes
#%end
#%option
#% key: output
#% type: string
#% description: output layer
#% required : yes
#%end
#%option
#% key: classescol
#% type: string
#% description: column that contains classification for points
#% required : no
#%end
if [ -z "$GISBASE" ] ; then
echo "You must be in GRASS GIS to run this program."
exit 1
fi
if [ "$1" != "@ARGS_PARSED@" ] ; then
exec g.parser "$0" "$@"
fi
### setup enviro vars ###
eval `g.gisenv`
: ${GISBASE?} ${GISDBASE?} ${LOCATION_NAME?} ${MAPSET?}
LOCATION=$GISDBASE/$LOCATION_NAME/$MAPSET
points=$GIS_OPT_points
polygon=$GIS_OPT_polygon
output=$GIS_OPT_output
tempsql=`g.tempfile pid=$$`
# overwrites the output map if it already exists
g.copy vect=$points,temppnts,$polygon,$output --o
if [ -n "$GIS_OPT_classescol" ]; then
classescol=$GIS_OPT_classescol
echo "Using classes!"
classes=$(db.select -c temppnts sql="select $classescol from temppnts" | uniq)
for j in $classes; do
v.db.addcol $output col="class_$j int"
done
fi
v.db.addcol temppnts col="cat_area int"
v.db.addcol $output col="count int"
v.what.vect vector=temppnts qvect=$output column=cat_area qcolumn=cat
areas=$(db.select -c $output sql="select cat from $output" | uniq)
for i in $areas; do
count=$( db.select -c temppnts sql="select cat_area from temppnts" | grep -c "^$i$")
echo "UPDATE $output SET count = $count WHERE cat = $i;" >> $tempsql
if [ -n "$GIS_OPT_classescol" ]; then
for j in $classes; do
kount=$( db.select -c temppnts sql="select $classescol from temppnts where cat_area = $i" | grep -c "^$j$")
echo "UPDATE $output SET class_$j = $kount WHERE cat = $i;" >> $tempsql
done
fi
done
cat $tempsql | db.execute
g.remove vect=temppnts
echo "Output written to map $output"
With PostGIS
Flavio Rigolon suggested this approach using PostGIS:
dbname => CREATE TABLE new_table AS SELECT grid.cat, COUNT(id) AS count FROM points,grid WHERE points.the_geom && grid.the_geom AND CONTAINS (grid.the_geom,points.the_geom) GROUP BY grid.cat;
You should obtain a table. You can then JOIN new_table
to your grid
table using the cat
column.