(ggplot2) SF 패키지 공간 관계 표현하기

sf 패키지는 공간 영역간에 겹치는 부분, 혹은 그 특정 경계내에만 위치하는 특정 공간을 표시하는 등의 공간간 연산 작업을 아주 쉽게 수행할 수 있도록 기능을 제공하고 있다. 예를 들어 특정 프랜차이즈 가맹점을 전국 지도에 x 로 모두 표시했는데, 서울 영등포구안에 있는 가맹점만 지도에 표시하고 싶을 때, sf 패지키의 공간간의 관계연산을 통해 쉽게 필터링 할 수 있다.

단순한 예시지만, 특정 경계를 기준으로 바깥 공간들과 내부 공간을 나누어 그릴 수 있다.

이전에 벤다이어그램을 이용해서 교집합, 합집합, 차집합을 구현해보았었는데, 아래 글도 참조하는게 좋다.

(ggplot2) 벤다이어그램 그리기 - 교집합,합집합,차집합

공간 정의

임의로 공간을 정의해보려한다. 첫번째로 삼각형 2개가 있는 공간이다. 삼각형 한개당 list 하나에 담는데, (x,y) 좌표를 기준으로 점과 점사이를 선으로 잇는다고 생각하면 된다.

sf_sam1 = list(list(rbind(c(3,7), c(9,9), c(8,3), c(3,7))),
               list(rbind(c(13,4), c(17,9), c(19,3), c(13,4)))) |> 
  st_multipolygon() |> 
  st_sfc() |> 
  st_sf(geometry = _)

# 출력결과
Simple feature collection with 1 feature and 0 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 3 ymin: 3 xmax: 19 ymax: 9
CRS:           NA
                        geometry
1 MULTIPOLYGON (((3 7, 9 9, 8...

데이터가 준비되었으니, 그리기만 하면 된다. 2개의 삼각형 공간이 생겼다.

ggplot() +
  geom_sf(data = sf_sam1) 

서로 다른 공간간에 연산해야하니, 공간 하나를 더 만들어야 한다. 이번에는 타일처럼 길이1인 정사각형 여러개의 공간을 만들어볼것이다. 여러개의 정사각형 공간을 만들어야 하다보니, polygon을 만드는 function 을 정의해 활용했다.

polygon_square = function(x, y, gap) {
  p1 = c(x, y) 
  p2 = c(x, y + gap)
  p3 = c(x + gap, y + gap)
  p4 = c(x + gap, y)
  p5 = c(x, y) 
  
  st_polygon(list(rbind(p1, p2, p3, p4, p5)))  
}

grid1 = expand.grid(x = seq(1, 10, by = 1), 
                    y = seq(1, 10, by = 1))
                    
sf_grid1 = tibble(grid1) |> 
  mutate(geometry = map2(x,y, polygon_square, gap = 1)) |> 
  pull(geometry) |> 
  st_sfc() |> 
  st_sf(geometry = _)

# 출력결과
Simple feature collection with 200 features and 0 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 1 ymin: 1 xmax: 21 ymax: 11
CRS:           NA
First 10 features:
                         geometry
1  POLYGON ((1 1, 1 2, 2 2, 2 ...
2  POLYGON ((2 1, 2 2, 3 2, 3 ...
3  POLYGON ((3 1, 3 2, 4 2, 4 ...
4  POLYGON ((4 1, 4 2, 5 2, 5 ...
5  POLYGON ((5 1, 5 2, 6 2, 6 ...
6  POLYGON ((6 1, 6 2, 7 2, 7 ...
7  POLYGON ((7 1, 7 2, 8 2, 8 ...
8  POLYGON ((8 1, 8 2, 9 2, 9 ...
9  POLYGON ((9 1, 9 2, 10 2, 1...
10 POLYGON ((10 1, 10 2, 11 2,...

그래프를 그려보면, 여러개의 정사각형 영역이 그려진걸 확인할 수 있다.

ggplot() +
  geom_sf(data = sf_grid1)

st_within

이제부터 삼각형 공간영역과 정사각형 공간영역을 이용해서 sf 패키지의 기능을 하나씩 알아볼 것이다. st_within 함수는 말그대로 특정 공간내에 있는 타 공간 영역을 추출할 수 있다.

log_within = st_within(sf_grid1, sf_sam1) |> 
  lengths() > 0

> log_within
 [56] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [67]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
 [78] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE
 [89] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE
[100] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE ...

나오는 결과를 가지고, 공간을 sf_grid1[log_within,] 와 같이 필터링만 해서 그리면 된다. 삼각형안에 포함되어 있는 정사각형들 공간만 그려진다.

ggplot() +
  geom_sf(data = sf_grid1[log_within,], fill = "red") +
  geom_sf(data = sf_sam1, fill = NA) 

st_touches

st_touches 는 딱 맞닿아있는 공간을 추출할 수 있다. 아래 그림을 보면 이해가 갈 것이다.

log_touches = st_touches(sf_grid1, sf_sam1) |> 
  lengths() > 0

ggplot() +
  geom_sf(data = sf_grid1[log_touches,], fill = "red") +
  geom_sf(data = sf_sam1, fill = NA) 

st_overlaps

st_overlaps 는 포함관계는 아니고, 경계에 걸쳐있는 공간만 추출해준다.

log_overlaps = st_overlaps(sf_grid1, sf_sam1) |> 
  lengths() > 0

ggplot() +
  geom_sf(data = sf_grid1[log_overlaps,], fill = "red") +
  geom_sf(data = sf_sam1, fill = NA) 

st_intersects

st_intersects 는 공간이 맞닿아있거나, 겹쳐있거나, 포함한 모든 공간을 추출할 수 있다. 한마디로 st_within, st_touches, st_overlaps 이 3개 영역을 합친 공간이다.

log_intersects = st_intersects(sf_grid1, sf_sam1) |> 
  lengths() > 0

ggplot() +
  geom_sf(data = sf_grid1[log_intersects,], fill = "red") +
  geom_sf(data = sf_sam1, fill = NA) 

st_disjoint

st_disjoint 는 여집합 개념처럼 나머지 영역을 필터링할 때 사용한다.

log_disjoint = st_disjoint(sf_grid1, sf_sam1) |> 
  lengths() > 0

ggplot() +
  geom_sf(data = sf_grid1[log_disjoint,], fill = "red") +
  geom_sf(data = sf_sam1, fill = NA) 

sf 함수 사용결과를 보면서, 공간간 관계에 따라 어떻게 영역을 추출하고 표시할 수 있는지 알아봤다. 아래 그림으로 정리해봤다.


더 보면 좋을 글들