How to make a package set up protected variables in R? - r

I am trying to create a R package mypckg with a function createShinyApp. The latter function should create a directory structure ready to use as shiny app at some location. In this newly created shiny app, I have some variables, which should be accessed from within the shiny app, but not by the user directly (to prevent a user from accidentally overwriting them). The reason for these variables to exist (I know one should not use global variables) is that the shiny app is treating a text corpus and I want to avoid passing (and hence copying) it between the many functions because this could lead to exhaustion of the memory. Somebody using mypckg should be able to set these variables and later use createShinyApp.
My ideas so far are:
I make mypckg::createShinyApp save the protected variables in a protectedVariables.rds file and get the shinyApp to load the variables from this file into a new environment. I am not very experienced with environments so I could not get this to work properly yet because the creation of a new environment is not working upon running a shiny app so far.
I make mypckg::createShinyApp save the protected variables in a protectedVariables.rds file and get the shinyApp to load the variables from this file into the options. Thereafter I would access the variables and set the variables with options() and getOption.
What are the advantages and disadvantages of these ideas and are there yet simpler and more elegant ways of achieving my goal?

It's a little bit difficult to understand the situation without seeing a concrete example of the kind of variable and context you're using it in, but I'll try to answer.
First of all: In R, it's very very difficult to achieve 100% protection of a variable. Even in shiny, the authors of shiny tried putting up a lot of mechanisms to disallow some variables from getting overwritten by users (like the input variable for example), and while it does make it much harder, you should know that it's impossible, or at least extremely difficult, to actually block all ways of changing a variable.
With that disclaimer out of the way, I assume that you'd be happy with something that prevents people from accidentally overwriting the variable, but if they go purposely out of their way to do it, then so be it. In that case, you can certainly read the variables from an RDS file like you suggest (with the caveat that the user can of course overwrite that file). You can also use a global package-level variable -- usually talking about global variables is bad, but in the context of a package it's a very common thing to do.
For example, you can define in a globals.R file in your package:
.mypkgenv <- new.env(parent = emptyenv())
.mypkgenv$var1 <- "some variable"
.mypkgenv$var2 <- "some other variable"
And the shiny app can access these using
mypckg:::.mypkgenv$var1
This is just one way, there are other ways too

Related

How to make r shiny load a separate instance for each user, so as each user has their own global variables?

I saw this post already
handling multiple users simulaneously in an R Shiny app
and I am aware that you can define anything inside of the shinyServer() expression to make it private to a single user's session. However, this limits my ability to define variables that depend on a reactive expression outside of a reactive context.
Reproducible example:
Assume I define ui to have a button "do"
server <- function(input, output, session) {
observeEvent(input$do, {
data<- read.csv("data.csv",check.names=F,row.names=1)
})
req(data) # doesn't work
matrix <- data # PRODUCES ERROR, see below error
})
Error I get when doing this is, and this makes sense because I data is not defined yet:
Error in server(...) : object 'data' not found
I don't want to define matrix in a reactive context, because that would pose a tremendous headache to work with in my code later one as I would have to define MANY variables this way, and would have to access them reactively each time. I really want to avoid doing so if possible.
What I have instead been doing, and it has been working, is define everything (reactive or not) in a reactive context so that I dont have a single line of code outside of a reactive function (not variables, I am trying everything to avoid those). This, however, does not allow me to access variables outside said functions. So what do I do? I use global variables even though its terrible coding practice (I know) but it saves me a big headache and seems to be working.
MY ONLY CONCERN is that users can access each other's data since data is defined globally!!!
However, I have heard from someone that I can allow each user to create their own instance and therefore not share their global variables with anyone else.
If someone can tell me how to do this that would be great. I know this isn't good for scalability, but I am only looking for a temporary solution right now and will probably switch all my variables to be reactive eventually.
Thanks so much

Is there a "correct" way to use exported data internally in an R package?

I know that exported data (access to users) belongs in the data/ folder and that internal data (data used internally by package functions) belongs in R/sysdata.rda. However, what about data I wish to both export to the user AND be available internally for use by package functions?
Currently, presumably due to the order in which objects/data are added to the NAMESPACE, my exported data is not available during devtools::check() and I am getting a NOTE: no visible binding for global variable 'data_x'.
There are probably a half dozen ways to get around this issue, many of which appear to me as rather hacky, so I was wondering if there was a "correct" way to have BOTH external and internal data (and avoid the NOTE from R CMD check).
So far I see these options:
write an internal function that calls the data and use that everywhere internally
Use the ':::' to access the data; which seems odd and invokes a different warning
Have a copy of data_x in BOTH data/ and R/sysdata.rda (super hacky)
Get over it and ignore the NOTE
Any suggestions greatly appreciated,
Thx.

Include library calls in functions?

Is it good practice to include every library I need to execute a function within that function?
For example, my file global.r contains several functions I need for a shiny app. Currently I have all needed packages at the top of the file. When I'm switching projects/copying these functions I have to load the packages/include them in the new code. Otherwise all needed packages are contained in that function. Of course I have to check all functions with a new R session, but I think this could help in the long run.
When I tried to load a package twice it won't load the package again but checks it's already loaded. My main question is if it would slow my functions if I restructure in that way?
I only saw that practice once, library calls inside functions, so I'm not sure.
As one of the commenters suggest, you should avoid loading packages within a function since
The function now has a global effect - as a general rule, this is something to avoid.
There is a very small performance hit.
The first point is the big one. As with most optimisation, only worry about the second point if it's an issue.
Now that we've established the principle, what are the possible solution.
In small projects, I have a file called packages.R that includes all the library calls I need. This is sourced at the top of my analysis script. BTW, all my functions are in a file call func.R. This workflow was stolen/adapted from a previous SO question
If you're only importing a single function, you could use the :: trick, e.g. package::funcA(...) That way you avoid loading the package.
For larger projects, I create an R package that handles all necessary imports. The benefit of creating a package is detailed in this answer on structuring large R projects.

Implement whole R script contains functions into shiny

I have a complex R script which contains many new declared functions. These functions are able to check and clear given file under some requirements.
I want to prepare a simple user interface, where people without any knowledge about R will be able to upload source file, choose some options, and download analysed file without looking into a code.
I prepared a simple shiny app which contains my archival R code in the past, however each time when I want to perform some calculations, I had to use reactive() and add () after each variable.
This time, script is too complex to adjust it to reactive() form.
Is there any way to implement whole R script with avoid this?

Redirect all plot output to specific file

I want to automatically redirect all plotting to a file (reason: see below). Is there a non-hacky way of accomplishing that?
Lacking that, I’m actually not afraid of overriding the built-in functions, I’m that desperate. The easiest way I can think of is to hook into the fundamental plot-window creation function and calling pdf(…) and then hooking into the plot-finalising function and calling dev.off() there.
But what are these functions? Through debugging I’ve tentatively identified dev.hold and dev.flush – but is this actually true universally? Can I hook into those functions? I cannot override them with R.utils’ reassignInNamespace because they are locked, and just putting same-name functions into the global namespace doesn’t work (they’re ignored by plot).
So, why would I want to do something so horrible?
Because I’m working on a remote server and despite my best attempts, and long debugging sessions with our systems support, I cannot get X11 forwarding to work reliably. Not being able to preview a plot is making my workflow horribly inefficient. I’ve given up on trying to get X11 to work so now I’m creating PDFs in my public_html folder and just refresh the browser.
This works quite well – except that it‘s really annoying and quite time-consuming to always have to surround your plotting function calls with pdf(…) … dev.off(), especially in interactive sessions where you want to quickly create a plot while in a meeting with collaborators. In fact, it’s really annoying and they (understandably) haven’t got the patience for that.
For now I’m helping myself with the following function definition:
preview <- function (.expr, ...) {
on.exit(dev.off())
pdf(PREVIEW_FILE_NAME, ...)
eval(substitute(.expr))
}
Which is used like this:
preview(plot(1:100, rnorm(100) * 1:100))
That works a-ok. But this workflow is a real bottleneck in meetings, and I’d like to get rid of the preview call to streamline it as much as possible.
Any chance at all?
If you set options(device=FUN) then the graphics device function FUN becomes the new default graphics device that will be opened when a plot is created and device is not already opened.
So, one option would be to write a function that calls pdf or png or other graphics device with the filename and options that you want (probably onefile=FALSE in pdf), then set this function as the default in the options. You may need to use one of dev.off, plot.new, or frame to finalize the current plot (R does not finalize until you close the device or go to a new plot in case you want to add anything to the current plot).
If you will never add to a plot then you could use addTaskCallback to call dev.off automatically for you. There may be other hooks that you could use to finalize as well.

Resources