gpt4 book ai didi

r - 如何将 RShiny reactiveFileReader 与 reactiveUI 和不存在的文件一起使用?

转载 作者:行者123 更新时间:2023-12-04 09:34:09 28 4
gpt4 key购买 nike

我将如何构建响应式 UI 来响应具有不同数据输入的 reactiveFileReader?

我有兴趣将一个 reactiveFileReader 集成到一个应用程序中,该应用程序在数据中绘制组图并逐组显示选定的点。

挑战:

  1. 并非所有我可以根据前缀和后缀识别的文件都存在。
  2. 每个文件有不同数量的组。

崩溃/失败时我

    <罢工>
  1. 试图打开一个不存在的文件。
  2. 更新文件(因此它确实检测到有更改)

可能的解决方案:

  1. 读取数据后减慢/延迟下一步,以便重新加载数据。 通过 reactive()req()
  2. 修复
  3. isolate() 依赖 UI,因此它只会在第一次加载文件时更改组数。

我包括模拟数据(及其生成)、UI、损坏的服务器和没有反应式文件读取器的工作服务器。

更新

唯一剩下的就是让 renderUI“组”在重新读取文件时不重置。通常这是一件好事,但在这里我不想要那样。

library(tidyr); library(dplyr); library(ggplot2); library(readr); library(stringr)
library(shiny)
#library(DT)

模拟数据

a1 <- structure(list(Group = c("alpha_1", "alpha_1", "alpha_2", "alpha_2", "alpha_3", "alpha_3"), Sample = c("ps_1", "ps_2", "ps_1", "ps_2", "ps_1", "ps_2"), x = c(1, 1.1, 4, 4.1, 6.8, 7), y = c(2.1, 2, 7.3, 7, 10, 9.7)), .Names = c("Group", "Sample", "x", "y"), row.names = c(NA,-6L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = structure(list(Group = structure(list(), class = c("collector_character", "collector")),Sample = structure(list(), class = c("collector_character","collector")), x = structure(list(), class = c("collector_double", "collector")), y = structure(list(), class = c("collector_double", "collector"))), .Names = c("Group", "Sample", "x", "y")), default = structure(list(), class = c("collector_guess", "collector"))), .Names = c("cols", "default"), class = "col_spec"))
a2 <- structure(list(Group = c("alpha_6", "alpha_6", "alpha_7", "alpha_7", "alpha_9", "alpha_9", "alpha_10", "alpha_10"), Sample = c("ps_1", "ps_2", "ps_1", "ps_2", "ps_1", "ps_2", "ps_1", "ps_2"), x = c(3,3.2, 5, 5.1, 1, 1.1, 5, 5.1), y = c(8.1, 7, 3, 4, 14, 15, 4,3)), .Names = c("Group", "Sample", "x", "y"), row.names = c(NA, -8L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = structure(list(Group = structure(list(), class = c("collector_character", "collector")), Sample = structure(list(), class = c("collector_character","collector")), x = structure(list(), class = c("collector_double", "collector")), y = structure(list(), class = c("collector_double", "collector"))), .Names = c("Group", "Sample", "x", "y")), default = structure(list(), class = c("collector_guess", "collector"))), .Names = c("cols", "default"), class = "col_spec"))
b2 <- structure(list(Group = c("beta_3", "beta_3", "beta_4", "beta_4", "beta_6", "beta_6"), Sample = c("ps_1", "ps_2", "ps_1", "ps_2", "ps_1", "ps_2"), x = c(3, 3.2, 5, 5.1, 1, 1.1), y = c(8.1, 7, 3, 4, 14, 15)),.Names = c("Group", "Sample", "x", "y"), row.names = c(NA, -8L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = structure(list(Group = structure(list(), class = c("collector_character", "collector")), Sample = structure(list(), class = c("collector_character","collector")), x = structure(list(), class = c("collector_double", "collector")), y = structure(list(), class = c("collector_double", "collector"))), .Names = c("Group", "Sample", "x", "y")), default = structure(list(), class = c("collector_guess", "collector"))), .Names = c("cols", "default"), class = "col_spec"))
b3 <- structure(list(Group = c("beta_3", "beta_3", "beta_4", "beta_4", "beta_6", "beta_6"), Sample = c("ps_1", "ps_2", "ps_1", "ps_2", "ps_1", "ps_2"), x = c(3, 3.2, 5, 5.1, 1, 1.1), y = c(8.1, 7, 3, 4, 14, 15)), .Names = c("Group", "Sample", "x", "y"), row.names = c(NA, -8L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = structure(list(Group = structure(list(), class = c("collector_character", "collector")), Sample = structure(list(), class = c("collector_character","collector")), x = structure(list(), class = c("collector_double", "collector")), y = structure(list(), class = c("collector_double", "collector"))), .Names = c("Group", "Sample", "x", "y")), default = structure(list(), class = c("collector_guess", "collector"))), .Names = c("cols", "default"), class = "col_spec"))

# Data export to simulate the problem
lz_write <- function(input) {
write_csv(input, paste0(substitute(input), ".csv"))
}
lz_write(a1); lz_write(a2); lz_write(b2); lz_write(b3) # Messed up function for lapply...
# rm(list = ls()) # Clean the environment

用户界面

ui <- fluidPage(
titlePanel("Minimal Example"),
fluidRow(
column(width = 2, class = "well",
# File selection
HTML(paste("Which file?")),
# Prefix:
selectInput(inputId = "p",
label = "Prefix:",
choices = c("a", "b", "c"),
selected = "a"),

# Suffix:
numericInput(inputId = "s",
label = "Suffix:",
min = 1,
max = 3,
value = 1,
step = 1)),
column(width = 10,
plotOutput(outputId = "scatterplot",
dblclick = "plot_dblclick", # Might not be necessary, but it's not more work to include but more work to exclude
brush = brushOpts(id = "plot_brush", resetOnNew = TRUE)))
),
fluidRow(
column(width = 3,
br(),
uiOutput(outputId = "group_n")),
column(width = 9,
fixedRow(
column(width = 3,
HTML(paste0("Arg 1"))),
column(width = 3,
HTML(paste0("Arg 2"))),
column(width = 3,
uiOutput(outputId = "num_2"))
)
)
),
fluidRow(
br(), br(), br(), #Lets add some gaps or spacing
DT::dataTableOutput(outputId = "Table")) # Summary table
) # Not sure if actually necessary for this example

损坏的服务器 现在唯一的问题是 UI 在重新读取文件时重置...

server_broken <- function(input, output, session) { # Broken version

#Larger subset: A Reactive Expression # May be used later...
args <- reactive({
list(input$p, input$s) #which file do we wish to input. This was our tag
})
# Reactive File-reader Subset
path <- reactive({
paste0(input$p, input$s, ".csv")
}) # Reactive Filename, kinda like our args...



filereader <- function(input) { # The function we pass into a reactive filereader.
suppressWarnings(read_csv(input, col_types = cols(
Group = col_character(),
Sample = col_character(),
x = col_double(),
y = col_double())
))
}

##BROKEN REACTIVE FILE READER HERE##
data_1 <- reactiveValues() # The function we use for livestream data
observe({
if(file.exists(path()) == TRUE) {
fileReaderData <- reactiveFileReader(500, session, path(), filereader)
} else {
message("This file does not exist")
## OR DO I DO SOMETHING ELSE HERE??##
}
data_1$df <- reactive({
## STOPS APP CRASHING, BUT NO LONGER REFRESHES CONSTANTLY ##
req(fileReaderData())
fileReaderData()
})
}) # Honestly don't understand still

data <- reactive(data_1$df()) # Pulling things out just so the rest of our code can stay the same.

## END OF BROKEN FILE READER##
## Reactive UI HERE##
data_m <- reactive({
req(data())
args()
tmp <- isolate(select(data(), Group))
tmp %>% distinct()
}) # number of groups

output$num_2 <- renderUI({
req(data())
numericInput(inputId = "n",
label = "Group:",
min = 1,
max = length(data_m()$Group),
value = 1
)
}) #This is our 'reactive' numeric input for groups. This caps the max of our function based on the number of groups there are per file

n <- reactive(input$n) #which marker number we are dealing with.
## End of reactive UI##
data_n <- reactive({
req(data()); req(data_m())
dt <- filter(data(), Group == data_m()[[1]][input$n])
})


# Create scatterplot object the plotOutput function is expecting ----
ranges <- reactiveValues(x = NULL, y = NULL)


output$scatterplot <- renderPlot({
validate(need(data(), "The specified file does not exist. Please try another"))
p <- as.numeric(input$p)
plot <- ggplot(data_n(), aes(x, y)) +
labs(title = paste0("Group ", data_n()$Group[1])) +
labs(x = "X vals", y = "Y vals") +
geom_point() + theme_bw() # I already have customized aesthetics. Removed for minimalism
plot + coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = TRUE) # So we see all points more readily. messes up the zoom but oh well
})

# When a double-click happens, check if there's a brush on the plot.
# If so, zoom to the brush bounds; if not, reset the zoom.
observeEvent(input$plot_dblclick, {
brush <- input$plot_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- NULL
ranges$y <- NULL
}
})


#Creating text ----
output$group_n <- renderText({
req(data())
paste0("There are ", length(data_m()$Group), " groups in this file.",
tags$br("This is Group: ", data_m()$Group[n()])
)
})

#Building a table for you to visibly see points. You may need to update the DT to the github version ----
output$Table <- DT::renderDataTable({
req(data())
brushedPoints(data_n(), brush = input$plot_brush) %>%
select(Sample)
})

}

功能服务器

它已经被删除了,因为坏掉的至少不会崩溃,而且问题很明显。查看原件之前的编辑。

咨询的消息来源

类(class)信息

  • R 版本 3.4.2 (2017-09-28)
  • 平台:x86_64-w64-mingw32/x64(64 位)
  • 运行在:Windows 7 x64 (build 7601) Service Pack 1

更新

Observe() 中放置一个 react 器可以阻止应用程序崩溃,并且它确实会更新文件(忘记删除一些东西)。剩下的就是将依赖的 UI 保存在某处......

最佳答案

简而言之,问题是由于没有正确理解 observers 的逻辑造成的, 缺少 ()在 react 后,而不是调用 req停止某些部分的重新执行(参见 HERE )。

具体逐行更新可以通过查找##CHANGE:找到下面...最重要的变化(排名不分先后)是:

  1. 使用 isolate()对于 renderUI
  2. 使用 req()renderUI减慢速度,直到组数更新后才运行,但调用 args()使其依赖于文件选择
  3. 预先计算renderUI 之外的组数

更新服务器

server_fixed <- function(input, output, session) { 

#Larger subset: A Reactive Expression # May be used later...
args <- reactive({
list(input$p, input$s) #which file do we wish to input. This was our tag
})
# Reactive File-reader Subset
path <- reactive({
paste0(input$p, input$s, ".csv")
}) # Reactive Filename, kinda like our args...



filereader <- function(input) { # The function we pass into a reactive filereader.
suppressWarnings(read_csv(input, col_types = cols(
Group = col_character(),
Sample = col_character(),
x = col_double(),
y = col_double())
))
}

data_1 <- reactiveValues() # The function we use for livestream data
observe({
if(file.exists(path()) == TRUE) {
fileReaderData <- reactiveFileReader(500, session, path(), filereader)
} else {
message("This file does not exist")
}
data_1$df <- reactive({
# if(exists(fileReaderData())) {
# fileReaderData()
# } # Crashed from the beginning
req(fileReaderData())
fileReaderData()
})
})

data <- reactive(data_1$df()) ##CHANGE: FORGOT THE ()##

# Group setting...
data_m <- reactive({
req(data())
args()
tmp <- isolate(select(data(), Group))
tmp %>% distinct()
}) #number of markers, keeping only the marker name

data_m_length <- reactive({ ##CHANGE: TOOK OUT OF output$num_2##
##CHANGE: ADDED AN ISOLATE to fix the # of groups per file ##

isolate(length(data_m()$Group))
})

output$num_2 <- renderUI({
req(data_m_length()) ## CHANGE: ONLY EXECUTE ONCE WE HAVE OUR isolated data_m_length##
args() ## CHANGE: DEPENDENT UPON changing files##
isolate(
numericInput(inputId = "n",
label = "Group:",
min = 1,
max = data_m_length(),
value = 1 # THIS SHOULD BE CACHED!
)) ##CHANGE: ADDED IT IN ISOLATE when testing. NOT SURE IF STILL NEEDED##
}) #This is our 'reactive' numeric input for groups. This caps the max of our function based on the number of groups there are per file

n <- reactive(input$n) #which marker number we are dealing with.

data_n <- reactive({
req(data()); req(data_m())
dt <- filter(data(), Group == data_m()[[1]][n()])
})


# Create scatterplot object the plotOutput function is expecting ----
ranges <- reactiveValues(x = NULL, y = NULL)


output$scatterplot <- renderPlot({
validate(need(data(), "The specified file does not exist. Please try another"))
p <- as.numeric(input$p)
plot <- ggplot(data_n(), aes(x, y)) +
labs(title = paste0("Group ", data_n()$Group[1])) +
labs(x = "X vals", y = "Y vals") +
geom_point() + theme_bw() # I already have customized aesthetics. Removed for minimalism
plot + coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = TRUE) # So we see all points more readily. messes up the zoom but oh well
})

# When a double-click happens, check if there's a brush on the plot.
# If so, zoom to the brush bounds; if not, reset the zoom.
observeEvent(input$plot_dblclick, {
brush <- input$plot_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- NULL
ranges$y <- NULL
}
})


#Creating text ----
output$group_n <- renderText({
req(data())
paste0("There are ", length(data_m()$Group), " groups in this file.",
tags$br("This is Group: ", data_m()$Group[n()])
)
})

#Building a table for you to visibly see points. You may need to update the DT to the github version ----
output$Table <- DT::renderDataTable({
req(data())
brushedPoints(data_n(), brush = input$plot_brush) %>%
select(Sample)
})

}

剩下的就是使用 suppressErrorvalidate适本地。

关于r - 如何将 RShiny reactiveFileReader 与 reactiveUI 和不存在的文件一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51087980/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com