R 如何组织大型闪亮应用程序?

R 如何组织大型闪亮应用程序?,r,shiny,R,Shiny,组织更大的应用程序的最佳做法是什么? 我认为最佳R实践也适用于Shiny。 此处讨论了最佳R实践: 谷歌R风格指南链接: 但是,在闪亮的环境中,我可以采用哪些独特的技巧和技巧来使闪亮的代码看起来更好(更可读)? 我想到的是: 利用面向对象编程技术进行软件开发 在server.R中应采购哪些零件 包含降价文档、图片、, xml和源文件 例如,如果我在每个tabPanel中使用navbarPage和tabsetPanel,添加几个UI元素后,我的代码开始变得非常混乱 示例代码: server &

组织更大的应用程序的最佳做法是什么?
我认为最佳R实践也适用于Shiny。
此处讨论了最佳R实践:
谷歌R风格指南链接:

但是,在闪亮的环境中,我可以采用哪些独特的技巧和技巧来使闪亮的代码看起来更好(更可读)? 我想到的是:

  • 利用面向对象编程技术进行软件开发
  • server.R
    中应采购哪些零件
  • 包含降价文档、图片、, xml和源文件
例如,如果我在每个
tabPanel
中使用
navbarPage
tabsetPanel
,添加几个UI元素后,我的代码开始变得非常混乱

示例代码:

server <- function(input, output) {

 #Here functions and outputs..

}

ui <- shinyUI(navbarPage("My Application",
  tabPanel("Component 1",
             sidebarLayout(
                sidebarPanel(
                    # UI elements..
                ),
                mainPanel(
                    tabsetPanel(
                        tabPanel("Plot", plotOutput("plot")
                                 # More UI elements..
                                 ), 
                        tabPanel("Summary", verbatimTextOutput("summary")
                                 # And some more...
                                 ), 
                        tabPanel("Table", tableOutput("table")
                                 # And...
                                 )
                    )
                )
    )           
  ),
  tabPanel("Component 2"),
  tabPanel("Component 3")
))

shinyApp(ui = ui, server = server)

我写了一封信。我还没有听到人们说代码组织的坏话,但我相信它会更好。一种选择是像Joe Cheng在闪亮的部分中那样分离ui和逻辑


另一种可能是尝试OO编程,例如使用R6。我非常喜欢马特·莱昂纳维奇组织应用程序的方式。我采用他的方法学习如何使用Shiny,因为我们都知道,如果管理不当,它可能会变得非常分散。看看他的结构,他概述了他在名为run\u alfresco的应用程序中组织应用程序的方式


在向R添加模块后。在闪亮的应用程序中管理复杂的结构变得容易多了

模块的详细说明:

使用模块的优点:

  • 一旦创建,它们很容易重用
  • ID冲突更容易避免
  • 基于模块输入和输出的代码组织
在基于选项卡的应用程序中,一个选项卡可以被视为一个模块,具有输入输出。然后,选项卡的输出可以作为输入传递给其他选项卡

基于标签结构的单文件应用程序,利用模块化思维。应用程序可以通过使用数据集进行测试。从Joe Cheng复制的部分代码(第一个链接)。欢迎大家发表意见

# Tab module
# This module creates new tab which renders dataTable

dataTabUI <- function(id, input, output) {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(sidebarLayout(sidebarPanel(input),

                        mainPanel(dataTableOutput(output))))

}

# Tab module
# This module creates new tab which renders plot
plotTabUI <- function(id, input, output) {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(sidebarLayout(sidebarPanel(input),

                        mainPanel(plotOutput(output))))

}

dataTab <- function(input, output, session) {
  # do nothing...
  # Should there be some logic?


}

# File input module
# This module takes as input csv file and outputs dataframe
# Module UI function
csvFileInput <- function(id, label = "CSV file") {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(
    fileInput(ns("file"), label),
    checkboxInput(ns("heading"), "Has heading"),
    selectInput(
      ns("quote"),
      "Quote",
      c(
        "None" = "",
        "Double quote" = "\"",
        "Single quote" = "'"
      )
    )
  )
}

# Module server function
csvFile <- function(input, output, session, stringsAsFactors) {
  # The selected file, if any
  userFile <- reactive({
    # If no file is selected, don't do anything
    validate(need(input$file, message = FALSE))
    input$file
  })

  # The user's data, parsed into a data frame
  dataframe <- reactive({
    read.csv(
      userFile()$datapath,
      header = input$heading,
      quote = input$quote,
      stringsAsFactors = stringsAsFactors
    )
  })

  # We can run observers in here if we want to
  observe({
    msg <- sprintf("File %s was uploaded", userFile()$name)
    cat(msg, "\n")
  })

  # Return the reactive that yields the data frame
  return(dataframe)
}
basicPlotUI <- function(id) {
  ns <- NS(id)
  uiOutput(ns("controls"))

}
# Functionality for dataselection for plot
# SelectInput is rendered dynamically based on data

basicPlot <- function(input, output, session, data) {
  output$controls <- renderUI({
    ns <- session$ns
    selectInput(ns("col"), "Columns", names(data), multiple = TRUE)
  })
  return(reactive({
    validate(need(input$col, FALSE))
    data[, input$col]
  }))
}

##################################################################################
# Here starts main program. Lines above can be sourced: source("path-to-module.R")
##################################################################################

library(shiny)


ui <- shinyUI(navbarPage(
  "My Application",
  tabPanel("File upload", dataTabUI(
    "tab1",
    csvFileInput("datafile", "User data (.csv format)"),
    "table"
  )),
  tabPanel("Plot", plotTabUI(
    "tab2", basicPlotUI("plot1"), "plotOutput"
  ))

))


server <- function(input, output, session) {
  datafile <- callModule(csvFile, "datafile",
                         stringsAsFactors = FALSE)

  output$table <- renderDataTable({
    datafile()
  })

  plotData <- callModule(basicPlot, "plot1", datafile())

  output$plotOutput <- renderPlot({
    plot(plotData())
  })
}


shinyApp(ui, server)
#选项卡模块
#此模块创建用于呈现数据表的新选项卡

dataTabUI现在还有一个包,它提供了组织闪亮代码的框架。它主要使用模块,但也提供了如何组织帮助函数和css/javascript文件的结构。还有一篇。

关于你的组织方法的博客文章会很好。此外,它将允许更多关于闪亮应用程序架构的对话。如果有更多的人谈论/思考,每个人都会受益it@MySchizoBuddy我看看我能做什么。不过,可能不会很快。今年教了两门新课。你有时间写关于闪亮应用程序组织的文章吗?不幸的是,没有。我建议你看看。另一个选择是创建一个闪亮的应用程序作为一组R包。这就是我现在使用的方法。感谢这个建议@Pork Chop-Matt有什么好的理由把io和reactives放在appSourceFiles子目录中而不是放在externals目录中吗?@micstr,我猜他采用了他过去做过的大型项目的结构。我建议查看VisualStudio项目设置以开发和构建应用程序(仅针对insight)。你也可以在你的书信中采用模型结构,并在他阅读时按文件夹进行分解does@jangorecki因为它被问问题的用户接受了,我认为它起到了作用,或者你可以发布一些东西,所以不要生气。你的帖子不是答案,而是对答案的引用,当回购协议被删除时,你的帖子将一文不值。你应该发表评论。确实,尽管4年过去了,github帐户仍然存在,但您确实不应该否决遗留问题,但示例中的前几个函数(尤其是
dataTabUI
&
plotTabUI
)只是普通函数,并不真正演示任何模块功能。在这两种情况下,对
ns@JoshO'Brien的调用至少是dataTabUI等。遵循闪亮应用程序的形式,并准备在将来需要时使用动态组件。
# Tab module
# This module creates new tab which renders dataTable

dataTabUI <- function(id, input, output) {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(sidebarLayout(sidebarPanel(input),

                        mainPanel(dataTableOutput(output))))

}

# Tab module
# This module creates new tab which renders plot
plotTabUI <- function(id, input, output) {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(sidebarLayout(sidebarPanel(input),

                        mainPanel(plotOutput(output))))

}

dataTab <- function(input, output, session) {
  # do nothing...
  # Should there be some logic?


}

# File input module
# This module takes as input csv file and outputs dataframe
# Module UI function
csvFileInput <- function(id, label = "CSV file") {
  # Create a namespace function using the provided id
  ns <- NS(id)

  tagList(
    fileInput(ns("file"), label),
    checkboxInput(ns("heading"), "Has heading"),
    selectInput(
      ns("quote"),
      "Quote",
      c(
        "None" = "",
        "Double quote" = "\"",
        "Single quote" = "'"
      )
    )
  )
}

# Module server function
csvFile <- function(input, output, session, stringsAsFactors) {
  # The selected file, if any
  userFile <- reactive({
    # If no file is selected, don't do anything
    validate(need(input$file, message = FALSE))
    input$file
  })

  # The user's data, parsed into a data frame
  dataframe <- reactive({
    read.csv(
      userFile()$datapath,
      header = input$heading,
      quote = input$quote,
      stringsAsFactors = stringsAsFactors
    )
  })

  # We can run observers in here if we want to
  observe({
    msg <- sprintf("File %s was uploaded", userFile()$name)
    cat(msg, "\n")
  })

  # Return the reactive that yields the data frame
  return(dataframe)
}
basicPlotUI <- function(id) {
  ns <- NS(id)
  uiOutput(ns("controls"))

}
# Functionality for dataselection for plot
# SelectInput is rendered dynamically based on data

basicPlot <- function(input, output, session, data) {
  output$controls <- renderUI({
    ns <- session$ns
    selectInput(ns("col"), "Columns", names(data), multiple = TRUE)
  })
  return(reactive({
    validate(need(input$col, FALSE))
    data[, input$col]
  }))
}

##################################################################################
# Here starts main program. Lines above can be sourced: source("path-to-module.R")
##################################################################################

library(shiny)


ui <- shinyUI(navbarPage(
  "My Application",
  tabPanel("File upload", dataTabUI(
    "tab1",
    csvFileInput("datafile", "User data (.csv format)"),
    "table"
  )),
  tabPanel("Plot", plotTabUI(
    "tab2", basicPlotUI("plot1"), "plotOutput"
  ))

))


server <- function(input, output, session) {
  datafile <- callModule(csvFile, "datafile",
                         stringsAsFactors = FALSE)

  output$table <- renderDataTable({
    datafile()
  })

  plotData <- callModule(basicPlot, "plot1", datafile())

  output$plotOutput <- renderPlot({
    plot(plotData())
  })
}


shinyApp(ui, server)