Shiny窗口缩放时动态调整facet_wrap类Plotly图表高度报错如何解决
报错原因
你遇到的Error in *: non-numeric argument to binary operator(翻译:*运算中存在非数值类型的参数)错误,以及图表无法正常渲染的问题,核心来自两个错误写法:
- 循环依赖:你的
he()响应式变量需要读取p1()的结果计算分面行数,但p1()生成时又要调用he()计算高度,导致首次执行时he()返回无效空值,乘法运算报错 - UI组件不匹配:Plotly图表在Shiny中需要使用
plotlyOutput作为容器,你代码中使用了仅支持静态ggplot的plotOutput,会导致后续渲染异常
优化实现方案
你可以拆分ggplot构建和Plotly转换的流程,破除循环依赖,同时实现分面高度动态适配,各分面尺寸统一,修改后的完整可运行代码如下:
library(ggplot2) library(shiny) library(tidyverse) library(plotly) library(magrittr) mtcars$cyl = sample(letters[1:5], 32, TRUE) # 计算分面行数的函数 gg_facet_nrow <- function(p){ num_panels <- length(unique(ggplot_build(p)$data[[1]]$PANEL)) num_cols <- ggplot_build(p)$layout$facet$params$ncol num_rows <- wrap_dims(num_panels, ncol=num_cols)[1] return(num_rows) } ui <- fluidPage( navbarPage(title="title", tabPanel("One", column(3, wellPanel( selectInput('name', 'NAME', c("A", "B")))), # 替换为plotly专用的输出组件 column(9, plotlyOutput('plot1'))) )) server <- function(input, output) { # 先构建纯ggplot对象,不转plotly gg_obj <- reactive({ if(input$name == "A"){ ggplot(mtcars, aes(mpg, wt)) + facet_wrap( . ~ gear, ncol = 1 ) }else{ ggplot(mtcars, aes(mpg, wt)) + facet_wrap( cyl ~ gear, ncol = 1 ) } }) # 基于纯ggplot对象计算分面行数,无循环依赖 facet_row <- reactive({ gg_facet_nrow(gg_obj()) }) # 转plotly时传入动态计算的高度,每行按300px计算,可自行调整单分面高度 output$plot1 <- renderPlotly({ ggplotly(gg_obj(), height = facet_row() * 300) }) } shinyApp(ui,server)
实现逻辑说明
- 先构建纯ggplot分面对象,不需要转换为Plotly就可以计算分面行数,完全避免循环依赖
- 宽度默认自适应父容器宽度,无需额外配置,高度按分面行数*单分面固定高度计算,保证所有分面尺寸统一,不会超出窗口范围
- 如需调整单分面尺寸,只需修改
height = facet_row() * 300中的300这个数值即可
内容的提问来源于stack exchange,提问作者QMan5
相关产品推荐
相关产品推荐

