如何用geom_quiver可视化风数据:简化箭头数量及解决箭头大小疑问
嘿,这两个问题我用geom_quiver做气象可视化的时候也踩过坑,给你详细说说解决方案:
问题1:减少箭头数量,用区域平均的大箭头代替密集小箭头
要只放3-5个代表区域平均的大箭头,核心思路是先把你的风速风向数据按五大湖的区域分组,计算每组的平均经纬度、平均风速、平均风向,再用汇总后的结果画箭头。这里有两种实用方法:
方法1:手动划分区域(适合对五大湖熟悉的情况)
你可以根据五大湖的地理范围,把经纬度切成3-5个区间,或者直接按湖划分(比如苏必利尔湖、密歇根湖等各一组),然后用dplyr做分组汇总:
library(dplyr) library(ggplot2) # 假设你的原始数据是df,包含lon(经度)、lat(纬度)、wind_speed(风速)、wind_dir(风向,单位度) # 手动按五大湖划分区域(这里示例用经度切分,你可以换成更精准的分组逻辑) df$lake_region <- cut(df$lon, breaks = 5, labels = c("苏必利尔湖", "密歇根湖", "休伦湖", "伊利湖", "安大略湖")) # 按区域计算平均值 summary_df <- df %>% group_by(lake_region) %>% summarize( avg_lon = mean(lon), avg_lat = mean(lat), avg_wind_speed = mean(wind_speed), avg_wind_dir = mean(wind_dir) ) %>% # 把风向转换成u/v分量(geom_quiver需要的是x/y方向的向量) mutate( u = avg_wind_speed * cos(avg_wind_dir * pi/180), v = avg_wind_speed * sin(avg_wind_dir * pi/180) ) # 绘制地图+大箭头 ggplot() + # 先叠加五大湖的底图(假设你有对应的sf格式数据great_lakes_sf) geom_sf(data = great_lakes_sf, fill = "#a8d1ff") + # 用汇总后的平均数据画大箭头,手动调大size让箭头更醒目 geom_quiver( data = summary_df, aes(x = avg_lon, y = avg_lat, u = u, v = v, color = avg_wind_speed), size = 3, # 控制箭杆的粗细和长度基础值 vecsize = 0.3 # 控制箭头头部与箭杆的比例,数值越小箭头头部相对越小 ) + scale_color_viridis_c(name = "平均风速")
方法2:自动聚类分组(适合不想手动划分的情况)
用k-means聚类对经纬度进行分组,自动生成3-5个区域,代码更灵活:
set.seed(123) # 设置随机种子保证结果可重复 # 对经纬度做k-means聚类,分成5组 clusters <- kmeans(df[, c("lon", "lat")], centers = 5) df$cluster <- as.factor(clusters$cluster) # 按聚类组汇总数据 summary_df <- df %>% group_by(cluster) %>% summarize( avg_lon = mean(lon), avg_lat = mean(lat), avg_wind_speed = mean(wind_speed), avg_wind_dir = mean(wind_dir) ) %>% mutate( u = avg_wind_speed * cos(avg_wind_dir * pi/180), v = avg_wind_speed * sin(avg_wind_dir * pi/180) ) # 后续绘图代码和上面一致
问题2:部分箭头尺寸过小,搞懂vecsize参数的真实作用
你困惑的点其实是把vecsize的功能理解错了——vecsize控制的是箭头头部和箭杆的比例,不是箭杆本身的长度!
为什么部分箭头小?
箭头的整体视觉大小主要由u和v的数值决定(也就是风速转换后的x/y向量分量):如果某个点的风速很小,那么u和v的数值就会很小,箭杆自然短,看起来整个箭头就小。vecsize只是调整箭头头部的长度相对于箭杆长度的比例,比如vecsize=0.3意味着箭头头部的长度是箭杆长度的30%,箭杆短的话,箭头头部也会跟着变小。
解决方案
根据你的需求,有两种调整方式:
缩放向量分量,让小风速的箭头也能看清
手动给u和v乘以一个系数,放大所有箭头的基础长度:df <- df %>% mutate( # 乘以0.5是示例系数,你可以根据你的数据范围调整,比如风速单位是m/s的话,乘1-2都可以 u = wind_speed * 0.5 * cos(wind_dir * pi/180), v = wind_speed * 0.5 * sin(wind_dir * pi/180) )然后绘图时再配合调整vecsize,让箭头头部比例合适:
geom_quiver( aes(x = lon, y = lat, u = u, v = v, color = wind_speed), vecsize = 0.25, # 小风速箭头的头部也不会太突兀 alpha = 0.8 )统一箭杆长度,用颜色单独表示风速
如果不需要用箭杆长度体现风速,只需要颜色区分,可以把向量转换成单位向量(方向不变,长度统一),然后用size参数固定箭杆粗细:df <- df %>% mutate( # 计算单位向量 dir_rad = wind_dir * pi/180, u = cos(dir_rad), v = sin(dir_rad) ) ggplot() + geom_sf(data = great_lakes_sf) + geom_quiver( data = df, aes(x = lon, y = lat, u = u, v = v, color = wind_speed), size = 1.5, # 统一箭杆粗细 vecsize = 0.3 ) + scale_color_viridis_c(name = "风速")
另外补充下vecsize的官方说明:默认NULL时,如果你的数据是规则网格(比如经纬度间隔一致的格点数据),ggplot会自动调整vecsize避免箭头重叠;如果是不规则散点数据,就用默认比例(大概0.2),这时候手动设置固定值会更可控。
内容的提问来源于stack exchange,提问作者ixodid

