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

Shiny中mapview绘制Choropleth图同位置点未求均值问题修复

问题根因

你的判断完全正确。当前传入mapview的空间数据是时序长表结构:同一个坐标点对应不同年份、月份的多条气温观测记录。mapview本身不会自动对同位置的重复要素做数值聚合,渲染时上层绘制的要素会直接覆盖下层要素,最终视觉上就只显示数据集最后一条记录的数值。

修复方案

核心修复逻辑是在传入mapview绘图前,先按空间位置对气温值做聚合计算,不要直接把原始长表数据丢给绘图函数。额外建议补充年、月筛选控件,否则直接对40年所有数据求均值没有实际分析意义。

  • 第一步:UI端补充时间筛选控件
    在原有文件上传控件下方,新增年份、月份选择器,让用户可以指定要查看的时间范围:
    # 加在sidebarPanel内fileInput控件的下方
    selectInput(inputId = "sel_year", label = "选择年份", choices = NULL),
    selectInput(inputId = "sel_month", label = "选择月份", 
                choices = c("全年" = 0, 1:12), selected = 0)
    
  • 第二步:修正Server端数据读取、聚合、渲染逻辑
    首先补全shapefile读取逻辑(原代码里的Read_Shapefile未定义,会直接报错),然后新增数据过滤、聚合步骤,最后用聚合后的数据绘图:
    server = function(input, output, session) {
      # 读取上传的shapefile
      Temp_map = reactive({
        req(input$filemap)
        # 从上传的多文件中找到.shp后缀的主文件路径
        shp_path = input$filemap$datapath[grep("\\.shp$", input$filemap$name)]
        st_read(shp_path, quiet = TRUE)
      })
      
      # 初始化下拉选项
      observe({
        req(Temp_map())
        dff = Temp_map()
        # 更新年份选项
        updateSelectInput(session, "sel_year", choices = sort(unique(dff$year)))
        # 更新气温变量选项,匹配数据里实际存在的气温字段
        updateSelectInput(session, "Temp", 
                          choices = names(dff)[grepl("tmean|tmin|tmax", names(dff), ignore.case = T)],
                          selected = "tmean")
      })
      
      # 按筛选条件聚合空间数据
      agg_map_data = reactive({
        req(Temp_map(), input$sel_year, input$sel_month, input$Temp)
        raw_df = Temp_map()
        
        # 按选中年份过滤
        filter_df = raw_df %>% filter(year == as.integer(input$sel_year))
        # 选了具体月份就加月份过滤,选全年就不过滤月份
        if (as.integer(input$sel_month) != 0) {
          filter_df = filter_df %>% filter(month == as.integer(input$sel_month))
        }
        
        # 按几何位置分组,对选中的气温变量求均值
        agg_df = filter_df %>%
          group_by(geometry) %>%
          summarise(
            temp_val = mean(.data[[input$Temp]], na.rm = TRUE),
            city = first(CITYNAME),
            .groups = "drop"
          )
        agg_df
      })
      
      # 渲染地图
      output$mapview = renderLeaflet({
        req(agg_map_data())
        plot_map = mapview(
          agg_map_data(),
          zcol = "temp_val",
          layer.name = input$Temp,
          col.regions = colorRampPalette(brewer.pal(9, "YlOrRd")),
          popup = ~paste0("城市: ", city, "<br>气温: ", round(temp_val, 2))
        )
        plot_map@map
      })
    }
    
  • 可选优化
    如果你需要绘制面状的分级统计图,可以先准备对应区域的行政边界sf对象,用st_join把气温点数据和行政边界做空间连接,再按行政单元分组聚合气温值后绘图,展示效果会比点要素更符合常规分级统计图的样式。如果不需要时间维度筛选,只要去掉时间过滤的代码,直接对全量数据按几何位置聚合即可。
注意事项
  • 聚合计算时必须加na.rm = TRUE参数,否则数据中存在缺失值会导致整组均值返回NA,出现地图空白的问题。
  • 上传shapefile时必须把.shp、.dbf、.shx、.prj等所有同名文件同时选中上传,否则会出现读取失败的问题。
  • 如果同位置点的统计需求不是求均值,只要把summarise里的mean()换成median()、max()等其他统计函数即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:57:15