使用ggplot/基础plot绘制多折线图追踪沿海房屋价格涨幅
房屋价格涨幅多折线图绘制问题
需求背景
需要展示某沿海区域约50套房屋自90年代以来的价格涨幅,现有数据为宽格式表格:57行(对应单套房屋)、40列(对应1983-2023各年份),每套房屋仅在2-5个年份有交易记录(其余为NA)。目标是绘制多折线图,每条折线代表一套房屋,X轴为年份,Y轴为成交价,需体现整体涨幅趋势。
当前遇到的问题
使用R基础绘图时,模拟数据能正常生成带折线的图,但代入真实数据后,折线消失仅显示散点:
years <- c(1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023) xx <- c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 330000, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 599000, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA) xxx <- c(NA, NA, NA, NA, NA, NA, NA, NA, 325000, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 621000, NA, NA, NA, NA, NA, 704000, NA, NA, NA, 100000000, NA, NA, NA, 100000000, NA, NA) plot(years, xx, type="o", col = "blue", pch="o", ylab="成交价",lty="solid") points(years, xxx, col="red", pch="o") lines(years, xxx, col="green", lty=2)
原因是lines()函数遇到NA会直接中断折线,而真实数据中NA占比极高,导致折线无法连续绘制。
解决方案
方案1:使用ggplot2(推荐)
ggplot2更适合处理这类带缺失值的多组数据,核心是先将宽格式数据转换为长格式:
- 构造示例宽格式数据(模拟真实表格):
set.seed(123) house_data <- data.frame( house_id = paste0("House_", 1:5), `1983` = c(NA, NA, 250000, NA, NA), `1992` = c(330000, NA, NA, 380000, NA), `2007` = c(NA, 621000, 580000, NA, 650000), `2013` = c(599000, 704000, NA, 720000, NA), `2017` = c(NA, NA, 850000, NA, 900000), `2023` = c(750000, 880000, NA, 950000, 1020000) )
- 转换为长格式:
library(tidyr) library(ggplot2) long_data <- house_data %>% pivot_longer(cols = -house_id, names_to = "year", values_to = "price") %>% mutate(year = as.integer(year)) %>% drop_na(price) # 去除价格为NA的行
- 绘制多折线图:
ggplot(long_data, aes(x = year, y = price, group = house_id, color = house_id)) + geom_line(alpha = 0.6) + # 降低透明度,避免线条重叠过乱 geom_point(size = 2) + labs(x = "年份", y = "成交价", title = "沿海区域房屋价格涨幅趋势") + theme_minimal() + theme(legend.position = "bottom") # 图例放底部,节省空间
若需突出整体趋势,可添加LOESS拟合的趋势线:
ggplot(long_data, aes(x = year, y = price)) + geom_line(aes(group = house_id, color = house_id), alpha = 0.4) + geom_point(size = 1.5) + geom_smooth(method = "loess", se = FALSE, color = "black", size = 1.2) + # 整体趋势线 labs(x = "年份", y = "成交价", title = "沿海区域房屋价格涨幅趋势(含整体趋势)") + theme_minimal() + theme(legend.position = "none") # 不需要单房屋图例可隐藏
方案2:修正R基础绘图
核心是对每套房屋的数据先过滤NA,只保留有交易记录的年份和价格,再绘制折线:
# 定义函数:绘制单套房屋的折线和点 plot_house <- function(years, prices, col, lty) { valid_idx <- !is.na(prices) valid_years <- years[valid_idx] valid_prices <- prices[valid_idx] points(valid_years, valid_prices, col = col, pch = "o") lines(valid_years, valid_prices, col = col, lty = lty) } # 初始化画布 plot(years, xx, type = "n", ylab = "成交价", xlab = "年份", ylim = c(min(c(xx, xxx), na.rm = TRUE), max(c(xx, xxx), na.rm = TRUE))) # 绘制第一套房屋 valid_idx_xx <- !is.na(xx) points(years[valid_idx_xx], xx[valid_idx_xx], col = "blue", pch = "o") lines(years[valid_idx_xx], xx[valid_idx_xx], col = "blue", lty = "solid") # 绘制第二套房屋(用函数简化) plot_house(years, xxx, col = "green", lty = 2)
批量绘制57套房屋可通过循环实现:
# 假设真实数据框为house_df,第一列是房屋ID,其余为年份列 house_prices <- as.list(house_df[, -1]) colors <- rainbow(length(house_prices)) # 生成区分颜色 # 初始化画布 plot(years, house_prices[[1]], type = "n", ylab = "成交价", xlab = "年份", ylim = range(unlist(house_prices), na.rm = TRUE)) # 循环绘制每套房屋 for (i in seq_along(house_prices)) { plot_house(years, house_prices[[i]], col = colors[i], lty = 1) }
内容的提问来源于stack exchange,提问作者PhobixPhobix
相关产品推荐
相关产品推荐

