R에서 GIS 맵에 대한 자동 레이블 배치


9

sf패키지 (및 관련 패키지)를 사용하여 shapefile을 읽고 ggplot2플로팅을 위해 (및 친구)를 사용하여 R에서 GIS 맵을 만들고 있습니다 . 이것은 잘 작동하지만 강이나 도로와 같은 지형지 물의 레이블 배치를 (자동 / 프로그래밍 방식으로) 만들 수있는 방법을 찾을 수 없습니다. 이러한 피처는 일반적으로 불규칙한 모양의 선 스트링입니다. 예를 들어 wikimedia에서 첨부 된 이미지를 참조하십시오.

여기에 이미지 설명을 입력하십시오

ggrepel패키지는 자동화 된 방식으로 포인트에 레이블을 지정하는 데 효과적이지만, 개별 Lat / Long 포인트가 아닌 다른 지리적 기능에는 적합하지 않습니다.

각 기능에 개별 텍스트 레이블을 개별적으로 배치 하여이 작업을 수행 할 수 있다고 생각하지만 가능한 경우 더 자동화 된 것을 찾고 있습니다. 그러한 자동화는 사소한 문제는 아니라는 것을 알고 있지만 이전에는 해결되었습니다 (ArcGIS는 maplex라는 확장명 으로이 작업을 수행하는 방법이 있지만 소프트웨어에 액세스 할 수 없으며 계속 유지하고 싶습니다. 가능하면 R).

누구든지 이것을하는 방법을 알고 있습니까?

여기 MWE :

#MWE Linestring labeling

library(tidyverse)
library(sf)
library(ggrepel)
set.seed(120)

#pick a county from the built-in North Carolina dataset
BuncombeCounty <- st_read(system.file("shapes/", package="maptools"), "sids") %>% 
  filter(NAME == "Buncombe") 

#pick 4 random points in that county
pts_sf <- data.frame(
  x = seq(-82.3, -82.7, by=-0.1) %>% 
    sample(4),
  y = seq(35.5, 35.7, by=0.05) %>% 
    sample(4),
  placenames = c("A", "B", "C", "D")
) %>% 
  st_as_sf(coords = c("x","y")) 

#link those points into a linestring
linestring_sf <- pts_sf %>% 
  st_coordinates() %>%
  st_linestring()
  st_cast("LINESTRING") 

#plot them with labels, using geom_text_repel() from the `ggrepel` package
ggplot() +
  geom_sf(data = BuncombeCounty) +
  geom_sf(data = linestring_sf) +
  geom_label_repel(data = pts_sf,
                  stat = "sf_coordinates",
                  aes(geometry = geometry,
                      label = placenames),
                  nudge_y = 0.05,
                  label.r = 0, #don't round corners of label boxes
                  min.segment.length = 0,
                  segment.size = 0.4,
                  segment.color = "dodgerblue")

여기에 이미지 설명을 입력하십시오


8
Yikes. 아닙니다. 원칙이 아닙니다. 나는 당신이 어떻게 음모를 꾸미고 있는지 또는 얼마나 멀리 왔는지, 또는 당신이 언급 한 것이 지리학 적이 아닌 데이터와 함께 모여 들었다는 것을 모른다. 당신은 "이것은 잘 작동한다"고 말하지만 "이것"이 무엇인지 보여주지 않습니다. 예를 들어 spData ship 샘플 데이터와 같은 다른 공간 패키지 또는 sf와 같은 작은 공간 패키지를 포함시킬 수 있었을 것입니다. 그러나 현재는 작은 더미 라인 스트링 객체를 만들 수 있습니다. 매우 유용하지 장기
카밀

8
최소한의 재현 가능한 예를 제공하지 않으면 기본적으로 다른 사람들에게 대신해달라고 요청하는 것입니다. 그렇지 않으면 일반적으로 아주 좋은 대답을 줄 수 없습니다. 이 경우 셰이프 파일을 찾아서 사용 방법을 알아 내야합니다 ggrepel. 기본적으로 이미 수행 한 작업을 다시 실행하십시오. 이렇게하면 유용한 답변을 얻을 가능성이 훨씬 줄어 듭니다.
Axeman

3
MWE가 이제 질문에 포함되었습니다. 반응에 대한 사과; 나는 무례하고 싶지 않으며 게시하기 전에 사람들의 시간을 낭비하지 않는 방법에 대해 열심히 생각했습니다. 개념적인 대답을 요구하는 것 같습니다. 즉, 그러한 도구가 있습니까? 내 특정 프로젝트에 대한 답변이 아니라.
반전

4
쿨, 이것은 지금 좋은 예이며 당신이 우리를 추측하게한다면 내가 생각해 낸 것이 아닙니다. 도구의 존재 여부와 같은 개념적인 것을 찾는 것은 SO의 주제가 아닌 것으로 간주됩니다. 질문은 특정 문제 나 프로젝트와 관련이있을 때 훨씬 좋습니다. 명확히하기 위해 레이블이 목표의 선 스트링 부분을 따라 기울어 지거나 피쳐 근처에 배치됩니까?
camille

8
@camille First : 첫 답변에 대해 사과드립니다. 나는 그것이 의미로 가득하기 때문에 SO에 게시하는 것을 주저했고, 그것을 위해 자신을 보강하면서, 나는 평균적인 사람이되었습니다. 나는 그것에 대해 끔찍한 느낌이 들며 정말 죄송합니다. 당면한 문제에 관해서는 : 라벨을 기울일 필요는 없다. 넓은 맥락에서 (주로 도로와 강), 줄줄은 불규칙하므로 레이블은 줄을 따라 어딘가에 있어야하지만 줄과 평행해야합니다.
invertdna

답변:


8

당신에게 도움이 될만한 것이 있다고 생각합니다. 나는 당신의 예제를 좀 더 현실적인 것으로 바꿀 자유를 얻었습니다. 매 100 포인트 길이의 부드러운 임의의 보행으로 만든 두 개의 임의의 "강":

library(tidyverse)
library(sf)
library(ggrepel)

BuncombeCounty <- st_read(system.file("shapes/", package = "maptools"), "sids") %>% 
                  filter(NAME == "Buncombe")
set.seed(120)

x1 <- seq(-82.795, -82.285, length.out = 100)
y1 <- cumsum(runif(100, -.01, .01))
y1 <- predict(loess(y1 ~ x1, span = 0.1)) + 35.6

x2 <- x1 + 0.02
y2 <- cumsum(runif(100, -.01, .01))
y2 <- predict(loess(y2 ~ x2, span = 0.1)) + 35.57

river_1 <- data.frame(x = x1, y = y1)     %>% 
           st_as_sf(coords = c("x", "y")) %>%
           st_coordinates()               %>%
           st_linestring()                %>%
           st_cast("LINESTRING") 

river_2 <- data.frame(x = x2, y = y2)     %>% 
           st_as_sf(coords = c("x", "y")) %>%
           st_coordinates()               %>%
           st_linestring()                %>%
           st_cast("LINESTRING") 

우리는 당신의 예에 따라 그것들을 그릴 수 있습니다 :

riverplot  <- ggplot() +
              geom_sf(data = BuncombeCounty) +
              geom_sf(data = river_1, colour = "blue", size = 2) +
              geom_sf(data = river_2, colour = "blue", size = 2)

riverplot

여기에 이미지 설명을 입력하십시오

내 해결책은 기본적으로 선 문자열에서 점을 추출하고 레이블을 지정하는 것입니다. 질문 상단의 그림과 같이 선 스트링 길이를 따라 각 레이블의 여러 사본을 원할 수 있으므로 n 개의 레이블을 원하면 n 개의 등 간격 점을 추출 하면 됩니다.

물론, 레이블 충돌없이 한 번에 두 강에 레이블을 지정할 수 있으므로 여러 지리적 지형을 명명 된 목록으로 전달할 수 있어야합니다.

다음은 모든 기능을 수행하는 기능입니다.

linestring_labels <- function(linestrings, n)
{
  do.call(rbind, mapply(function(linestring, label)
  {
  n_points <- length(linestring)/2
  distance <- round(n_points / (n + 1))
  data.frame(x = linestring[1:n * distance],
             y = linestring[1:n * distance + n_points],
             label = rep(label, n))
  }, linestrings, names(linestrings), SIMPLIFY = FALSE)) %>%
  st_as_sf(coords = c("x","y"))
}

따라서 객체를 넣으면 다음과 같이 명명 된 목록에 레이블을 지정합니다.

river_list <- list("River 1" = river_1, "River 2" = river_2)

그런 다음이 작업을 수행 할 수 있습니다.

riverplot + 
   geom_label_repel(data = linestring_labels(river_list, 3),
                    stat = "sf_coordinates",
                    aes(geometry = geometry, label = label),
                    nudge_y = 0.05,
                    label.r = 0, #don't round corners of label boxes
                    min.segment.length = 0,
                    segment.size = 0.4,
                    segment.color = "dodgerblue")

여기에 이미지 설명을 입력하십시오


2
sfheaders::sf_linestring(obj = data.frame(x = x1, y = y1))sf생성 코드 중 일부를 완화 합니다.
SymbolixAU
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.