Working with GRASS without starting it explicitly: Difference between revisions
(outdated, update forthcoming) |
(+GRASS GIS 7 example) |
||
Line 19: | Line 19: | ||
=== Accessing GRASS modules without starting a GRASS session === | === Accessing GRASS modules without starting a GRASS session === | ||
==== Python | ==== Python examples ==== | ||
See also [[GRASS Python Scripting Library]] | |||
===== Python: GRASS GIS 7 ===== | |||
The script initializes the session and lists available raster and vector maps: | |||
<source lang=python> | |||
#!/usr/bin/env python | |||
import os | |||
import sys | |||
import subprocess | |||
# some predefined variables, name of the GRASS launch script + location/mapset | |||
#grass7bin = 'C:\Program Files (x86)\GRASS GIS 7.0.svn\grass70svn.bat' | |||
grass7bin = 'grass71' | |||
location = "nc_spm_08_grass7" | |||
mapset = "user1" | |||
########### SOFTWARE | |||
# query GRASS 7 itself for its GISBASE | |||
# we assume that GRASS GIS' start script is available and in the PATH | |||
startcmd = grass7bin + ' --config path' | |||
p = subprocess.Popen(startcmd, shell=True, | |||
stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |||
out, err = p.communicate() | |||
if p.returncode != 0: | |||
print >>sys.stderr, "ERROR: Cannot find GRASS GIS 7 start script (%s)" % startcmd | |||
sys.exit(-1) | |||
gisbase = out.strip('\n') | |||
# Set GISBASE environment variable | |||
os.environ['GISBASE'] = gisbase | |||
# define GRASS-Python environment | |||
gpydir = os.path.join(gisbase, "etc", "python") | |||
sys.path.append(gpydir) | |||
########### DATA | |||
# define GRASS DATABASE | |||
gisdb = os.path.join(os.path.expanduser("~"), "grassdata") | |||
# Set GISDBASE environment variable | |||
os.environ['GISDBASE'] = gisdb | |||
# import GRASS Python bindings (see also pygrass) | |||
import grass.script as grass | |||
import grass.script.setup as gsetup | |||
########### | |||
# launch session | |||
gsetup.init(gisbase, | |||
gisdb, location, mapset) | |||
grass.message('Current GRASS GIS 7 environment:') | |||
print grass.gisenv() | |||
grass.message('Available raster maps:') | |||
for rast in grass.list_strings(type = 'rast'): | |||
print rast | |||
grass.message('Available vector maps:') | |||
for vect in grass.list_strings(type = 'vect'): | |||
print vect | |||
sys.exit(0) | |||
</source> | |||
===== Python: GRASS GIS 6 ===== | |||
The script initializes the session and lists available raster maps: | |||
<source lang=python> | <source lang=python> |
Revision as of 06:37, 12 June 2014
GRASS sessions
It is possible to access GRASS modules without explicitly starting a "GRASS session". GRASS libraries require certain environment variables to be set. In fact a "GRASS session" is just a set of processes (e.g. a shell and/or GUI) which have the necessary environment settings, specifically:
- GISBASE needs to be set to the top-level directory of the GRASS installation.
- GISRC needs to contain the absolute path to a file containing settings for GISDBASE, LOCATION_NAME and MAPSET.
- PATH needs to include $GISBASE/bin and $GISBASE/scripts.
If the GRASS libraries are shared libraries, the loader needs to be able to find them. This normally means that LD_LIBRARY_PATH (Linux, Solaris), DYLD_LIBRARY_PATH (MacOSX) or PATH (Windows) need to contain $GISBASE/lib, although there are other means to the same end (e.g. on Linux, putting $GISBASE/lib (with $GISBASE replaced by its actual value) into /etc/ld.so.conf then running ldconfig).
Some libraries and modules use other variables. More information for most of them is available in the file $GISBASE/docs/html/variables.html. The display libraries used by d.* commands use additional variables, which are documented along with the individual drivers.
Batch jobs
You can run GRASS scripts non-interactively from outside of a GRASS session with the GRASS_BATCH_JOB environment variable. When GRASS is started with this environment variable set it will automatically run the contents of the script given in the variable, then close the GRASS session when complete. In this way full lock-checking, GRASS variables setup, and temporary file cleaning tasks are still performed.
See the Batch jobs section of the GRASS shell-help wiki page for details.
Accessing GRASS modules without starting a GRASS session
Python examples
See also GRASS Python Scripting Library
Python: GRASS GIS 7
The script initializes the session and lists available raster and vector maps:
#!/usr/bin/env python
import os
import sys
import subprocess
# some predefined variables, name of the GRASS launch script + location/mapset
#grass7bin = 'C:\Program Files (x86)\GRASS GIS 7.0.svn\grass70svn.bat'
grass7bin = 'grass71'
location = "nc_spm_08_grass7"
mapset = "user1"
########### SOFTWARE
# query GRASS 7 itself for its GISBASE
# we assume that GRASS GIS' start script is available and in the PATH
startcmd = grass7bin + ' --config path'
p = subprocess.Popen(startcmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
print >>sys.stderr, "ERROR: Cannot find GRASS GIS 7 start script (%s)" % startcmd
sys.exit(-1)
gisbase = out.strip('\n')
# Set GISBASE environment variable
os.environ['GISBASE'] = gisbase
# define GRASS-Python environment
gpydir = os.path.join(gisbase, "etc", "python")
sys.path.append(gpydir)
########### DATA
# define GRASS DATABASE
gisdb = os.path.join(os.path.expanduser("~"), "grassdata")
# Set GISDBASE environment variable
os.environ['GISDBASE'] = gisdb
# import GRASS Python bindings (see also pygrass)
import grass.script as grass
import grass.script.setup as gsetup
###########
# launch session
gsetup.init(gisbase,
gisdb, location, mapset)
grass.message('Current GRASS GIS 7 environment:')
print grass.gisenv()
grass.message('Available raster maps:')
for rast in grass.list_strings(type = 'rast'):
print rast
grass.message('Available vector maps:')
for vect in grass.list_strings(type = 'vect'):
print vect
sys.exit(0)
Python: GRASS GIS 6
The script initializes the session and lists available raster maps:
import os
import sys
gisbase = os.environ['GISBASE'] = "/usr/local/src/grass_trunk/dist.x86_64-unknown-linux-gnu"
gisdbase = os.path.join(os.environ['HOME'], "grassdata")
location = "nc_spm_08"
mapset = "user1"
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "python"))
import grass.script as grass
import grass.script.setup as gsetup
gsetup.init(gisbase,
gisdbase, location, mapset)
print grass.gisenv()
grass.message('Raster maps:')
for rast in grass.list_strings(type = 'rast'):
print rast
Bash examples (GNU/Linux)
Below an example of a ~/.bash_profile script to set the required settings in order to access GRASS commands outside of a GRASS-session. Specifically it is for GRASS 7 (commented parts for GRASS 6.4.2), and uses the version from the dist.<arch> directory in the GRASS source tree rather than an installed version.
# example for GRASS 7
export GISBASE=/usr/local/src/grass_trunk/dist.x86_64-unknown-linux-gnu
# example for GRASS 6.4.2
### export GISBASE=/usr/local/grass-6.4.2svn
# GRASS 7
export GRASS_VERSION="7.0.svn"
# GRASS 6.4.2
### export GRASS_VERSION="6.4.2svn"
#generate GISRCRC
MYGISDBASE=$HOME/grassdata
MYLOC=nc_spm_08
MYMAPSET=user1
# Set the global grassrc file to individual file name
MYGISRC="$HOME/.grassrc.$GRASS_VERSION.$$"
echo "GISDBASE: $MYGISDBASE" > "$MYGISRC"
echo "LOCATION_NAME: $MYLOC" >> "$MYGISRC"
echo "MAPSET: $MYMAPSET" >> "$MYGISRC"
echo "GRASS_GUI: text" >> "$MYGISRC"
# path to GRASS settings file
export GISRC=$MYGISRC
export GRASS_PYTHON=python
export GRASS_MESSAGE_FORMAT=plain
export GRASS_TRUECOLOR=TRUE
export GRASS_TRANSPARENT=TRUE
export GRASS_PNG_AUTO_WRITE=TRUE
export GRASS_GNUPLOT='gnuplot -persist'
export GRASS_WIDTH=640
export GRASS_HEIGHT=480
export GRASS_HTML_BROWSER=firefox
export GRASS_PAGER=cat
export GRASS_WISH=wish
export PATH="$GISBASE/bin:$GISBASE/scripts:$PATH"
export LD_LIBRARY_PATH="$GISBASE/lib"
export GRASS_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
export PYTHONPATH="$GISBASE/etc/python:$PYTHONPATH"
export MANPATH=$MANPATH:$GISBASE/man
export GIS_LOCK=$$
# test a command
g.list rast
######### below not needed ########
# GRASS 7
tmp=/tmp/grass7-"`whoami`"-$GIS_LOCK
# GRASS 6.4.2
### tmp=/tmp/grass6-"`whoami`"-$GIS_LOCK
export GISRC="$tmp/rc"
mkdir "$tmp"
# GRASS 7
cp ~/.grass7/rc "$GISRC"
# GRASS 6.4.2
### cp ~/.grassrc6 "$GISRC"
######### END below not needed ########
The above script will allow GRASS commands to be used anywhere. Furthermore, if the ~/.Xsession sources the bash startup scripts, the settings aren't limited to interactive shells, but also work for e.g. M-! in XEmacs). Each interactive shell gets a separate "session" (i.e. a separate $GISRC file), while GUI programs share a common session.
Note, however, that ~/.bash_profile is a personal initialization startup script and, thus, read during the login process. Any modifications to it will be read after (re-)login or explicitly sourcing it.
At the end of the ~/.bash_profile file, the following lines can be added to ensure no duplication of entries in the PATH variable.
PATH=`awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH`
PYTHONPATH=`awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PYTHONPATH`
Important notes
Launching a grassXY session could still permit access on GRASS modules of the version that is set with the above script. The reason being is that grassXY scripts (e.g.: grass64, grass65, grass70) prepend the GRASS directories to PATH, LD_LIBRARY_PATH, etc. They won't remove any entries which are already there. A solution to this is to switch between GRASS versions by using a script like the following:
strippath()
{
(
oldpath="$1"
newpath=
IFS=:
for dir in $oldpath ; do
case "${dir}" in
*grass*)
;;
*)
newpath="$newpath:$dir"
;;
esac
done
echo "${newpath#:}"
)
}
PATH=`strippath $PATH`
export GISBASE=$PWD/dist.i686-pc-linux-gnu
export PATH="$GISBASE/bin:$GISBASE/scripts:$PATH"
export LD_LIBRARY_PATH="$GISBASE/lib"
export PYTHONPATH="$GISBASE/etc/python"
Note: the above script needs to be "source"d; executing it won't work. It might also require some adjustments (e.g. the GISBASE variable).
Using normal grass sessions commands are recorded in $GISDBASE/$LOCATION_NAME/$MAPSET/.bash_history. While working with "pure" bash, shell entries go in ~/.bash_history. Merging existing "grass-bash_history(-ies)" with the bash history log, would probably be not a good idea. Perhaps it is wise(r) to use normal GRASS sessions when working on real projects. Nevertheless, it is upon the users preferences and expertise level to decide what is best.
References
- Instructions and discussion on how to access GRASS mapsets outside of a GRASS session in the grass-user mailing list [1].
- removing duplicate entries in $PATH taken from [2]
GRASS databases
(project file structure)
Minimal mapsets
within a functional LOCATION (see below) the minimal mapset is a subdirectory of the MAPSET's name, containing a WIND file. The WIND file can simply be copied from PERMANENT/DEFAULT_WIND. Optionally you can put a VAR file in there too to define the default database driver to use.
- You can create a new mapset when starting GRASS with the -c flag. e.g.
grass64 -c /path/to/location/new_mapset_name
Minimal locations
Within the GISDATABASE (which is simply a subdirectory some where), the minimum LOCATION consists of a directory giving the LOCATION its name, which in turn contains a PERMANENT subdirectory for the PERMANENT mapset. The PERMANENT mapset contains a few special files that regular mapsets don't. These are:
- PROJ_INFO
- contains the location's projection information
- PROJ_UNITS
- contains the location's map units definition
- DEFAULT_WIND
- the default region (WINDow file). The format is identical to the WIND files created by g.region
- WIND
- (optional?)
- see also demolocation in the GRASS source code