RでのGISマップの自動ラベル配置


9

sfシェープファイルを読み込むためのパッケージ(および関連パッケージ)を使用して、RでGISマップを作成していますggplot2。これは正常に機能しますが、川や道路などのフィーチャのラベル配置を(自動/プログラムで)作成する方法を見つけることができません。これらの機能は通常、不規則な形状のラインストリングです。ウィキメディアの例の添付画像を参照してください。

ここに画像の説明を入力してください

ggrepelパッケージには、自動化された方法でポイントを標識に適していますが、これは個別の緯度/経度のポイントではありません、他の地理的特徴のためにあまり意味がありません。

各機能に個別のテキストラベルを個別に配置することでこれを行うことは想像できますが、可能であれば、より自動化されたものを探しています。そのような自動化はささいな問題ではないことに気づきましたが、以前に解決されています(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
うわぁ。いいえ、原理だけではありません。どのようにプロットしているのか、どこまで到達したのか、または非地理的データを使用したggrepelで機能していることについてはわかりません。あなたは「これはうまくいく」と言いますが、「これ」が何であるかを示しません。例を含めることができたでしょう— sfやspDataのような他の空間パッケージがサンプルデータを出荷したり、小さなダミーのラインストリングオブジェクトを作成したりできましたが、現在のところ、状況に役立つのはどれだけかを推測できます。あまり役に立たない長期
カミーユ

8
最小限の再現可能な例を提供しない場合は、基本的に他の人に作成してもらいます。そうでなければ、彼らは通常、非常に良い答えを与えることができません。この場合、彼らはシェープファイルを見つけ、どのように使用しているかを理解する必要があることを意味ggrepelします。基本的には、すでに行った作業をやり直します。これにより、有用な回答が得られる可能性がはるかに低くなります。
アックスマン

3
MWEが質問に含まれるようになりました。反応の謝罪; 私は失礼になりたくないので、投稿する前に人々の時間を無駄にしないように一生懸命考えました。私は概念的な答えを求めていたように見えました-つまり、そのようなツールは存在しますか?-私の特定のプロジェクトに固有の答えではなく。
invertdna

4
かっこいい、これは今や良い例であり、私たちが推測したままにしておいたとしたら私が思いつくものではありません。ツールが存在するかどうかなどの概念的なものを探すことは、SOのトピック外と見なされます。質問は、特定の問題またはプロジェクトに関連付けられていると、はるかに優れています。明確にするために、ラベルをゴールの折れ線部分に沿って角度を付けていますか、それとも単にフィーチャの近くに配置していますか?
カミーユ

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.