====== Calculate R Expression ======
===== Description =====
This is a **[[ego_script#container_functors|container functor]]** that calls R externally with the user-defined expression. Like the other calculator functors, data is connected through hook functors placed inside its ''{{ … }}'' block.
===== Inputs =====
^ Name ^ Type ^ Description ^
| Expression | [[ego_script#constants|Code]] | The expression that will run on R. ''Code'' values cannot be written as plain text constants in EGO Script — see [[#writing_the_expression_in_ego_script|Writing the expression in EGO Script]] below. |
| Treat Warning As Errors | [[Boolean Value Type]] | Warnings raised by the R script will be treated as errors. |
===== Optional Inputs =====
None.
===== Outputs =====
^ Name ^ Type ^ Description ^
| result | [[struct_type|Struct]] | A struct containing the output values generated by the expression. |
===== Notes =====
==== Expression inputs ====
Data is passed into the expression through **hook** functors placed inside the container's ''{{ … }}'' block — the same [[ego_script#verbose_form|verbose form]] hook mechanism used by the calculator functors. Hooks can be added using the //Create a hook// button on the functor bar, or by dragging them in individually.
* Tables and lookup tables → [[Number Table]] → available in R as ''t1'', ''t2'', …, ''t100''
* Scalar values → [[Number Value]] → available as ''v1'', ''v2'', …, ''v100''
* Strings → [[Number String]] → available as ''s1'', ''s2'', …, ''s100''
Maps cannot be connected — this functor has no cell context. There is no shorthand notation; see [[calculate_functors|Calculate Functors — Complete Operator Documentation]] for the general hook mechanism and syntax.
=== Tables and lookup tables ===
Lookup tables and tables require extra care, since each is transferred to R using a different representation.
A **lookup table** is transferred as a list with two columns, ''Key'' and ''Value''. Each column is accessed with the ''$'' operator:
# Access the third key and its corresponding value in lookup table t1
patchId <- t1$Key[3];
patchArea <- t1$Value[3];
A **table** is transferred as a [[https://en.wikibooks.org/wiki/R_Programming/Working_with_data_frames|DataFrame]], with each column likewise accessed using ''$''. Two conventions apply to tables in either direction:
* **Key columns** are marked by an asterisk (''*'') appended to their column name — this is the same convention used throughout Dinamica EGO's table representation (see [[calculate_functors#connecting_data_inputs|Connecting Data Inputs]]). A key column can be Real or String, the same as any other column.
* Each column's type is inferred from its data, the same rule that applies to any table (see [[ego_script#constants|Constants]]): a numeric vector produces a Real column, a character vector produces a String column. R automatically converts string columns to **Factors** inside a ''data.frame'', and a Factor is neither of those — Dinamica requires plain **Character Vectors** to infer String correctly. Always build tables with ''stringsAsFactors = FALSE'' to prevent this conversion.
For further detail on the underlying table representation, see [[external_communication#table|External Communication]].
==== Expression outputs ====
Values are returned to Dinamica by calling one of the following functions from the R script. Every call requires an identifier as its first parameter — the name Dinamica uses to place the value into the output struct — and the value itself, which can be constructed inline, as in the examples below, or supplied as a variable:
^ Function ^ Output type ^ Notes ^ Example ^
| ''outputDouble()'' | Real | Accepts any numeric value. | ''outputDouble("myDouble", 3.14)'' |
| ''outputNumberVector()'' | Tuple | Accepts any collection of numbers. | ''outputNumberVector("myTuple", c(1:10))'' |
| ''outputString()'' | String | Accepts any string value. | ''outputString("myString", "This is a string")'' |
| ''outputLookupTable()'' | [[Lookup Table Type|Lookup Table]] | Requires two number vectors of equal length — one for the keys, one for the values. Lookup tables are always Real-typed on both sides; there is no String option. | ''outputLookupTable("myLUT", c(1:10), c(1:10) * 10)'' |
| ''outputTable()'' | Table | Requires a table built with the [[https://www.r-tutor.com/r-introduction/data-frame|data.frame]] function, using ''stringsAsFactors = FALSE'' as described above. Its optional second parameter (default ''1'') sets how many leading columns, from the left, are key columns. | ''outputTable("myTable", data.frame(State = c("Massachusetts", "Massachusetts"), City = c("Boston", "Chelsea"), Population = c(667137, 39398), stringsAsFactors = FALSE), 2)'' |
==== Retrieving outputs ====
''CalculateRExpression'' returns a single [[struct_type|Struct]] value (via its ''result'' output port) containing every value passed to an ''output*()'' function. To retrieve individual values from that struct, use the corresponding functor from the //Integration// group:
^ Functor ^ Retrieves ^
| [[Extract Struct Number]] | A value passed to ''outputDouble()'' |
| [[Extract Struct Tuple]] | A value passed to ''outputNumberVector()'' |
| [[Extract Struct String]] | A value passed to ''outputString()'' |
| [[Extract Struct Lookup Table]] | A value passed to ''outputLookupTable()'' |
| [[Extract Struct Table]] | A value passed to ''outputTable()'' |
Each functor takes two inputs: the ''Struct'' returned by ''CalculateRExpression'', and the name of the entry to extract as a string constant.
==== Installing packages ====
Packages are installed by calling ''dinamicaPackage("packageName")'' from within the expression — one call per package. Unlike [[calculate_python_expression|Calculate Python Expression]], there is no separate input port for listing packages; ''dinamicaPackage()'' is the only mechanism available.
''dinamicaPackage("packageName")'' also acts as R's ''library()'' call: when the package name matches the name of the module to load, calling it both installs the package (if not already present) and loads it, in a single call.
dinamicaPackage("moments");
==== Setup ====
There are two ways to run R scripts from ''CalculateRExpression'' — though only the local installation is available on Linux.
=== Dinamica EGO Enhancement Plugin ===
Windows only. Download and install the [[plugins_4|Dinamica EGO Enhancement Plugin]]. It contains everything needed to run R scripts inside Dinamica EGO, with no further configuration.
=== Local R installation ===
On Linux, this is the only option — Dinamica EGO always uses the R installation already present on the system. On Windows, it can be used as an alternative to the plugin. Either way, it requires:
* R installed on the machine, with the ''Rscript'' executable (''Rscript.exe'' on Windows) present in its ''bin'' sub-folder.
* The [[external_communication|Dinamica package]] for R installed and at its latest version.
On Windows, this alternative installation is selected in the Dinamica EGO GUI by going to //Tools// → //Options// → //Integration// tab and enabling //Use alternative R installation for Calculate R Expression//.
==== Examples ====
The following examples use a consistent set of inputs:
* ''t1'' — a lookup table of land cover patches, mapping ''Key'' (patch identifier) to ''Value'' (patch area)
* ''v1'' — a scalar minimum area threshold
* ''s1'' — a string giving the name to use for the threshold flag column
Compute the mean and total area across all patches, and report progress to the Message Log:
patchMean <- mean(t1$Value);
patchTotal <- sum(t1$Value);
print(paste("Processed", length(t1$Value), "patches"));
outputDouble("meanArea", patchMean);
outputDouble("totalArea", patchTotal);
> **Note:** The ''print()'' call is visible in Dinamica EGO's Message Log, shown as a Result-level message. Log levels are ordered Unconditional, Error, Warning, Result, Info, Info2, Debug, Debug2 — messages printed from R are only shown when the Message Log level is set to Result or a more verbose level; at Unconditional, Error, or Warning they are suppressed.
Filter the lookup table down to patches whose area meets the threshold, and return the filtered lookup table:
aboveThreshold <- t1$Value >= v1;
filteredKeys <- t1$Key[aboveThreshold];
filteredValues <- t1$Value[aboveThreshold];
outputLookupTable("filteredPatches", filteredKeys, filteredValues);
Build and return a table with one row per patch, including a column that flags whether each patch meets the threshold. The column's name is taken from the passed string ''s1'' rather than being hard-coded:
patchFlags <- data.frame(
PatchId = t1$Key,
Area = t1$Value,
MeetsThreshold = t1$Value >= v1,
stringsAsFactors = FALSE
);
names(patchFlags)[3] <- s1;
outputTable("patchSummary", patchFlags, 1);
Install the ''moments'' package and use it to compute the skewness of the patch area distribution — a statistic not available in base R — then flag patches whose area is a statistical outlier:
dinamicaPackage("moments");
patchMean <- mean(t1$Value);
patchStdDev <- sd(t1$Value);
patchSkewness <- skewness(t1$Value);
isOutlier <- abs(t1$Value - patchMean) > 2 * patchStdDev;
outlierPatches <- data.frame(
PatchId = t1$Key[isOutlier],
Area = t1$Value[isOutlier],
stringsAsFactors = FALSE
);
outputDouble("meanArea", patchMean);
outputDouble("stdDevArea", patchStdDev);
outputDouble("skewnessArea", patchSkewness);
outputTable("outlierPatches", outlierPatches, 1);
==== Writing the expression in EGO Script ====
Like [[calculate_python_expression|Calculate Python Expression]], the ''Expression'' input is type [[ego_script#constants|Code]], which is represented in the underlying script using base64 encoding — impractical to write or edit directly as a text constant. Instead, connect a ''String'' carrier functor containing the R expression text to the ''Expression'' port; its output is accepted wherever a ''Code'' value is expected. Since only this one output is needed, the carrier can be [[ego_script#inline_syntax|inlined]] directly into the call.
This limitation is specific to hand-written EGO Script. In the Dinamica EGO GUI, the ''Expression'' port has a dedicated code editor that edits the ''Code'' value directly — the ''String'' carrier workaround is only necessary when writing or editing the ''.ego'' file as text.
result := CalculateRExpression (String $"(
aboveThreshold <- t1$Value >= v1;
outputLookupTable("filteredPatches", t1$Key[aboveThreshold], t1$Value[aboveThreshold]);
)") .no {{
NumberTable landCoverAreas 1;
NumberValue minimumArea 1;
}};
filteredPatches := ExtractStructLookupTable result "filteredPatches";
===== Group =====
[[Functor List#Integration|Integration]]
===== Internal Name =====
CalculateRExpression