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

R Shiny动态切换图表类型故障排查:仅条形图正常,散点图与箱线图失效问题

Fixing Conditional Plot Rendering in Shiny Based on Variable Types

Let's break down the issues in your code and fix them one by one:

Key Issues in Your Current Code

  • Wrong type check logic: You're checking the type of input$X_variable/input$Y_variable—but these are just string values (the column names you selected), not the actual data columns. You need to check the type of the columns in your dataframe instead.
  • Missing closing brace: Your first if block doesn't have a closing }, which causes a syntax error that breaks the whole app.
  • Broken ggplot aesthetic mappings: Using data2[,input$X_variable] inside aes() isn't the right way to reference dynamic columns in ggplot. Also, passing input$Y_variable directly to shape/color in geom_point uses the string value (like "Price") instead of the actual column values.
  • Redundant code: The choices definition in the server and data2 <- data.frame(data) are unnecessary and can be removed.

Corrected Code

library(shiny)
library(ggplot2)
library(readr)
library(tidyverse)

# Load data (note: read_table is for tab-separated files; if cars.xls is Excel, use read_excel instead)
df <- read_table("cars.xls")

# Preprocess data once outside the server
df <- df %>%
  mutate(across(c(Model, Manufacturer, Origin), factor))

ui <- shinyUI(fluidPage(
  titlePanel("Car Dataset Analysis"),
  sidebarLayout(
    sidebarPanel(
      selectInput("X_variable", "X Variable:",
                  c("No of Cylinders" = "Cylinders",
                    "Type of car" = "Type",
                    "Engine Size" = "EngineSize",
                    "Fuel Tank capacity" = "Fuel.tank.capacity",
                    "Origin of the car"="Origin",
                    "Prices"="Price",
                    "Rev /min"="RPM",
                    "Weight of car"="Weight",
                    "MPG city"="MPG.city",
                    "Horsepower of car"="HorsePower",
                    "Passengers capacity"="Passengers",
                    "Length of car"="Length",
                    "Manufacturer of car"="Manufacturer",
                    "Model of car"="Model"
                  )),
      selectInput("Y_variable", "Y Variable:",
                  c("No of Cylinders" = "Cylinders",
                    "Type of car" = "Type",
                    "Engine Size" = "EngineSize",
                    "Fuel Tank capacity" = "Fuel.tank.capacity",
                    "Origin of the car"="Origin",
                    "Prices"="Price",
                    "Rev /min"="RPM",
                    "Weight of car"="Weight",
                    "MPG city"="MPG.city",
                    "Horsepower of car"="HorsePower",
                    "Passengers capacity"="Passengers",
                    "Length of car"="Length",
                    "Manufacturer of car"="Manufacturer",
                    "Model of car"="Model"
                  ))
    ),
    mainPanel(
      tabsetPanel(type="tabs",
                  tabPanel("Plots", plotOutput("main_plot"))
      )
    )
  )
))

server <- shinyServer(function(input, output) {
  output$main_plot <- renderPlot({
    # Get the actual columns from the dataframe
    x_col <- df[[input$X_variable]]
    y_col <- df[[input$Y_variable]]
    
    # Check types of the selected columns
    x_is_num <- is.numeric(x_col)
    y_is_num <- is.numeric(y_col)
    x_is_factor <- is.factor(x_col)
    y_is_factor <- is.factor(y_col)
    
    if(x_is_num && y_is_num) {
      # Scatter plot for two numeric variables
      ggplot(df, aes(x = .data[[input$X_variable]], y = .data[[input$Y_variable]])) +
        geom_point(alpha = 0.7) +
        labs(x = input$X_variable, y = input$Y_variable)
    } else if((x_is_factor && y_is_num) || (y_is_factor && x_is_num)) {
      # Boxplot for one factor + one numeric
      # Determine which is factor and which is numeric for correct axis mapping
      if(x_is_factor) {
        ggplot(df, aes(x = .data[[input$X_variable]], y = .data[[input$Y_variable]])) +
          geom_boxplot(fill = "lightblue") +
          labs(x = input$X_variable, y = input$Y_variable)
      } else {
        ggplot(df, aes(x = .data[[input$Y_variable]], y = .data[[input$X_variable]])) +
          geom_boxplot(fill = "lightblue") +
          labs(x = input$Y_variable, y = input$X_variable)
      }
    } else {
      # Bar plot for two categorical variables
      ggplot(df, aes(x = .data[[input$X_variable]], fill = .data[[input$Y_variable]])) +
        geom_bar(position = "dodge") +
        labs(x = input$X_variable, fill = input$Y_variable) +
        theme(axis.text.x = element_text(angle = 45, hjust = 1))
    }
  })
})

shinyApp(ui, server)

Key Improvements Explained

  1. Preprocessing outside server: We convert categorical columns to factors once when loading the data, instead of doing it inside the server (which runs every time input changes).
  2. Correct type checks: We first extract the actual columns from df and check their types, not the input strings.
  3. Proper ggplot dynamic column references: Using .data[[input$X_variable]] is the recommended way to reference dynamic column names in ggplot (avoids evaluation issues).
  4. Fixed boxplot axis logic: We make sure the categorical variable is always on the x-axis and numeric on the y-axis, regardless of which one the user selects as X or Y.
  5. Cleaned up redundant code: Removed unnecessary variable definitions and simplified the code flow.

One quick note: If cars.xls is an Excel file (not a tab-separated text file), you should use read_excel() from the readxl package instead of read_table().

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:59:11