ggplot2绘制密度图/直方图并高亮负值区域及计算占比问题
解决方案
先把原始数据整理成数据框,方便后续处理:
res_cost <- c(1553872.0297353, 3987850.7333411, 3149751.04758742, 139690.256184131, 2659359.58444917, 4424034.10243952, -164716.863161922, 1032117.65430564, 1012016.7065469, 4846572.29657933, 3226129.15792111, 4017430.43881163, 3828193.63192272, 3829708.57524592, 1332388.79071537, 2089023.58090538, 1644671.18495059, 4460304.42245758, 3371828.92991641, 4113191.0440754, 3113751.73357746, 617900.379054606, 1317373.8428064, 6300890.66407368, 3296661.03616896, 4118518.49087673, 4542392.60001633, 2195633.29577509, 3704255.4295885, 3256168.15662825, 3859226.70793027, 4302788.70683497, 1212610.90730169, 1100156.02674204, 3877506.61645749, 2679633.27812409, 3873805.93153843, -260211.296112984, 3245236.76979178, 1287142.02860096, 940739.460417479, 2994090.66052949, 4945187.39388016, 4245739.22159749, 1834826.91901863, 4007125.98655838, 2441363.58320388, 3927976.3634389, 3311368.65232602, 7075557.77947983, 3243219.14157882, 2517657.51519752, 3171624.62320739, 3402860.88835126, 4842785.56583616, 3855876.39565095, 2405788.12178841, 2880195.38919339, 3290479.8769342, 5214395.40981439, 4303049.42485616, 2195917.90046817, 3177092.87433431, 2380356.21216434, 3387837.07527694, 1638340.56836534, 4622169.45155907, 2364584.07782942, 3739518.62696525, 3297125.04237121, 1406550.84702262, 4524851.84638035, 5300405.1815232, 2307646.3613227, 2102213.83460057, 2520455.84518903, 4988206.87073815, 2121162.4699674, 4603996.13556966, 4977903.73829612, 5327575.83245304, 4454316.67896575, 3115751.54495466, 3802810.69212559, -719107.265338242, 879256.548205465, 3757467.72037339, 1397266.77760947, 2683252.17093566, 2267063.20041564, 3507007.12497479, 2671586.12385416, 2883476.2559073, 1646404.25714463, 1480966.75076908, 6262630.29895663, 2270844.80306551, 4490116.75684258, 3300223.17061254, 1470747.71921301) df <- data.frame(res_cost = res_cost)
1. 计算红色高亮区域的占比
直接统计原始数据中≤0的样本比例,比从密度曲线积分更准确:
neg_prop <- mean(df$res_cost <= 0) # 格式化标签,保留两位小数 neg_prop_label <- sprintf("负数值占比: %.2f%%", neg_prop * 100)
后续用annotate把标签加到图上即可。
2. 修复密度图缺失边界
默认geom_density会截断曲线两端,设置trim = FALSE保留完整范围,同时补充边界点让红色区域闭合:
# 绘制完整密度曲线 plt <- ggplot(df, aes(x = res_cost)) + geom_density(fill = "skyblue", trim = FALSE) + theme_minimal() # 获取密度数据 d <- ggplot_build(plt)$data[[1]] # 整理负区间数据,补充x轴底部的点确保区域闭合 d_neg <- subset(d, x <= 0) d_neg <- rbind(d_neg, data.frame(x = 0, y = 0), data.frame(x = min(d_neg$x), y = 0)) d_neg <- d_neg[order(d_neg$x), ] # 最终绘图 p <- plt + geom_area(data = d_neg, aes(x = x, y = y), fill = "red", alpha = 0.7) + geom_segment(x = 0, xend = 0, y = 0, yend = approx(x = d$x, y = d$y, xout = 0)$y, colour = "blue", linewidth = 2) + annotate("text", x = max(df$res_cost)*0.8, y = max(d$y)*0.9, label = neg_prop_label, size = 4, fontface = "bold") print(p)
3. 直方图的红色高亮问题
直方图用geom_area会出现多边形错位,推荐两种方法:
方法一:直接给负数值的柱子上色
# 获取直方图分箱信息 hist_data <- ggplot_build(ggplot(df, aes(res_cost)) + geom_histogram())$data[[1]] ggplot(df, aes(x = res_cost)) + geom_histogram(fill = "skyblue", colour = "black") + geom_histogram(data = subset(df, res_cost <= 0), aes(x = res_cost), fill = "red", alpha = 0.7, colour = "black") + geom_vline(xintercept = 0, colour = "blue", linewidth = 2) + annotate("text", x = max(df$res_cost)*0.8, y = max(hist_data$count)*0.9, label = neg_prop_label, size = 4, fontface = "bold") + theme_minimal()
方法二:用半透明矩形覆盖负半轴
ggplot(df, aes(x = res_cost)) + geom_rect(xmin = -Inf, xmax = 0, ymin = 0, ymax = Inf, fill = "red", alpha = 0.2) + geom_histogram(fill = "skyblue", colour = "black") + geom_vline(xintercept = 0, colour = "blue", linewidth = 2) + annotate("text", x = max(df$res_cost)*0.8, y = max(hist_data$count)*0.9, label = neg_prop_label, size = 4, fontface = "bold") + theme_minimal()
内容的提问来源于stack exchange,提问作者user3483060
相关产品推荐
相关产品推荐

