आर में जीआईएस नक्शे के लिए स्वचालित लेबल प्लेसमेंट


9

मैं sfपैकेज में (और संबंधित पैकेज) का उपयोग करके आकार में जीआईएस मैप्स बना रहा हूं , पढ़ने के लिए शेपफाइल्स में, और ggplot2(और दोस्तों) प्लॉटिंग के लिए। यह ठीक काम करता है, लेकिन मैं नदियों और सड़कों जैसी सुविधाओं के लिए (स्वचालित रूप से / प्रोग्राम रूप से) लेबल प्लेसमेंट बनाने का कोई रास्ता नहीं ढूँढ सकता। ये विशेषताएं आम तौर पर अनियमित आकार के साथ, अलंकृत हैं। उदाहरण के लिए विकिमीडिया से जुड़ी छवि देखें।

यहां छवि विवरण दर्ज करें

ggrepelपैकेज स्वचालित रूप से अंक लेबलिंग के लिए अच्छी तरह से काम है, लेकिन यह अन्य भौगोलिक विशेषताओं कि असतत अक्षांश / देशांतर अंक नहीं हैं के लिए ज्यादा मतलब नहीं है।

मैं व्यक्तिगत रूप से प्रत्येक फीचर पर अलग-अलग टेक्स्ट लेबल लगाकर ऐसा करने की कल्पना कर सकता हूं, लेकिन यदि संभव हो तो मैं कुछ और स्वचालित खोज रहा हूं। मुझे पता है कि इस तरह की स्वचालन एक तुच्छ समस्या नहीं है, लेकिन इसे पहले ही हल कर लिया गया है (आर्किस ने स्पष्ट रूप से मेप्लेक्स नामक एक्सटेंशन के साथ ऐसा करने का एक तरीका है, लेकिन मेरे पास सॉफ़्टवेयर तक पहुंच नहीं है, और मैं इसमें रहना चाहता हूं यदि संभव हो तो आर)।

क्या किसी को ऐसा करने का एक तरीका पता है?

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 और अन्य स्थानिक पैकेजों को शामिल करना संभव होता है जैसे कि स्पैडा शिप नमूना डेटा, या आप एक छोटी डमी लिनेस्ट्रिंग ऑब्जेक्ट बना सकते हैं - लेकिन अभी हम केवल अनुमान लगा सकते हैं कि आपकी स्थिति में से कौन सी मदद करेगा, और बस बहुत उपयोगी नहीं दीर्घकालिक
कैमिल

8
यदि आप एक न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण की आपूर्ति नहीं करते हैं, तो आप मूल रूप से दूसरों को आपके लिए एक बनाने के लिए कह रहे हैं। अन्यथा वे आमतौर पर बहुत अच्छा जवाब नहीं दे सकते हैं। इस मामले में इसका मतलब है कि उन्हें एक आकृति खोजने की ज़रूरत है, यह पता लगाएँ कि आप कैसे उपयोग कर रहे हैं ggrepel, मूल रूप से फिर से काम करें जो आपने पहले ही किया है। इससे यह बहुत कम संभावना है कि आप एक उपयोगी उत्तर देंगे।
एक्समैन

3
MWE अब सवाल में शामिल है। प्रतिक्रिया के लिए माफी; मैं असभ्य नहीं बनना चाहता हूं, और मैंने इस बारे में कठिन सोचा कि पोस्ट करने से पहले लोगों का समय कैसे बर्बाद न किया जाए। ऐसा लगता है कि मैं एक वैचारिक उत्तर के लिए पूछ रहा था - यानी, क्या ऐसा उपकरण मौजूद है? - मेरे विशेष प्रोजेक्ट के लिए विशिष्ट उत्तर के बजाय।
invertdna

4
कूल, यह अब एक अच्छा उदाहरण है, न कि मैं जिसके साथ हमें अनुमान लगाने के लिए छोड़ दिया था, मैं आ सकता हूं। कुछ वैचारिक खोज करना जैसे कि क्या कोई टूल मौजूद है, SO के लिए ऑफ-टॉपिक माना जाता है; जब वे किसी विशेष समस्या या प्रोजेक्ट से जुड़े होते हैं तो प्रश्न बहुत बेहतर होते हैं। स्पष्ट करने के लिए, क्या लेबल लक्ष्य के लिनेस्ट्रिंग भाग के साथ कोण है, या बस उन्हें सुविधाओं के पास रखने के लिए है?
कैमिली

8
@ कैमिल प्रथम: मैं वास्तव में अपने पहले उत्तर के लिए माफी चाहता हूं। मैं एसओ को पोस्ट करने में झिझक रहा हूं क्योंकि यह मतलबी से भरा है, और उसके लिए खुद को तैयार करने में, मैं खुद एक मतलब बन गया। मैं उसके बारे में भयानक महसूस करता हूं, और मुझे वास्तव में खेद है। हाथ में सवाल के रूप में: लेबल की जरूरत नहीं angled; व्यापक संदर्भ में (सड़क और नदियाँ, मुख्य रूप से), अलंकरण अनियमित हैं, और इसलिए शायद लेबल को लाइन के साथ कहीं और होना चाहिए, लेकिन (महत्वपूर्ण रूप से) लाइन के समानांतर।
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

यहां छवि विवरण दर्ज करें

मेरा समाधान मूल रूप से linestrings से अंक निकालने और उन्हें लेबल करने के लिए है। अपने प्रश्न के शीर्ष पर दिए गए चित्र की तरह, आप प्रत्येक लेबल की कई प्रतियाँ लिनस्टृंग की लंबाई के साथ चाह सकते हैं, इसलिए यदि आप चाहते हैं कि 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कोड बनाने में आसानी होगी ।
सिंबलिक्सएयू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.