r.drain(1grass)
๐ง r.drain ๐ง
okay bestie, welcome to r.drain from the GRASS User's Manual โ it's the module that traces a flow through an elevation model or a cost surface on a raster map. it's giving main character hydrology energy and honestly? obsessed. ๐
๐ท๏ธ KEYWORDS ๐ท๏ธ
raster, hydrology, cost surface
โจ SYNOPSIS โจ
r.drain
r.drain --help
r.drain [-cand] input=name [direction=name] output=name [drain=name]
[start_coordinates=east,north[,east,north,...]]
[start_points=name[,name,...]] [--overwrite] [--help] [--verbose]
[--quiet] [--ui]
๐ Flags ๐
-cโ copies the input cell values straight onto the output, verbatim, no glow-up. โจ-aโ accumulates the input values as you go along the path, like a running total bestie ๐-nโ counts cell numbers along the path, numerically, one by one ๐ข-dโ says "bestie, the input raster map is a cost surface", which means the direction surface must also be specified. no exceptions. periodt.--overwriteโ lets output files overwrite files that already exist, lowkey dangerous but okay ๐--helpโ prints the usage summary, iykyk--verboseโ verbose module output, she's chatty ๐ธ--quietโ quiet module output, she's mysterious ๐คซ--uiโ forces the GUI dialog to launch
๐ฆ Parameters ๐ฆ
input=name[required] โ the name of the input elevation or cost surface raster map. you NEED this one, no cap.direction=nameโ the name of the input movement direction map that goes with the cost surface. direction is in degrees CCW from east. โญoutput=name[required] โ the name for the output raster map ๐drain=nameโ the name for the output drain vector map. recommended for a cost surface made using knight's move.start_coordinates=east,north[,east,north,...]โ coordinates of the starting point(s) (E,N) ๐start_points=name[,name,...]โ name of the starting vector points map(s)
๐ DESCRIPTION ๐
okay so here's the tea ๐ต โ r.drain traces a flow through a least-cost path in an elevation model or a cost surface. for cost surfaces you HAVE to give a movement direction map with the direction option and the -d flag so it can trace a flow path following the directions you gave. and guess what bestie, you can generate that movement direction map with r.walk, r.cost, r.slope.aspect or r.watershed โ as long as the direction is in degrees, measured counterclockwise from east. ๐
the output raster map is gonna show one or more least-cost paths between each user-provided location(s) and the minima (low category values) in the raster input map. if you use the -d flag, the output least-cost paths get found using the direction raster map. by default, the output is an integer CELL map with category 1 along the least cost path, and null cells everywhere else. it's giving โจminimalโจ.
so, the flags, because this is the part where u need to lock in ๐:
- with
-c(copy), the input raster map cell values are copied verbatim along the path. - with
-a(accumulate), the accumulated cell value from the starting point up to the current cell gets written on output. - with either
-cor-a, the output map is created with the same cell type as the input raster map (integer, float or double). - with
-n(number), the cells are numbered consecutively from the starting point to the final point.
โ ๏ธ tbh the-c,-a, and-nflags are mutually incompatible. pick one, bestie, you can't have all three, that's not how this works ๐ญ
for an elevation surface, the path is calculated by choosing the steeper "slope" between adjacent cells. and the slope calculation accurately accounts for the variable scale in lat-lon projections โ she did her homework. ๐
for a cost surface, the path is calculated by following the movement direction surface back to the start point you gave in r.walk or r.cost. the path search stops as soon as it hits a region border or a neighboring NULL cell, because in those cases the direction can not be determined (the path could continue outside the current region). ๐
the start_coordinates parameter is made of map E and N grid coordinates of a starting point. each x,y pair is the easting and northing (respectively) of a starting point from which a least-cost corridor will be developed. the start_points parameter can take multiple vector maps containing additional starting points. you can input up to 1024 starting points from a combination of the start_coordinates and start_points parameters. that's a lot of starting points bestie, go off ๐
๐ง Explanation of output values ๐ง
consider this glow-up of an example โจ:
Input: Output:
ELEVATION SURFACE LEAST COST PATH
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 19. 20. 18. 19. 16. 15. 15. . . . . . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 20| 19| 17. 16. 17. 16. 16. . . 1 . 1 . 1 . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 18. 18. 24. 18. 15. 12. 11. . . . . . 1 . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 22. 16. 16. 18. 10. 10. 10. . . . . . 1 . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 15. 15. 15. 10. 8 . 8 . . . . . . . 1 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 24. 16. 8 . 7 . 8 . 0 . 12. . . . . . . 1 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 9 . 8 . 7 . 8 . 6 . 12. . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
the user-provided starting location in the above example is the boxed 19 in the left-hand map. the path in the output shows the least-cost corridor for moving from the starting box to the lowest (smallest) possible point. this is the path a raindrop would take in this landscape. ๐ง๏ธ iconic honestly
with the -c (copy) flag, you get this:
Input: Output:
ELEVATION SURFACE LEAST COST PATH
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 19. 20. 18. 19. 16. 15. 15. . . . . . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 20| 19| 17. 16. 17. 16. 16. . . 19. 17. 16. . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 18. 18. 24. 18. 15. 12. 11. . . . . . 15. . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 22. 16. 16. 18. 10. 10. 10. . . . . . 10. . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 15. 15. 15. 10. 8 . 8 . . . . . . . 8 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 24. 16. 8 . 7 . 8 . 0 .12 . . . . . . . 0 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 9 . 8 . 7 . 8 . 6 .12 . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
note that the last 0 will not be put in the null values map. ๐ซถ
with the -a (accumulate) flag, you get this:
Input: Output:
ELEVATION SURFACE LEAST COST PATH
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 19. 20. 18. 19. 16. 15. 15. . . . . . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 20| 19| 17. 16. 17. 16. 16. . . 19. 36. 52. . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 18. 18. 24. 18. 15. 12. 11. . . . . . 67. . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 22. 16. 16. 18. 10. 10. 10. . . . . . 77. . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 15. 15. 15. 10. 8 . 8 . . . . . . . 85. .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 24. 16. 8 . 7 . 8 . 0 .12 . . . . . . . 85. .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 9 . 8 . 7 . 8 . 6 .12 . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
with the -n (number) flag, you get this:
Input: Output:
ELEVATION SURFACE LEAST COST PATH
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 19. 20. 18. 19. 16. 15. 15. . . . . . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 20| 19| 17. 16. 17. 16. 16. . . 1 . 2 . 3 . . . .
. . --- . . . . . . . . . . . . . . . . . . . . . . . . .
. 18. 18. 24. 18. 15. 12. 11. . . . . . 4 . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 22. 16. 16. 18. 10. 10. 10. . . . . . 5 . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 15. 15. 15. 10. 8 . 8 . . . . . . . 6 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 24. 16. 8 . 7 . 8 . 0 .12 . . . . . . . 7 . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 17. 9 . 8 . 7 . 8 . 6 .12 . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
with the -d (direction) flag, the direction raster is used for the input, rather than the elevation surface. the output is then created according to one of the -can flags. ๐
the directions are recorded as degrees CCW from East:
112.5 67.5 i.e. a cell with the value 135
157.5 135 90 45 22.5 means the next cell is to the North-West
180 x 0
202.5 225 270 315 337.5
247.5 292.5
๐ NOTES ๐
okay important stuff, don't skip this part ๐ซฃ
if no direction input map is given, r.drain currently finds only the lowest point (the cell having the smallest category value) in the input file that can be reached through directly adjacent cells that are less than or equal in value to the cell reached immediately prior to it; therefore, it will not necessarily reach the lowest point in the input file. it currently finds pits in the data, rather than the lowest point in the entire input map. you can use the r.fill.dir, r.terraflow, and r.basins.fill modules to fill in subbasins before you process with r.drain. ๐ณ๏ธ
๐จr.drainwill not give sane results at the region boundary. on outer rows and columns bordering the edge of the region, the flow direction is always directly out of the map. in this case, you could try adjusting the region extents slightly withg.regionto allow additional outlet paths forr.drain. bestie pls check ur region, i'm begging ๐
๐ EXAMPLES ๐
โจ Path to the lowest point โจ
okay so bestie, in this example we compute drainage paths from two given points, following decreasing elevation values all the way down to the lowest point ๐ง We're using the full North Carolina sample dataset, periodt.
First, we create the two points from a text file using the v.in.ascii module (the text file here is CSV and we're using unix here-file syntax with EOF โ in the GUI you just type the values directly into the parameter input, no biggie):
v.in.ascii input=- output=start format=point separator=comma <<EOF
638667.15686275,220610.29411765
638610.78431373,220223.03921569
EOF
Now we compute the drainage path ๐ฆ:
r.drain input=elev_lid792_1m output=drain_path drain=drain start_points=start
Before we visualize the result, we set a color table for the elevation we're using, and we create a shaded relief map โจ:
r.colors map=elev_lid792_1m color=elevation
r.relief input=elev_lid792_1m output=relief
Finally we visualize all the input and output data ๐:
d.shade shade=relief color=elev_lid792_1m
d.vect map=drain_path color=0:0:61 width=4 legend_label="drainage paths"
d.vect map=start color=none fill_color=224:0:0 icon=basic/circle size=15 legend_label=origins
d.legend.vect -b
Figure: Drainage paths from two points flowing into the points with lowest values โ it's giving โจartโจ, fr fr.
๐ Path following directions ๐
To continue flow even after it hits a depression, we need to supply a direction raster map which will tell the r.drain module how to continue from the depression ๐ณ๏ธโก๏ธ To get these directions, we use the r.watershed module:
r.watershed elevation=elev_lid792_1m accumulation=accum drainage=drain_dir
The directions are categorical, and we convert them to degrees using raster algebra ๐งฎ:
r.mapcalc "drain_deg = if(drain_dir != 0, 45. * abs(drain_dir), null())"
Together with directions, we need to provide the r.drain module with cost values. We don't have any cost to assign to specific cells, so we create a constant surface ๐:
r.mapcalc "const1 = 1"
Now we're ready to compute the drainage paths ๐ We're using the two points from the previous example:
r.drain -d input=const1 direction=drain_deg output=drain_path_2 drain=drain_2 start_points=start
We visualize the result in the same way as in the previous example.
Figure: Drainage paths from two points where directions from r.watershed were used โ iconic behavior honestly ๐
โ ๏ธ KNOWN ISSUES โ ๏ธ
Sometimes, when the differences among integer cell category values in the r.cost cumulative cost surface output are small, this cumulative cost output cannot accurately be used as input to r.drain โ and r.drain will output bad results ๐ Yeah. Not the vibe.
This problem can be circumvented by making the differences between cell category values in the cumulative cost output bigger. It is recommended that if the output fromr.costis to be used as input tor.drain, the user multiply ther.costinput cost surface map by the value of the map's cell resolution, before runningr.cost.
This can be done using r.mapcalc. The map resolution can be found using g.region. ๐ซถ
And the good news? This problem doesn't arise with floating point maps. Slay. โจ
๐ SEE ALSO ๐
g.regionr.costr.fill.dirr.basins.fillr.watershedr.terraflowr.mapcalcr.walk
the way this is literally the whole friend group ๐ฅน go say hi to all of them
๐ AUTHORS ๐
- Completely rewritten by Roger S. Miller, 2001
- July 2004 at WebValley 2004, error checking and vector points added by Matteo Franchi (Liceo Leonardo Da Vinci, Trento) and Roberto Flor (ITC-irst, Trento, Italy)
๐ง SOURCE CODE ๐ง
Available at: r.drain source code (history)
Latest change: Saturday Oct 25 22:50:58 2025 in commit: ee87f21833475fd40805f58d1702f7d64478a27b
Main index | Raster index | Topics index | Keywords index | Graphical index | Full index
okay that's the whole page bestie, you ate that ๐ this was GRASS 8.5.0 Reference Manual, r.drain(1grass), ยฉ 2003-2026 GRASS Development Team, and yeah โ you're officially a drainage path main character now ๐๐
๐ฆ where this page comes from
- alpine 3.24: grass-gis-doc 8.5.0-r1 ยท GPL-2.0-or-later
- ubuntu stonking: grass-doc 8.5.0-1ubuntu1 ยท GPL-2.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms