I'm adapting code for a map made by someone else that uses a package concaveman
to generate concave hulls from points. The goal is to plot a number of different polygons in the oceans, and to color-code them by a grouping variable. The code works great to make a map of all the polygons and color-code them by identity:
library(sf)
library(concaveman)
library(data.table)
library(ggplot2)
dat <- data.table(longitude = c(-131.319783, -131.141266, -131.08165, -131.079066, -130.894966,
-131.063783, -131.10855, -131.215533, -131.189816, -131.14565,
-131.200866, -131.046466, -130.94055, -130.928983, -130.7513,
-130.8406, -130.833433, -130.830666, -130.82205, -130.89, -63.3666666666667,
-63.3666666666667, -63.1666666666667, -64.1833333333333, -63.3166666666667,
-63.3, -63.85, -63.9333333333333, -63.9333333333333, -63.5833333333333,
-63.5833333333333, -63.7, -63.7, -63.2833333333333, -63.5833333333333,
-63.95, -64.1833333333333, -63.8833333333333, -63.8, -63.2166666666667,
-5.6788, -5.4408, -5.6835, -5.424, -5.6475, -5.4371, -5.6181,
-5.4446, -5.6753, -5.4366, -5.6746, -5.4448, -5.6642, -5.4411,
-5.666, -5.4408, -5.624, -5.4321, -5.6806, -5.4473),
latitude = c(52.646633, 52.589683, 52.556516, 52.559816, 52.402916, 52.5983,
52.554216, 52.550883, 52.539166, 52.658216, 52.627966, 52.481733,
52.486033, 52.469033, 52.469166, 52.261833, 52.292133, 52.301066,
52.3523, 52.366966, 48.4666666666667, 48.4666666666667, 48.65,
49.0166666666667, 48.8166666666667, 48.8166666666667, 49.1, 48.8666666666667,
48.8666666666667, 48.8, 48.8166666666667, 48.4833333333333, 48.4833333333333,
48.8, 48.8166666666667, 48.8833333333333, 49.05, 49.0833333333333,
48.7166666666667, 48.6666666666667, 54.7201, 54.6033, 54.7191,
54.5733, 54.7225, 54.5923, 54.7261, 54.6076, 54.719, 54.5978,
54.7195, 54.6108, 54.7204, 54.6062, 54.7214, 54.5923, 54.7275,
54.592, 54.7207, 54.6188),
group = c(rep('NEPac',20),rep('NWAtl',20),rep('NEAtl',20))
)
split <- split(dat, dat$group)
split.sf <- lapply(split, st_as_sf, coords = c("longitude", "latitude"))
concave <- lapply(split.sf, concaveman, concavity = 3, length_threshold = 2)
concave.binded <- do.call('rbind', concave)
concave.spdf <- as_Spatial(concave.binded)
ggplot()
geom_polygon(data = concave.spdf,
aes(x = long, y = lat, group = group, fill = group, color = group))
However, I can't figure out how to fill the polygons by anything other than whatever group
is. Here is my attempt:
concave.spdf$ocean <- c('P','A','A')
ggplot()
geom_polygon(data = concave.spdf,
aes(x = long, y = lat, group = group, fill = ocean, color = ocean))
Which throws this error: Error in FUN(X[[i]], ...) : object 'ocean' not found
I think the issue is that split
groups the polygons by identity when passed to concaveman
, but if I change that, they won't plot correctly (because the points of different polygons will be merged). How do I keep the polygons plotted individually but color them by a grouping variable? (If it's possible I'd prefer to stick with concaveman
for aesthetic reasons in the true plot [which is much more complicated than this reprex] -- I know that if I use a different approach to plotting the polygons this would be easier.)
CodePudding user response:
The simplest way to do this is by adding a scale_fill_manual
:
ggplot()
geom_polygon(data = concave.spdf,
aes(x = long, y = lat, group = group, fill = group))
scale_fill_manual(values = c("red", "green", "blue"),
labels = c("Ocean 1", "Ocean 2", "Ocean 3"))
Arguably, a better method is to convert to a simple features collection, to which you can add any columns you like, and automatically plot with geom_sf
concave.spdf <- st_as_sf(concave.spdf)
concave.spdf$ocean <- c("Ocean 1", "Ocean 2", "Ocean 3")
ggplot(concave.spdf)
geom_sf(aes(fill = ocean))
Note that this automatically gives the correct co-ordinate proportions too.