2013-08-08 25 views
16

Điều đó không quan trọng đối với câu hỏi của tôi, nhưng đây là ví dụ cốt truyện của tôi, trên đó tôi muốn thêm một thanh tỷ lệ.Có cách nào để thêm thanh tỷ lệ (cho khoảng cách tuyến tính) vào ggmap không?

ggmap(get_map(location = "Kinston, NC", zoom = 12, maptype = 'hybrid')) + 
geom_point(x = -77.61198, y = 35.227792, colour = "red", size = 5) + 
geom_point(x = -77.57306, y = 35.30288, colour = "blue", size = 3) + 
geom_point(x = -77.543, y = 35.196, colour = "blue", size = 3) + 
geom_text(x = -77.575, y = 35.297, label = "CRONOS Data") + 
geom_text(x = -77.54, y = 35.19, label = "NOAA") + 
geom_text(x = -77.61, y = 35.22, label = "PP Site") 

NC map

+0

Xin chào, hãy xem '? OSM_scale_lookup' và các liên kết Câu hỏi thường gặp liên quan –

Trả lời

13

Có một vài điều bạn cần phải làm gì để thực hiện điều này.

Đầu tiên là để đưa dữ liệu của bạn vào một data.frame():

sites.data = data.frame(lon = c(-77.61198, -77.57306, -77.543), 
         lat = c(35.227792, 35.30288, 35.196), 
         label = c("PP Site","NOAA", "CRONOS Data"), 
         colour = c("red","blue","blue")) 

Bây giờ chúng ta có thể nhận được các bản đồ cho khu vực này bằng cách sử dụng gg_map gói:

require(gg_map) 
map.base <- get_map(location = c(lon = mean(sites.data$lon), 
           lat = mean(sites.data$lat)), 
        zoom = 10) # could also use zoom = "auto" 

Chúng tôi sẽ cần mức độ đó hình ảnh:

bb <- attr(map.base,"bb") 

Bây giờ chúng tôi bắt đầu tìm ra tỷ lệ. Đầu tiên, chúng ta cần một hàm cho chúng ta khoảng cách giữa hai điểm, dựa trên lat/long. Cho rằng, chúng ta sử dụng công thức Haversine, mô tả bởi Floris tại Calculate distance in (x, y) between two GPS-Points:

distHaversine <- function(long, lat){ 

    long <- long*pi/180 
    lat <- lat*pi/180 
    dlong = (long[2] - long[1]) 
    dlat = (lat[2] - lat[1]) 

    # Haversine formula: 
    R = 6371; 
    a = sin(dlat/2)*sin(dlat/2) + cos(lat[1])*cos(lat[2])*sin(dlong/2)*sin(dlong/2) 
    c = 2 * atan2(sqrt(a), sqrt(1-a)) 
    d = R * c 
    return(d) # in km 
} 

Bước tiếp theo là để tìm ra những điểm mà sẽ xác định thanh tỷ lệ của chúng tôi. Đối với ví dụ này, tôi đặt thứ gì đó ở phía dưới bên trái của ô, sử dụng hộp giới hạn mà chúng tôi đã tìm ra:

sbar <- data.frame(lon.start = c(bb$ll.lon + 0.1*(bb$ur.lon - bb$ll.lon)), 
        lon.end = c(bb$ll.lon + 0.25*(bb$ur.lon - bb$ll.lon)), 
        lat.start = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)), 
        lat.end = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat))) 

sbar$distance = distHaversine(long = c(sbar$lon.start,sbar$lon.end), 
           lat = c(sbar$lat.start,sbar$lat.end)) 

Cuối cùng, chúng ta có thể vẽ bản đồ theo tỷ lệ.

ptspermm <- 2.83464567 # need this because geom_text uses mm, and themes use pts. Urgh. 

map.scale <- ggmap(map.base, 
        extent = "normal", 
        maprange = FALSE) %+% sites.data + 
    geom_point(aes(x = lon, 
       y = lat, 
       colour = colour)) + 
    geom_text(aes(x = lon, 
       y = lat, 
       label = label), 
      hjust = 0, 
      vjust = 0.5, 
      size = 8/ptspermm) +  
    geom_segment(data = sbar, 
       aes(x = lon.start, 
        xend = lon.end, 
        y = lat.start, 
        yend = lat.end)) + 
    geom_text(data = sbar, 
      aes(x = (lon.start + lon.end)/2, 
      y = lat.start + 0.025*(bb$ur.lat - bb$ll.lat), 
      label = paste(format(distance, 
           digits = 4, 
           nsmall = 2), 
         'km')), 
      hjust = 0.5, 
      vjust = 0, 
      size = 8/ptspermm) + 
    coord_map(projection="mercator", 
      xlim=c(bb$ll.lon, bb$ur.lon), 
      ylim=c(bb$ll.lat, bb$ur.lat)) 

Sau đó chúng ta lưu nó ...

# Fix presentation ---- 
map.out <- map.scale + 
    theme_bw(base_size = 8) + 
    theme(legend.justification=c(1,1), 
     legend.position = c(1,1)) 

ggsave(filename ="map.png", 
     plot = map.out, 
     dpi = 300, 
     width = 4, 
     height = 3, 
     units = c("in")) 

nào mang đến cho bạn một cái gì đó như thế này:

Map with scale bar

Những điều tốt đẹp là tất cả các âm mưu sử dụng ggplot2(), vì vậy bạn có thể sử dụng tài liệu tại http://ggplot2.org để làm cho giao diện này như thế nào bạn cần.

+0

Đây là câu trả lời cực kỳ hữu ích @AndyClifton! – Mikko

+0

cố gắng sử dụng mã của bạn và tôi không chắc liệu có lỗi nào không? hãy kiểm tra lại ví dụ lat/long của bạn tại đây: [link] (http://www.movable-type.co.uk/scripts/latlong.html) cho tôi 12,02 km thay vì 13,52 công thức của bạn được? – maja

+1

Cập nhật ngày 30 tháng 11 năm 2015 để khắc phục sự cố mà @maja nhận thấy, điều này gây ra bởi tôi không thể hiện vĩ độ/Lon bằng radian trong tính toán khoảng cách của tôi. –

5

Tôi đã làm lại mã của @Andy Clifton để thêm thước đo chính xác hơn về khoảng cách và để cho thanh tỷ lệ có chiều dài mong muốn, trái ngược với tùy thuộc vào vị trí của thanh.

Mã của Andy cho tôi 99%, nhưng công thức Haversine được sử dụng trong mã của anh ấy không được xác thực với kết quả từ các nguồn khác, mặc dù tôi không thể tự tìm ra lỗi.

phần đầu tiên này được sao chép từ câu trả lời Andy Clifton của trên chỉ cho đầy đủ các mã:

sites.data = data.frame(lon = c(-77.61198, -77.57306, -77.543), 
         lat = c(35.227792, 35.30288, 35.196), 
         label = c("PP Site","NOAA", "CRONOS Data"), 
         colour = c("red","blue","blue")) 
map.base <- get_map(location = c(lon = mean(sites.data$lon), 
            lat = mean(sites.data$lat)), 
         zoom = 10) 
bb <- attr(map.base,"bb") 
sbar <- data.frame(lon.start = c(bb$ll.lon + 0.1*(bb$ur.lon - bb$ll.lon)), 
        lon.end = c(bb$ll.lon + 0.25*(bb$ur.lon - bb$ll.lon)), 
        lat.start = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat)), 
        lat.end = c(bb$ll.lat + 0.1*(bb$ur.lat - bb$ll.lat))) 

Hai bước tiếp theo là khác nhau:

đầu tiên sử dụng distVincentyEllipsoid chức năng từ gói geosphere để tính toán khoảng cách thậm chí còn nhiều hơn preciseley so với công thức Haversine:

sbar$distance <- geosphere::distVincentyEllipsoid(c(sbar$lon.start,sbar$lat.start), 
c(sbar$lon.end,sbar$lat.end)) 

Sau đó sửa thanh tỷ lệ vì vậy đó là độ dài chuẩn - tùy thuộc vào tỷ lệ bản đồ của bạn. Trong ví dụ này 20km có vẻ như một sự lựa chọn hợp lý tốt đẹp, tức là 20.000 mét:

scalebar.length <- 20 
sbar$lon.end <- sbar$lon.start + 
((sbar$lon.end-sbar$lon.start)/sbar$distance)*scalebar.length*1000 

Một lần nữa sử dụng mã của Andy, tôi đã chỉ thêm các mũi tên để các geom_segment vì tôi nghĩ rằng nó trông đẹp hơn

ptspermm <- 2.83464567 # need this because geom_text uses mm, and themes use pts. Urgh. 

map.scale <- ggmap(map.base, 
        extent = "normal", 
        maprange = FALSE) %+% sites.data + 
    geom_point(aes(x = lon, 
       y = lat, 
       colour = colour)) + 
    geom_text(aes(x = lon, 
       y = lat, 
       label = label), 
      hjust = 0, 
      vjust = 0.5, 
      size = 8/ptspermm) +  
    geom_segment(data = sbar, 
       aes(x = lon.start, 
        xend = lon.end, 
        y = lat.start, 
        yend = lat.end), 
       arrow=arrow(angle = 90, length = unit(0.1, "cm"), 
          ends = "both", type = "open")) + 
    geom_text(data = sbar, 
      aes(x = (lon.start + lon.end)/2, 
       y = lat.start + 0.025*(bb$ur.lat - bb$ll.lat), 
       label = paste(format(scalebar.length), 
           'km')), 
      hjust = 0.5, 
      vjust = 0, 
      size = 8/ptspermm) + 
    coord_map(projection = "mercator", 
      xlim=c(bb$ll.lon, bb$ur.lon), 
      ylim=c(bb$ll.lat, bb$ur.lat)) 

# Fix presentation ---- 
map.out <- map.scale + 
    theme_bw(base_size = 8) + 
    theme(legend.justification = c(1,1), 
     legend.position = c(1,1)) 

ggsave(filename ="map.png", 
     plot = map.out, 
     dpi = 300, 
     width = 4, 
     height = 3, 
     units = c("in")) 

reworked scale bar example

Các vấn đề liên quan