Splitting line or polygon with sf: st_intersection doesn’t work?

huangapple go评论64阅读模式
英文:

Splitting line or polygon with sf: st_intersection doesn't work?

问题

I'm trying to do the seemingly simple task of split Russia along the Ural mountains, but I must be misunderstanding something basic in sf_intersection. I can't even split the line, much less create two new polygons.

rm(list=ls())
library(rworldmap)
library(tidyverse)
library(sf)

setwd("/Users/mr56267/Documents/UT_web/TLAH_Maps_2023/Mapping_textbook")
world_sp <- fortify(getMap())

world_sf <- world_sp %>%
  st_as_sf(coords = c("long", "lat"), crs = 4326, row.names="group") %>%
  group_by(group) %>%
  summarise(geometry = st_combine(geometry)) %>%
  st_cast("POLYGON")

ggplot() +
  geom_sf(data = world_sf)

world_robinson <- st_transform(world_sf, 
                               crs = '+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs')

Russia.sf <- world_robinson$geometry[which(world_robinson$group=="Russia.1")]
### good to here
### now split Russia on Urals

https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson
Urals.sf <- st_read("https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson")
Urals.sf <- st_transform(Urals.sf, crs = st_crs(world_robinson$geometry[which(world_robinson$group=="Russia.1")]))
Russia_line.sf <- st_cast(Russia.sf,"MULTILINESTRING")

intersection_points <- st_intersection(Russia_line.sf,Urals.sf)
intersection_points
st_intersects(intersection_points,Russia_line.sf)

What's going on here? How can the points created with st_intersection not be points of intersection? Everything looks good:

ggplot() + geom_sf(data=Russia_line.sf) + geom_sf(data=Urals.sf, color="red") + 
  geom_sf(data=intersection_points, color="green")

How do I split Russia into east and west?

英文:

I'm trying to do the seemingly simple task of split Russia along the Ural mountains, but I must be misunderstanding something basic in sf_intersection. I can't even split the line, much less create two new polygons

rm(list=ls())
library(rworldmap)
library(tidyverse)
library(sf)

setwd(&quot;/Users/mr56267/Documents/UT_web/TLAH_Maps_2023/Mapping_textbook&quot;)
world_sp &lt;- fortify(getMap())




world_sf &lt;- world_sp %&gt;% st_as_sf(coords = c(&quot;long&quot;, &quot;lat&quot;), crs = 4326, row.names=&quot;group&quot;) %&gt;%
  group_by(group) %&gt;% summarise(geometry = st_combine(geometry)) %&gt;% st_cast(&quot;POLYGON&quot;)

ggplot() +
  geom_sf(data = world_sf)

world_robinson &lt;- st_transform(world_sf, 
                               crs = &#39;+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs&#39;)



Russia.sf &lt;- world_robinson$geometry[which(world_robinson$group==&quot;Russia.1&quot;)]
### good to here
### now split Russia on Urals

https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson
Urals.sf &lt;- st_read(&quot;https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson&quot;)
Urals.sf &lt;- st_transform(Urals.sf, crs = st_crs(world_robinson$geometry[which(world_robinson$group==&quot;Russia.1&quot;)]))
Russia_line.sf &lt;- st_cast(Russia.sf,&quot;MULTILINESTRING&quot;)

intersection_points &lt;- st_intersection(Russia_line.sf,Urals.sf)
intersection_points
st_intersects(intersection_points,Russia_line.sf)

What's going on here? How can the points created with st_intersection not be points of intersection? Everything looks good:

ggplot() + geom_sf(data=Russia_line.sf) + geom_sf(data=Urals.sf, color=&quot;red&quot;) + 
  geom_sf(data=intersection_points, color=&quot;green&quot;)

How do I split Russia into east and west?

答案1

得分: 3

使用建议中提到的lwgeom::st_split()函数,形式为lwgeom::st_split(POLYGON, LINESTRING)。需要注意的一点是,您正在使用的边界相当详细,因此取决于Russia.sf的分辨率(例如边界的详细程度),可能会在里海附近产生不希望出现的伪影,特别是在陆地边界上(这里预期边界应与陆地边界匹配)。

以下是使用giscoR世界地图的完整示例,具有合理的分辨率(我使用了rworldmap进行测试,伪影出现在那里):

library(giscoR)
library(tidyverse)
library(sf)
#&gt; Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE

# 使用 giscoR
world_sf &lt;- gisco_get_countries(resolution = 10)

ggplot() +
  geom_sf(data = world_sf)

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->


world_robinson &lt;- st_transform(world_sf,
  crs = &quot;+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs&quot;
)

# 提取俄罗斯并将其分解为所有相邻的陆地区域(POLYGONS)
Russia_exploded &lt;- world_robinson %&gt;%
翻译部分结束

<details>
<summary>英文:</summary>

Use `lwgeom::st_split()` as suggested in the comments, in the form of `lwgeom::st_split(POLYGON, LINESTRING)`. One thing to bear in mind is that the borders you are using are quite detailed, hence depending on the resolution of `Russia.sf`(e.g. how detailed are the borders) it may produce undesired artifacts, specially in the near the Caspian Sea (where the limits are expected to match the landmass borders).

See a full example using `giscoR` world map with a reasonable good resolution (I tested with `rworldmap` and that&#39;s when artifacts appear):

``` r
library(giscoR)
library(tidyverse)
library(sf)
#&gt; Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE

# Using giscoR instead
world_sf &lt;- gisco_get_countries(resolution = 10)


ggplot() +
  geom_sf(data = world_sf)

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->


world_robinson &lt;- st_transform(world_sf,
  crs = &quot;+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs&quot;
)

# Extract Russia and explode it in all the contiguous landmasses (POLYGONS)
Russia_exploded &lt;- world_robinson %&gt;%
  filter(ISO3_CODE == &quot;RUS&quot;) %&gt;%
  st_cast(&quot;POLYGON&quot;)
#&gt; Warning in st_cast.sf(., &quot;POLYGON&quot;): repeating attributes for all
#&gt; sub-geometries for which they may not be constant

# Extract mainland as the largest contiguous portion of Russia
# Equivalent to your world_robinson$group==&quot;Russia.1&quot;
Russia.sf &lt;- Russia_exploded[which.max(st_area(Russia_exploded)), ] %&gt;%
  st_union() %&gt;%
  st_sf(cntry = &quot;Russia&quot;)

ggplot(Russia.sf) +
  geom_sf()

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->



### now split Russia on Urals
# https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson
download.file(&quot;https://raw.githubusercontent.com/sashatrubetskoy/asia_europe_border/master/asia_europe_border.geojson&quot;,
  &quot;border.geojson&quot;,
  mode = &quot;wb&quot;
)

Urals.sf &lt;- read_sf(&quot;border.geojson&quot;) %&gt;%
  st_geometry() %&gt;%
  st_combine() %&gt;%
  st_line_merge() %&gt;%
  st_transform(st_crs(world_robinson))


ggplot(Russia.sf) +
  geom_sf() +
  geom_sf(data = Urals.sf)

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->



# Split with lwgeom
Russia_splitted &lt;- lwgeom::st_split(Russia.sf, Urals.sf) %&gt;%
  st_collection_extract(&quot;POLYGON&quot;)

Russia_splitted$gr &lt;- factor(seq_len(nrow(Russia_splitted)))


ggplot(Russia_splitted) +
  geom_sf(aes(fill = gr))

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->


# Done, now identify resulting polygons (visually) and assign continent
Russia_splitted_end &lt;- Russia_splitted %&gt;%
  mutate(Continent = ifelse(gr == &quot;1&quot;, &quot;Asia&quot;, &quot;Europe&quot;)) %&gt;%
  group_by(Continent) %&gt;%
  summarise()

ggplot(Russia_splitted_end) +
  geom_sf(aes(fill = Continent))

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->


# Same but faceted

ggplot(Russia_splitted_end) +
  geom_sf(aes(fill = Continent)) +
  facet_wrap(~Continent, ncol = 1)

Splitting line or polygon with sf: st_intersection doesn’t work?<!-- -->

<sup>Created on 2023-06-28 with reprex v2.0.2</sup>

huangapple
  • 本文由 发表于 2023年6月27日 20:16:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76564769.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定