This article describes some aspects of how R works in Displayr that are different to how it works in some other programs. In general, the biggest difference between standalone R and R in Displayr is that R code is used for individual items in the document and there is not one single script or console, see How to Use R in Displayr for more detail. Other differences include:
1. R code is run from R servers and not from your local machine
3. Only the final object returned in R code is able to be referenced by other R-based items.
Method
1. R code is typically run from R servers and not from your local machine
If the R code is simple and straightforward enough, Displayr is able to process the code using Displayr's Native R Interpreter. More typically, code is complex enough to require processing via the R software. Instead of requiring customers to download R to their computers to run R-based items, Displayr owns cloud-based servers with R already installed. When Displayr performs calculations in R, it does so by sending the data and code to our R servers (see Security and R), and then returns the results to Displayr, see the diagram below.
This means customers don't need to download any R packages or software, as these are instead loaded on our R servers. Displayr has many packages pre-loaded:
- You can see which packages have been installed, and their versions, by selecting Calculation
> Custom Code and entering
installed.packages()
. - You can also see if a particular R package is present by entering
library(package_name)
. - If you wish to use a package that is not installed, please contact support@displayr.com.
Additionally, as customers will be interacting with Displayr R servers, Displayr is not able to load or save to your computer's local disk (C:) or local network via R.
2. You must explicitly use variable and output names in your code so Displayr knows what data to send to the R servers
When R code is run, both the code and any associated data is sent to the R server, which then returns the result to Displayr. The associated data is identified by scanning through the code and looking for the names of Variables, Variable Sets, and Calculations. Where these do not appear in the code, they are not uploaded.
As an example, consider two Calculations. The first contains myVariable <- 10
. This causes a Calculation to be created with a Name of myVariable
and a value of 10. The second contains the following code:
myVariable * eval(parse(text = "myVariable")) * eval(parse(text = paste0("my","Variable")))
This will return a value of 1,000, as it retrieves the value 10 three times, and multiplies them together. This is identical to how R normally works.
By contrast, if the second Calculation contains:
eval(parse(text = "myVariable")) * eval(parse(text = paste0("my","Variable")))
we get the error that object myVariable not found
. This is because the R code does not contain the Variable Name outside double quotes. Rather, myVariable is interpreted as a string which is then converted into a variable name twice.
In situations where it is necessary to use code of this form, a solution is to have some irrelevant usage of the Variable Names at the beginning of the code block, which will cause the data to be uploaded. For example, the following code will return the correct result of 100:
tempVar = myVariable
eval(parse(text = "myVariable")) * eval(parse(text = paste0("my","Variable")))
3. Only the final object returned in R code is able to be referenced by other R-based items.
Because Calculations are each processed individually via a separate request to the R servers, there is no shared Global Environment across them. So any intermediate functions, variables, or calculations created within the R code cannot be referenced by other R items. Only the final item created in the R code can be referenced by other R items. Consider the following Calculation:
f <- 1
b <- function()
{
print(f)
}
Where a Calculation ends with a function, that function can be used within other places that can run R code (i.e., a different Calculation, R Variable, or when creating an R Data Set). However, if the function refers to a variable, such as f in this example, which is not defined within the function, or within its signature, an error will typically occur (the exception is described below). For example, a Calculation containing b(1)
, will return an error of object 'f' not found
.
A similar error will occur if, for example, f <- 1
appears in a separate Calculation with a name of f. In this case, a more voluminous error message is provided, saying, for example: A Calculation called 'f' has been used in the R code. Although this does exist in this document, it is not available where it is referred to. A common cause of this is where referring to objects within a function. A solution is to change the function to accept 'f' (e.g., function(..., f))..
There are two ways to work around this:
- As described in the longer error message, the way to resolve this issue is to pass the variables into the function as arguments (e.g.,
b <- function(f)
). - When calling the function, you can refer to the variable elsewhere in the same Calculation, as is done in the example below. The reason that this works is that any variables referred to within a Calculation, other than within a function, are automatically loaded prior to computing a Calculation.
z = f
b(1)
4. Recursive functions
For more information and examples of custom functions in Displayr, see How to Create Custom R Functions.
a) Permitted recursions
In Displayr, it is fine to write recursive R functions. For example:
fib = function(i) {
if (i < 2)
i
else
fib(i-1) + fib(i-2)
}
It is also fine to write mutually recursive R functions. So, for example, the above function could have been written as:
fibsum = function(k, j) {
fib(k) + fib(j)
}
fib = function(i) {
if (i < 2)
i
else
fibsum(i-1, i-2)
}
b) Problematic Recursion
However, it is a requirement in Displayr to have these two functions defined within the same R item. That is, it is not fine to create two R items:
fibsum = function(k, j) {
fib(k) + fib(j)
}
and
fib = function(i) {
if (i < 2)
i
else
fibsum(i-1, i-2)
}
as they both require that the other one is defined before it is. If two (or more) functions are mutually defined, then Displayr will complain of mutual recursion, and suggest that you solve this by either rewriting the code to eliminate the recursion, or by defining all associated functions within the one R item.
c) Recursive Functions and Implications for S3 Classes
Displayr achieves S3 class functionality by making not only objects which are explicitly referenced in the code available to R for computation, but also objects which have the same initial prefix as objects referred to in the code. That is, if Displayr sees the code
plot(mydata)
and if there are functions which have been defined with the "plot." prefix, such as "plot.myclass", then these functions are made available for the R server to use when evaluating "plot(mydata)". If "mydata" is of class "myclass", then "plot.myclass" will be called, giving the functionality of S3 classes. On the other hand, if "mydata" is not of class "myclass", then "plot.myclass" will be ignored when evaluating "plot(mydata)".
This has an implication when it comes to recursion, because mutual recursion (above) may be present although not necessarily apparent. For example, two objects defined as
auxiliary_plotting = function(x) {
…
plot(x)
…
}
and
plot.myclass = function(x) {
…
auxiliary_plotting(x)
…
}
exhibit mutual recursion. As the definition of "auxiliary_plotting" refers to "plot", which may mean "plot.myclass", there is an implicit reference to "plot.myclass". For this reason, "auxiliary_plotting" implicitly requires "plot.myclass" and "plot.myclass" requires "auxiliary_plotting", resulting in mutual recursion.