ggplot面积图无法正确呈现数据问题求助
问题描述
从UN Comtrade获取并汇总贸易数据,自定义ns_eu_category字段划分世界区域。将各贸易部门数值转换为百分比后,用ggplot绘制面积图时出现异常:SITC Code 0(食品及活畜)类别出现无数据空白段,但单独绘制该类别的折线图显示其数值从未为0,其他区域也存在相同问题。
数据结构
> longterm_trade_data # A tibble: 7,364 × 6 ns_eu_category year sitc_code import_or_export value sector <chr> <dbl> <chr> <chr> <dbl> <chr> 1 East Asia and Pacific 1962 0 Export 946694358 Food And Live Animals 2 East Asia and Pacific 1962 0 Import 745286120 Food And Live Animals # ℹ 7,354 more rows
数据处理代码
trade_data_sector <- longterm_trade_data %>% group_by(ns_eu_category, year, import_or_export) %>% mutate(total_of_sectors = sum(value)) %>% ungroup() %>% drop_na() %>% mutate(percent = value / total_of_sectors)
面积图绘制代码
region <- "Sub-Saharan Africa" ix <- "Export" trade_data_sector %>% mutate(truncated_name = sector %>% substr(0L, 10L), descriptor = paste0(sitc_code, ": ", truncated_name)) %>% filter(ns_eu_category == region, import_or_export == ix) %>% ggplot(aes(x = year, y = percent, fill = descriptor)) + geom_area() + theme_minimal() + labs(title = paste0(import_or_export, "s in ", region, " Over Time"), caption = "Source: UN COMTRADE Database 1962-2023") + scale_y_continuous(breaks = seq(from = 0, to = 1, by = 0.1), labels = scales::percent, limits = c(0, 1)) + scale_x_discrete(limits = 1962:2023, expand = c(0,0)) + theme( axis.ticks.x=element_line(linewidth=0.2), axis.text.x = element_text(size = 6, family=my_font, angle=-90, vjust=0.5), axis.title.x = element_text(size = 8, family=my_font), axis.text.y=element_text(size = 6, family=my_font), axis.title.y = element_text(size = 8, family=my_font), panel.grid = element_blank(), legend.position="bottom", plot.title = element_text(size = 12, family=my_font), plot.subtitle = element_text(size = 10, family=my_font), legend.title = element_text( size=8, family=my_font), legend.text = element_text( size=8, family=my_font), strip.text = element_text(size=8, family=my_font), legend.key.size = unit(0.3, "cm"), plot.caption = element_text(size = 7, color="dark gray", family=my_font) )
单类别折线图代码
sector_code <- "0" trade_data_sector %>% filter(ns_eu_category == region, import_or_export == ix, sitc_code == sector_code) %>% ggplot(aes(x = year, y = value)) + geom_line() + theme_minimal() + labs(title = paste0(import_or_export, "s in ", region, " Over Time (Sector ", sector, ")"), caption = "Source: UN COMTRADE Database 1962-2023") + scale_x_discrete(limits = 1962:2022) + theme( panel.grid.major.y = element_line(color = "dark gray", linewidth = 0.1, linetype = "dashed"), axis.text.x = element_text(size = 6, family=my_font, angle=-90, vjust=0.5), axis.title.x = element_text(size = 8, family=my_font), axis.text.y=element_text(size = 6, family=my_font), axis.title.y = element_text(size = 8, family=my_font), panel.grid = element_blank(), legend.position="bottom", plot.title = element_text(size = 10, family=my_font), plot.subtitle = element_text(size = 8, family=my_font), legend.title = element_text( size=8, family=my_font), legend.text = element_text( size=8, family=my_font), strip.text = element_text(size=8, family=my_font), legend.key.size = unit(0.3, "cm"), plot.caption = element_text(size = 7, color="dark gray", family=my_font) )
排查与解决思路
1. 核心原因:缺失年份-部门的完整数据组合
geom_area要求每个年份下所有分组(即descriptor对应的部门)都存在数据,否则会出现空白断层。而原始数据中可能存在某年份下某个部门没有记录行的情况(并非value为0,而是数据缺失):
- 折线图
geom_line只需要该部门有数据的年份即可连线,因此不会显示空白; - 面积图需要所有部门在同一年份都有数据才能堆叠,缺失的部门会导致堆叠中断,出现空白。
2. 解决步骤
(1)补全所有数据组合
使用tidyr::complete()函数补全ns_eu_category、year、import_or_export、sitc_code的所有可能组合,缺失的value填充为0,确保每个年份每个部门都有数据:
library(tidyr) trade_data_sector <- longterm_trade_data %>% # 补全所有维度的组合,缺失value填0 complete(ns_eu_category, year, import_or_export, sitc_code, fill = list(value = 0)) %>% group_by(ns_eu_category, year, import_or_export) %>% mutate(total_of_sectors = sum(value)) %>% ungroup() %>% # 避免总贸易额为0时的除以0错误 mutate(percent = ifelse(total_of_sectors == 0, 0, value / total_of_sectors))
(2)修正x轴的离散化设置
year字段是数值型(<dbl>),用scale_x_discrete会强制将其转为离散值,若数据中存在年份缺失,会导致x轴出现空白。改为使用scale_x_continuous更合适:
# 在面积图代码中替换x轴设置 scale_x_continuous(breaks = seq(1962, 2023, by = 5), limits = c(1962, 2023), expand = c(0,0))
(3)修复折线图的变量错误
单类别折线图的标题中使用了未定义的sector变量,应改为sector_code:
labs(title = paste0(import_or_export, "s in ", region, " Over Time (Sector ", sector_code, ")"), caption = "Source: UN COMTRADE Database 1962-2023")
3. 验证逻辑
补全数据后,每个年份下所有部门都有对应的percent值(即使为0),geom_area可以正常堆叠,不会出现空白段;同时x轴使用连续型刻度,与year的数值类型匹配,避免离散化导致的异常。
内容的提问来源于stack exchange,提问作者saladmobster
相关产品推荐
相关产品推荐

