我正在尝试对Shiny代码进行模块化,以便将CSV文件作为输入上传到scatterD3图中。其他UI控件将来自renderUI来更改x变量和y变量。这只是Mikael Jumppanen的一小部分修改,该答案来自 如何组织大型R Shiny应用程序?,但我一直在努力,无法让这最后一点起作用。
对于此数据集,我使用的是mtcars数据集https://gallery.shinyapps.io/066-upload-file/_w_469e9927/mtcars.csv
## load libraries
library(shiny)
library(stringr)
library(scatterD3)
#source("/Users/echang/scratch/tmp/MSD_D3scatter/csvFile_Module.R")
csvFileInput <- function(id, label="CSV file") {
## Create namespace
ns<-NS(id)
tagList(
uiOutput(ns("controls"))
)
}
csvFileControl <- function(id){
ns <- NS(id)
tagList(
column(width=3, uiOutput(ns("ColName"))),
column(width=3, uiOutput(ns("ColEntry")))
)
}
csvFileUI <- function(id){
ns <- NS(id)
tagList(
uiOutput(ns("csvTable"))
)
}
## server module
csvFile <- function(input, output, session, stringsAsFactors) {
ns <- session$ns
## to reuse namespace, session must be first!!!
## User selected file
userFile <- reactive({
# If no file is selected, don't do anything
validate(need(input$file, message = FALSE))
input$file
})
dataframe <- reactive({
read.csv(
userFile()$datapath,
header = input$header,
sep=input$sep,
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")
})
output$controls <- renderUI({
## use taglist to keep everything together
tagList(
fileInput(ns('file'), 'Choose CSV file',
accept=c('txt/csv','text/comma-separated-values,text/plain','.csv')),
checkboxInput(ns('header'), 'Has heading', TRUE),
radioButtons(ns('sep'),'Separator', c(Comma=',',Semicolon=';',Tab='\t'), ','),
selectInput(ns('quote'),'Quote', c(None ='','Double Quote'='"','Single Quote'="'"),'"')
)
})
## use renderUI to display table
output$csvTable <- renderUI({
output$table <- renderDataTable(dataframe())
dataTableOutput(ns("table"))
})
## Column Name
output$ColName <- renderUI({
df <- dataframe()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
tagList(
selectInput(ns("xvar"), "Column Names", items),
selectInput(ns("yvar"), "Column Names", items)
)
})
## Column Entry
output$ColEntry <- renderUI({
df <- dataframe()
if (is.null(input$col)) return(NULL)
tagList(
selectInput(ns("entry"), "Entry Names", df[,input$xvar])
)
})
# Return the reactive that yields the data frame
return(dataframe)
}## End of module
## scatterD3 module -------------------------------------------------------------
D3scatterUI <- function(id){
ns<-NS(id)
tagList(
scatterD3Output(ns("scatterplot1"))
)
}
D3scatter <- function(input,output,session,data,xvar,yvar){
ns <- session$ns
output$scatterplot1 <- renderScatterD3({
#scatterD3(data = data, x=mpg, y=carb,
scatterD3(data = data, x=xvar, y=yvar,
labels_size= 9, point_opacity = 1,
#col_var=cyl, symbol_var= data$Assay,
#lab= paste(mpg, carb, sep="|") , lasso=TRUE,
#xlab= "IFN-?", ylab= "IL-10",
#click_callback = "function(id, index) {
# alert('scatterplot ID: ' + id + ' - Point index: ' + index)
# }",
transitions= T)
})
}
## Shiny ######################################################################
ui <- fluidPage(
titlePanel("Upload"),
tabsetPanel(type="tabs",
tabPanel("tab1",
sidebarLayout(
sidebarPanel(csvFileInput("basic")),
mainPanel(csvFileUI("basic"))
)
),
tabPanel("tab2",
tagList(
fluidRow(csvFileControl("basic")),
fluidRow(D3scatterUI("first"))
)
)
)
)
server <- function(input, output, session) {
## Option 1. CSV uploaded file
datafile <- callModule(csvFile, "basic", stringsAsFactors = FALSE)
## Option 2. mtcar data loaded at start
#datafile <- reactive({mtcars}) ## data loaded at runApp()
#callModule(csvFile, "basic")
xvar <- reactive(input$xvar)
yvar <- reactive(input$yvar)
callModule(D3scatter, "first", datafile(), xvar, yvar)
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
我还从https://itsalocke.com/shiny-module-design-patterns-pass-module-input-to-other-modules/咨询了Shiny模块设计。
我观看了网络研讨会,但无法掌握正确的逻辑。https://www.rstudio.com/resources/webinars/understanding-shiny-modules/任何帮助将不胜感激!
好的,这确实有点困难,因为使用模块并不十分简单。您接近了……您的主要问题不是将所有反应堆包装在列表中,而是将它们传递到需要的地方。
我进行了以下更改:
csvFile:声明了额外的反应性功能,xvar并且yvar在csvFile服务器模块中的功能与您已经完成的类似dataframe。csvFile:将所有需要的反应堆打包为一个列表,并将其作为返回值返回,如您帖子中设计模式链接中所述。(谢谢斯蒂芬·洛克)。server:callModule(D3scatter,... )再次将该链接中的列表向下传递,如该链接所述。D3scatter:通过调用scatterD3使用从指定数据帧提取的向量来进行重构。这是因为我无法使其与作为列说明符的字符串一起使用(但是肯定有某种方式)。这是上面更改的代码部分:
csvFile <- function(input, output, session, stringsAsFactors) {
ns <- session$ns
## to reuse namespace, session must be first!!!
## User selected file
userFile <- reactive({
# If no file is selected, don't do anything
validate(need(input$file, message = FALSE))
input$file
})
dataframe <- reactive({
read.csv(
userFile()$datapath,
header = input$header,
sep=input$sep,
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")
})
xvar <- reactive({input[[ "xvar" ]] })
yvar <- reactive({input[[ "yvar" ]] })
output$controls <- renderUI({
## use taglist to keep everything together
tagList(
fileInput(ns('file'), 'Choose CSV file',
accept=c('txt/csv','text/comma-separated-values,text/plain','.csv')),
checkboxInput(ns('header'), 'Has heading', TRUE),
radioButtons(ns('sep'),'Separator', c(Comma=',',Semicolon=';',Tab='\t'), ','),
selectInput(ns('quote'),'Quote', c(None ='','Double Quote'='"','Single Quote'="'"),'"')
)
})
## use renderUI to display table
output$csvTable <- renderUI({
output$table <- renderDataTable(dataframe())
dataTableOutput(ns("table"))
})
## Column Name
output$ColName <- renderUI({
df <- dataframe()
if (is.null(df)) return(NULL)
items=names(df)
print(items)
names(items)=items
tagList(
selectInput(ns("xvar"), "Column Names", items),
selectInput(ns("yvar"), "Column Names", items)
)
})
## Column Entry
output$ColEntry <- renderUI({
df <- dataframe()
if (is.null(input$col)) return(NULL)
tagList(
selectInput(ns("entry"), "Entry Names", df[,input$xvar])
)
})
rlist <- list(dataframe=dataframe,xvar=xvar,yvar=yvar)
# Return the reactive that yields the data frame
return(rlist)
}## End of module
Run Code Online (Sandbox Code Playgroud)
server <- function(input, output, session) {
## Option 1. CSV uploaded file
rlist <- callModule(csvFile, "basic", stringsAsFactors = FALSE)
## Option 2. mtcar data loaded at start
#datafile <- reactive({mtcars}) ## data loaded at runApp()
#callModule(csvFile, "basic")
callModule(D3scatter, "first", rlist)
}
Run Code Online (Sandbox Code Playgroud)
D3scatter <- function(input,output,session,rlist){
ns <- session$ns
output$scatterplot1 <- renderScatterD3({
#scatterD3(data = data, x=mpg, y=carb,
mtdf <- rlist$dataframe()
x <- mtdf[[rlist$xvar()]]
y <- mtdf[[rlist$yvar()]]
scatterD3(x=x,y=y,
labels_size= 9, point_opacity = 1,
#col_var=cyl, symbol_var= data$Assay,
#lab= paste(mpg, carb, sep="|") , lasso=TRUE,
#xlab= "IFN-?", ylab= "IL-10",
#click_callback = "function(id, index) {
# alert('scatterplot ID: ' + id + ' - Point index: ' + index)
# }",
transitions= T)
})
}
Run Code Online (Sandbox Code Playgroud)
然后工作了:
这是所有正在运行的代码,以防万一我忘记了某个地方的更改,或者有人只想运行它。顺便说一句,散点图从一个图变到另一个图是很酷的……它以类似动画的效果连续变形。异常。
## load libraries
library(shiny)
library(stringr)
library(scatterD3)
#source("/Users/echang/scratch/tmp/MSD_D3scatter/csvFile_Module.R")
csvFileInput <- function(id, label="CSV file") {
## Create namespace
ns<-NS(id)
tagList(
uiOutput(ns("controls"))
)
}
csvFileControl <- function(id){
ns <- NS(id)
tagList(
column(width=3, uiOutput(ns("ColName"))),
column(width=3, uiOutput(ns("ColEntry")))
)
}
csvFileUI <- function(id){
ns <- NS(id)
tagList(
uiOutput(ns("csvTable"))
)
}
## server module
csvFile <- function(input, output, session, stringsAsFactors) {
ns <- session$ns
## to reuse namespace, session must be first!!!
## User selected file
userFile <- reactive({
# If no file is selected, don't do anything
validate(need(input$file, message = FALSE))
input$file
})
dataframe <- reactive({
read.csv(
userFile()$datapath,
header = input$header,
sep=input$sep,
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")
})
xvar <- reactive({input[[ "xvar" ]] })
yvar <- reactive({input[[ "yvar" ]] })
output$controls <- renderUI({
## use taglist to keep everything together
tagList(
fileInput(ns('file'), 'Choose CSV file',
accept=c('txt/csv','text/comma-separated-values,text/plain','.csv')),
checkboxInput(ns('header'), 'Has heading', TRUE),
radioButtons(ns('sep'),'Separator', c(Comma=',',Semicolon=';',Tab='\t'), ','),
selectInput(ns('quote'),'Quote', c(None ='','Double Quote'='"','Single Quote'="'"),'"')
)
})
## use renderUI to display table
output$csvTable <- renderUI({
output$table <- renderDataTable(dataframe())
dataTableOutput(ns("table"))
})
## Column Name
output$ColName <- renderUI({
df <- dataframe()
if (is.null(df)) return(NULL)
items=names(df)
print(items)
names(items)=items
tagList(
selectInput(ns("xvar"), "Column Names", items),
selectInput(ns("yvar"), "Column Names", items)
)
})
## Column Entry
output$ColEntry <- renderUI({
df <- dataframe()
if (is.null(input$col)) return(NULL)
tagList(
selectInput(ns("entry"), "Entry Names", df[,input$xvar])
)
})
rlist <- list(dataframe=dataframe,xvar=xvar,yvar=yvar)
# Return the reactive that yields the data frame
return(rlist)
}## End of module
## scatterD3 module -------------------------------------------------------------
D3scatterUI <- function(id){
ns<-NS(id)
tagList(
scatterD3Output(ns("scatterplot1"))
)
}
D3scatter <- function(input,output,session,rlist){
ns <- session$ns
output$scatterplot1 <- renderScatterD3({
#scatterD3(data = data, x=mpg, y=carb,
mtdf <- rlist$dataframe()
x <- mtdf[[rlist$xvar()]]
y <- mtdf[[rlist$yvar()]]
scatterD3(x=x,y=y,
labels_size= 9, point_opacity = 1,
#col_var=cyl, symbol_var= data$Assay,
#lab= paste(mpg, carb, sep="|") , lasso=TRUE,
#xlab= "IFN-?", ylab= "IL-10",
#click_callback = "function(id, index) {
# alert('scatterplot ID: ' + id + ' - Point index: ' + index)
# }",
transitions= T)
})
}
## Shiny ######################################################################
ui <- fluidPage(
titlePanel("Upload"),
tabsetPanel(type="tabs",
tabPanel("tab1",
sidebarLayout(
sidebarPanel(csvFileInput("basic")),
mainPanel(csvFileUI("basic"))
)
),
tabPanel("tab2",
tagList(
fluidRow(csvFileControl("basic")),
fluidRow(D3scatterUI("first"))
)
)
)
)
server <- function(input, output, session) {
## Option 1. CSV uploaded file
rlist <- callModule(csvFile, "basic", stringsAsFactors = FALSE)
## Option 2. mtcar data loaded at start
#datafile <- reactive({mtcars}) ## data loaded at runApp()
#callModule(csvFile, "basic")
callModule(D3scatter, "first", rlist)
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)