- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我将如何构建响应式 UI 来响应具有不同数据输入的 reactiveFileReader?
我有兴趣将一个 reactiveFileReader 集成到一个应用程序中,该应用程序在数据中绘制组图并逐组显示选定的点。
挑战:
崩溃/失败时我
可能的解决方案:
reactive()
和 req()
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)
})
}
功能服务器
它已经被删除了,因为坏掉的至少不会崩溃,而且问题很明显。查看原件之前的编辑。
咨询的消息来源
isolate
和 observers
上寻找灵感类(class)信息
更新
在 Observe()
中放置一个 react 器可以阻止应用程序崩溃,并且它确实会更新文件(忘记删除一些东西)。剩下的就是将依赖的 UI 保存在某处......
最佳答案
简而言之,问题是由于没有正确理解 observers
的逻辑造成的, 缺少 ()
在 react 后,而不是调用 req
停止某些部分的重新执行(参见 HERE )。
具体逐行更新可以通过查找##CHANGE:
找到下面...最重要的变化(排名不分先后)是:
isolate()
对于 renderUI
req()
在renderUI
减慢速度,直到组数更新后才运行,但调用 args()
使其依赖于文件选择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)
})
}
剩下的就是使用 suppressError
和 validate
适本地。
关于r - 如何将 RShiny reactiveFileReader 与 reactiveUI 和不存在的文件一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51087980/
我的代码在下面,演示站点在这里:http://glimmer.rstudio.com/kdavenport/test1/ 第一个输入(下拉菜单)加载 global.R 中定义的数据框 第二个输入(下拉
我使用了一个可移植模板创建了一个 Xamarin 应用程序,并且我已经在可移植库和 Android 库中安装了响应式(Reactive) UI。但是,当我将应用程序部署到我的手机并导致触发 Raise
我有 WPF 列表框: 我喜欢使用后面的代码按名称绑定(bind) ListBox 的能力:this.OneWayBind(ViewModel, vm
我喜欢 ReactiveUI 的基于代码的绑定(bind)机制。但是,有时您需要使用 XAML 绑定(bind)。在这些情况下,需要在 View 和 ViewModel 之间正确设置 DataCont
在将我的项目中的 Xamarin Forms 包更新到 3.4.0.1009999 后,当使用 ReactiveUI x.DiscountSliderValue).Throttle(TimeSpan.
我正在测试 ReactiveUI,看起来很不错。 但是,我对 MessageBus 有点困惑。 示例代码: var bus = new MessageBus(); int result = -1; b
我无法在设计时在Visual Studio中使用ViewModelViewHost。这是设计使然还是我设置有误? 在我看来,我有: Locator.CurrentMutable.Initializ
我正在将 MvvmCross 与 ReactiveUI 进行比较,用于 Win Store、WP8、iOS、Droid 上的一个主要制药项目。我们已经选择了 Xamarin。 我对 ReactiveU
RX官方博客上有此example: var scheduler = new TestScheduler(); var xs = scheduler.CreateColdObservable(
ReactiveUI.Routing要求我们在Splat容器(Locator.CurrentMutable)中注册 View 。如果我未在Splat中注册,则无法正常工作。 如果我们正在使用其他一些I
所以,当我为我的系统开发新功能时,我也尝试做 TDD - 遗憾的是,现在对于旧功能来说代码太大了。 但是,我发现有时在测试过程中会遇到困难 - 特别是在使用 Delay 和 Throttle 时。 我
所以,当我为我的系统开发新功能时,我也尝试做 TDD - 遗憾的是,现在对于旧功能来说代码太大了。 但是,我发现有时在测试过程中会遇到困难 - 特别是在使用 Delay 和 Throttle 时。 我
我一直在研究在生产代码中使用响应式 UI 的可行性。有些功能确实很吸引人,但我担心依赖这个库。其中包括: 古怪的命名和约定。例如, protected 成员以小写字母开头,而 RaiseAndSetI
我正在将 WPF 应用程序移植到 Windows 应用商店应用程序。我有一些要放入可移植类库的 View 模型。该代码使用 reactui 框架。我创建了库,并使用 nuget 包管理器将 react
我通过 nuget 下载最新的 ReactiveUI (5.0.2) 到我基于 .NET 4.5 的项目。 我创建了具有一个属性的简单 View 模型类: using System; using Sy
在我使用 ReactiveUI 的 WPF 应用程序中,我注意到一个性能不佳的区域。 我有一个 View 模型,其中包含许多其他轻量级 View 模型(想想 30ish)。这些嵌套的 View 模型很
我有一个关于 reactiveui View 模型的问题。 我的 View 模型上有两个属性,月和年,并希望有一个进一步的输出属性 DateLabel,它将两者结合起来并很好地格式化,例如“2015
我查看了许多 ReactiveUI 示例,但我看不到一个很好的简单示例来说明如何处理异常,即应该向用户显示一条消息。 (如果有一个很好的例子,有人可以指点我吗?)。 我的第一个问题是如何使用 Reac
我有一个窗口使用 ReactiveUI Interaction 打开第二个窗口作为模态对话框,然后从第二个窗口中的 ListBox 返回数据。 问题是当 .ShowDialog() 完成时,ViewM
我有一个 WPF MVVM 应用程序。我的模型对象是我可以完全控制的 POCO。这些对象中的某些属性之间存在关系。 例如:假设我有 public class Model { public Ob
我是一名优秀的程序员,十分优秀!