Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I am trying to do what my title says. The goal is to input a line, segment it in an evenly distributed way by a specified distance, convert the vertices to points, then draw lines perpendicular to the segment at a specified distance. These lines will then be converted to point in a similar fashion and return the maximum elevation value both east and west of each point. This whole process is meant to extract samples of an approximation of bank height for a river. I have found tools and processes that do the line segmentation (even though annoyingly it seems one cannot access the nifty Editor toolbar processes in python), but I am having trouble finding a script that makes the perpendicular transect lines. Has anyone done anything like this before? Note: I have found the script here, but it has too many malfunctions and I gave up trying to fix it (http://forums.arcgis.com/threads/49206-Perpendicular-transects-at-regular-intervals). Thank you!

share|improve this question
Starting with the DEM, extracting the focal max (with a circular neighborhood of the desired radius) along the stream is a simple, direct way to obtain the desired information at all locations along the stream. –  whuber Feb 25 '12 at 18:51
Thanks for the input, Dr. Huber. I have tried using the River Bathymetry Toolkit, which relies on the kernel density method and was developed via advice you gave on the esri forums. How will the results of this focal max technique differ from that of the kernel density one (relating to bank height)? –  gotanuki Feb 26 '12 at 19:09
I am unsure of the details of the kernel density method, but in general this will compute a weighted (focal) average of elevations, which will not be the full bank height you're looking for. One necessary thing I lack--which you may have--is an operational definition of "bank height" for a stream. Is there a standard one? –  whuber Feb 26 '12 at 19:45
Sorry, correction: the toolbox is called "Riparian Topography Toolbox" by Thomas Dilts (forums.esri.com/Thread.asp?c=93&f=995&t=252754&mc=0). His term was "height above river" and was basically producing a detrended DEM equal to height above the centerline of the river (flow accumulation product). This is then used to "flood" the DEM by specifying a threshold height and running cost distance on a binary raster. This technique is valid and runs very quickly, but for my dataset results in a raster product with heights above river greater than 0 on the river thalweg itself. –  gotanuki Feb 26 '12 at 20:24
Re: local bank height. You could always go back to the beginning of that ESRI forums discussion, which took a Euclidean Allocation solution as its point of departure: this will be quite close to the bank height you're looking for. –  whuber Feb 26 '12 at 20:35
show 5 more comments

3 Answers

we had to do something similar and found you can manually do it. It is tedious, but by creating a random point on the line and then adding equal interval points from that origin, you have equal interval points. Then snap to each point and draw a perpendicular line from your stream line or thalweg line, which you have to do individually in each direction (right and left). You can then merge those perpendicular lines and use them as transects, or convert to points. There are two toolsets which may be useful, one is called ET GeoWizards which requires a license, but has tools which do pretty much exactly what you need. The other option is a freely available tool set, called "Geospatial Modelling Environment" (used to be Hawths' tools). See the vector tools "generate random points" and "convert lines to points". Hope this helps...it is a tedious task.

share|improve this answer
add comment
up vote 1 down vote accepted

I found code courtesy of Gerry Gabrisch posted on an old ArcGIS 9.2 forum (http://arcscripts.esri.com/details.asp?dbid=15756) and modified it so that it works in ArcGIS 10. The original output was a text file with coordinates, and this version writes geometry to an empty shapefile. Assume "inLine" is your input line feature. All that needs to be done once this code is run is to call the function "buildTransects". The code works pretty well, but all perpendicular lines in the output do not have the same length. Perhaps needs a bit more tweaking, but the lengths match up just enough for the least discriminatory user =D

# Create empty polyline for transects
spatialref = arcpy.Describe(inLine).spatialReference
if arcpy.Exists('transects'): 
transects = arcpy.CreateFeatureclass_management(temp,'transects.shp',"POLYLINE",'','','',spatialref)
arcpy.AddField_management(transects, "slope", "DOUBLE")

# inLine = input line, transects = new shapefile created above,
# transDist = length of transect (approximate), workspace = workspace
def buildTransects(inLine,transects,transDist,workspace):

    # Define orientation (start, mid, end) and draw transect function
    # This function is defined before it is called
    def orientTransect(feat,ix,iy):

            # If the line is horizontal or vertical, the slope and
            # negative reciprocal calculations will fail, so do this instead
            if starty==endy or startx==endx:
                if starty == endy:
                    y1 = iy + transDist
                    y2 = iy - transDist
                    x1 = ix
                    x2 = ix

                if startx == endx:
                    y1 = iy
                    y2 = iy
                    x1 = ix + transDist
                    x2 = ix - transDist


                # Get slope of line
                m = ((starty - endy)/(startx - endx))

                # Get negative reciprocal
                negativereciprocal = -1*((startx - endx)/(starty - endy))

                # For all values of slope, calculate perpendicular line
                # with length = transDist
                if m > 0:
                    if m >= 1:
                        y1 = negativereciprocal*(transDist)+ iy
                        y2 = negativereciprocal*(-transDist) + iy
                        x1 = ix + transDist
                        x2 = ix - transDist
                    if m < 1:
                        y1 = iy + transDist
                        y2 = iy - transDist
                        x1 = (transDist/negativereciprocal) + ix
                        x2 = (-transDist/negativereciprocal)+ ix

                if m < 0:
                    if m >= -1:
                        y1 = iy + transDist
                        y2 = iy - transDist
                        x1 = (transDist/negativereciprocal) + ix
                        x2 = (-transDist/negativereciprocal)+ ix

                    if m < -1:
                        y1 = negativereciprocal*(transDist)+ iy
                        y2 = negativereciprocal*(-transDist) + iy
                        x1 = ix + transDist
                        x2 = ix - transDist
            point1.X = x1
            point1.Y = y1
            point2.X = x2
            point2.Y = y2

            del x1
            del x2
            del y1
            del y2

    # Create search cursor in inLine
    rows = arcpy.SearchCursor(inLine)

    # Get number of records in inLine
    numRecords = int(arcpy.GetCount_management(inLine).getOutput(0))

    # Create new point files and array to collect values
    point1 = arcpy.Point()
    point2 = arcpy.Point()
    lineArray = arcpy.Array()

    # Define counter
    counter = 0

    # Loop over rows in outLine
    for row in rows:

        # Create the geometry object
        feat = row.Shape

        # Get coordinate values as lists
        firstpoint = feat.firstPoint
        lastpoint = feat.lastPoint
        midpoint = feat.centroid

        # Get X and Y values for each point
        startx = firstpoint.X
        starty = firstpoint.Y
        endx = lastpoint.X
        endy = lastpoint.Y
        midx = midpoint.X
        midy = midpoint.Y

        m = ((starty - endy)/(startx - endx))

        # For all points besides the last one
        if counter < numRecords - 1:
        # For the last point

        #Create insert cursor
        cur = arcpy.InsertCursor(transects)

        #Insert new row from array
        feat = cur.newRow()
        feat.slope = m
        feat.shape = lineArray

        del cur

        # Increase counter by 1 and start again
        counter = counter + 1

    del row
    del rows

    printit('Added %s transects to inLine and saved to temp/transects.shp' % str(counter))
share|improve this answer
add comment

I did this awhile back. Here’s what I did. 1. Using the linear referenced river centerlines, added hatches every one-mile (you can choose the interval). Made the hatches 2 miles wide. (you can choose the width) 2. Converted hatches to graphic lines (draw toolbar) 3. Converted graphic lines into a line feature class. 4. Assigned route ID and measure back to the feature class using “Locate features along Routes”. 5. The resultant lines were perpendicular to the river line, not necessary the general floodplain. Rotated several cross sections to conform to the floodplain trends. This was done on more than one occasion. From here I was able to extract elevations from the DEM and then find min, max, etc.

share|improve this answer
add comment

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.