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冲突更容易避免
- 基于模块输入和输出的代码组织
# 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)