如何使用 ggmap 正确连接数据和几何图形
How to properly join data and geometry using ggmap
一图胜一千字:
观察到的行为: 从上图中可以看出,国家名称与其实际几何形状不符。
预期行为: 我想正确连接数据框及其几何图形并在 ggmap 中显示结果。
我以前加入过不同的数据框,但显然 ggmap
需要 "fortify"(实际上我不知道真正的意思)数据框的顺序显示结果。
这是我目前所做的:
library(rgdal)
library(dplyr)
library(broom)
library(ggmap)
# Load GeoJSON file with countries.
countries = readOGR(dsn = "https://gist.githubusercontent.com/ccamara/fc26d8bb7e777488b446fbaad1e6ea63/raw/a6f69b6c3b4a75b02858e966b9d36c85982cbd32/countries.geojson")
# Load dataframe.
df = read.csv("https://gist.githubusercontent.com/ccamara/fc26d8bb7e777488b446fbaad1e6ea63/raw/a6f69b6c3b4a75b02858e966b9d36c85982cbd32/sample-dataframe.csv")
# Join geometry with dataframe.
countries$iso_a2 = as.factor(countries$iso_a2)
countries@data = left_join(countries@data, df, by = c('iso_a2' = 'country_code'))
# Convert to dataframe so it can be used by ggmap.
countries.t = tidy(countries)
# Here's where the problem starts, as by doing so, data has been lost!
# Recover attributes' table that was destroyed after using broom::tidy.
countries@data$id = rownames(countries@data) # Adding a new id variable.
countries.t = left_join(countries.t, countries@data, by = "id")
ggplot(data = countries.t,
aes(long, lat, fill = country_name, group = group)) +
geom_polygon() +
geom_path(colour="black", lwd=0.05) + # polygon borders
coord_equal() +
ggtitle("Data and geometry have been messed!") +
theme(axis.text = element_blank(), # change the theme options
axis.title = element_blank(), # remove axis titles
axis.ticks = element_blank()) # remove axis ticks
虽然你的工作是一个合理的方法 - 我想重新考虑你的设计,主要是因为两个简单的原因:
1) 虽然 GeoJSON 是未来,但 R 仍然严重依赖 sp 包及其对应的 sp* 对象 - 很快你希望早点切换。它只是关于包,其中大部分(如果不是全部)依赖于 sp* 对象。
2) ggplot 结合 ggmap 具有强大的绘图功能 - 但与 sp* 结合 R 的传单等相比,它仍然相当有限
可能最快的方法很简单:
library(sp)
library(dplyr)
library(geojsonio)
library(dplyr)
library(tmap)
#get sp* object instead of geojson
countries <- geojsonio::geojson_read("foo.geojson",what = "sp")
#match sp* object with your data.frame
countries@data <- dplyr::left_join(countries@data, your_df, by =
c("identifier_1" = "identifier_2"))
#creates a fast and nice looking plot / lots of configuration available
p1 <- tm_shape(countries) +
tm_polygons()
p1
#optional interactive leaflet plot
tmap_leaflet(p1)
这是我脑子里写的/如果有小问题请多多包涵。
这是一种不同的方法,但至少在我看来,它现在是 R 中更快、更简洁的方法(希望 geojson 将来会得到更多支持)。
混乱的行为是有原因的。
countries
开始时是一个大型 SpatialPolygonsDataFrame,其中包含 177 个元素(相应地 countries@data
中有 177 行)。当您对 countries@data
和 df
执行 left_join
时,countries
中的元素数不受影响,但 countries@data
中的行数增长到 210.
使用 broom::tidy
强化 countries
将 countries
及其 177 个元素转换为具有 id
运行 从 0 到 176 的数据框。(我不确定为什么它是零索引的,但我通常更喜欢明确指定区域)。
另一方面,基于rownames(countries@data)
将id
添加到countries@data
,结果id
值运行从1到210,因为那是较早加入 df
后 countries@data
中的行数。因此,一切都不同步。
请尝试以下操作:
# (we start out right after loading countries & df)
# no need to join geometry with df first
# convert countries to data frame, specifying the regions explicitly
# (note I'm using the name column rather than the iso_a2 column from countries@data;
# this is because there are some repeat -99 values in iso_a2, and we want
# one-to-one matching.)
countries.t = tidy(countries, region = "name")
# join with the original file's data
countries.t = left_join(countries.t, countries@data, by = c("id" = "name"))
# join with df
countries.t = left_join(countries.t, df, by = c("iso_a2" = "country_code"))
# no change to the plot's code, except for ggtitle
ggplot(data = countries.t,
aes(long, lat, fill = country_name, group = group)) +
geom_polygon() +
geom_path(colour="black", lwd = 0.05) +
coord_equal() +
ggtitle("Data and geometry are fine") +
theme(axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank())
p.s。您实际上不需要 ggmap 包。只是它加载的 ggplot2 包。
一图胜一千字:
观察到的行为: 从上图中可以看出,国家名称与其实际几何形状不符。
预期行为: 我想正确连接数据框及其几何图形并在 ggmap 中显示结果。
我以前加入过不同的数据框,但显然 ggmap
需要 "fortify"(实际上我不知道真正的意思)数据框的顺序显示结果。
这是我目前所做的:
library(rgdal)
library(dplyr)
library(broom)
library(ggmap)
# Load GeoJSON file with countries.
countries = readOGR(dsn = "https://gist.githubusercontent.com/ccamara/fc26d8bb7e777488b446fbaad1e6ea63/raw/a6f69b6c3b4a75b02858e966b9d36c85982cbd32/countries.geojson")
# Load dataframe.
df = read.csv("https://gist.githubusercontent.com/ccamara/fc26d8bb7e777488b446fbaad1e6ea63/raw/a6f69b6c3b4a75b02858e966b9d36c85982cbd32/sample-dataframe.csv")
# Join geometry with dataframe.
countries$iso_a2 = as.factor(countries$iso_a2)
countries@data = left_join(countries@data, df, by = c('iso_a2' = 'country_code'))
# Convert to dataframe so it can be used by ggmap.
countries.t = tidy(countries)
# Here's where the problem starts, as by doing so, data has been lost!
# Recover attributes' table that was destroyed after using broom::tidy.
countries@data$id = rownames(countries@data) # Adding a new id variable.
countries.t = left_join(countries.t, countries@data, by = "id")
ggplot(data = countries.t,
aes(long, lat, fill = country_name, group = group)) +
geom_polygon() +
geom_path(colour="black", lwd=0.05) + # polygon borders
coord_equal() +
ggtitle("Data and geometry have been messed!") +
theme(axis.text = element_blank(), # change the theme options
axis.title = element_blank(), # remove axis titles
axis.ticks = element_blank()) # remove axis ticks
虽然你的工作是一个合理的方法 - 我想重新考虑你的设计,主要是因为两个简单的原因:
1) 虽然 GeoJSON 是未来,但 R 仍然严重依赖 sp 包及其对应的 sp* 对象 - 很快你希望早点切换。它只是关于包,其中大部分(如果不是全部)依赖于 sp* 对象。
2) ggplot 结合 ggmap 具有强大的绘图功能 - 但与 sp* 结合 R 的传单等相比,它仍然相当有限
可能最快的方法很简单:
library(sp)
library(dplyr)
library(geojsonio)
library(dplyr)
library(tmap)
#get sp* object instead of geojson
countries <- geojsonio::geojson_read("foo.geojson",what = "sp")
#match sp* object with your data.frame
countries@data <- dplyr::left_join(countries@data, your_df, by =
c("identifier_1" = "identifier_2"))
#creates a fast and nice looking plot / lots of configuration available
p1 <- tm_shape(countries) +
tm_polygons()
p1
#optional interactive leaflet plot
tmap_leaflet(p1)
这是我脑子里写的/如果有小问题请多多包涵。
这是一种不同的方法,但至少在我看来,它现在是 R 中更快、更简洁的方法(希望 geojson 将来会得到更多支持)。
混乱的行为是有原因的。
countries
开始时是一个大型 SpatialPolygonsDataFrame,其中包含 177 个元素(相应地 countries@data
中有 177 行)。当您对 countries@data
和 df
执行 left_join
时,countries
中的元素数不受影响,但 countries@data
中的行数增长到 210.
使用 broom::tidy
强化 countries
将 countries
及其 177 个元素转换为具有 id
运行 从 0 到 176 的数据框。(我不确定为什么它是零索引的,但我通常更喜欢明确指定区域)。
另一方面,基于rownames(countries@data)
将id
添加到countries@data
,结果id
值运行从1到210,因为那是较早加入 df
后 countries@data
中的行数。因此,一切都不同步。
请尝试以下操作:
# (we start out right after loading countries & df)
# no need to join geometry with df first
# convert countries to data frame, specifying the regions explicitly
# (note I'm using the name column rather than the iso_a2 column from countries@data;
# this is because there are some repeat -99 values in iso_a2, and we want
# one-to-one matching.)
countries.t = tidy(countries, region = "name")
# join with the original file's data
countries.t = left_join(countries.t, countries@data, by = c("id" = "name"))
# join with df
countries.t = left_join(countries.t, df, by = c("iso_a2" = "country_code"))
# no change to the plot's code, except for ggtitle
ggplot(data = countries.t,
aes(long, lat, fill = country_name, group = group)) +
geom_polygon() +
geom_path(colour="black", lwd = 0.05) +
coord_equal() +
ggtitle("Data and geometry are fine") +
theme(axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank())
p.s。您实际上不需要 ggmap 包。只是它加载的 ggplot2 包。