web-dev-qa-db-ja.com

大きな光沢のあるアプリを整理する方法は?

大規模なShinyアプリケーションを整理するためのベストプラクティスは何ですか?
RのベストプラクティスはShinyにも適用できると思います。
Rのベストプラクティスは次のとおりです。 大規模なRプログラムの編成方法
GoogleのRスタイルガイドへのリンク: スタイルガイド

しかし、Shinyのコードをより良く(そしてより読みやすく)するために採用できるShinyコンテキストのユニークなヒントとコツは何ですか?私は次のようなことを考えています:

  • Shinyでのオブジェクト指向プログラミングの活用
  • server.Rどの部品を調達する必要がありますか?
  • マークダウンドキュメント、写真、xml、およびソースファイルを含むプロジェクトのファイル階層

たとえば、すべてのnavbarPagetabsetPaneltabPanelを使用している場合、いくつかの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から非常に素晴らしいソリューションを見つけました: 放射コード
解決策は、renderUIを使用してすべてのtabPanelおよびserver.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)
57

modulesをR shinyに追加した後。光沢のあるアプリケーションでの複雑な構造の管理が非常に簡単になりました。

光沢のあるモジュールの詳細な説明: ここ

モジュールを使用する利点:

  • 作成したら、簡単に再利用できます
  • IDの衝突は簡単に回避できます
  • モジュールの入力と出力に基づくコード編成

タブベースの光沢のあるアプリでは、1つのタブはinputsおよびoutputs。その後、タブの出力を入力として他のタブに渡すことができます。

モジュラー思考を活用するタブベースの構造のための単一ファイルアプリ。アプリは 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)
23

Matt Leonawiczがアプリを整理する方法がとても気に入っています。私たちは皆、適切に管理されていないと散らばる可能性があることを知っているので、私は彼のアプローチを採用しました。彼の構造を見て、彼はrun_alfrescoというアプリでアプリを整理する方法の概要を説明します。

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

23
Pork Chop

Radiantを書きました。私は人々がコード組織について悪いことを言っているのを聞いたことはありませんが(まだ)、それがより良いものになると確信しています。 1つのオプションは、Joe Chengが光沢のある部分で行うように、UIとロジックを分離することです。

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

別の方法として、OOプログラミング、たとえば、R6を使用してください http://rpubs.com/wch/17459

8
Vincent