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

条件表格过滤下ggplot饼图图例与标签位置异常问题

问题诊断与修复

问题根源

饼图标签位置错误的核心原因是pie_final()生成的数据框行顺序不统一:

  • 当char1与player1顺序不一致时,pie_filtered()会交换列,最终pie_final里先放char1的胜率,再放char2的胜率(对应原数据的败率)
  • 当顺序一致时,pie_final里先放char1的胜率,再放char2的败率,但此时char2的败率实际是char1的败率,而非char2的胜率,导致数据行逻辑与顺序不匹配,进而csum(累计和)计算错误,标签位置偏移。

同时,pie_filtered()的if-else逻辑存在冗余过滤,列交换后的处理可以更简洁。

修复方案

  1. 简化pie_filtered()逻辑,统一输出以input$char1为player1的记录,确保胜率对应char1,败率对应char2
  2. 强制pie_final()的数据行顺序为char1在前、char2在后,保证累计和计算的一致性

修改后的完整代码

library(tidyverse)
library(ggrepel)
library(shiny)
library(ggplot2)

#create sample dataframe
player1 <- c("Mario","Mario", "Peach")
player2 <- c("Luigi", "Peach", "Luigi")
pcnt_wins <- c(.75,.20,.55)
pcnt_loss <- c(.25,.80,.45)
data <- data.frame(player1, player2, pcnt_wins, pcnt_loss)

ui <- fluidPage(
  selectInput("char1", "Character 1:",
              c("Mario" = "Mario",
                "Luigi" = "Luigi",
                "Peach" = "Peach")),
  selectInput("char2","Character 2",
              c("Mario" = "Mario",
                "Luigi" = "Luigi",
                "Peach" = "Peach")),
  tableOutput("data_table"),
  textOutput("text"),
  plotOutput("plot")
)

server <- function(input, output) {
  
  #intermediate steps to create output table 
  table_filtered <- reactive({
    data %>% filter((player1 == input$char1 & player2 == input$char2) |
                    (player1 == input$char2 & player2 == input$char1))
  })
  
  # 简化逻辑:统一输出以char1为player1的记录
  pie_filtered <- reactive ({
    filtered <- table_filtered()
    # 判断是否需要交换列
    if (filtered$player1[1] != input$char1) {
      filtered %>%
        mutate(
          player1 = player2,
          player2 = player1,
          pcnt_wins = 1 - pcnt_wins,
          pcnt_loss = 1 - pcnt_loss
        )
    } else {
      filtered
    }
  })
  
  # 强制pie_final的行顺序:先char1,再char2
  pie_final <- reactive({
    data.frame(
      character = c(input$char1, input$char2),
      pie_win_pcnt = c(pie_filtered()$pcnt_wins, pie_filtered()$pcnt_loss)
    )
  })
  
  #create table output 
  output$data_table <- renderTable({
    pie_filtered()
  })
  
  output$text <- renderText({ class(pie_final()$pie_win_pcnt) })
  
  #create plot output 
  output$plot <- renderPlot({
    pie_final() %>%
      mutate(csum = rev(cumsum(rev(100*pie_win_pcnt))), 
             pos = 100*pie_win_pcnt/2 + lead(csum, 1),
             pos = if_else(is.na(pos), 100*pie_win_pcnt/2, pos)) %>%
      ggplot(aes(x = "", y = 100*pie_win_pcnt, fill = character)) +
      geom_col(width = 1, color = 1) + 
      coord_polar("y", start = 0) +
      theme_void() +
      geom_label_repel(
        aes(y = pos, 
            label = paste0(round(100*pie_win_pcnt,0), "%")),
        size = 6, 
        nudge_x = 1, 
        show.legend = FALSE
      )
  })
  
}

shinyApp(ui,server)

关键修改点说明

  • pie_filtered():移除冗余的select和filter操作,直接修改原列;通过判断第一条记录的player1是否等于char1来决定是否交换,逻辑更简洁。
  • pie_final():不再依赖pie_filtered()的列顺序,直接指定字符顺序为char1在前、char2在后,确保数据行顺序完全统一,csum计算逻辑能正确匹配饼图分段。
  • 移除重复的geom_bar(geom_col已包含stat="identity"功能),简化绘图代码。

内容的提问来源于stack exchange,提问作者user1243jsat1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:54:56