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

如何用ggplot2或plotly复现hist()的混合直方图与柱状图效果?

嘿,我来帮你搞定这个需求!你要的温度区间对应居住总人数的交互式图表,不管用ggplot2还是plotly都能完美复刻,还能轻松整合到Shiny应用里。下面一步步给你演示:

核心思路说明

首先要明确:你需要的不是传统直方图(展示频率/密度),而是基于温度区间统计总人数后的柱状图——先把温度划分成区间,再计算每个区间内的居住总人数,最后用柱状图展示并标注数值,这就是你说的“混合直方图与柱状图”的本质。


用ggplot2实现基础图表(可直接整合到Shiny)

先从基础的静态图表开始,再扩展到交互式Shiny应用:

1. 数据预处理(模拟+统计)

先模拟一组类似的数据集,再按温度区间统计总人数:

library(dplyr)

# 模拟温度和对应居住人数的数据(实际替换成你的真实数据)
set.seed(123)
temp_data <- data.frame(
  temperature = rnorm(500, mean = 20, sd = 5),  # 温度数据
  people = sample(1:10, 500, replace = TRUE)    # 每个温度点对应的居住人数
)

# 自定义温度区间并统计总人数
temp_summary <- temp_data %>%
  mutate(temp_bin = cut(temperature, breaks = seq(5, 35, 5))) %>%  # 5℃为间隔的区间
  group_by(temp_bin) %>%
  summarise(total_people = sum(people)) %>%  # 计算每个区间的总人数
  ungroup()

2. 绘制带标注的柱状图

用ggplot2绘制柱状图,并在每个柱形上方标注对应的总人数:

library(ggplot2)

p <- ggplot(temp_summary, aes(x = temp_bin, y = total_people)) +
  geom_col(fill = "#2196F3", alpha = 0.7) +  # 绘制柱状图
  geom_text(aes(label = total_people), vjust = -0.5, size = 4) +  # 柱形上方标注数值
  labs(
    x = "温度区间(℃)",
    y = "区间内居住总人数",
    title = "温度区间与居住总人数分布"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))  # 标题居中

print(p)

整合到Shiny应用(ggplot2版本)

把上面的代码改成交互式的Shiny应用,比如添加调整温度区间宽度的控件:

library(shiny)
library(dplyr)
library(ggplot2)

ui <- fluidPage(
  titlePanel("温度区间居住人数交互式图表"),
  sidebarLayout(
    sidebarPanel(
      # 交互式控件:调整温度区间宽度
      numericInput("bin_width", "温度区间宽度(℃)", value = 5, min = 1, max = 10)
    ),
    mainPanel(
      plotOutput("temp_plot")
    )
  )
)

server <- function(input, output) {
  # 模拟数据(实际替换为你的真实数据集)
  temp_data <- reactive({
    set.seed(123)
    data.frame(
      temperature = rnorm(500, mean = 20, sd = 5),
      people = sample(1:10, 500, replace = TRUE)
    )
  })
  
  # 动态统计区间总人数(根据用户选择的区间宽度)
  temp_summary <- reactive({
    temp_data() %>%
      mutate(temp_bin = cut(
        temperature, 
        breaks = seq(min(temperature()) - 1, max(temperature()) + 1, input$bin_width)
      )) %>%
      group_by(temp_bin) %>%
      summarise(total_people = sum(people)) %>%
      ungroup()
  })
  
  # 生成交互式图表
  output$temp_plot <- renderPlot({
    ggplot(temp_summary(), aes(x = temp_bin, y = total_people)) +
      geom_col(fill = "#2196F3", alpha = 0.7) +
      geom_text(aes(label = total_people), vjust = -0.5, size = 4) +
      labs(
        x = "温度区间(℃)",
        y = "区间内居住总人数",
        title = "温度区间与居住总人数分布"
      ) +
      theme_minimal() +
      theme(plot.title = element_text(hjust = 0.5))
  })
}

shinyApp(ui, server)

用plotly实现(更适合Shiny交互式体验)

如果想要更流畅的交互式效果(比如hover显示详情、缩放等),可以用plotly实现,同样能整合到Shiny:

1. 静态plotly图表

library(plotly)

# 基于之前的temp_summary数据绘制
p_plotly <- plot_ly(temp_summary, x = ~temp_bin, y = ~total_people, 
                    type = 'bar', marker = list(color = '#2196F3', opacity = 0.7)) %>%
  add_text(text = ~total_people, textposition = 'top center', textfont = list(size = 12)) %>%
  layout(
    title = list(text = "温度区间与居住总人数分布", x = 0.5),
    xaxis = list(title = "温度区间(℃)"),
    yaxis = list(title = "区间内居住总人数"),
    showlegend = FALSE
  )

p_plotly

2. Shiny + plotly版本

只需要把Shiny里的plotOutput换成plotlyOutput,renderPlot换成renderPlotly即可:

library(shiny)
library(dplyr)
library(plotly)

ui <- fluidPage(
  titlePanel("温度区间居住人数交互式图表"),
  sidebarLayout(
    sidebarPanel(
      numericInput("bin_width", "温度区间宽度(℃)", value = 5, min = 1, max = 10)
    ),
    mainPanel(
      plotlyOutput("temp_plot")
    )
  )
)

server <- function(input, output) {
  temp_data <- reactive({
    set.seed(123)
    data.frame(
      temperature = rnorm(500, mean = 20, sd = 5),
      people = sample(1:10, 500, replace = TRUE)
    )
  })
  
  temp_summary <- reactive({
    temp_data() %>%
      mutate(temp_bin = cut(
        temperature, 
        breaks = seq(min(temperature()) - 1, max(temperature()) + 1, input$bin_width)
      )) %>%
      group_by(temp_bin) %>%
      summarise(total_people = sum(people)) %>%
      ungroup()
  })
  
  output$temp_plot <- renderPlotly({
    plot_ly(temp_summary(), x = ~temp_bin, y = ~total_people, 
            type = 'bar', marker = list(color = '#2196F3', opacity = 0.7)) %>%
      add_text(text = ~total_people, textposition = 'top center', textfont = list(size = 12)) %>%
      layout(
        title = list(text = "温度区间与居住总人数分布", x = 0.5),
        xaxis = list(title = "温度区间(℃)"),
        yaxis = list(title = "区间内居住总人数"),
        showlegend = FALSE
      )
  })
}

shinyApp(ui, server)

关键注意点

  • 为什么不用hist():因为hist()默认统计的是区间内的观测数量,而你需要的是观测对应的人数总和,所以必须先手动用cut()划分区间,再用sum(people)统计总人数,最后用柱状图展示。
  • 标注位置:ggplot2里用vjust = -0.5把文字放在柱形上方,plotly里用textposition = 'top center'实现同样效果。
  • 数据替换:把代码里的模拟数据temp_data换成你自己的真实数据集即可。

内容的提问来源于stack exchange,提问作者G. Sozu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:54:46