GRASS and Python
(for discussions on the new GRASS GUI, see here)
Python SIGs
Python Special Interest Groups are focused collaborative efforts to develop, improve, or maintain specific Python resources. Each SIG has a charter, a coordinator, a mailing list, and a directory on the Python website. SIG membership is informal, defined by subscription to the SIG's mailing list. Anyone can join a SIG, and participate in the development discussions via the SIG's mailing list. Below is the list of currently active Python SIGs, with links to their resources.
See more at http://www.python.org/community/sigs/
Writing python scripts in GRASS
Python is between shell and C programs. For C part - it can handle GRASS C functions via SWIG. For shell part, it can be processed with g.parser, so automatic input check and help generation (apart from translation) can be processed.
Example of python script, which is processed by g.parser:
#!/usr/bin/python import sys import os #%Module #% description: g.parser test script #% keywords: keyword1, keyword2 #%End #%flag #% key: f #% description: a flag #%END #%option #% key: raster #% type: string #% gisprompt: old,cell,raster #% description: raster input map #% required : yes #%end #%option #% key: vector #% type: string #% gisprompt: old,vector,vector #% description: vector input map #% required : yes #%end #%option #% key: option1 #% type: string #% description: an option #% required : yes #%end def main(): #add your code here print "" if ( os.getenv("GIS_FLAG_f") != "0" ): print "Flag -f set" else: print "Flag -f not set" print "Value of GIS_OPT_option1: %s" % os.getenv("GIS_OPT_option1") print "Value of GIS_OPT_raster: %s" % os.getenv("GIS_OPT_raster") print "Value of GIS_OPT_vect: %s" % os.getenv("GIS_OPT_vect") #end of your code return if __name__ == "__main__": if ( len(sys.argv) <= 1 or sys.argv[1] != "@ARGS_PARSED@" ): os.execvp("g.parser", [sys.argv[0]] + sys.argv) else: main();
SUBMITTING_PYTHON proposal
NOTE: Please improve this list! Dear (new) GRASS Developer, When submitting PYTHON SCRIPTS to GRASS SVN repository, please take care of following rules: [ see SUBMITTING for C code hints ] [ see SUBMITTING_SCRIPTS for shell script hints ] [ see SUBMITTING_TCLTK for TCL/TK script hints ] 1. Indentation As Python determines nesting based upon indentation, it isn't just a stylistic issue. Please use 4-space indentation (GNU Emacs python-mode default). 2. Add a header section to the script you submit and make sure you include the copyright. The purpose section is meant to contain a general over view of the code in the file to assist other programmers that will need to make changes to your code. For this purpose use Python Docstring. Example (fictitious header for a script called r.myscript): """ MODULE: r.myscript AUTHOR(S): Me <email AT some domain> PURPOSE: Calculates univariate statistics from a GRASS raster map 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. """ The copyright protects your rights according to GNU General Public License (www.gnu.org). ... [please add further hints if required]
Python extensions for GRASS GIS
wxPython GUI development for GRASS
- See the GRASS GUI wiki page
Python-SWIG-GRASS interface
There is a prototype GRASS-SWIG interface available (thanks to Sajith VK), find it in GRASS 6-CVS: swig/python/. Draft documentation is here. It now wraps both raster and vector data C functions plus the general GIS (G_*()) functions.
Background: SWIG (Simplified Wrapper and Interface Generator) is:
- A compiler that turns ANSI C/C++ declarations into scripting language interfaces.
- Completely automated (produces a fully working Python extension module).
- Language neutral. SWIG can also target Tcl, Perl, Guile, MATLAB, etc...
- Attempts to eliminate the tedium of writing extension modules.
Sample script for raster access (use within GRASS, Spearfish session):
#!/usr/bin/python import python_grass6 as g6lib input = 'roads' mapset = 'PERMANENT' # initialize g6lib.G_gisinit() infd = g6lib.G_open_cell_old(input, mapset) cell = g6lib.G_allocate_cell_buf() rown=0 # the API still needs error checking to be added while 1: myrow = g6lib.G_get_map_row_nomask(infd, cell, rown) print rown,myrow[0:10] rown = rown+1 if rown==476:break g6lib.G_close_cell(infd) g6lib.G_free(cell)
Sample script for vector access (use within GRASS, Spearfish session):
#!/usr/bin/python import python_grass6 as g6lib input = 'soils' mapset = 'PERMANENT' # initialize g6lib.G_gisinit() # define map structure map = g6lib.Map_info() # define open level (level 2: topology) g6lib.Vect_set_open_level (2) # open existing map g6lib.Vect_open_old(map, input, mapset) # query print 'Vect is 3D: ', g6lib.Vect_is_3d (map) print 'Vect DB links: ', g6lib.Vect_get_num_dblinks(map) print 'Map Scale: 1:', g6lib.Vect_get_scale(map) # close map g6lib.Vect_close(map)
TODO: Implement modules support in a Python class using --interface-description and a Python-XML parser. This should be a generic class with module's name as parameter, returning back an object which describes the module (description, flags, parameters, status of not/required). See GRASS 6 wxPython interface for inspiration. Important is to auto-generate the GRASS-Python class at compile time with a Python script.
Python-GRASS add-ons
Stand-alone addons:
- Jáchym Čepický's G-ps.map, a GUI to typeset printable maps with ps.map (http://193.84.38.2/~jachym/index.py?cat=gpsmap)
- Jáchym Čepický's v.pydigit, a GUI to v.edit (http://les-ejk.cz/?cat=vpydigit)
- Jáchym Čepický's PyWPS, GRASS-Web Processing Service (http://pywps.wald.intevation.org)
Using Grass gui.tcl in python
Here is some example code to use the grass automatically generated guis in python code. This could (should) all be bundled up and abstracted away so that the implementation can be replaced later.
import Tkinter import os # Startup (once): tk = Tkinter.Tk() tk.eval ("wm withdraw .") tk.eval ("source $env(GISBASE)/etc/gui.tcl") # Here you could do various things to change what the gui does # See gui.tcl and README.GUI # Make a gui (per dialog) # This sets up a window for the command. # This can be different to integrate with tkinter: tk.eval ('set path ".dialog$dlg"') tk.eval ('toplevel .dialog$dlg') # Load the code for this command: fd = os.popen ("d.vect --tcltk") gui = fd.read() # Run it tk.eval(gui) dlg = tk.eval('set dlg') # This is used later to get and set # Get the current command in the gui we just made: currentcommand = tk.eval ("dialog_get_command " + dlg) # Set the command in the dialog we just made: tk.eval ("dialog_set_command " + dlg + " {d.vect map=roads}")
Links
Programming
- Quick Python tutorial for programmers of other languages
- More Python tutorials for programmers
- Python programming style guide
- GRASS-SWIG interface http://mpa.itc.it/markus/grass63progman/swig/
- SWIG http://www.swig.org/
- SIP (C/C++ bindings generator) http://directory.fsf.org/all/Python-SIP.html
- Python and GDAL/OGR:
- Python bindings to PROJ:
- Other external projects
- Scientific Python: http://www.scipy.org/
Presentations
From FOSS4G2006:
- A Python sweeps in the GRASS - A. Frigeri 2006
- GRASS goes web: PyWPS - J. Cepicky 2006