如何将条形图绘制到 ggplot2 地图上
How to plot barchart onto ggplot2 map
我找到了类似这个问题的类似答案,但大多数答案都使用包 rworldmap
、ggmap
、ggsubplot
或 geom_subplot2d
。参见示例 here or here。
我想知道如何将其他 ggplot 对象(例如条形图)绘制到从 shapefile 创建的地图上。我用的那个可以下载here.
编辑
正如@beetroot 正确指出的那样,可以在上面发布的 link 下下载的新文件发生了重大变化。因此调整了shapefile等的名称。
library(rgdal)
library(ggplot2)
library(rgeos)
library(maptools)
map.det<- readOGR(dsn="<path to your directory>/swissBOUNDARIES3D100216/swissBOUNDARIES3D/V200/SHAPEFILE_LV03", layer="VECTOR200_KANTONSGEBIET")
map.kt <- map.det[map.det@data$KANTONSNUM=="CH01000000"|map.det@data$KANTONSNUM=="CH19000000",]
#get centroids
map.test.centroids <- gCentroid(map.kt, byid=T)
map.test.centroids <- as.data.frame(map.test.centroids)
map.test.centroids$KANTONSNR <- row.names(map.test.centroids)
#create df for ggplot
kt_geom <- fortify(map.kt, region="KANTONSNUM")
#Plot map
map.test <- ggplot(NULL)+
geom_polygon(data=kt_geom, aes(long, lat, group=group), fill="white")+
coord_fixed()+
geom_path(data=kt_geom, color="gray48", mapping=aes(long, lat, group=group), size=0.2)+
geom_point(data=map.test.centroids, aes(x=x, y=y), size=9, alpha=6/10)
mapp
这样就产生了这样一张地图。到目前为止,一切都很好。
但是,我在合并两个图时遇到了困难,例如地图 map.test
和这个图:
geo_data <- data.frame(who=rep(c(1:2), each=2),
value=as.numeric(sample(1:100, 4, replace=T)),
KANTONSNR=rep(c(1,19), 2))
bar.testplot <- ggplot()+
geom_bar(data=geo_data, aes(factor(id),value,group=who),position='dodge',stat='identity')
条形图应位于两个多边形的中心,即两个点所在的位置。我可以生成条形图并将它们分别绘制到地图上,如果这样更容易的话。
我对您的代码做了一些修改,使该示例更具说明性。我不仅要绘制 2 个 kanton,还要绘制 47 个。
library(rgdal)
library(ggplot2)
library(rgeos)
library(maptools)
library(grid)
library(gridExtra)
map.det<- readOGR(dsn="c:/swissBOUNDARIES3D/V200/SHAPEFILE_LV03", layer="VECTOR200_KANTONSGEBIET")
map.kt <- map.det[map.det$ICC=="CH" & (map.det$OBJECTID %in% c(1:73)),]
# Merge polygons by ID
map.test <- unionSpatialPolygons(map.kt, map.kt@data$OBJECTID)
#get centroids
map.test.centroids <- gCentroid(map.test, byid=T)
map.test.centroids <- as.data.frame(map.test.centroids)
map.test.centroids$OBJECTID <- row.names(map.test.centroids)
#create df for ggplot
kt_geom <- fortify(map.kt, region="OBJECTID")
#Plot map
map.test <- ggplot(kt_geom)+
geom_polygon(aes(long, lat, group=group), fill="white")+
coord_fixed()+
geom_path(color="gray48", mapping=aes(long, lat, group=group), size=0.2)+
geom_point(data=map.test.centroids, aes(x=x, y=y), size=2, alpha=6/10)
map.test
让我们为条形图生成数据。
set.seed(1)
geo_data <- data.frame(who=rep(c(1:length(map.kt$OBJECTID)), each=2),
value=as.numeric(sample(1:100, length(map.kt$OBJECTID)*2, replace=T)),
id=rep(c(1:length(map.kt$OBJECTID)), 2))
现在制作 47 个条形图,稍后应在 center-points 绘制。
bar.testplot_list <-
lapply(1:length(map.kt$OBJECTID), function(i) {
gt_plot <- ggplotGrob(
ggplot(geo_data[geo_data$id == i,])+
geom_bar(aes(factor(id),value,group=who), fill = rainbow(length(map.kt$OBJECTID))[i],
position='dodge',stat='identity', color = "black") +
labs(x = NULL, y = NULL) +
theme(legend.position = "none", rect = element_blank(),
line = element_blank(), text = element_blank())
)
panel_coords <- gt_plot$layout[gt_plot$layout$name == "panel",]
gt_plot[panel_coords$t:panel_coords$b, panel_coords$l:panel_coords$r]
})
在这里,我们将 ggplot
s 转换为 gtable
s,然后将它们裁剪为只有每个条形图的面板。您可以修改此代码以保留比例、添加图例、标题等。
我们可以在 annotation_custom
的帮助下将此条形图添加到初始地图中。
bar_annotation_list <- lapply(1:length(map.kt$OBJECTID), function(i)
annotation_custom(bar.testplot_list[[i]],
xmin = map.test.centroids$x[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] - 5e3,
xmax = map.test.centroids$x[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] + 5e3,
ymin = map.test.centroids$y[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] - 5e3,
ymax = map.test.centroids$y[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] + 5e3) )
result_plot <- Reduce(`+`, bar_annotation_list, map.test)
我找到了类似这个问题的类似答案,但大多数答案都使用包 rworldmap
、ggmap
、ggsubplot
或 geom_subplot2d
。参见示例 here or here。
我想知道如何将其他 ggplot 对象(例如条形图)绘制到从 shapefile 创建的地图上。我用的那个可以下载here.
编辑
正如@beetroot 正确指出的那样,可以在上面发布的 link 下下载的新文件发生了重大变化。因此调整了shapefile等的名称。
library(rgdal)
library(ggplot2)
library(rgeos)
library(maptools)
map.det<- readOGR(dsn="<path to your directory>/swissBOUNDARIES3D100216/swissBOUNDARIES3D/V200/SHAPEFILE_LV03", layer="VECTOR200_KANTONSGEBIET")
map.kt <- map.det[map.det@data$KANTONSNUM=="CH01000000"|map.det@data$KANTONSNUM=="CH19000000",]
#get centroids
map.test.centroids <- gCentroid(map.kt, byid=T)
map.test.centroids <- as.data.frame(map.test.centroids)
map.test.centroids$KANTONSNR <- row.names(map.test.centroids)
#create df for ggplot
kt_geom <- fortify(map.kt, region="KANTONSNUM")
#Plot map
map.test <- ggplot(NULL)+
geom_polygon(data=kt_geom, aes(long, lat, group=group), fill="white")+
coord_fixed()+
geom_path(data=kt_geom, color="gray48", mapping=aes(long, lat, group=group), size=0.2)+
geom_point(data=map.test.centroids, aes(x=x, y=y), size=9, alpha=6/10)
mapp
这样就产生了这样一张地图。到目前为止,一切都很好。
但是,我在合并两个图时遇到了困难,例如地图 map.test
和这个图:
geo_data <- data.frame(who=rep(c(1:2), each=2),
value=as.numeric(sample(1:100, 4, replace=T)),
KANTONSNR=rep(c(1,19), 2))
bar.testplot <- ggplot()+
geom_bar(data=geo_data, aes(factor(id),value,group=who),position='dodge',stat='identity')
条形图应位于两个多边形的中心,即两个点所在的位置。我可以生成条形图并将它们分别绘制到地图上,如果这样更容易的话。
我对您的代码做了一些修改,使该示例更具说明性。我不仅要绘制 2 个 kanton,还要绘制 47 个。
library(rgdal)
library(ggplot2)
library(rgeos)
library(maptools)
library(grid)
library(gridExtra)
map.det<- readOGR(dsn="c:/swissBOUNDARIES3D/V200/SHAPEFILE_LV03", layer="VECTOR200_KANTONSGEBIET")
map.kt <- map.det[map.det$ICC=="CH" & (map.det$OBJECTID %in% c(1:73)),]
# Merge polygons by ID
map.test <- unionSpatialPolygons(map.kt, map.kt@data$OBJECTID)
#get centroids
map.test.centroids <- gCentroid(map.test, byid=T)
map.test.centroids <- as.data.frame(map.test.centroids)
map.test.centroids$OBJECTID <- row.names(map.test.centroids)
#create df for ggplot
kt_geom <- fortify(map.kt, region="OBJECTID")
#Plot map
map.test <- ggplot(kt_geom)+
geom_polygon(aes(long, lat, group=group), fill="white")+
coord_fixed()+
geom_path(color="gray48", mapping=aes(long, lat, group=group), size=0.2)+
geom_point(data=map.test.centroids, aes(x=x, y=y), size=2, alpha=6/10)
map.test
让我们为条形图生成数据。
set.seed(1)
geo_data <- data.frame(who=rep(c(1:length(map.kt$OBJECTID)), each=2),
value=as.numeric(sample(1:100, length(map.kt$OBJECTID)*2, replace=T)),
id=rep(c(1:length(map.kt$OBJECTID)), 2))
现在制作 47 个条形图,稍后应在 center-points 绘制。
bar.testplot_list <-
lapply(1:length(map.kt$OBJECTID), function(i) {
gt_plot <- ggplotGrob(
ggplot(geo_data[geo_data$id == i,])+
geom_bar(aes(factor(id),value,group=who), fill = rainbow(length(map.kt$OBJECTID))[i],
position='dodge',stat='identity', color = "black") +
labs(x = NULL, y = NULL) +
theme(legend.position = "none", rect = element_blank(),
line = element_blank(), text = element_blank())
)
panel_coords <- gt_plot$layout[gt_plot$layout$name == "panel",]
gt_plot[panel_coords$t:panel_coords$b, panel_coords$l:panel_coords$r]
})
在这里,我们将 ggplot
s 转换为 gtable
s,然后将它们裁剪为只有每个条形图的面板。您可以修改此代码以保留比例、添加图例、标题等。
我们可以在 annotation_custom
的帮助下将此条形图添加到初始地图中。
bar_annotation_list <- lapply(1:length(map.kt$OBJECTID), function(i)
annotation_custom(bar.testplot_list[[i]],
xmin = map.test.centroids$x[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] - 5e3,
xmax = map.test.centroids$x[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] + 5e3,
ymin = map.test.centroids$y[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] - 5e3,
ymax = map.test.centroids$y[map.test.centroids$OBJECTID == as.character(map.kt$OBJECTID[i])] + 5e3) )
result_plot <- Reduce(`+`, bar_annotation_list, map.test)