[GRASS-SVN] r37816 - grass/trunk/scripts/v.colors
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jun 10 22:53:54 EDT 2009
Author: glynn
Date: 2009-06-10 22:53:54 -0400 (Wed, 10 Jun 2009)
New Revision: 37816
Added:
grass/trunk/scripts/v.colors/v.colors.py
Log:
Convert v.colors to Python (untested)
Added: grass/trunk/scripts/v.colors/v.colors.py
===================================================================
--- grass/trunk/scripts/v.colors/v.colors.py (rev 0)
+++ grass/trunk/scripts/v.colors/v.colors.py 2009-06-11 02:53:54 UTC (rev 37816)
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE: v.colors
+# AUTHOR: M. Hamish Bowman, Dept. Marine Science, Otago Univeristy,
+# New Zealand
+# Converted to Python by Glynn Clements
+# PURPOSE: Populate a GRASSRGB column with a color map and data column
+# Helper script for thematic mapping tasks
+#
+# COPYRIGHT: (c) 2008 Hamish Bowman, and 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: Set color rules for features in a vector using a numeric attribute column.
+#% keywords: vector, color table
+#%End
+#% option
+#% key: map
+#% type: string
+#% gisprompt: old,vector,vector
+#% key_desc: name
+#% description: Name of input vector map
+#% required: yes
+#%end
+#%option
+#% key: column
+#% type: string
+#% description: Name of column containg numeric data
+#% gisprompt: old_dbcolumn,dbcolumn,dbcolumn
+#% required : yes
+#%end
+#%option
+#% key: layer
+#% type: integer
+#% description: Layer number of data column
+#% gisprompt: old_layer,layer,layer
+#% answer: 1
+#% required: no
+#%end
+#%Option
+#% key: rgb_column
+#% type: string
+#% required: no
+#% description: Name of color column to populate
+#% gisprompt: old_dbcolumn,dbcolumn,dbcolumn
+#% answer: GRASSRGB
+#% guisection: Colors
+#%End
+#% option
+#% key: range
+#% type: double
+#% required: no
+#% multiple: no
+#% key_desc: min,max
+#% description: Manually set range (min,max)
+#%End
+#% option
+#% key: color
+#% type: string
+#% key_desc: style
+#% options: aspect,aspectcolr,bcyr,bgyr,byg,byr,celsius,curvature,differences,elevation,etopo2,evi,grey,grey1.0,grey255,gyr,ndvi,population,precipitation,rainbow,ramp,ryb,ryg,sepia,slope,srtm,terrain,wave,random
+#% description: Type of color table
+#% required: no
+#% guisection: Colors
+#%end
+#%Option
+#% key: raster
+#% type: string
+#% required: no
+#% description: Raster map name from which to copy color table
+#% gisprompt: old,cell,raster
+#% guisection: Colors
+#%End
+#%Option
+#% key: rules
+#% type: string
+#% required: no
+#% description: Path to rules file
+#% gisprompt: old_file,file,input
+#% guisection: Colors
+#%End
+#%Flag
+#% key: s
+#% description: Save placeholder raster map for use with d.legend
+#%End
+#%Flag
+#% key: n
+#% description: Invert colors
+#% guisection: Colors
+#%End
+
+
+## TODO: implement -e (equalized) and -g (logarithmic) methods in r.colors
+## 'v.db.select column= | wc -l' to set region size (1xLength)
+## then create r.in.ascii 1xLength matrix with data (WITHOUT uniq)
+## and run r.colors on that raster map.
+## or
+## v.to.rast, r.colors -g, then parse colr/ file. But that's resolution dependent
+
+
+import sys
+import os
+import atexit
+import string
+import grass.script as grass
+
+def cleanup():
+ if tmp:
+ grass.try_remove(tmp)
+ if tmp_vcol:
+ grass.try_remove(tmp_vcol)
+ if tmp_colr:
+ grass.run_command('g.remove', rast = tmp_colr, quiet = True)
+
+def main():
+ color = options['color']
+ column = options['column']
+ layer = options['layer']
+ map = options['map']
+ range = options['range']
+ raster = options['raster']
+ rgb_column = options['rgb_column']
+ rules = options['rules']
+ flip = flags['n']
+
+ global tmp, tmp_colr, tmp_vcol
+ pid = os.getpid()
+ tmp = None
+ tmp_colr = None
+ tmp_vcol = None
+
+ os.environ['GRASS_VERBOSE'] = '0'
+
+ kv = grass.gisenv()
+ mapset = kv['MAPSET']
+ gisbase = os.getenv('GISBASE')
+
+ #### does map exist in CURRENT mapset?
+ kv = grass.find_file(map, element = 'vector', mapset = mapset)
+ map_split = map.split('@')
+ vect_mapset = map_split[1:]
+ if vect_mapset == []:
+ vect_mapset = mapset
+ else:
+ vect_mapset = vect_mapset[0]
+ if not kv['file'] or vect_mapset != mapset:
+ grass.fatal("Vector map <%s> not found in current mapset" % map)
+
+ vector = map_split[0]
+
+ # sanity check mutually exclusive color options
+ ctest = 0
+ for opt in ['color', 'raster', 'rules']:
+ if options[opt]:
+ ctest += 1
+ if ctest != 1:
+ grass.fatal("Pick one of color, rules, or raster options")
+
+ if color:
+ #### check the color rule is valid
+ color_opts = os.listdir(os.path.join(gisbase,'etc','colors'))
+ color_opts += ['random', 'grey.eq', 'grey.log', 'rules']
+ if color not in color_opts:
+ grass.fatal(("Invalid color rule <%s>\n" % color) +
+ ("Valid options are: %s" % ' '.join(color_opts)))
+ elif raster:
+ if not grass.find_file(raster)['name']:
+ grass.fatal("Unable to open raster map <%s>" % raster)
+ elif rules:
+ if not os.access(rules, os.R_OK):
+ grass.fatal("Unable to read color rules file <%s>" % rules)
+
+ #### column checks
+ # check input data column
+ cols = grass.vector_columns(map, layer = layer)
+ if column not in cols:
+ grass.fatal("Column <%s> not found" % column)
+ ncolumn_type = cols[column]
+ if ncolumn_type not in ["INTEGER", "DOUBLE PRECISION"]:
+ grass.fatal("Column <%s> is not numeric" % column)
+
+ #g.message "column <$GIS_OPT_COLUMN> is type [$NCOLUMN_TYPE]"
+
+ # check if GRASSRGB column exists, make it if it doesn't
+ table = grass.vector_db(map)[layer]['table']
+ if rgb_column not in cols:
+ # RGB Column not found, create it
+ grass.message("Creating column <%s> ..." % rgb_column)
+ if 0 != grass.run_command('v.db.addcol', map = map, layer = layer, column = "%s varchar(11)" % rgb_column):
+ grass.fatal("Creating color column")
+ else:
+ column_type = cols[rgb_column]
+ if column_type not in ["CHARACTER", "TEXT"]:
+ grass.fatal("Column <%s> is not of compatible type (found %s)" % (rgb_column, column_type))
+ else:
+ num_chars = dict([(v[0], int(v[2])) for v in grass.db_describe(table)['cols']])[rgb_column]
+ if num_chars < 11:
+ grass.fatal("Color column <%s> is not wide enough (needs 11 characters)", rgb_column)
+
+ cvals = grass.vector_db_select(map, layer = layer, column = column)['values'].values()
+
+ # find data range
+ if range:
+ #order doesn't matter
+ vals = range.split(',')
+ else:
+ grass.message("Scanning values ...")
+ vals = [float(x[0]) for x in cvals]
+
+ minval = min(vals)
+ maxval = max(vals)
+
+ grass.message(" min=[%s] max=[$%s]" % (minval, maxval))
+ if not minval or not maxval:
+ grass.fatal("Scanning data range")
+
+ # setup internal region
+ use_temp_region()
+ grass.run_command('g.region', rows = 2, cols = 2)
+
+ tmp_colr = "tmp_colr_%d" % pid
+
+ # create dummy raster map
+ if ncolumn_type == "INTEGER":
+ grass.mapcalc("$tmp_colr = if(row() == 1, $minval, $maxval)",
+ tmp_colr = tmp_colr, minval = minval, maxval = maxval)
+ else:
+ grass.mapcalc("$tmp_colr = double(if(row() == 1, $minval, $maxval))",
+ tmp_colr = tmp_colr, minval = minval, maxval = maxval)
+
+ if color:
+ color_cmd = {'color': color}
+ elif raster:
+ color_cmd = {'raster': raster}
+ elif rules:
+ color_cmd = {'rules': rules}
+
+ if flip:
+ flip_flag = 'n'
+ else:
+ flip_flag = ''
+
+ grass.run_command('r.colors', map = tmp_colr, flags = flip_flag, **color_cmd)
+
+ tmp = grass.tempfile()
+
+ # calculate colors and write SQL command file
+ grass.message("Looking up colors ...")
+
+ p = grass.start_command('r.what.color', flags = 'i', input = tmp_colr,
+ stdin = grass.PIPE, stdout = grass.PIPE)
+ lastval = None
+ for v in sorted(cvals):
+ if v == lastval:
+ continue
+ p.stdin.write('%f\n' % v)
+ p.stdin.close()
+ p.wait()
+
+ tmp_vcol = "%s_vcol.sql" % tmp
+ f = open(tmp_vcol, 'w')
+ t = string.Template("UPDATE $table SET $rgb_column = '$colr' WHERE $column = $value;\n")
+ found = 0
+ for line in p.stdout:
+ [value, colr] = line.split(':')
+ colr = colr.strip()
+ if len(colr.split(':')) != 3:
+ continue
+ #g.message message="LINE=[$LINE]"
+ f.write(t.substitute(table = table, rgb_column = rgb_column, colr = colr, value = value))
+ found += 1
+ f.close()
+
+ if not found:
+ grass.fatal("No values found in color range")
+
+ # apply SQL commands to update the table with values
+ grass.message("Writing %s colors ..." % found)
+ # less "$TMP"
+ if 0 != grass.run_command('db.execute', input = tmp_vcol):
+ grass.fatal("Processing SQL transaction")
+
+ if flags['s']:
+ vcolors = "vcolors_%d" % pid
+ grass.run_command('g.rename', rast = (tmp_colr, vcolors))
+ grass.message("Raster map containing color rules saved to <%s>" % vcolors)
+ # TODO save full v.colors command line history
+ grass.run_command('r.support', map = vcolors,
+ history = "",
+ source1 = "vector map = %s" % map,
+ source2 = "column = %s" % column,
+ title = "Dummy raster to use as thematic vector legend",
+ description = "generated by v.colors using r.mapcalc")
+ grass.run_command('r.support', map = vcolors,
+ history = "RGB saved into <%s> using <%s%s%s>" % (rgb_column, color, raster, rules))
+ else:
+ grass.run_command('g.remove', rast = tmp_colr)
+
+ #v.db.dropcol map=vcol_test col=GRASSRGB
+ #d.vect -a vcol_test icon=basic/circle color=none size=8
+
+if __name__ == "__main__":
+ options, flags = grass.parser()
+ atexit.register(cleanup)
+ main()
More information about the grass-commit
mailing list