Turns out to be more work then I have expected, but here is my solution. The basic idea is to use the maps::map function along with boundary = TRUE and interior = FALSE to get the coordinates of "north dekota" and "south dekota" without the interior boundary and plot that separately from other states.
Step 1: Grab "megakotas" coordinates...
# To install gissr
# library(devtools)
# Install dependency
# install_github("skgrange/threadr")
# Install gissr
# install_github("skgrange/gissr")
library(dplyr)
library(maps)
library(gissr)
us_coord <- map_data("state")
megakotas_coord <- map("state", regions = c("north dakota", "south dakota"),
boundary = TRUE, interior = FALSE, plot = FALSE)[c("x", "y")] %>%
as.data.frame() %>%
sort_points(y = "y", x = "x") %>%
mutate(region = "megakotas")
Output:
> head(megakotas_coord)
x y region
1 -104.0491 45.21210 megakotas
2 -104.0434 45.87673 megakotas
3 -104.0491 45.93976 megakotas
4 -104.0491 45.93976 megakotas
5 -104.0434 46.27207 megakotas
6 -104.0434 46.53563 megakotas
Here, we use gissr::sort_points to sort the coordinates from map in clockwise order, then replaced region with "megakotas" instead of "north dakota" and "south dakota".
Step 2: Replace "north dakota" and "south dakota" with "megakotas" in arr and sum their values...
arr <- USArrests %>%
add_rownames("region") %>%
mutate(region = replace(tolower(region), tolower(region) %in% c("north dakota", "south dakota"),
"megakotas")) %>%
group_by(region) %>%
mutate_all(sum)
Output:
> arr %>% filter(region == "megakotas")
# A tibble: 2 x 5
# Groups: region [1]
region Murder Assault UrbanPop Rape
<chr> <dbl> <int> <int> <dbl>
1 megakotas 4.6 131 89 20.1
2 megakotas 4.6 131 89 20.1
Step 3: Plot us_coord and megakotas_coord separately, and use the data argument in geom_map to control what gets printed...
library(ggplot2)
ggplot(mapping = aes(map_id=region)) +
geom_map(data = filter(arr, region != "megakotas"),
map = us_coord, aes(fill = Murder),
size = 0.15, color="#ffffff") +
expand_limits(x = us_coord$long, y = us_coord$lat)

ggplot(mapping = aes(map_id=region)) +
geom_map(data = filter(arr, region == "megakotas"),
map = megakotas_coord, aes(fill = Murder),
size = 0.15, color = "#ffffff") +
expand_limits(x = us_coord$long, y = us_coord$lat)

Final Step: Combine everything...
# To install gissr
# library(devtools)
# Install dependency
# install_github("skgrange/threadr")
# Install gissr
# install_github("skgrange/gissr")
library(ggplot2)
library(dplyr)
library(maps)
library(gissr)
us_coord <- map_data("state")
megakotas_coord <- map("state", regions = c("north dakota", "south dakota"),
boundary = TRUE, interior = FALSE, plot = FALSE)[c("x", "y")] %>%
as.data.frame() %>%
sort_points(y = "y", x = "x") %>%
mutate(region = "megakotas")
arr <- USArrests %>%
add_rownames("region") %>%
mutate(region = replace(tolower(region), tolower(region) %in% c("north dakota", "south dakota"),
"megakotas")) %>%
group_by(region) %>%
mutate_all(sum)
ggplot(mapping = aes(map_id=region, fill = Murder)) +
geom_map(data = filter(arr, region != "megakotas"),
map = us_coord, size = 0.15, color = "#ffffff") +
geom_map(data = filter(arr, region == "megakotas"),
map = megakotas_coord, size = 0.15, color = "#ffffff") +
expand_limits(x = us_coord$long, y = us_coord$lat) +
scale_fill_continuous(low = 'thistle2', high = 'darkred', guide = 'colorbar') +
labs(x=NULL, y=NULL) +
coord_map("albers", lat0 = 39, lat1 = 45) +
theme(panel.border = element_blank(),
panel.background = element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank())

Note: This solution would be much simpler if map_data respects boundary = TRUE and interior = FALSE, which it should according to the documentation of map_data (?map_data clearly says one can pass other arguments to maps::map()). Somehow map_data("state", region = c("north dakota", "south dakota"), boundary = TRUE, interior = FALSE) doesn't seem to work.