You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny中如何为reactive对象渲染原生绘图解决ylim报错问题

错误原因

  • vectorsAll返回的Yld_Rate列是经pct()函数处理的带百分号的字符串,R基础绘图无法将字符串识别为数值计算坐标轴范围,因此抛出Error: need finite 'ylim' values错误
  • vectorsAll初始逻辑存在漏洞:用户未点击「Input Liabilities」按钮时,input$showLiabilityGrid为NULL,此时返回空值,表格渲染字符串无影响,但绘图无法识别有效数据

修正后完整代码

library(shiny)
library(shinyMatrix)
library(shinyjs)

button2 <- function(x,y){actionButton(x,y,style="width:90px;margin-bottom:5px;font-size:80%")}

matrix1Input <- function(x){
  matrixInput(x, 
              value = matrix(c(0.2), 4, 1,dimnames=list(c("A","B","C","D"),NULL)),
              rows = list(extend=FALSE,names=TRUE),
              cols = list(extend=FALSE,names=FALSE,editableNames=FALSE),
              class = "numeric")}

pct <- function(x){paste(format(round(x*100,digits=1),nsmall=1),"%",sep="")} # convert to percentage

vectorBase <- function(x,y){
  a <- rep(y,x)
  b <- seq(1:x)
  c <- data.frame(x = b, y = a)
  return(c)}

ui <- 
  pageWithSidebar(
    headerPanel("Model..."),
    sidebarPanel(
      fluidRow(helpText(h5(strong("Base Input Panel")),align="center",
                        style="margin-top:-15px;margin-bottom:5px")),
      # Panels rendered with uiOuput & renderUI in server to stop flashing at invocation
      uiOutput("Panels") 
    ), # close sidebar panel
    mainPanel(
      tabsetPanel(
        tabPanel("By balances", value=2),
        tabPanel("By accounts", value=3), 
        tabPanel("Liabilities module", value=4,
                 fluidRow(h5(strong(helpText("Select model output to view:")))),
                 fluidRow(
                   button2('showVectorValueBtn','Vector values'),
                   button2('showVectorPlotBtn','Vector plots'),
                 ), # close fluid row
                 
                 div(style = "margin-top: 5px"),
                 
                 # Shows outputs on each page of main panel   
                 uiOutput('showResults')), 
        id = "tabselected"
      ) # close tabset panel
    ) # close main panel
  ) # close page with sidebar

server <- function(input,output,session)({
  
  base_input  <- reactive(input$base_input)
  showResults <- reactiveValues()
  
  yield   <- function(){vectorBase(60,input$base_input[1,1])} # Must remain in server section
  
  # --- Conditional panels rendered here rather than in UI to eliminate invocation flashing ------------>
  output$Panels <- renderUI({
    tagList( 
      conditionalPanel(
        condition="input.tabselected==4",
        actionButton('showLiabilityGrid','Input Liabilities',style='width:100%;background-color:LightGrey'),
        setShadow(id='showLiabilityGrid'),
        div(style = "margin-bottom: 10px"),
      ), # close conditional panel
      conditionalPanel(condition="input.tabselected==3"),
      conditionalPanel(condition="input.tabselected==4")
    ) # close tagList
  }) # close renderUI
  
  # --- 调整vectorsAll返回数值型数据,不再提前做百分号格式化 ---->
  vectorsAll <- reactive({
    if (is.null(input$showLiabilityGrid)){
      df <- cbind(Period = 1:60,Yld_Rate = 0.2)
    } else {
      if(input$showLiabilityGrid < 1){
        df <- cbind(Period = 1:60,Yld_Rate = 0.2)
      } else {
        req(input$base_input)
        df <- cbind(Period = 1:60,Yld_Rate = yield()[,2])
      } 
    }
    df
  }) # close reactive
  
  # --- 表格渲染时单独做百分号格式化,保证展示效果不变 ---->
  output$table1 <- renderTable({
    df <- vectorsAll()
    df$Yld_Rate <- pct(df$Yld_Rate)
    df
  })
  
  # --- Below produces vector values after clicking "Vector Values" button; see above for pre-click ---->
  observeEvent(input$showVectorValueBtn,
               {showResults$showme <-
                 tagList(tableOutput("table1"))
               },ignoreNULL = FALSE)
  
  # --- 直接用数值型数据绘图,原生plot可正常识别 ---->   
  output$graph1 <-renderPlot(
    plot(vectorsAll()[,1], vectorsAll()[,2], 
         type = "l", xlab = "周期", ylab = "收益率",
         main = "收益率走势")
  )
  observeEvent(input$showVectorPlotBtn,{showResults$showme <- plotOutput("graph1")})
  
  # --- Below sends both vector plots and vector values to UI section above ---------------------------->
  output$showResults <- renderUI({showResults$showme})
  
  # --- Below for modal dialog inputs ------------------------------------------------------------------>
  observeEvent(input$showLiabilityGrid,
               {showModal(modalDialog(
                 matrix1Input("base_input"),
                 div(style = "margin-top: 0px"),
                 useShinyjs(),
               ) # close modalDialog
               ) # close showModal
               } # close showModal function
  ) # close observeEvent
  
}) # close server

shinyApp(ui, server)

效果说明

  • 未点击侧边栏「Input Liabilities」按钮时,点击「Vector plots」可直接绘制60个周期取值为0.2的默认折线图
  • 点击「Input Liabilities」修改A行数值后,数据表和绘图会同步更新
  • 全程使用R原生绘图能力,未引入第三方绘图包,可直接在此基础上调整样式优化外观

内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 09:27:03