ggplot2绘制异常等高线图问题咨询及平滑优化求助
ggplot2等高线图异常问题分析与优化方案
问题背景
使用ggplot2绘制的等高线图效果异常,而plotly::plot_ly生成的等高线图更符合预期,需要明确ggplot2方法的问题所在,并优化图表使其更平滑。
用户提供的原始代码及数据集:
library(ggplot2) mydat = structure(list(Col1 = c(65L, 65L, 65L, 65L, 65L, 65L, 65L, 65L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 515L, 515L, 515L, 515L, 515L, 515L, 515L, 515L, 765L, 765L, 765L, 765L, 765L, 765L, 765L, 765L, 1015L, 1015L, 1015L, 1015L, 1015L, 1015L, 1015L, 1015L, 1265L, 1265L, 1265L, 1265L, 1265L, 1265L, 1265L, 1265L, 1515L, 1515L, 1515L, 1515L, 1515L, 1515L, 1515L, 1515L, 2015L, 2015L, 2015L, 2015L, 2015L, 2015L, 2015L, 2015L), Col2 = c(5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 15L), Value = c(0.68378, 0.68815, 0.68754, 0.68887, 0.68742, 0.68857, 0.68758, 0.68789, 0.67, 0.70059, 0.70054, 0.69983, 0.69921, 0.70505, 0.70422, 0.70567, 0.66182, 0.67798, 0.67769, 0.67904, 0.68013, 0.6867, 0.68662, 0.68569, 0.67497, 0.70433, 0.70314, 0.70737, 0.70684, 0.70739, 0.70696, 0.7077, 0.67808, 0.69216, 0.69106, 0.69153, 0.69172, 0.70421, 0.70419, 0.70416, 0.65267, 0.65736, 0.66198, 0.69238, 0.69056, 0.69074, 0.69193, 0.69187, 0.68101, 0.70799, 0.70821, 0.70827, 0.70846, 0.70803, 0.70902, 0.70768, 0.64015, 0.6744, 0.67539, 0.67862, 0.68034, 0.68014, 0.67996, 0.67873)), class = "data.frame", row.names = c(NA, -64L)) ggplot(mydat, aes(Col1, Col2, z = Value)) + geom_raster(aes(fill = Value)) + geom_contour(aes(colour = Value))
用户使用plotly绘制的对比代码:
plotly::plot_ly(x = sort(unique(mydat$Col1)), y = sort(unique(mydat$Col2)), z = matrix(mydat$Value, nr = 8)) %>% plotly::add_surface(contours = list(z = list(show=TRUE,usecolormap=TRUE,highlightcolor="#ff0000",project=list(z=TRUE))))
问题原因
- 数据网格非均匀:Col2的取值为5、6、7、8、9、10、11、15,跳过了12-14,属于非规则离散网格。ggplot2的
geom_contour依赖R基础包的contour()函数,对非均匀网格支持较差,易生成断裂、生硬的等高线;而plotly会自动对非均匀数据进行插值补全,因此效果更平滑。 - 默认无插值处理:ggplot2默认仅基于现有离散点计算等高线,当数据点稀疏或分布不均时,等高线的连续性和平滑度都会受影响。
优化方案
方案1:插值生成均匀网格数据(推荐)
使用akima包对原始数据进行双线性插值,补全缺失的网格点,生成均匀分布的数据集后再绘图:
library(ggplot2) library(akima) library(tidyr) # 生成100x100的均匀网格插值结果 interp_result <- interp( x = mydat$Col1, y = mydat$Col2, z = mydat$Value, xo = seq(min(mydat$Col1), max(mydat$Col1), length.out = 100), yo = seq(min(mydat$Col2), max(mydat$Col2), length.out = 100), linear = TRUE ) # 转换为ggplot可用的数据框格式 interp_df <- as.data.frame(interp_result) interp_df <- pivot_longer(interp_df, cols = -x, names_to = "y", values_to = "Value") interp_df$y <- as.numeric(gsub("V", "", interp_df$y)) # 绘制平滑等高线图 ggplot(interp_df, aes(x, y, z = Value)) + geom_raster(aes(fill = Value), interpolate = TRUE) + # 开启光栅图插值,让颜色过渡更自然 geom_contour(aes(colour = Value), bins = 20) + # 增加bins数量,生成更密集的等高线 scale_fill_viridis_c(option = "plasma") + scale_colour_viridis_c(option = "plasma") + labs(x = "Col1", y = "Col2")
方案2:使用metR包简化处理
metR包针对空间数据可视化优化,对非均匀网格的等高线支持更好,无需手动插值:
library(ggplot2) library(metR) ggplot(mydat, aes(Col1, Col2, z = Value)) + geom_contour_fill(breaks = seq(0.64, 0.71, length.out = 20)) + # 自定义等高线间隔 geom_contour(colour = "white", size = 0.5) + # 添加白色等高线边框增强可读性 scale_fill_viridis_c(option = "plasma") + labs(x = "Col1", y = "Col2")
效果说明
- 插值后的均匀网格数据能让
geom_contour生成连续、平滑的等高线,geom_raster的interpolate=TRUE参数可让填充区域颜色过渡更自然。 - 增加
bins数量(或自定义breaks)能让等高线更细腻,更准确还原数据的变化趋势。
内容的提问来源于stack exchange,提问作者Brian Smith
相关产品推荐
相关产品推荐

