2014-11-22 52 views
45

組織更大的Shiny應用程序的最佳實踐是什麼?
我認爲最好的R實踐也適用於Shiny。
最佳R實踐這裏討論:How to organize large R programs
鏈接到谷歌的[R風格指南:Style Guide如何組織大型閃亮應用程序?

但什麼是我可以採取使我的閃亮代碼閃亮背景下獨特的技巧和竅門更好看(更可讀)? 我想到的東西,如:

  • 在閃亮
  • server.R開拓面向對象的編程這部分應採購?
  • 含降價文檔,圖片, XML文件和源文件

例如項目的文件層次如果我使用的每一個tabPanel我的代碼navbarPagetabsetPanel開始另外幾個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) 

組織ui.R代碼,我發現相當不錯的解決方案從GitHub:radiant code
解決方案是使用renderUI渲染每一個tabPanelserver.R選項卡外包給不同的文件。

server <- function(input, output) { 

    # This part can be in different source file for example component1.R 
    ################################### 
    output$component1 <- renderUI({ 
     sidebarLayout(
       sidebarPanel(
       ), 
       mainPanel(
        tabsetPanel(
         tabPanel("Plot", plotOutput("plot")), 
         tabPanel("Summary", verbatimTextOutput("summary")), 
         tabPanel("Table", tableOutput("table")) 
        ) 
       ) 
    ) 
    }) 
##################################### 

} 
ui <- shinyUI(navbarPage("My Application", 
    tabPanel("Component 1", uiOutput("component1")), 
    tabPanel("Component 2"), 
    tabPanel("Component 3") 
)) 

shinyApp(ui = ui, server = server) 

回答

21

我真的很喜歡馬特Leonawicz如何組織自己的應用程序。我採取了他的方法學習如何使用Shiny,因爲我們都知道如果管理不當,它會變得非常分散。看看他的結構,他給出了他的方式來組織應用程序的應用程序稱爲run_alfresco

https://github.com/ua-snap/shiny-apps

+0

感謝您的建議@Pork Chop - 是否有一個很好的理由,爲什麼馬特將io和反應物放在* appSourceFiles *子目錄中,而不是將它留在外部目錄中? – micstr 2016-06-30 10:05:23

+0

@micstr,我想他會採用他過去做的大型項目的結構。我會建議看一下開發和構造應用程序的Visual Studio項目設置(僅用於洞察)。你也可以在你的Rshiny中採用[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)模型結構並按文件夾分解它 – 2016-06-30 11:20:22

6

我寫了Radiant。我還沒有聽到有人說過代碼組織的壞處,但我相信它可能會更好。一種選擇是將Joe的用法和邏輯分開,就像Joe Cheng在閃亮的部分中所做的那樣。

https://github.com/jcheng5/shiny-partials

另外也可以嘗試面向對象編程,例如,使用R6 http://rpubs.com/wch/17459

+1

有關您的組織方法的博客文章很好。此外,它將允許有關閃亮的應用程序架構的更多對話如果有更多的人在談論/思考,每個人都會受益 – MySchizoBuddy 2015-07-30 00:47:14

+0

@MySchizoBuddy我會看看我能做些什麼。但可能不會很快。今年教授兩門新課程。 – Vincent 2015-07-30 04:31:42

+0

你有沒有得到任何時間寫有關閃亮的應用程序組織 – MySchizoBuddy 2016-11-16 13:38:56

17

添加模塊至R閃亮後的概述。在有光澤的應用程序中管理複雜結構已變得容易很多。

光澤模塊的詳細描述:使用模塊的Here

優點:

  • 一旦被創建,它們很容易被再利用
  • ID衝突更容易避免
  • 代碼組織基於在模塊的輸入和輸出上

在基於標籤的閃亮應用中,一個選項卡可以被視爲一個模塊,它具有輸入輸出。標籤的輸出可以作爲輸入傳遞給其他標籤。

基於標籤結構的單文件應用程序,它利用模塊化思維。應用程序可以使用cars數據集進行測試。從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) 
相關問題