Reputation: 489
I am currently writing a shiny application. I want to decrease the rendering time of plots (because it takes a long time to initialise a plot). Let's say I want to render a plot dynamically, e.g.
plot(x=1:10)
(plot
will not be the function which I will use in the shiny app.)
Now I want to divide the plotting into several parts, here:
plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
points(x=1:10)
where plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
will take a very long time in the shiny app to render and points(x=1:10)
will take a short time. I need a procedure which will execute plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
only when loading the app for the first time and then the plot will be build bottom-up (add points, lines, etc. to the plot). Has anybody an idea how to write this into an app? Problem here is that the function I will use in the shiny app to plot will not return anything. The plotting function is based on the base graphics
system (not on ggplot2
, not on lattice
).
Here's a minimal working example for such an app:
library(shiny)
shinyAPP <- function() {
ui <- fluidPage(
sidebarPanel(),
mainPanel(
plotOutput("plotPoints"))
)
server <- function(input, output, session) {
output$plotPoints <- renderPlot(
plot(x=1:10)
## this needs to be replaced with:
##plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
##points(x=1:10)
)
}
app <- list(ui = ui, server = server)
runApp(app)
}
shinyAPP()
Thank you very much!
Upvotes: 0
Views: 1380
Reputation: 3162
So maybe try grDevices
, like here:
server.R:
library("shiny")
library("grDevices")
data(iris)
plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
p <- recordPlot()
function(input, output, session) {
output$plotPoints <- renderPlot({
replayPlot(p)
points(1:input$ile)
})
}
and ui.R:
library(shiny)
fluidPage(
sidebarPanel(
sliderInput("ile", min=1, max=10, label="", value=5)
),
mainPanel(
plotOutput("plotPoints"))
)
Upvotes: 2
Reputation: 1434
Here is a little trick that should work if I understood your problem. However, it's not R't, just a quick fix.
test/ui.R :
fluidPage(
sidebarPanel(
actionButton("trickButton","Useless"),
sliderInput("something", min=1, max=5, label="Useful", value=5)
),
mainPanel(
plotOutput("plotPoints")
)
)
test/server.R :
data(iris)
myData <<- NULL
superHeavyLoad <- function() {
print("That is super heavy !")
myData <<- iris
}
function(input, output, session) {
observe({
if (!input$trickButton)
superHeavyLoad()
})
output$plotPoints <- renderPlot(
plot(myData[,1:as.numeric(input$something)])
)
}
Now, on your R console :
require(shiny)
runApp("test")
Listening on http://127.0.0.1:7175
[1] "That is super heavy !"
And no matter what you do, you will never update the super-heavy part ever again. Now, from what I understood, what you did is to divide your processing between heavy-one-time functions, and reactive things. This is a (not very beautiful) way of doing it ;-)
About how it works : it's all in the button that we add. The observe
function will be called each time we interact with the button, plus at server start. The if(!input$trickButton)
states that we just run our code at
server start (because then the button is not valued).
You could also hide this useless button with a renderUI
mechanism.
Upvotes: 0
Reputation: 3162
You said that you won't use plot
, but it's important what you're going to use. For example, for ggplot
you can do it like here (see reactive
):
ui.R:
library(shiny)
fluidPage(
sidebarPanel(
sliderInput("ile", min=1, max=10, label="", value=5)
),
mainPanel(
plotOutput("plotPoints"))
)
server.R
library("shiny")
library("ggplot2")
data(iris)
function(input, output, session) {
wyk <- reactive({ggplot(iris)})
output$plotPoints <- renderPlot(
wyk() + geom_point(aes(x=Sepal.Length, y=Sepal.Width), col=input$ile)
)
}
Upvotes: 0