简体   繁体   中英

R/shiny: render elements of plots only when needed in shiny apps

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, eg

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!

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"))
    )

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)

    )
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM