问题
I am trying to use facet_wrap in ggplot2 to map a different state into each facet of a multi-faceted plot. My code is listed here, where 'dataset' is a data frame containing a variable named 'state', which contains the names of the different states I want mapped by facet.
library(maps)
library(ggplot2)
states <- c('Oklahoma','Arizona','Washington','North
Dakota','Michigan','Florida')
map <- ggplot(data=datatest) + geom_polygon(data=map_data
('state',region=datatest$state),aes
(x=long,y=lat,group=group),colour='black',fill='white') +
facet_wrap(~state,ncol=3)
I'm not able to get each facet to be a map of a different state. Instead, each facet is a map of the whole United States with the six listed states appearing on it. If anyone knows of a way to get this to work where each facet is a different state by itself, I would greatly appreciate it. I'm pretty sure it has to do with how the 'region' is defined in the call to map_data, but nothing I've tried is working. It's possible this can't be done, but I thought I'd see if anyone has an idea. Thank you!
回答1:
The column state
is not present in the return from map_data
. There, the column you are looking for is called region
. Further, at least in your example, there is no data being plotted from the datatest
data. So, you can omit it.
This code should work. Note that I added scales = "free"
because I am assuming that you want each state to fill it's corresponding facet.
ggplot(map_data('state',region=states)
, aes(x=long,y=lat,group=group)) +
geom_polygon(colour='black',fill='white') +
facet_wrap(~region
, scales = "free"
, ncol=3)
Gives
Note that the aspect ratios are going to be off using facet_wrap
because the facets can't handle the coord_map
controls. To make the plot better, I would suggest making each state map separately and then using plot_grid
from cowplot
to stitch them together. Note that cowplot
loads a default theme, so you will want to either reset your default (with theme_set
) or explicitly set a theme for the plots (as I do here):
sepStates <-
lapply(states, function(thisState){
ggplot(map_data('state',region=thisState)
, aes(x=long,y=lat,group=group)) +
geom_polygon(colour='black',fill='white') +
facet_wrap(~region) +
coord_map() +
theme_void()
})
library(cowplot)
plot_grid(plotlist = sepStates)
gives
If you want to include data from another source, you will need to make sure that it is compatible. In particular, you need to make sure that the column you want to be facetting based on is called the same thing in both.
Let's imagine you have the following data that you want to add to the plot:
datatest <-
structure(list(zip = c("85246", "85118", "85340", "34958", "33022",
"32716", "49815", "48069", "48551", "58076", "58213", "58524",
"73185", "74073", "73148", "98668", "98271", "98290"), city = c("Chandler",
"Gold Canyon", "Litchfield Park", "Jensen Beach", "Hollywood",
"Altamonte Springs", "Channing", "Pleasant Ridge", "Flint", "Wahpeton",
"Ardoch", "Braddock", "Oklahoma City", "Sperry", "Oklahoma City",
"Vancouver", "Marysville", "Snohomish"), state = c("AZ", "AZ",
"AZ", "FL", "FL", "FL", "MI", "MI", "MI", "ND", "ND", "ND", "OK",
"OK", "OK", "WA", "WA", "WA"), latitude = c(33.276539, 33.34,
33.50835, 27.242402, 26.013368, 28.744752, 46.186913, 42.472235,
42.978995, 46.271839, 48.204374, 46.596608, 35.551409, 36.306323,
35.551409, 45.801586, 48.093129, 47.930902), longitude = c(-112.18717,
-111.42, -112.40523, -80.224613, -80.144217, -81.22328, -88.04546,
-83.14051, -83.713124, -96.608142, -97.30774, -100.09497, -97.407537,
-96.02081, -97.407537, -122.520347, -122.21614, -122.03976)), .Names = c("zip",
"city", "state", "latitude", "longitude"), row.names = c(NA,
-18L), class = c("tbl_df", "tbl", "data.frame"))
which looks like this:
zip city state latitude longitude
<chr> <chr> <chr> <dbl> <dbl>
1 85246 Chandler AZ 33.27654 -112.18717
2 85118 Gold Canyon AZ 33.34000 -111.42000
3 85340 Litchfield Park AZ 33.50835 -112.40523
4 34958 Jensen Beach FL 27.24240 -80.22461
5 33022 Hollywood FL 26.01337 -80.14422
6 32716 Altamonte Springs FL 28.74475 -81.22328
7 49815 Channing MI 46.18691 -88.04546
8 48069 Pleasant Ridge MI 42.47223 -83.14051
9 48551 Flint MI 42.97899 -83.71312
10 58076 Wahpeton ND 46.27184 -96.60814
11 58213 Ardoch ND 48.20437 -97.30774
12 58524 Braddock ND 46.59661 -100.09497
13 73185 Oklahoma City OK 35.55141 -97.40754
14 74073 Sperry OK 36.30632 -96.02081
15 73148 Oklahoma City OK 35.55141 -97.40754
16 98668 Vancouver WA 45.80159 -122.52035
17 98271 Marysville WA 48.09313 -122.21614
18 98290 Snohomish WA 47.93090 -122.03976
If you want to facet on the state, you need to make it into the same format (i.e., full name and lower case) as in the map data and call the column the same thing (region
instead of state). In addition, it is easest if you make the column names all the same as well. Here, I am adding columns to match the three that are being plotted from the map_data
and adding a region
column that will allow the facetting:
stateList <-
setNames(tolower(state.name), state.abb)
datatest$lat <- datatest$latitude
datatest$long <- datatest$longitude
datatest$group <- NA
datatest$region <- stateList[datatest$state]
Now, you can add a geom_point()
line to the plot, and it will facet correctly:
ggplot(map_data('state',region=states)
, aes(x=long,y=lat,group=group)) +
geom_polygon(colour='black',fill='white') +
geom_point(data = datatest) +
facet_wrap(~region
, scales = "free"
, ncol=3)
Gives
Or, you can add it to the cowplot
approach (note that I am just titling now and skipping the facetting).
sepStates <-
lapply(states, function(thisState){
ggplot(map_data('state',region=thisState)
, aes(x=long,y=lat,group=group)) +
geom_polygon(colour='black',fill='white') +
geom_point(data = datatest[datatest$region == tolower(thisState), ]) +
ggtitle(thisState) +
coord_map() +
theme_void() +
theme(plot.title = element_text(hjust = 0.5))
})
plot_grid(plotlist = sepStates)
gives
来源:https://stackoverflow.com/questions/44814768/mapping-different-states-in-r-using-facet-wrap