Shiny多选下拉场景下为不同指标折线配置对应线型的实现问题
问题描述
- 目标是基于Shiny侧边栏下拉多选的指标,绘制点线结合的折线图
- 线型规则要求:
SellOut 对应的x、y字段使用实线(solid)
GrossProfit 对应的x1、y1字段使用虚线(dashed)
GrossSales 对应的x2、y2字段使用点线(dotted) - 现存问题:仅单个指标选中时可正常绘图,选中2个及以上指标时仅能渲染1条实线,无法展示多指标对应不同线型的折线,多选分支无有效绘图代码。
修复方案
核心修改点:
- 取消按选中指标数量分支写绘图逻辑的写法,提前建立指标、对应字段、线型的映射表
- 将宽格式的指标数据转为长格式,统一数据结构后,无论选中多少个指标都用同一套ggplot逻辑绘图
- 在线条映射中单独指定线型规则,保证不同指标严格匹配要求的线型,品牌颜色映射保持原有规则不变
修复后可运行完整代码
library(shiny) library(shinydashboard) library(plotly) library(tidyr) library(dplyr) library(DT) library(ggplot2) BRAND<-c("CHOKIS","CHOKIS","CHOKIS","CHOKIS","CHOKIS","CHOKIS","LARA CHOCO CHIPS","LARA CHOCO CHIPS","LARA CHOCO CHIPS") BRAND_COLOR<-c("#8050f0","#8050f0","#8050f0","#8050f0","#8050f0","#8050f0","#f050c0","#f050c0","#f050c0") SellOut.x<-c(23,34,56,77,78,34,34,64,76) SellOut.y<-c(43,54,76,78,87,98,76,76,56) GrossProfit.x1<-c(23,34,56,75,78,34,34,64,76) GrossProfit.y1<-c(33,54,76,76,87,98,76,76,56) GrossSales.x2<-c(53,34,56,77,78,34,34,84,76) GrossSales.y2<-c(63,54,76,78,87,98,76,76,86) r<-c(58,46,76,76,54,21,69,98,98) graph1.data<-data.frame(BRAND,BRAND_COLOR,r) df6 <- data.frame(SellOut.x, SellOut.y, GrossProfit.x1, GrossProfit.y1, GrossSales.x2, GrossSales.y2) # 提前配置指标和字段、线型的映射规则 metric_config <- data.frame( metric_input = c("Sell Out", "Gross Profit", "Gross Sales"), metric_col = c("SellOut", "GrossProfit", "GrossSales"), x_col = c("x", "x1", "x2"), y_col = c("y", "y1", "y2"), line_type = c("solid", "dashed", "dotted") ) ui <- dashboardPage( dashboardHeader(), dashboardSidebar( selectInput("metric","Metric",c('Gross Sales','Gross Profit','Sell Out'),multiple = T,selected = "Sell Out") ), dashboardBody( DTOutput("df"), plotlyOutput("plot") ) ) server <- function(input, output) { reactiveDf <- reactive({ req(input$metric) # 匹配选中的指标对应的配置 selected_config <- metric_config[metric_config$metric_input %in% input$metric, ] # 提取对应字段转长表 plot_data <- lapply(1:nrow(selected_config), function(i){ tmp_config <- selected_config[i, ] x_col_name <- paste0(tmp_config$metric_col, ".", tmp_config$x_col) y_col_name <- paste0(tmp_config$metric_col, ".", tmp_config$y_col) data.frame( BRAND = graph1.data$BRAND, BRAND_COLOR = graph1.data$BRAND_COLOR, r = graph1.data$r, metric = tmp_config$metric_input, x = df6[[x_col_name]], y = df6[[y_col_name]], line_type = tmp_config$line_type ) }) %>% bind_rows() return(plot_data) }) output$df<-renderDT({ reactiveDf() }) output$plot<-renderPlotly({ Df <- req(reactiveDf()) # 品牌颜色映射 brand.colors <- unique(Df[,c("BRAND","BRAND_COLOR")]) color_vals <- brand.colors$BRAND_COLOR names(color_vals) <- brand.colors$BRAND # 线型映射 linetype_vals <- c("solid"="solid", "dashed"="dashed", "dotted"="dotted") p <- ggplot(Df, aes(x=x, y=y, color=BRAND, linetype=line_type, group=interaction(BRAND, metric))) + geom_line(linewidth=1) + geom_point(aes(size=r), show.legend=TRUE) + scale_color_manual(values=color_vals) + scale_linetype_manual(values=linetype_vals, labels=c("实线(Sell Out)","虚线(Gross Profit)","点线(Gross Sales)")) + labs(linetype="指标类型", color="品牌", size="r值") + theme_minimal() ggplotly(p) }) } shinyApp(ui, server)
效果说明
- 选中任意数量指标都可正常渲染,每个品牌对应固定颜色
- 不同指标严格匹配预设线型:Sell Out为实线、Gross Profit为虚线、Gross Sales为点线
- 点的大小保持原有映射r值的规则,表格输出同步展示绘图所用的长格式数据
内容的提问来源于stack exchange,提问作者firmo23
相关产品推荐
相关产品推荐

