r3.mapcalc(1)
okay bestie, sit down, hydrate, because we're reading the GRASS GIS User's Manual page for r3.mapcalc and it is a whole journey ๐ฆ this is part 1, so grab a snack, we're going in ๐
โจ NAME โจ
r3.mapcalc โ Raster map calculator. that's it. that's the name. short, sweet, devastating. ๐
๐ KEYWORDS ๐
raster, algebra
๐ SYNOPSIS ๐
r3.mapcalc
r3.mapcalc --help
r3.mapcalc [-sl] [expression=string] [region=string] [file=name]
[seed=integer] [--overwrite] [--help] [--verbose] [--quiet] [--ui]
๐ฉ Flags
-sโ generate random seed. heads up bestie, the result is non-deterministic, so like, don't expect the same thing twice ๐ฒ-lโ list input and output maps. love that for us, receipts please ๐งพ--overwriteโ lets output files overwrite existing files. use with intent, okay? ๐ญ--helpโ print usage summary. the classic. ๐ซถ--verboseโ verbose module output. give us everything โจ--quietโ quiet module output. shhh ๐คซ--uiโ force launching GUI dialog. for the girlies who love a window ๐ช
๐ Parameters
expression=stringโ expression to evaluate. this is the main character here ๐region=stringโ the computational region that should be used.- options:
current,intersect,union - default:
current current: uses the current region of the mapset ๐ธintersect: computes the intersection region between all input maps and uses the smallest resolution โ๏ธunion: computes the union extent of all map regions and uses the smallest resolution ๐ค
- options:
file=nameโ file containing expression(s) to evaluate ๐seed=integerโ seed for therand()function ๐ฐ
๐ DESCRIPTION ๐
so what does it even do?? r3.mapcalc performs arithmetic on raster map layers. new raster map layers can be created which are arithmetic expressions involving existing raster map layers, integer or floating point constants, and functions. basically it's a calculator but the numbers are maps and the vibe is immaculate ๐ฅ
๐งฎ Program use
r3.mapcalc expressions have the form:
result = expression
where result is the name of a raster map layer to contain the result of the calculation, and expression is any legal arithmetic expression involving existing raster map layers (except result itself, no self-referencing bestie ๐), integer or floating point constants, and functions known to the calculator. parentheses are allowed in the expression and may be nested to any depth. result will be created in the user's current mapset. ๐
as expression= is the first option, it is the default. this means that passing an expression on the command line is possible as long as the expression is quoted and a space is included before the first = sign. example (foo is the resulting map):
r3.mapcalc "foo = 1"
or:
r3.mapcalc 'foo = 1'
an unquoted expression (i.e. split over multiple arguments) won't work, nor will omitting the space before the = sign:
r3.mapcalc 'foo=1'
Sorry, <foo> is not a valid parameter
the space before = is NOT optional and the shell will humble you about it. no cap. ๐ญ
if no options are given, it manufactures "file=-" (which reads from stdin), so you can continue to use e.g.:
r3.mapcalc < file
or:
r3.mapcalc <<EOF
foo = 1
EOF
but unless you need compatibility with previous versions, use file= explicitly, e.g.:
r3.mapcalc file=file
or:
r3.mapcalc file=- <<EOF
foo = 1
EOF
the formula entered to r3.mapcalc by the user is recorded both in the result map title (which appears in the category file for result) and in the history file for result. it's giving receipts, it's giving accountability ๐ง
some characters have special meaning to the command shell. if the user is entering input to r3.mapcalc on the command line, expressions should be enclosed within single quotes. see NOTES, below. (yes bestie, NOTES is coming, we're just not there yet ๐ซ )
โ Operators and order of precedence
the following operators are supported:
-โ negation ยท Arithmetic ยท precedence 12~โ one's complement ยท Bitwise ยท precedence 12!โ not ยท Logical ยท precedence 12^โ exponentiation ยท Arithmetic ยท precedence 11%โ modulus ยท Arithmetic ยท precedence 10/โ division ยท Arithmetic ยท precedence 10*โ multiplication ยท Arithmetic ยท precedence 10+โ addition ยท Arithmetic ยท precedence 9-โ subtraction ยท Arithmetic ยท precedence 9<<โ left shift ยท Bitwise ยท precedence 8>>โ right shift ยท Bitwise ยท precedence 8>>>โ right shift (unsigned) ยท Bitwise ยท precedence 8>โ greater than ยท Logical ยท precedence 7>=โ greater than or equal ยท Logical ยท precedence 7<โ less than ยท Logical ยท precedence 7<=โ less than or equal ยท Logical ยท precedence 7==โ equal ยท Logical ยท precedence 6!=โ not equal ยท Logical ยท precedence 6&โ bitwise and ยท Bitwise ยท precedence 5|โ bitwise or ยท Bitwise ยท precedence 4&&โ logical and ยท Logical ยท precedence 3&&&โ logical and[1] ยท Logical ยท precedence 3||โ logical or ยท Logical ยท precedence 2|||โ logical or[1] ยท Logical ยท precedence 2?:โ conditional ยท Logical ยท precedence 1
(modulus is the remainder upon division) ๐ฐ
[1] the &&& and ||| operators handle null values differently to other operators. see the section entitled NULL support below for more details. ๐
the operators are applied from left to right, with those of higher precedence applied before those with lower precedence. division by 0 and modulus by 0 are acceptable and give a NULL result โ yes really, no crash, just vibes โจ. the logical operators give a 1 result if the comparison is true, 0 otherwise. binary. periodt. ๐
๐บ๏ธ 3D Grid names
anything in the expression which is not a number, operator, or function name is taken to be a 3D grid name. examples:
volume
x3
3d.his
most GRASS raster map layers and 3D grids meet this naming convention. however, if a 3D grid has a name which conflicts with the above rule, it should be quoted. for example, the expression
x = a-b
would be interpreted as: x equals a minus b, whereas
x = "a-b"
would be interpreted as: x equals the 3D grid named a-b. see how much the quotes are doing?? the quotes are the whole plot twist ๐ญ
also
x = 3107
would create x filled with the number 3107, while
x = "3107"
would copy the 3D grid 3107 to the 3D grid x. literally the same characters, completely different outcome. iykyk ๐
quotes are not required unless the 3D grid names look like numbers or contain operators, OR unless the program is run non-interactively. examples given here assume the program is run interactively. see NOTES, below. (again with the NOTES, we get it, it's coming ๐)
r3.mapcalc will look for the 3D grids according to the user's current mapset search path. it is possible to override the search path and specify the mapset from which to select the 3D grid. this is done by specifying the 3D grid name in the form:
name@mapset
for example, the following is a legal expression:
result = x@PERMANENT / y@SOILS
the mapset specified does not have to be in the mapset search path. (this method of overriding the mapset search path is common to all GRASS commands, not just r3.mapcalc.) so like, it's a GRASS-wide thing, not a r3.mapcalc exclusive. we're just the ones talking about it rn ๐ซถ
๐ง The neighborhood modifier
3D grids are data base files stored in voxel format, i.e., three-dimensional matrices of float/double values. in r3.mapcalc, 3D grids may be followed by a neighborhood modifier that specifies a relative offset from the current cell being evaluated. the format is map[r,c,d], where r is the row offset, c is the column offset and d is the depth offset. for example, map[1,2,3] refers to the cell one row below, two columns to the right and 3 levels below of the current cell, map[-3,-2,-1] refers to the cell three rows above, two columns to the left and one level below of the current cell, and map[0,1,0] refers to the cell one column to the right of the current cell. this syntax permits the development of neighborhood-type filters within a single 3D grid or across multiple 3D grids. it's giving spatial awareness ๐ง โจ
๐ Functions
the functions currently supported are listed in the table below. the type of the result is indicated in the last column. F means that the functions always results in a floating point value, I means that the function gives an integer result, and * indicates that the result is float if any of the arguments to the function are floating point values and integer if all arguments are integer. ๐
ok so bestie, here's the โจfull function menuโจ โ every single one, no skipping, I promise. The type column at the end is the vibe: F means float, I means integer, and * means it depends on what u feed it (more on that in a sec, iykyk).
๐งฎ functions
abs(x)โ hands u the absolute value ofx๐ type*acos(x)โ inverse cosine ofx(and yes, the result comes out in degrees) โจ typeFasin(x)โ inverse sine ofx(result is in degrees, no cap) typeFatan(x)โ inverse tangent ofx(in degrees) typeFatan(x,y)โ inverse tangent ofy/x(still degrees, slay) typeFceil(x)โ the smallest integral value that's not less thanxtype*cos(x)โ cosine ofx(andxis in degrees here, not radians, ok?) typeFdouble(x)โ convertsxto double-precision floating point typeFeval([x,y,...,]z)โ evaluates the values of the listed exprs, then passes the results toz๐ซถexp(x)โ the exponential function ofxtypeFexp(x,y)โxto the powerytypeFfloat(x)โ convertsxto single-precision floating point typeFfloor(x)โ the largest integral value not greater thanxtype*graph(x,x1,y1[x2,y2..])โ converts thexto aybased on points in a graph ๐ typeFgraph2(x,x1[,x2,..],y1[,y2..])โ the alternative form ofgraph()typeFifโ decision options, the whole lil family ๐ type*if(x)โ1ifxis not zero,0otherwiseif(x,a)โaifxis not zero,0otherwiseif(x,a,b)โaifxis not zero,botherwiseif(x,a,b,c)โaifx > 0,bifxis zero,cifx < 0
int(x)โ convertsxto integer [ truncates, it's giving brutal honesty ] typeIisnull(x)โ checks ifx = NULLlog(x)โ natural log ofxtypeFlog(x,b)โ log ofxbasebtypeFmax(x,y[,z...])โ the largest value of all the ones listed type*median(x,y[,z...])โ the median value of those listed type*min(x,y[,z...])โ the smallest value of those listed type*mod(x,y)โ returns the modulus (aka the remainder) ofx/ytype*mode(x,y[,z...])โ the mode value of those listed type*nmax(x,y[,z...])โ largest value of those listed, but it excludes the NULLs ๐ type*nmedian(x,y[,z...])โ median value of those listed, NULLs excluded type*nmin(x,y[,z...])โ smallest value of those listed, NULLs excluded type*nmode(x,y[,z...])โ mode value of those listed, NULLs excluded type*not(x)โ1ifxis zero,0otherwisepow(x,y)โxto the powerytype*rand(a,b)โ a random valuexwherea <= x < b๐ฒ type*round(x)โ roundsxto the nearest integer typeIround(x,y)โ roundsxto the nearest multiple ofyround(x,y,z)โ roundsxto the nearesty*i+zfor some integerisin(x)โ sine ofx(xis in degrees) typeFsqrt(x)โ square root ofxtypeFtan(x)โ tangent ofx(xis in degrees) typeFxor(x,y)โ exclusive-or (XOR) ofxandytypeI
๐ internal variables
row()โ current row of the moving window typeIcol()โ current col of the moving window typeIdepth()โ returns the current depth typeInrows()โ number of rows in the computation region typeIncols()โ number of columns in the computation region typeIndepths()โ number of depth levels in the computation region typeIx()โ current x-coordinate of the moving window typeFy()โ current y-coordinate of the moving window typeFz()โ returns the current z value typeFewres()โ current east-west resolution typeFnsres()โ current north-south resolution typeFtbres()โ current top-bottom resolution typeFarea()โ area of the current cell in square meters typeFnull()โ the NULL value
heads up bestie:row(),col()anddepth()all start their indexing at 1. Not zero. One. Remember it, it'll get u every time ๐
๐ Floating point values in the expression
Floating point numbers are 100% allowed in the expression. A floating point number is just a number that contains a decimal point:
2.3 12.0 12. .81
Floating point values get handled in a special way and honestly it's iconic. With arithmetic and logical operators, if either operand is float, the other one gets converted to float, and the result of the operation is float. Which means โ and this is the part people get wrong โ dividing integers gives u a (truncated) integer, while dividing floats gives u an accurate floating point value โจ. And with functions of type * (peep the table above ๐), the result is float if any argument is float, and integer otherwise.
Note: if u calculate with integer numbers, the resulting map will be integer. If u want a float result, just add the decimal point to the integer number(s). That's it, that's the whole trick ๐
If u want floating point division, at least one of the arguments has to be a floating point value. Multiplying one of them by 1.0 will produce a floating-point result, and so will using float():
r3.mapcalc "ratio = float(soil.4 - soil.3) / soil.3)"
๐ฆ NULL support
- Division by zero should result in
NULL. - Modulus by zero should result in
NULL. - NULL-values in any arithmetic or logical operation should result in
NULL. (however,&&&and|||are treated specially, as described below ๐). - The
&&&and|||operators observe the following axioms even whenxis NULL:
x &&& false == false
false &&& x == false
x ||| true == true
true ||| x == true
- NULL-values in function arguments should result in
NULL(however,if(),eval()andisnull()are treated specially, as described below ๐). - The
eval()function always returns its last argument. - The situation for
if()is:
if(x)
NULL if x is NULL; 0 if x is zero; 1 otherwise
if(x,a)
NULL if x is NULL; a if x is non-zero; 0 otherwise
if(x,a,b)
NULL if x is NULL; a if x is non-zero; b otherwise
if(x,n,z,p)
NULL if x is NULL; n if x is negative;
z if x is zero; p if x is positive
- The (new) function
isnull(x)returns:1ifxis NULL;0otherwise. The (new) functionnull()(which has no arguments) returns an integer NULL. - Non-NULL, but invalid, arguments to functions should result in
NULL.
Examples:
log(-2)
sqrt(-2)
pow(a,b) where a is negative and b is not an integer
NULL support: Please note that any math performed with NULL cells always results in a NULL value for these cells ๐ซ . If u want to replace a NULL cell on-the-fly, use the isnull() test function inside an if-statement.
Example: the user wants the NULL-valued cells to be treated like zeros. To add maps A and B (where B contains NULLs) to get a map C, the user can use a construction like:
C = A + if(isnull(B),0,B)
๐ NULL and conditions
For the one argument form:
if(x) = NULL if x is NULL
if(x) = 0 if x = 0
if(x) = 1 otherwise (i.e. x is neither NULL nor 0).
For the two argument form:
if(x,a) = NULL if x is NULL
if(x,a) = 0 if x = 0
if(x,a) = a otherwise (i.e. x is neither NULL nor 0).
For the three argument form:
if(x,a,b) = NULL if x is NULL
if(x,a,b) = b if x = 0
if(x,a,b) = a otherwise (i.e. x is neither NULL nor 0).
For the four argument form:
if(x,a,b,c) = NULL if x is NULL
if(x,a,b,c) = a if x > 0
if(x,a,b,c) = b if x = 0
if(x,a,b,c) = c if x < 0
More generally, all operators and most functions return NULL if any of their arguments are NULL.
The functions if(), isnull() and eval() are the exceptions ๐. The function isnull() returns 1 if its argument is NULL and 0 otherwise. If the user wants the opposite, the ! operator, e.g. "!isnull(x)" must be used.
All forms of if() return NULL if the first argument is NULL. The 2, 3 and 4 argument forms of if() return NULL if the "selected" argument is NULL, e.g.:
if(0,a,b) = b regardless of whether a is NULL
if(1,a,b) = a regardless of whether b is NULL
eval() always returns its last argument, so it only returns NULL if the last argument is NULL.
Note: the user cannot test for NULL using the==operator, as that returns NULL if either or both arguments are NULL. i.e. ifxandyare both NULL, then"x == y"and"x != y"are both NULL rather than1and0respectively. ๐
The behaviour makes sense if the user considers NULL as representing an unknown quantity. E.g. if x and y are both unknown, then the values of "x == y" and "x != y" are also unknown; if they both have unknown values, the user doesn't know whether or not they both have the same value ๐ง
๐ NOTES ๐
๐ป Usage from command line
okay bestie, listen up, because this part is important. If you're typing your expression straight onto the command line, you gotta be careful โ some characters mean stuff to the UNIX shell. Which ones? Among others:
*()>&|
so the move is to wrap your expression in single quotes, like:
'result = volume * 2'
because without the quotes, that * (which the shell thinks is its business, not yours) would get messed with, and r3.mapcalc would see something totally different from a *. no cap. ๐
๐ Multiple computations
general vibe: it's lowkey preferable to do as much as you can inside each single r3.mapcalc command, using multi-line input. one command, many lines, main character energy. โจ
๐ฐ๏ธ Backwards compatibility
for backwards compatibility with GRASS 6, if you give no options at all, it manufactures file=- for you (which reads from stdin), so you can keep doing stuff like:
r3.mapcalc < file
or:
r3.mapcalc <<EOF
foo = 1
EOF
but โ and I mean this lovingly โ unless you actually need compatibility with previous GRASS GIS versions, just use file= explicitly, like we said above. ๐
Also: when the map name contains uppercase letter(s) or a dot, which aren't allowed in module option names, the r3.mapcalc command is still valid without quotes:
r3.mapcalc volume_A=1
r3.mapcalc volume.1=1
However, this syntax is not recommended โ quotes, as stated above, are more safe. Using quotes is both backwards compatible and valid in the future. so like, just use quotes? ๐ซถ
โจ๏ธ Interactive input in command line
for formulas the user enters from standard input (not from the command line), there's a line continuation feature now. If you slap a backslash at the end of an input line, r3.mapcalc assumes the formula keeps going on the next input line. There is no limit to the possible number of input lines, or to the length of a formula. iconic. ๐
If the r3.mapcalc formula you entered is very long, the map title will contain only some of it โ but most (if not all) of the formula will be placed into the history file for the result map. so it's not lost, bestie, it's just shy. ๐
โ ๏ธ When the user enters input to r3.mapcalc non-interactively on the command line, the program will not warn you about overwriting existing map layers. So you gotta take care to assign program outputs raster map names that don't already exist in your current mapsets. be careful out there. ๐ญ
๐ญ 3D GRID MASK handling
r3.mapcalc follows the common GRASS behavior of raster MASK handling, so the MASK is only applied when reading an existing GRASS raster map. This implies that, for example, the command:
r3.mapcalc "volume_amplified = volume * 3"
creates a map that respects the masked pixels if MASK is active. slay. โจ
However, when creating a map which is not based on any map โ like a map from a constant:
r3.mapcalc "volume_const = 200.0"
the created raster map is limited only by a computation region but it is not affected by an active MASK. This is expected, because (as we just said) MASK is only applied when reading, not when writing a raster map.
If in this case you do want the MASK applied, use an if() statement that includes the MASK, e.g.:
r3.mapcalc "volume_const = if(MASK, 200.0, null())"
When testing MASK related expressions, keep in mind that when MASK is active you don't see data in masked areas even if they are not NULL. See r.mask for details. ๐ฆ
๐ฒ Random number generator initialization
The pseudo-random number generator used by the rand() function can be initialised to a specific value using the seed option. This can be used to replicate a previous calculation. ๐
Alternatively, it can be initialised from the system time and the PID using the -r flag. This should result in a different seed being used each time. ๐ฐ
In either case, the seed will be written to the map's history, and can be seen using r.info.
If you want other people to be able to verify your results, it's preferable to use the seed option to supply a seed which is either specified in the script or generated from a deterministic process such as a pseudo-random number generator given an explicit seed.
๐ Note that therand()function will generate a fatal error if neither theseedoption nor the-sflag are given. not a vibe. so don't forget it.
๐ EXAMPLES ๐
To compute the average of two 3D grids a and b:
ave = (a + b)/2
To form a weighted average:
ave = (5*a + 3*b)/8.0
To produce a binary representation of the 3D grid a so that category 0 remains 0 and all other categories become 1:
mask = a != 0
This could also be accomplished by:
mask = if(a)
To mask 3D grid b by 3D grid a:
result = if(a,b)
To change all values below 5 to NULL, keep value otherwise:
newmap = if(map < 5, null(), map)
The graph() function allows users to specify a x-y conversion using pairs of x,y coordinates. In some situations a transformation from one value to another is not easily established mathematically, but can be represented by a 2-D graph and then linearly interpolated. The graph() function provides the opportunity to accomplish this. An x-axis value is provided to the graph function along with the associated graph represented by a series of x,y pairs. The x values must be monotonically increasing (each larger than or equal to the previous). The graph function linearly interpolates between pairs. Any x value lower the lowest x value (i.e. first) will have the associated y value returned. Any x value higher than the last will similarly have the associated y value returned. Consider the request:
newmap = graph(map, 1,10, 2,25, 3,50)
X (map) values supplied and y (newmap) values returned:
0,101,101.5,17.52.9,47.54,50100,50
๐ KNOWN ISSUES ๐
- The result variable on the left hand side of the equation should not appear in the expression on the right hand side.
mymap = if( mymap > 0, mymap, 0)
- Any maps generated by a
r3.mapcalccommand only exist after the entire command has completed. All maps are generated concurrently, row-by-row (i.e. there is an implicit"for row in rows {...}"around the entire expression). Thus the#,@, and[ ]operators cannot be used on a map generated within samer3.mapcalccommand run.
newmap = oldmap * 3.14
othermap = newmap[-1, 0] / newmap[1, 0]
- Continuation lines must end with a
\and have no trailing white space (blanks or tabs). If the user does leave white space at the end of continuation lines, the error messages produced byr3.mapcalcwill be meaningless and the equation will not work as the user intended. This is particularly important for theeval()function. ๐ - Currently, there is no comment mechanism in
r3.mapcalc. Perhaps adding a capability that would cause the entire line to be ignored when the user inserted a#at the start of a line as if it were not present, would do the trick. - The function should require the user to type
"end"or"exit"instead of simply a blank line. This would make separation of multiple scripts separable by white space. r3.mapcalcdoes not print a warning in case of operations on NULL cells. It is left to the user to utilize theisnull()function.
๐ REFERENCES ๐
r.mapcalc: An Algebra for GIS and Image Processing, by Michael Shapiro and Jim Westervelt, U.S. Army Construction Engineering Research Laboratory (March/1991).- Performing Map Calculations on GRASS Data:
r.mapcalcProgram Tutorial, by Marji Larson, Michael Shapiro and Scott Tweddale, U.S. Army Construction Engineering Research Laboratory (December 1991) - Neteler, M. (2001): Volume modelling of soils using GRASS GIS 3D tools. - in: Brovelli, M. (ed.)(2001): The Geomatics Workbook N. 2. Politecnico di Milano, Italy (ISSN 1591-092X) (PDF)
๐ SEE ALSO ๐
g.regionr3.colorsr.mapcalc
๐ AUTHORS ๐
- Tomas Paudits & Jaro Hofierka, funded by GeoModel s.r.o., Slovakia
tpaudits@mailbox.sk,hofierka@geomodel.sk - Glynn Clements
๐ SOURCE CODE ๐
Available at: r3.mapcalc source code (history)
Accessed: Saturday Jan 17 05:40:51 2026
Main index | 3D raster index | Topics index | Keywords index | Graphical index | Full index
ยฉ 2003-2025 GRASS Development Team, GRASS GIS 8.4.2 Reference Manual
and that's a wrap, bestie!! ๐ this whole thing lives in the <b>GRASS 8.4.2</b> reference manual, it's the <b>r3.mapcalc(1)</b> page, and it got accessed on <b>Saturday Jan 17 05:40:51 2026</b>. go make some 3D grids, you absolute legend. ๐
โจ
๐ฆ where this page comes from
- fedora 44: grass 8.4.2-4.fc44 ยท 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