r - 带有 R 的交互式闪亮应用程序 - 悬停在点上并显示信息
问题描述
我在 R 中工作以创建一个闪亮的应用程序。
这是我正在使用的示例数据:
data <- data.frame("name" = c("A", "A", "B", "B", "C", "C"),
"code_name" = c("A1", "A2", "B1", "B2", "C1", "C2"),
"x" = c(.13, .64, .82, .39, .51, .03),
"y" = c(.62, .94, .10, .24, .20, .84))
我正在尝试拥有一个 Shiny 应用程序,它允许用户从 column 中选择一个选项name
,显示x
和y
值的散点图,并code_name
在您将鼠标悬停在某个点附近时打印绘图下方列中的值。
这是代码ui
:
library(ggplot2)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "x",
label = "Choose a Letter:",
choices = levels(data$name),
selected = "A")
),
mainPanel(
plotOutput(outputId = "scatterplot",
hover = hoverOpts(id ="plot_hover")),
verbatimTextOutput("hover_info")
)
)
)
这是代码server
:
server <- function(input, output) {
output$scatterplot <- renderPlot({
data %>%
filter(name == input$x) %>%
ggplot(aes(x, y)) +
geom_point() +
xlim(c(0, 1)) +
ylim(c(0, 1))
})
output$hover_info <- renderPrint({
if(!is.null(input$plot_hover)){
hover = input$plot_hover
dist = sqrt((hover$x-data$x)^2 + (hover$y-data$y)^2)
cat("Name\n")
if(min(dist) < 3)
data$code_name[which.min(dist)]
}
})
}
然后,当然:
shinyApp(ui, server)
第一个输出对象 ,output$scatterplot
按需要工作。它是x
和y
观察值的散点图,其中data$name
是从 中选择的值input$x
。
问题出在第二个对象上output$hover_info
。我想要的是文本框结果renderPrint
,仅打印code_name
用于观察 where data$name == input$x
。现在的方式是,如果我从下拉菜单中选择“A”,并将鼠标悬停在其中一个绘图点上,它会正确地打印该点code_name
在绘图下方。但是,如果我将鼠标悬停在两个点附近的随机点上,它将获取其他name
选项点之一的位置,并显示该观察值code_name
。
例如,如果您按原样运行代码(name == "A"
下拉菜单中的默认选择在哪里),并将鼠标悬停在坐标 x = 0.5, y = 0.5 附近,它将打印B2
在绘图下方。我想避免这种情况。这里没什么大不了的,每个名称选择只有 2 个数据点,但是当使用具有更大数据集的相同框架时,它会变得非常混乱。
我一直试图filter
在对象中包含某种类型的调用,output$hover_info
以便它只考虑通过下拉菜单定义的观察结果,但每次尝试时都会出错。
有任何想法吗?谢谢!
解决方案
我通常推荐一种方法,您可以reactive
为任何类型的用户操作数据创建一个对象,然后reactive
在您的render*
调用中引用该对象。我发现它比尝试在render*
调用中完成所有事情的限制更少,更容易调试,并且更好地理解数据的反应性应该如何工作。
在这里,我创建了一个filtered_data
响应式对象,该对象根据下拉列表进行过滤,然后进一步向下引用。您的代码无法正常工作的原因是因为您的dist
计算是针对完整数据集而不是过滤后的数据集进行的。另外,我认为您的阈值 3 太宽了,所以我在这里将其更改为 0.3。
最后,注意req()
代替的用法if(!is.null())
,它更简洁,并且在我们希望它何时显示数据方面更加一致。
server <- function(input, output) {
filtered_data <- reactive({
filter(data, name == input$x)
})
output$scatterplot <- renderPlot({
ggplot(filtered_data(), aes(x, y)) +
geom_point() +
xlim(c(0, 1)) +
ylim(c(0, 1))
})
displayed_text <- reactive({
req(input$plot_hover)
hover <- input$plot_hover
dist <- sqrt((hover$x - filtered_data()$x)^2 + (hover$y - filtered_data()$y)^2)
if(min(dist) < 0.3) {
filtered_data()$code_name[which.min(dist)]
} else {
NULL
}
})
output$hover_info <- renderPrint({
req(displayed_text())
cat("Name\n")
displayed_text()
})
}
让我知道这是否符合您的要求。
推荐阅读
- mysql - SQL“NOT IN”功能无法正常工作
- django - 具有可变标签集的文档分类
- python - 为什么我无法使用有效凭据登录 Django 用户,但可以登录我原来的超级用户?
- winapi - 关闭窗口时消息循环未退出
- google-cloud-storage - 从元数据服务器获取访问令牌时出错:http://metadata/computeMetadata/v1/instance/service-accounts/default/token
- java - 如何将库导入 Android Studio
- arcore - Sceneform 1.17.1 是开源的吗?
- python - Heroku:连接到套接字的ErrorTimeout
- node.js - 如何修复 Mongoose 5.11.8 model.find() 错误操作 `thanks-leaderboards.find()` 缓冲在 10000 毫秒后超时
- vba - 列中大于/小于时间