分解闪亮代码的最佳实践

时间:2014-08-01 16:03:53

标签: r shiny shiny-server

我正在开发一个相当复杂的ShinyApp来处理数据,并且想知道什么是分解代码的好策略。理想情况下,为每个选项卡等单独的脚本,然后在ui.R和server.R中将它们粘合在一起。任何做过类似事情并且可以分享经验和/或代码的人都会有很大的帮助。

例如,我应该如何分解不同tabPanel的代码

shinyUI( navbarPage("Synodos Data Explorer", id="nav",

  tabPanel("Public Data",
           titlePanel("Explore Public Datasets"),
           source("code1.R")
  ),

  tabPanel("Kinome Screens",
           titlePanel("Exploring Kinome Screening Data"),
           source("code2.R")

  )

) #END navbar
) #END ShinyUI

1 个答案:

答案 0 :(得分:5)

您可以使用专为此设计的Ramd package。首先devtools::install_github('robertzk/Ramd')。现在您可以包含任意脚本(在node.js项目中以相同的“异步模块依赖关系”格式):

ui.r

library(Ramd)
define('public_data', function(public_data) {
  shinyUI( navbarPage("Synodos Data Explorer", id="nav",
    public_data, kinome_screens
  ))
}) 

public_data.r

tabPanel("Public Data",
  titlePanel("Explore Public Datasets"),
  source("code1.R")
)

kinome_screens.r

tabPanel("Kinome Screens",
  titlePanel("Exploring Kinome Screening Data"),
  source("code2.R")
)

解释

define函数允许您包含相对于当前正在执行的文件所在目录的R脚本。例如,如果您希望将代码结构化为目录格式,则可以执行以下操作:

define('dir/some_file', 'dir2/some_other_file', function(one, two) {
   # You can use one and two, the "return value" (last expression) in the
   # above files
})

请注意,正确使用此功能可以完全消除全局变量的使用,并且可以解决管理全局状态和代码组织问题。这背后的主要诀窍是,当您获取文件时,如下所示:

# test.r
c(1,2,3) # This will be ignored, since it isn't at the end of the file
list(1, "hello!")

# otherfile.r
x <- source('test.r')$value

然后x现在是list(1, "hello!")(特别是,调用base::source这样的“返回值”总是会给出文件中的最后一个表达式。你想要的一切传递到包含此文件的其他文件应该在最后包装,如果你想返回多个东西,可能在列表中。你可以使用它来将复杂的Shiny项目分层嵌套在一个理智的组织结构中。

这是一个完整的工作示例,演示了如何使用Ramd构建目录中的某些代码:

### main.r
define('blah/foo', 'blah2/faa', function(one, two) {
  print(one + two)
})

### blah/foo.r
x <- 1
y <- 2
x + y

### blah2/faa.r
z <- 1
w <- 5
w - z

### R console
library(Ramd); source('main.r')
# [1] 7