Shiny 调用地理编码服务示例



注:地址请输入城市名以便地图在指定的城市有效查找。
百度地图的地图调起API及天地图的静态图API嵌入Shiny APP IFRAME碰到问题, 未找到原因,转换坐标系后暂时分别在高德、腾讯地图中标注显示。 如果地图的标注有偏差,说明是地图地理编码服务返回的坐标有偏差, 原因是地图里面可能没有收录附近的信息点。所以对同一个地址, 不同地图返回的坐标可能是不同的,因为它们收录的信息点不一样。 选择地图时要考察其信息点的数量与质量,解析的坐标是否比较准确。 查找所属乡镇街道代码用的是广东省2014年的乡镇街道行政区域矢量地图。
show with app
library(reticulate)
library(sf)

location<- substr(getwd(),1,4)
# 调用Pyhton脚本连接 Neo4j, Neo4j的官方Python Driver比开源R Driver好用。
if (location != '/srv'){    # Rstudio 开发环境
  part<- '~'
}else{                       # 服务器部署环境
  part<- '..'
}
path<- paste(part,"/scripts/","test_GeoCode.py",sep="")
#使用指定的Conda虚拟环境"openai"运行Python程序
use_condaenv(condaenv="base", conda = "/usr/lib64/anaconda3/bin/conda", required = TRUE)
t1<-proc.time()
source_python(path)
t2<-proc.time()
cat(t2-t1);cat("\n")

# 1.天地图 提供的是静态地图及标注夫妇,不是其它地图的地图调起API
TDURL_mask<- function (location,address, application_key){
  url_a <- 'http://api.tianditu.gov.cn/staticimage? width=1024&height=1024&zoom=18&layers=vec_c,cva_c'
  url_b <- paste("&center=", location, "&markers=", location, "&markerStyles=-1,,", address, sep="")
  url_c <- paste('&tk=', application_key, sep="")
  URL <- URLencode(paste(url_a, url_b, url_c, sep=""))
  # cat(URL)
  # browseURL(URL)
  return (URL)
}

# 2.腾讯地图 
TxURL_mask<- function(location, address){
  url_a <- 'https://apis.map.qq.com/uri/v1/marker?marker=coord:'
  url_b <- paste(location, ";title:", address, ";addr:", address, sep="")
  url_c <- '&ref=myapp'
  URL <- URLencode(paste(url_a, url_b, url_c, sep=""))
  # cat(URL)
  # browseURL(URL)
  return (URL)
}

# 3.高德地图 
GaoDeURL_mask<- function(location, address){
  url_a <- 'https://uri.amap.com/marker'
  url_b <- paste("?markers=", location, ",", address, sep="")
  url_c <- '&src=mypage&callnative=0'
  URL <- URLencode(paste(url_a, url_b, url_c, sep=""))
  # cat(URL)
  # browseURL(URL)
  return (URL)
}

# 4.百度地图
BaiDuURL_mask<- function(location, address){
  url_a <- 'http://api.map.baidu.com/marker'
  url_b <- paste("?location=", location, "&title=", address, "&content=", address, sep="")
  url_c = '&output=html&src=webapp.baidu.openAPIdemo&zoom=20'
  URL <- URLencode(paste(url_a, url_b, url_c, sep=""))
  # cat(URL)
  # browseURL(URL)
  return (URL)
}

# 读取 GeoJSON 文件
gdf <- st_read('/home/jean/data/MapGDXZJD2014.json')  # 替换为你的文件路径
# embed iframe inside shiny app
# https://stackoverflow.com/questions/33020558/embed-iframe-inside-shiny-app/33021018#33021018
shinyServer(function(input, output, session) {
  
  vendor<- reactive({
    input$vendor
  })
  
  address<- reactive({
    input$address
  })
  
  observe({
     print(vendor())
     print(address())
  })
  
  lnglat<- reactive({
    if (vendor()=='天地图')
        TDGeoCode(address())
    else if (vendor()=='腾讯')
        TXGeoCode(address())
    else if (vendor()=='高德')
        GDGeoCode(address())
    else if (vendor()=='百度')
        BDGeoCode(address())
  })
  
  wgslnglat<- reactive({
    tryCatch({
      lng<- as.numeric(lnglat()[[1]])
      lat<- as.numeric(lnglat()[[2]])
      if (vendor()=='腾讯')
        wgslocation<- geoChina::gcj2wgs(lat,lng)
      else if (vendor()=='高德')
        wgslocation<- geoChina::gcj2wgs(lat,lng)
      else if (vendor()=='百度')
        wgslocation<- geoChina::bd2wgs(lat,lng)
      
      if (vendor()!='天地图')
          wgslocation<- list(round(wgslocation[[2]],6),round(wgslocation[[1]],6))
      else
          wgslocation<- lnglat()
    }, error = function(e){
      print(e$message)
      wgslocation<- list(NULL,NULL)
    })
  })
  
  xzjd<-reactive({
    tryCatch({
      # 用WGS 84坐标
      loaction<- wgslnglat()
      # 创建一个坐标点
      point <- st_point(c(loaction[[1]] , loaction[[2]]))  # 经度在前,纬度在后
      point_sf <- st_sfc(point, crs = st_crs(gdf))
      # 查找包含该点的多边形
      matches <- st_intersects(gdf, point_sf)
      matches3<- matrix(matches,length(matches),1)
      matches3<- as.data.frame(matches3)
      matches3$index<- as.integer(row.names(matches3))
      intersecting_indices<- matches3$index[which(matches3$V1==1)]
      xzjd<- gdf[intersecting_indices,]
      paste(xzjd$city[[1]],xzjd$county[[1]],xzjd$name[[1]],xzjd$xzdm[[1]],sep=":")
    }, error = function(e){
      print(e$message)
      temp<- "找不到广东省内所属的乡镇街道"
    })
  })
  
  output$longlat<-renderText({
    paste(vendor(),paste(lnglat()[[1]],lnglat()[[2]],sep=" , "),sep=" : ")
  })
  
  output$wgslonglat<-renderText({
    paste("WGS 84",paste(wgslnglat()[[1]],wgslnglat()[[2]],sep=" , "),sep=" : ")
  }) 
  
  output$xzjd<-renderText({
    xzjd()
  }) 
  
  output$frame <- renderUI({
    location<- lnglat()
    if (vendor()=='天地图'){
      # 天地图在高德中显示,要从WGS-> GCJ,注意这里调的是Python包
      location2<- wgs2gcj(location[[1]], location[[2]])
      # url<- TDURL_mask(paste(location[[1]],location[[2]],sep=","), address(), application_key)
      url<- GaoDeURL_mask(paste(location2[[1]],location2[[2]],sep=","), address())
    }else if (vendor()=='腾讯'){
      url<- TxURL_mask(paste(location[[2]],location[[1]],sep=","), address())
    }else if (vendor()=='高德'){
      url<- GaoDeURL_mask(paste(location[[1]],location[[2]],sep=","), address())
    }else if (vendor()=='百度'){
      location2<- bd2gcj(location[[1]], location[[2]])
      # url<- BaiDuURL_mask(paste(location[[2]],location[[1]],sep=","), address())
      url<- TxURL_mask(paste(location2[[2]],location2[[1]],sep=","), address())
    }
    my_test <- tags$iframe(src=url, height=600, width="100%")
    print(my_test)
    my_test
  })
  
})
fluidPage(
  tags$head(
    tags$script(HTML("
                // 触发了shiny:inputchanged事件,屏蔽输入引起的改变
                $(document).on('shiny:inputchanged', function(event) {
                    if (event.name === 'address') {
                        event.preventDefault();                    
                    }
                });    
    
                // 点击时触发识别    
                $(document).on('click', '.btn-success', function (evt) {
                      evt.preventDefault(); 
                      var address = document.getElementById('address');
                      if (address.value ==null || address.value ==''){
                         alert('没有输入地址!');
                      }else{
                          try{
                            Shiny.setInputValue('address', address.value);
                          } catch(error){
                            alert(error);
                          }
                      }
                });  
    
              "))
  ),
  
  titlePanel("Shiny 调用地理编码服务示例"), 
  HTML("
            <table width='100%'>
                <tr>
                    <td width='20%'> 
           "),
  selectInput(
    'vendor',
    '地图',
    c('百度','高德','腾讯','天地图'),
    selected = '天地图'
  ),
  HTML("
                    </td>
                    <td width='60%'>
           "),
  textInput("address","地址:", value ="珠海市香洲区香山湖公园", width="400px"),
  HTML("
                    </td>
                    <td width='20%'>
           "),
  actionButton("geocode", "解析并标示", class = "btn-success"),
  HTML("
                    </td>
                    </tr>
                    <tr>
                    <td>
           "),
  textOutput("longlat"),
  HTML("<br>"),
  textOutput("wgslonglat"),
  HTML("<br>"),
  textOutput("xzjd"),
  HTML("
                    </td>
                    <td  colspan=2>
注:地址请输入城市名以便地图在指定的城市有效查找。<br>
百度地图的地图调起API及天地图的静态图API嵌入Shiny APP IFRAME碰到问题,
未找到原因,转换坐标系后暂时分别在高德、腾讯地图中标注显示。
如果地图的标注有偏差,说明是地图地理编码服务返回的坐标有偏差,
原因是地图里面可能没有收录附近的信息点。所以对同一个地址,
不同地图返回的坐标可能是不同的,因为它们收录的信息点不一样。
选择地图时要考察其信息点的数量与质量,解析的坐标是否比较准确。
查找所属乡镇街道代码用的是广东省2014年的乡镇街道行政区域矢量地图。
                    </td>
                    </tr>
                    <tr>
                    <td colspan=3>
           "),
  htmlOutput("frame"),
  HTML("
                    </td>
                    </tr>
                    </table>
           ")
)