在R中制作动态人口金字塔时遇pivot_longer报错求助
R动态人口金字塔制作报错修复
运行制作动态人口金字塔的代码时,出现以下错误:
Error in
pivot_longer():
! Can't select columns past the end.
ℹ Locations 2 and 3 don't exist.
ℹ There is only 1 column.
Runrlang::last_trace()to see where the error occurred.
错误原因
报错核心是pivot_longer(-c(1:3))试图排除前3列,但读取后的数据仅存在1列,说明数据读取环节出现问题:
- 文件路径拼写错误,导致读取内容不符合预期
- CSV文件分隔符不匹配(比如实际用分号分隔,但默认以逗号读取)
- 下载的文件格式损坏或结构与预期不符
解决方案步骤
- 确认文件读取正确性
- 用
file.choose()手动选择文件,避免路径拼写错误 - 读取后执行
str(d)查看数据结构,确认是否包含year、gender、past.future及各年龄列
- 用
- 指定正确的分隔符
- 如果CSV是分号分隔,给
read.csv添加sep=";"参数
- 如果CSV是分号分隔,给
- 修正
pivot_longer列选择逻辑- 确认前3列存在后,使用列名指定更稳妥:
cols = -c(year, gender, past.future)
- 确认前3列存在后,使用列名指定更稳妥:
修正后的完整代码
library(dplyr) library(tidyr) library(stringr) library(gganimate) # 手动选择文件,避免路径错误 d <- read.csv( file.choose(), check.names = FALSE, sep = "," # 若文件为分号分隔,改为sep=";" ) # 检查数据结构,确认列数符合预期 str(d) head(d, n = 3) # 数据整理:用列名指定排除项,避免列索引错误 d.tidy <- d %>% as_tibble() %>% pivot_longer(cols = -c(year, gender, past.future), values_to = "population", names_to = "age") # 调整人口数值:女性为负、男性为正,偏移中心横幅覆盖区域 d.tidy <- d.tidy %>% mutate(population = ifelse(gender == "f", -population - 80, population + 80)) # 设置年龄因子顺序,保证金字塔按年龄排序 d.tidy$age <- factor(d.tidy$age, levels = colnames(d)[-c(1:3)]) # 计算性别间人口差异的最小值,用于高亮显示 d.tidy <- d.tidy %>% group_by(year, age) %>% mutate(pop.min = min(abs(population)), pop.min = ifelse(gender == "m", pop.min, -pop.min)) %>% ungroup() # 生成时间-性别分组,用于区分配色 d.tidy <- d.tidy %>% mutate(time.gender = str_c(past.future, "_", gender)) my.colors <- c("past_m" = "steelblue4", "past_f" = "red4", "future_m" = "steelblue1", "future_f" = "red1") # 基础金字塔绘图 p1 <- d.tidy %>% ggplot(aes(x = age, y = population, fill = time.gender)) + geom_col(position = "identity", width = 1) + coord_flip(clip = "off") + scale_fill_manual(values = my.colors) # 添加性别人口差异高亮层 p2 <- p1 + geom_col(aes(y = pop.min), fill = "white", alpha = .5, width = 1, position = "identity") # 添加中心横幅遮挡重叠区域 p3 <- p2 + annotate(geom = "rect", xmin = -Inf, xmax = Inf, ymin = 80, ymax = -80, fill = "floralwhite") # 在中心横幅添加年龄标签 p4 <- p3 + annotate(geom = "text", x = seq(0, 100, 5), y = 0, label = seq(0, 100, 5), size = 3, fontface = "bold") # 调整坐标轴刻度与标题 breaks <- seq(0, 700, by = 100) breaks.updated <- c(breaks + 80, -breaks - 80) p5 <- p4 + scale_y_continuous( breaks = breaks.updated, labels = function(x) {abs(x) - 80 }) + labs(y = "女性(单位:千) 男性(单位:千) ", title = "模拟年份", subtitle = "{frame_time}") # 优化主题样式 p6 <- p5 + theme_void() + theme( axis.text.x = element_text(size = 10, color = "snow4", margin = margin(t = 5)), axis.title.x = element_text(face = "bold", margin = margin(t = 5, b = 5)), plot.title = element_text(hjust = .1, vjust = -10, size = 10), plot.subtitle = element_text(hjust = .1, vjust = -6, face = "bold", size = 20), legend.position = "none") # 创建年份过渡动画 p7 <- p6 + transition_time(time = year) p7 # 保存动画(自动创建graphics文件夹) dir.create("graphics", showWarnings = FALSE) anim_save(filename = "Population pyramid animation.gif", path = "graphics")
额外提示
- 若运行
str(d)后仍只有1列,打开下载的CSV文件检查表头、分隔符是否正确 - 若文件为Excel格式,改用
readxl::read_excel()读取更稳妥
内容的提问来源于stack exchange,提问作者Ana-Maria
相关产品推荐
相关产品推荐

