2009-06-15

Ecology Journals LaTeX Class

LaTeX is a document markup language used to create manuscripts that have nice typesetting. Professional looking documents can be created from simple text files. It is particularly useful for creating manuscripts that have math equations in them. Writing documents in LaTeX should allow authors to focus on content of the manuscript rather than the formatting. All La-tex documents are associated with a class file which sets the formatting for the document. Users simply associate a document with a class and the text is formatted appropriately. Unfortunately, many academic journals have very specific formatting requirements not built into LaTeX. The journals of the Ecological Society of America do not have LaTeX class files appropriate for their major journals: Ecology, Ecological Applications and Ecological Monographs (even though they will accept documents in LaTeX format). One user-created LaTeX class file for ecology is available here. However, this class formats a LaTeX file into a proof-style document, not a submission-style document. I have recently been writing a submission for Ecological Applications that is in LaTeX. I had to write my own class file for formatting this document according to the ESA guidelines (http://esapubs.org/esapubs/preparation.htm). I am sure that others have run into the same problem. So, I am making my class file publicly available. Please consider this class to be in alpha. I have not, yet, written support for multiple author addresses simply because I didn't need it for the current manuscript. Feel free to improve the class. Just let me know about it, so I can use it as well. To use this class in a LaTeX document, you can either install the class file into your LaTeX distribution or simply place the file in the same folder as your LaTeX document. Bibliography formatting using BibTex requires the natbib package be installed and the ecology.bst bibliography format file. I have packaged the ecology.cls class along with an example latex file, the proof pdf, an example figure, and an example bibligraphy into a tarball available below. Download: ecologyLatexClass.tar.gz

Labels: ,

2009-06-01

Add a column to a text file from a raster

Text files are great

I have mixed feelings about software interoperability. Sure GRASS interfaces with R, and R can interface with Excel and Access if you have the ODBC drivers. But, often users do not have the energy to learn the best techniques for moving data back and forth between programs. Further, there always seems to be some quirk with data that prevents the transfer from going as smoothly as the user's manual examples do. Then, I remember the lowly text file. Whether you use comma separated values (csv) files or tab-delimited files, every software platform on the planet can read text files of records (lines) and fields (values on a line separated by commas,tabs or some other character). If you're trying to send data to someone else, you can be confident that your recipient can read them. It may not be the flashiest or fastest way to move data between people and systems, but it always works. Finally, when you use plain text files for data, you have many more options for working with the files. Tools such as bash, awk, sed, perl, and any other programming language you can think of will can be brought to bear on data analysis problems.

Attaching raster data to points in GIS

Switch gears for a moment from a common file format to a common analysis task. For researchers who work with spatial point patterns (like plots), a regular step in data analysis is to pull data from raster layers where they intersect the point data and add it as columns to the point data. Informally, these are known as "drill-down" operations. You have a stack of maps and you want to drill down through them vertically at point locations, grab the data, and add it to the points. This is an a relatively simple task in ArcGIS if you use Hawth's tools. It's also pretty easy in GRASS, though it involves a couple of steps. The function v.what.rast will put raster values into a column of a point dataset. The column must already exist in the dataset, which can be done through the command v.db.addcol and v.what.rast function just fills in the missing values with values where the raster intersects the points.

Adding raster values to text files

Now, back to text files. I recently worked with a graduate student who wanted elevation values from a lidar-derived digital elevation model (dem) on 4 samples totalling about 1100 plots. She is not a GRASS user, and so she sent me the locations of all the plots along with an identifier in csv format. I wanted to send her back the same csv files with elevation simply added as a field. I wrote a bash script to accomplish this quickly and repeatably for her files. In this script, all the GRASS functions are hidden from the user. Users simply input a csv file and the raster column you wish to add, and a csv file is output with that column added. The script requires the awk script that I posted previously, which recognizes the types of varibles present in the input csv. I have included a portion of the full script below. GRASS has a very particaular code style that it uses for running scripts natively (See g.parser for details). This makes the script very long. So, I've cut out the not-so-important parts. If you would like the full file you can get it here.

v.ascii.addrastcol

#!/bin/sh
##################################################################
#
# MODULE:       v.ascii.addrastcol
# AUTHOR(S):    R. Todd Jobe 
# PURPOSE:      Add a raster value field to a csv of points
# COPYRIGHT:    (C) 2009 by R. Todd Jobe
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
##################################################################
# . . . Grass header information removed
# . . . The cut code creates variables GIS_OPT_* and GIS_FLAG_*
# . . . Get the full code at:
# . . . http://www.unc.edu/~toddjobe/src/v.ascii.addrastcol
##################################################################
# Need space-delimited arguments for looping
GIS_OPT_INPUT=${GIS_OPT_INPUT//,/ }

# test for input raster map
eval `g.findfile element=cell file="$GIS_OPT_RAST"`
if [ ! "$file" ] ; then
   g.message -e "Raster map <$GIS_OPT_RAST> not found in mapset search path"
   exit 1
fi

for i in $GIS_OPT_INPUT; do
   # Check that input files exist
   if [ ! "$i" ] ; then
 echo "file $i does not exist" >&2
 exit $E_NOTFOUND
   fi

   # Create header line if necessary and get variable types
   if [ $GIS_FLAG_H -eq 1 ]; then
 skip=1
   else
 skip=0
   fi

   # Intermediate variables
   map=`basename $i .csv`
   tmp=`tempfile -s ".csv"`
   of="${map}${GIS_OPT_SUFFIX}"
   col=`typeVars.awk -v h=$GIS_FLAG_H -F, $i`

   # Get the raster type
   if `r.info -t $GIS_OPT_RAST | grep -q "FCELL"`; then
 rtype="double precision"
   else
 rtype="int"
   fi
  
   # Grass-specific calls
   v.in.ascii --overwrite input="$i" output="$map" fs="$GIS_OPT_FS" \
 skip=$skip column="$col" x="$GIS_OPT_X" y="$GIS_OPT_Y"
   v.db.addcol map="$map" \
 columns="$GIS_OPT_RAST $rtype"
   v.what.rast vector="$map" column="$GIS_OPT_RAST" \
 raster="$GIS_OPT_RAST"
   v.out.ascii input="$map" fs="," \
 columns="$GIS_OPT_RAST" | \
   awk -F, -v meters="$GIS_FLAG_M" -v head="$GIS_FLAG_H" \
 -v rast="$GIS_OPT_RAST" '
   BEGIN{ if(head == 1) print rast;}
   {
        # Convert Ft. elevation to meters if necessary
        if($4!="" && meters==1) $4=$4 * 0.30480060
        print $4
   }' >"$tmp"
   # Join raster values to input and write to output
   paste -d$GIS_OPT_FS "$i" "$tmp" >"$of"

   # Cleanup
   rm "$tmp"
   if [ $GIS_FLAG_R -eq 1 ] ; then
 g.remove -f --quiet vect=$map
   fi
done
To see the useage for the full script, you can simply start GRASS and from the command line type v.ascii.addrastcol --help. Here's a short example for a random set of 25 points on Ft. Bragg North Carolina.
GRASS 6.4.0RC3 (ftBragg):~ > head locs.csv
"","V1","V2","V3"
"1",594927.510605283,153893.107849400,1
"2",590884.780751329,155855.275043186,2
"3",594095.580107841,155284.234116311,3
"4",605646.865006463,154397.274762958,4
"5",603002.815879479,153284.801461238,5
"6",603453.085431226,152633.248500899,6
"7",602981.046299442,152156.288326646,7
"8",604160.50828444,151921.617483228,8
"9",603752.189821169,152062.642227756,9
GRASS 6.4.0RC3 (ftBragg):~ > v.ascii.addrastcol --quiet -hr \
input=locs.csv rast=iLandcover x=2 y=3 --quiet -r
GRASS 6.4.0RC3 (ftBragg):~ > head locs_isect.csv
"","V1","V2","V3",iLandcover
"1",594927.510605283,153893.107849400,1,3
"2",590884.780751329,155855.275043186,2,3
"3",594095.580107841,155284.234116311,3,1
"4",605646.865006463,154397.274762958,4,3
"5",603002.815879479,153284.801461238,5,3
"6",603453.085431226,152633.248500899,6,3
"7",602981.046299442,152156.288326646,7,3
"8",604160.50828444,151921.617483228,8,1
"9",603752.189821169,152062.642227756,9,3

Labels: , , ,