简体   繁体   English

R /发光:仅在闪亮的应用程序中需要时才渲染图的元素

[英]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.) plot将不是我将在闪亮的应用程序中使用的功能。)

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. 其中plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))将在闪亮的应用程序中花费很长时间进行渲染并points(x=1:10)将花费很短的时间。 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). 我需要一个仅在首次加载应用程序时才会执行plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))自底向上构建(将点,线等添加到绘图中)。 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 ). 绘图功能基于基本graphics系统(不在ggplot2 ,不在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: 因此,也许像下面这样尝试grDevices

server.R: 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: 和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. 您说过不会使用plot ,但是要使用的内容很重要。 For example, for ggplot you can do it like here (see reactive ): 例如,对于ggplot你可以像这里(见reactive ):

ui.R: 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. 但是,这不是R't,只是一个快速修复。

test/ui.R : 测试/ui.R:

fluidPage(
    sidebarPanel(
        actionButton("trickButton","Useless"),
        sliderInput("something", min=1, max=5, label="Useful", value=5)
    ),
    mainPanel(
        plotOutput("plotPoints")
    )
)

test/server.R : 测试/服务器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 : 现在,在您的R控制台上:

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. 每当我们与按钮交互时,以及在服务器启动时,都会调用observe函数。 The if(!input$trickButton) states that we just run our code at server start (because then the button is not valued). if(!input$trickButton)指出我们只是在服务器启动时运行代码(因为按钮没有值)。 You could also hide this useless button with a renderUI mechanism. 您还可以使用renderUI机制隐藏此无用的按钮。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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