Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
calculate_r_expression [2026/07/19 21:35] hermann |
calculate_r_expression [2026/07/22 18:13] (current) hermann |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| ===== Description ===== | ===== Description ===== | ||
| - | This is a **[[ego_script#container_functors|container functor]]** that calls R externally and processes the script's outputs as if they were part of Dinamica EGO itself. Like the other calculator functors, data is connected through hook functors placed inside its ''<nowiki>{{ … }}</nowiki>'' block. | + | 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 ''<nowiki>{{ … }}</nowiki>'' block. |
| ===== Inputs ===== | ===== Inputs ===== | ||
| Line 24: | Line 24: | ||
| ==== Expression inputs ==== | ==== Expression inputs ==== | ||
| - | Data is passed into the expression through **hook** functors placed inside the container's ''<nowiki>{{ … }}</nowiki>'' block. Hooks can be added using the //Create a hook// button on the functor bar, or by dragging them in individually. | + | Data is passed into the expression through **hook** functors placed inside the container's ''<nowiki>{{ … }}</nowiki>'' 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'' | * Tables and lookup tables → [[Number Table]] → available in R as ''t1'', ''t2'', …, ''t100'' | ||
| Line 40: | Line 40: | ||
| <code rsplus> | <code rsplus> | ||
| # Access the third key and its corresponding value in lookup table t1 | # Access the third key and its corresponding value in lookup table t1 | ||
| - | patchId <- t1$Key[ 3 ]; | + | patchId <- t1$Key[3]; |
| - | patchArea <- t1$Value[ 3 ]; | + | patchArea <- t1$Value[3]; |
| </code> | </code> | ||
| 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: | 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]]). | + | * **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. |
| - | * R automatically converts string columns to **Factors** inside a ''data.frame'', but Dinamica requires plain **Character Vectors**. Always build tables with ''stringsAsFactors = FALSE'' to prevent this conversion. | + | * 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]]. | For further detail on the underlying table representation, see [[external_communication#table|External Communication]]. | ||
| Line 53: | Line 53: | ||
| ==== Expression outputs ==== | ==== 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: | + | 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 ^ Example ^ | + | ^ Function ^ Output type ^ Notes ^ Example ^ |
| - | | ''outputDouble()'' | Real | ''outputDouble("myDouble", 3.14)'' | | + | | ''outputDouble()'' | Real | Accepts any numeric value. | ''outputDouble("myDouble", 3.14)'' | |
| - | | ''outputNumberVector()'' | Tuple | ''outputNumberVector("myTuple", c(1:10))'' | | + | | ''outputNumberVector()'' | Tuple | Accepts any collection of numbers. | ''outputNumberVector("myTuple", c(1:10))'' | |
| - | | ''outputString()'' | String | ''outputString("myString", "This is a string")'' | | + | | ''outputString()'' | String | Accepts any string value. | ''outputString("myString", "This is a string")'' | |
| - | | ''outputLookupTable()'' | Lookup Table | ''outputLookupTable("myLUT", c(1:10), c(1:10) * 10)'' | | + | | ''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 | ''outputTable("myTable", data.frame(State = c("Massachusetts", "Massachusetts"), City = c("Boston", "Chelsea"), Population = c(667137, 39398), stringsAsFactors = FALSE), 2)'' | | + | | ''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)'' | |
| - | + | ||
| - | Values passed to these functions can be constructed inline, as in the examples above, or supplied as variables. | + | |
| - | + | ||
| - | * Any numeric value can be passed to ''outputDouble()''. | + | |
| - | * Collections of numbers are valid number vectors for ''outputNumberVector()''. | + | |
| - | * A [[Lookup Table Type|lookup table]] requires two number vectors of equal length — one for the keys, one for the values. | + | |
| - | * ''outputTable()'' requires a table built with the [[http://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. | + | |
| ==== Retrieving outputs ==== | ==== Retrieving outputs ==== | ||
| Line 81: | Line 74: | ||
| Each functor takes two inputs: the ''Struct'' returned by ''CalculateRExpression'', and the name of the entry to extract as a string constant. | 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. | ||
| + | |||
| + | <code rsplus> | ||
| + | dinamicaPackage("moments"); | ||
| + | </code> | ||
| ==== Setup ==== | ==== Setup ==== | ||
| - | There are two ways to run R scripts from ''CalculateRExpression''. | + | There are two ways to run R scripts from ''CalculateRExpression'' — though only the local installation is available on Linux. |
| === Dinamica EGO Enhancement Plugin === | === Dinamica EGO Enhancement Plugin === | ||
| - | 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. | + | 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 === | === Local R installation === | ||
| - | Alternatively, a local R installation can be used instead. This requires: | + | 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 version 3.3.1 or later. | + | * R installed on the machine, with the ''Rscript'' executable (''Rscript.exe'' on Windows) present in its ''bin'' sub-folder. |
| - | * A valid ''Rscript.exe'' located in the R installation's ''bin'' sub-folder. | + | |
| * The [[external_communication|Dinamica package]] for R installed and at its latest version. | * The [[external_communication|Dinamica package]] for R installed and at its latest version. | ||
| - | To use a custom R installation, go to //Tools// → //Options// → //Integration// tab and enable //Use alternative R installation for Calculate R Expression//: | + | 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//. |
| - | + | ||
| - | {{:dinamica_options_use_alternative_r_install.png?nolink|}} | + | |
| ==== Examples ==== | ==== Examples ==== | ||
| Line 113: | Line 113: | ||
| <code rsplus> | <code rsplus> | ||
| - | patchMean <- mean( t1$Value ); | + | patchMean <- mean(t1$Value); |
| - | patchTotal <- sum( t1$Value ); | + | patchTotal <- sum(t1$Value); |
| - | print( paste( "Processed", length( t1$Value ), "patches" ) ); | + | print(paste("Processed", length(t1$Value), "patches")); |
| - | outputDouble( "meanArea", patchMean ); | + | outputDouble("meanArea", patchMean); |
| - | outputDouble( "totalArea", patchTotal ); | + | outputDouble("totalArea", patchTotal); |
| </code> | </code> | ||
| Line 127: | Line 127: | ||
| <code rsplus> | <code rsplus> | ||
| aboveThreshold <- t1$Value >= v1; | aboveThreshold <- t1$Value >= v1; | ||
| - | filteredKeys <- t1$Key[ aboveThreshold ]; | + | filteredKeys <- t1$Key[aboveThreshold]; |
| - | filteredValues <- t1$Value[ aboveThreshold ]; | + | filteredValues <- t1$Value[aboveThreshold]; |
| - | outputLookupTable( "filteredPatches", filteredKeys, filteredValues ); | + | outputLookupTable("filteredPatches", filteredKeys, filteredValues); |
| </code> | </code> | ||
| Line 142: | Line 142: | ||
| stringsAsFactors = FALSE | stringsAsFactors = FALSE | ||
| ); | ); | ||
| - | names( patchFlags )[ 3 ] <- s1; | + | names(patchFlags)[3] <- s1; |
| - | outputTable( "patchSummary", patchFlags, 1 ); | + | outputTable("patchSummary", patchFlags, 1); |
| + | </code> | ||
| + | |||
| + | 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: | ||
| + | |||
| + | <code rsplus> | ||
| + | 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); | ||
| </code> | </code> | ||
| ==== Writing the expression in EGO Script ==== | ==== Writing the expression in EGO Script ==== | ||
| - | Like [[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. | + | 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. | 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. | ||
| Line 156: | Line 178: | ||
| result := CalculateRExpression (String $"( | result := CalculateRExpression (String $"( | ||
| aboveThreshold <- t1$Value >= v1; | aboveThreshold <- t1$Value >= v1; | ||
| - | outputLookupTable( "filteredPatches", t1$Key[ aboveThreshold ], t1$Value[ aboveThreshold ] ); | + | outputLookupTable("filteredPatches", t1$Key[aboveThreshold], t1$Value[aboveThreshold]); |
| )") .no {{ | )") .no {{ | ||
| NumberTable landCoverAreas 1; | NumberTable landCoverAreas 1; | ||
| Line 171: | Line 193: | ||
| CalculateRExpression | CalculateRExpression | ||
| - | |||
| - | ===== See Also ===== | ||
| - | |||
| - | * [[r_coupling|R Coupling]] | ||
| - | * [[Calculate Python Expression]] | ||
| - | * [[External Communication]] | ||
| - | * [[ego_script#container_functors|EGO Script — Container Functors]] | ||
| - | * [[ego_script#verbose_form|EGO Script — Verbose Form (Hooks)]] | ||
| - | * [[calculate_functors|Calculate Functors — Complete Operator Documentation]] | ||
| - | |||
| - | |||