R Shiny中isTruthy()运行不符合预期,如何实现矩阵条件绘图?
问题根源
- Shiny的
isTruthy()仅判断输入是否存在、非空/非NA/非FALSE,不会区分输入值是UI预设的默认值还是用户手动修改后的值。你取消matrix2的注释后,只要UI中存在该输入控件,isTruthy(input$matrix2)就会永远返回TRUE,导致渲染matrix1的else分支永远不会触发。 - 你原有逻辑是二选一渲染矩阵结果,也不符合「matrix2有手动输入时两者同时显示」的业务需求。
修改方案
我们需要先记录matrix2的初始默认值,判断用户是否对其做过手动修改,再调整绘图数据的拼接逻辑:
- 新增变量存储matrix2的初始默认值,用于比对修改状态
- 绘图逻辑调整为:始终生成matrix1的绘图数据,仅当matrix2被手动修改过时,追加其对应的数据
- 补充matrix2的行名自动补全监听,和matrix1逻辑对齐
library(dplyr) library(ggplot2) library(shiny) library(shinyMatrix) sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))} ui <- fluidPage( sidebarLayout( sidebarPanel( matrixInput("matrix1", value = matrix(c(60,5), ncol = 2, dimnames = list(NULL,c("X","Y"))), rows = list(extend = TRUE, delete = TRUE), class = "numeric"), # 取消matrix2的注释 matrixInput("matrix2", label = "Matrix 2 (Value Y applied in Period X):", value = matrix(c(60,5),ncol=2,dimnames=list(NULL,rep("Scenario 1",2))), rows = list(extend = TRUE, delete = TRUE), cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE), class = "numeric"), ), mainPanel(plotOutput("plot")) ) ) server <- function(input, output, session){ # 新增:记录matrix2的初始默认值,用于判断是否被用户修改 init_mat2 <- isolate(input$matrix2) observeEvent(input$matrix1, { tmpMat1 <- input$matrix1 if(any(rownames(input$matrix1) == "")){rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))} updateMatrixInput(session, inputId = "matrix1", value = tmpMat1) }) # 新增:matrix2的行名自动补全逻辑,和matrix1对齐 observeEvent(input$matrix2, { tmpMat2 <- input$matrix2 if(any(rownames(input$matrix2) == "")){rownames(tmpMat2) <- paste("Row", seq_len(nrow(input$matrix2)))} updateMatrixInput(session, inputId = "matrix2", value = tmpMat2) }) plotData <- reactive({ tryCatch({ # 始终先生成matrix1的绘图数据 plot_df <- tibble(Scenario = "Matrix1-Scenario1", X = seq_len(10),Y = sumMat(input$matrix1)) # 仅当matrix2被手动修改过,才追加它的绘图数据 # 用identical判断当前值和初始值是否完全一致,不一致则判定为有手动输入 if(isTruthy(input$matrix2) && !identical(input$matrix2, init_mat2)){ mat2_df <- lapply(seq_len(ncol(input$matrix2)/2), function(i){ tibble(Scenario = paste0("Matrix2-",colnames(input$matrix2)[i*2-1]), X = seq_len(10),Y = sumMat(input$matrix2[,(i*2-1):(i*2), drop = FALSE])) }) %>% bind_rows() plot_df <- bind_rows(plot_df, mat2_df) } return(plot_df) }, error = function(e) NULL) }) output$plot <- renderPlot({ req(plotData()) plotData() %>% ggplot() + geom_line(aes(x = X, y = Y, colour = as.factor(Scenario))) }) } shinyApp(ui, server)
如果不需要同时显示两个矩阵的结果,只需要「有手动修改的matrix2就显示它,否则显示matrix1」,只需要把plotData里的逻辑改回二选一即可,判断条件保留!identical(input$matrix2, init_mat2)就行。
内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072
相关产品推荐
相关产品推荐

