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.
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.
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"
Here are some result maps made with d.vect.chart
:
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.