我想使用带有
sf
和 ggplot
的变量为 geom_sf
LINESTRING 的不同部分着色。我可以使用 geom_path
做类似的事情,但在 geom_sf
中,类似的方法似乎不起作用。有人可以提供可能的方法吗?
样本数据
library(sf)
library(ggplot2)
library(dplyr)
library(tibble)
df <- tibble(time = seq(1,21),
lon = seq(-50,-30, 1) + rnorm(n = 21),
lat = seq(10, 20, 0.5) + rnorm(n = 21),
type = c(rep('A',5),rep('B',10), rep('A',6)))
使用 tibble/dataframe:
使用 tibble 和基本的 ggplot 我可以做到这一点,合并
group = 1
,并且将用 type
着色的不同部分绘制一条线。这是我想要制作的绘图类型,但使用 sf
对象代替。
ggplot() +
geom_path(data = df,
aes(lon, lat, color = type, group = 1))
使用
sf
对象/LINESTRING
如果我使用
group_by
和 type
投射到 LINESTRING,我最终会得到两个 LINESTRINGs
df_sf <- st_as_sf(df, coords = c('lon','lat')) %>%
st_set_crs(.,value = 4326) %>%
group_by(type) %>%
summarize(do_union = TRUE) %>%
st_cast(.,'LINESTRING')
然后,当我对下面的代码进行修改时,我最终得到两条单独的线,并且 type = A 的两个部分被连接起来。
ggplot() +
geom_sf(data = df_sf,
aes(color = type, group = 1))
有没有办法使用
ggplot + geom_path()
方法来实现 geom_sf()
类型行为(这样我就可以投影变量等)?
我找到了一种将线分成段的方法here,但这对于您的用例来说可能有点过分了...
试试这个:
df_sf <- df %>%
# ensure data is sorted along x-axis
arrange(lon) %>%
# detect each time type changes, & create a duplicate point with previous type
mutate(change.type = tidyr::replace_na(lag(type) != type, FALSE)) %>%
mutate(type = ifelse(change.type,
paste(lag(type), type, sep = ";"),
type) %>%
strsplit(";")) %>%
tidyr::unnest(cols = c(type)) %>%
# create new group column that increments with every colour change
mutate(change.type = tidyr::replace_na(lag(type) != type, FALSE)) %>%
mutate(new.type = cumsum(change.type)) %>%
st_as_sf(coords = c('lon', 'lat')) %>%
st_set_crs(., value = 4326) %>%
# group by both original type (for colour) & new type (for group)
group_by(type, new.type) %>%
summarize(do_union = TRUE) %>%
st_cast(.,'LINESTRING') %>%
ungroup()
比较结果
cowplot::plot_grid(
ggplot() +
geom_path(data = arrange(df, lon),
aes(lon, lat, color = type, group = 1), size = 1) +
ggtitle("geom_path approach") +
theme(legend.position = "bottom"),
ggplot() +
geom_sf(data = df_sf,
aes(color = type, group = new.type), size = 1) +
ggtitle("geom_sf approach") +
theme(legend.position = "bottom"),
nrow = 1
)
数据:
set.seed(123)
df <- tibble(time = seq(1,21),
lon = seq(-50,-30, 1) + rnorm(n = 21),
lat = seq(10, 20, 0.5) + rnorm(n = 21),
type = c(rep('A', 5), rep('B', 10), rep('A', 6)))
另一种选择是继续使用
geom_path
来绘制线条,然后使用 coord_sf
将空间坐标系应用于 ggplot:
ggplot() +
geom_path(data = df,
aes(lon, lat, color = type, group = 1)) +
coord_sf(crs = "EPSG:4326")
如果您想将其投影到不同的 CRS 中,请使用
st_transform
投影坐标,然后拉出投影坐标并再次使用 geom_path
绘制它们。
df_projected <-
st_as_sf(df, coords = c("lon", "lat")) |>
st_set_crs("EPSG:4326") |>
st_transform("EPSG:32624") |>
mutate(easting = st_coordinates(geometry)[, "X"],
northing = st_coordinates(geometry)[, "Y"])
ggplot() +
geom_path(data = df_projected,
aes(easting, northing, color = type, group = 1)) +
coord_sf(crs = "EPSG:32624")
数据:
df <- tibble(time = seq(1,21),
lon = seq(-50,-30, 1) + {set.seed(123); rnorm(n = 21)},
lat = seq(10, 20, 0.5) + {set.seed(456); rnorm(n = 21)},
type = c(rep('A',5),rep('B',10), rep('A',6)))