R Shiny 中的反应式桑基图,以多个数据帧作为输入
Reactive Sankey Diagram in R Shiny with multiple dataframes as input
这是我第一次创建仪表板,我 运行 遇到了一个我似乎无法解决的问题。我创建了一个桑基图,我希望能够通过不同的数据帧交互地更改其内容(在本例中:level_1、level_2、level_3)。我只用常规图练习过这个,其中输入来自一个数据框中的变量,这是我在这段代码中的起点(例如,我有一个 df$country,所以我在我的中使用 input$country plot --> 然后我可以在仪表板侧边栏中选择不同的国家,以更改 plot 的内容)。当输入必须来自单独的数据帧时,我不知道该怎么做。
我的代码:(在app.R)
level_1 <- as.data.frame(matrix(sample(seq(0,40), 15, replace=T ), 3, 5))
level_2 <- as.data.frame(matrix(sample(seq(0,40), 20, replace=T ), 4, 5))
level_3 <- as.data.frame(matrix(sample(seq(0,40), 25, replace=T ), 5, 5))
levels <- list(level_1, level_2, level_3)
ui <- dashboardPage(
dashboardHeader(title = "title"),
dashboardSidebar(
selectInput("in_levels", "Levels", choices = levels)
),
dashboardBody(
fluidRow(sankeyNetworkOutput("widget1"))
)
)
server <- function(input, output) {
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name=c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = links, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
shinyApp(ui, server)
我认为创建一个包含所有数据帧的 list()、levels 可能会有所帮助,但这不起作用。我收到此错误:
Error : Can't access reactive value 'in_levels' outside of reactive consumer.
i Do you need to wrap inside reactive() or observer()?
我已经在 google 上搜索了 reactive() 和 observer() 以试图找出我的下一步应该是什么,但我还没有找到解决方案。如果有人可以就如何继续、进行更改或阅读一些可以增加我的理解的内容给我建议,我将不胜感激。
提前致谢!
如果您想访问服务器中的任何 input
值,您需要使用反应式上下文。 shiny
不允许您做其他事情,但即使这样做了,如果更新了 input
值,服务器端代码也不会更新以反映更改。由于您希望 links
和 nodes
都是动态的并且彼此依赖,一个简洁的解决方案可能是将两个对象存储在列表中,如下所示:
server <- function(input, output) {
plot_data <- reactive({
# Perform all your computation inside this reactive!
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name = c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
# Return the data in a list
list(links = links, nodes = nodes)
})
# Access the datasets by calling the reactive and then treating as a normal list
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = plot_data()$links, Nodes = plot_data()$nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
这是未经测试的,因为我当前的 R 版本不支持 network3d
包。
反应性的概念很棘手,但如果您是 shiny
的新手,chapter 3 of Mastering Shiny 应该很有启发性。
这是我第一次创建仪表板,我 运行 遇到了一个我似乎无法解决的问题。我创建了一个桑基图,我希望能够通过不同的数据帧交互地更改其内容(在本例中:level_1、level_2、level_3)。我只用常规图练习过这个,其中输入来自一个数据框中的变量,这是我在这段代码中的起点(例如,我有一个 df$country,所以我在我的中使用 input$country plot --> 然后我可以在仪表板侧边栏中选择不同的国家,以更改 plot 的内容)。当输入必须来自单独的数据帧时,我不知道该怎么做。
我的代码:(在app.R)
level_1 <- as.data.frame(matrix(sample(seq(0,40), 15, replace=T ), 3, 5))
level_2 <- as.data.frame(matrix(sample(seq(0,40), 20, replace=T ), 4, 5))
level_3 <- as.data.frame(matrix(sample(seq(0,40), 25, replace=T ), 5, 5))
levels <- list(level_1, level_2, level_3)
ui <- dashboardPage(
dashboardHeader(title = "title"),
dashboardSidebar(
selectInput("in_levels", "Levels", choices = levels)
),
dashboardBody(
fluidRow(sankeyNetworkOutput("widget1"))
)
)
server <- function(input, output) {
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name=c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = links, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
shinyApp(ui, server)
我认为创建一个包含所有数据帧的 list()、levels 可能会有所帮助,但这不起作用。我收到此错误:
Error : Can't access reactive value 'in_levels' outside of reactive consumer.
i Do you need to wrap inside reactive() or observer()?
我已经在 google 上搜索了 reactive() 和 observer() 以试图找出我的下一步应该是什么,但我还没有找到解决方案。如果有人可以就如何继续、进行更改或阅读一些可以增加我的理解的内容给我建议,我将不胜感激。
提前致谢!
如果您想访问服务器中的任何 input
值,您需要使用反应式上下文。 shiny
不允许您做其他事情,但即使这样做了,如果更新了 input
值,服务器端代码也不会更新以反映更改。由于您希望 links
和 nodes
都是动态的并且彼此依赖,一个简洁的解决方案可能是将两个对象存储在列表中,如下所示:
server <- function(input, output) {
plot_data <- reactive({
# Perform all your computation inside this reactive!
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name = c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
# Return the data in a list
list(links = links, nodes = nodes)
})
# Access the datasets by calling the reactive and then treating as a normal list
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = plot_data()$links, Nodes = plot_data()$nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
这是未经测试的,因为我当前的 R 版本不支持 network3d
包。
反应性的概念很棘手,但如果您是 shiny
的新手,chapter 3 of Mastering Shiny 应该很有启发性。