我创建了一个闪亮的应用程序,用于将图像分类为几个选项之一。我们的想法是收集每个图像中出现的数据(如果有的话)。
我的应用程序运行良好,但为了让它按照我想要的方式运行,我在一些地方使用了<<-
调用来改变全局环境中的值,这样我可以稍后在脚本中再次调用它们。我已尝试使用<-
,但输出错误,图像(每次按下按钮时应更新为新图像)保持不变,这意味着image.source
变量不是正确更新。全局变量方法的问题在于,所有用户都会更改这些变量,这意味着如果多个用户同时工作,他们会互相干扰关键变量(纠正我)如果我错了)。
我已经在下面的应用中包含了(一个剥离后的版本),但这里是关键部分,我已经使用了<<-
:
# when a button is pressed:
observeEvent( input$Shearwater, {
# print some data to the output file
cat( paste0( image.source, ",Shearwater\n" ), file = output.file, append = T )
# remove the image we just looked at from the file list
file.list <<- file.list[ file.list != image.source ]
# get the next image to work on
image.source <<- file.list[1]
# and render that next image
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
以下是我现在的应用程序的剥离版本,以显示我正在做的事情(请告诉我,如果有更多方法可以最大限度地减少此示例;这在我看来就像就像我可以在不丢失要点的情况下削减它一样):
library( shiny )
# define the inputs and outputs
file.list <- list.files( path = "www", pattern = ".jpg", ignore.case = T )
output.file <- "classifications.txt"
# check for images already classified, and remove them (to avoid duplicating analysis)
if( file.exists( output.file ) && length( readLines( output.file ) ) > 0 ) {
already.classified <- try( read.csv( output.file,
header = F,
stringsAsFactors = F ),
silent = TRUE )
if( class( already.classified ) != "try-error" ) {
already.classified <- unique( already.classified[,1] )
file.list <- file.list[ !file.list %in% already.classified ]
}
}
# get the first image to display
image.source <- file.list[1]
ui <- shinyUI( fluidPage(
titlePanel( "Image classification" ),
# define multiple submit buttons, one for each classification type
sidebarLayout(
sidebarPanel(
actionButton( inputId = "Shearwater", label = "Shearwater" ),
br(),br(),
actionButton( inputId = "Penguin", label = "Penguin" ),
br(),br(),
actionButton( inputId = "Other.bird", label = "Other.bird" )
),
# Display the image
mainPanel( uiOutput( 'image' ) )
)
) )
server <- shinyServer( function( input, output, session ) {
# display the first image to the user
output$image <- renderUI(
img( src = image.source, width = 600 )
)
# when a button is pressed:
observeEvent( input$Shearwater, {
# print some data to the output file
cat( paste0( image.source, ",Shearwater\n" ), file = output.file, append = T )
# remove the image we just looked at from the file list
file.list <<- file.list[ file.list != image.source ]
# get the next image to work on
image.source <<- file.list[1]
# and render that next image
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
# repeat the above for each button type
observeEvent( input$Penguin, {
cat( paste0( image.source, ",Penguin\n" ), file = output.file, append = T )
file.list <<- file.list[ file.list != image.source ]
image.source <<- file.list[1]
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
observeEvent( input$Other.bird, {
cat( paste0( image.source, ",Other.bird\n" ), file = output.file, append = T )
file.list <<- file.list[ file.list != image.source ]
image.source <<- file.list[1]
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
})
shinyApp(ui = ui, server = server)
app.R
文件一起包含几个jpgs,它应该为你运行。我的问题是,我如何才能更改image.source
和file.list
个对象,并在用户按下下一个按钮时引用它们,而不必回复更改全局变量环境,这样每个用户都维护自己的变量?
谢谢!
答案 0 :(得分:1)
(我在这里回复,因为评论中没有限制)
即使在你上一次评论之后,我对你的计划有点困惑:
为了说明的目的,我将用代码澄清(只有server
部分 - 如果这符合您的需求,您可以轻松地找出如何更改其余部分)其中一个替代方案。
我认为用户需要对所有图像进行分类(仅一次)。
server <- shinyServer( function( input, output, session ) {
#-------------------------------------------------------------
# The following chunk of code will be executed first at the start of each shiny session,
# i.e. for each user (but to be clear, it will be executed as well if the user will refresh
# the browser, which triggers a new session)
# define the inputs and outputs
file.list <- list.files( path = "www", pattern = ".jpg", ignore.case = T )
output.file <- "classifications.txt"
# check for images already classified, and remove them (to avoid duplicating analysis)
if( file.exists( output.file ) && length( readLines( output.file ) ) > 0 ) {
already.classified <- try( read.csv( output.file,
header = F,
stringsAsFactors = F ),
silent = TRUE )
if( class( already.classified ) != "try-error" ) {
already.classified <- unique( already.classified[,1] )
file.list <- file.list[ !file.list %in% already.classified ]
}
}
# get the first image to display
image.source <- file.list[1]
# display the first image to the user
#
# end of the chunk of code
#-------------------------------------------------------------
output$image <- renderUI(
img( src = image.source, width = 600 )
)
# when a button is pressed:
observeEvent( input$Shearwater, {
# print some data to the output file
cat( paste0( image.source, ",Shearwater\n" ), file = output.file, append = T )
# remove the image we just looked at from the file list
file.list <<- file.list[ file.list != image.source ]
# get the next image to work on
image.source <<- file.list[1]
# and render that next image
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
# repeat the above for each button type
observeEvent( input$Penguin, {
cat( paste0( image.source, ",Penguin\n" ), file = output.file, append = T )
file.list <<- file.list[ file.list != image.source ]
image.source <<- file.list[1]
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
observeEvent( input$Other.bird, {
cat( paste0( image.source, ",Other.bird\n" ), file = output.file, append = T )
file.list <<- file.list[ file.list != image.source ]
image.source <<- file.list[1]
output$image <- renderUI(
img( src = image.source, width = 600 )
)
})
})
根据R作用域规则,闪亮函数调用中的每个file.list <<-
赋值都将更新全局file.list
值。
同时,由于file.list
值未在服务器功能之外定义,因此每个会话(通常对应于用户会话,除非用户确实刷新浏览器实际上重新启动会话)将重新初始化它
您可以使用此概念来决定在server
函数调用范围内放置什么以及在外部管理什么(即真正全局)。
当不需要reactiveValues时,我觉得这个解决方案更可取(这是非常有用的,但只有当你以某种方式利用他们的reactivity
时才会这样做。)
如果您的要求不同,请澄清/修改您的问题,我将修改我的答案:)
答案 1 :(得分:-1)
执行您想要做的事情的方法是将image.source
(可能更多)指定为被动,然后将其包装在isolate语句中。所以像这样:
image.source <- reactive({
isolate({output <- file.list[input$Shearwater] })
})
output$image <- renderUI(
img( src = image.source(), width = 600 )
抱歉,我还没有这样做。但是这个想法是每次按下Shearwater按钮,input$Shearwater
增加1.您可以使用它来索引图像矢量。
“反应”允许您在不将其作为全局变量的情况下引用它。
隔离意味着它不会重新计算,除非input$Shearwater
发生变化(我认为)