【Shiny】基于R-Shiny制作地图App(百度地图)
估計每個愛好編程的都想某天可以開發出一個專屬于自己的軟件or應用,在下也是。然而由于當初入門編程的時候偷懶特地避開了那些以開發為目的源代碼級的語言(比如說java,C和C++)而選擇了R,我離這個目標估計是越走越遠了。雖然R語言擁有自己的GUI開發工具,但是由于不能封裝所以只能給留給自己看。不過好在Rstudio公司開發的Shiny包可以基于R語言制作web端的APP,依托于互聯網,算是間接實現了封裝并傳播的功能。不過shiny所實現的web app只能實現些比較簡單的功能,設計出來的初衷是為了在結果展示的時候作為Data Product來保證展示的過程更流暢更直觀。所以想做游戲的還是安心學java吧。這次想分享的是我自己閑著沒事兒整出來的一個閹割版的百度地圖,照著Shiny Gallery里面的某些大神那里得到的靈感,閑著沒事兒去里面轉轉,確實可以學到很多東西。
Shiny
Shiny在這里就不過多介紹了,簡言之他就是一個可以將R代碼的架構轉換為HTML架構的神奇的東西,換言之就是某尊大神將HTML給封裝成了R語言的一個包大概的工作原理是這樣的
一般網頁開發分為前段和后端,前端差不多就是網頁里的那些圖標啊排版啊啥的,后端就是在你對網頁進行操作時,網頁該如何進行反饋的交互邏輯。一般即使有HTML文件也是用不了的,因為沒有后端的話這網頁除了看沒什么用,不過牛逼的是Shiny還能幫你把后端給組織好。跟web開發類似,Shiny包里的架構邏輯也是需要分好前端和后端的,分別用 ui.R和 server.R兩個文件來儲存。先來個簡單的:
Sample 1
這是一個用來反映Kmeans均值聚類實時效果的簡單應用,可以自己DIY中心點個數以及要聚類的兩個變量,數據集是鳶尾花。
界面是這樣的,目前這圖里反應的是將Sepal.Length和Sepal.Width分為3類后,樣本分布情況。
代碼也分為前端和后端,前端是ui,后端是sever ## The UI of the web library(shiny) library(ggplot2)ui <- shinyUI(fluidPage(headerPanel(title = 'Test Kmeans'),sidebarPanel(selectInput(inputId = 'Col',label = 'The Variables',choices = c('Sepal.Length','Sepal.Width','Petal.Length','Petal.Width'),selected = c('Sepal.Length','Sepal.Width'),multiple = T),numericInput(inputId = 'center',label = 'Centroids',value = 3,min = 1,max = 10,step = 1),submitButton(text='submit')),mainPanel(h1('The result of Kmeans'),plotOutput(outputId = 'plot')) ))## The server of the web server <- shinyServer(function(input,output){output$plot <- renderPlot({da <- iris[,input$Col]fit <- kmeans(da,centers = input$center)da$cluster <- fit$clusterda2 <- as.data.frame(fit$centers)ggplot()+geom_point(data = da,aes(x=da[,input$Col[1]],y=da[,input$Col[2]],color=factor(cluster)))+geom_point(data = da2,aes(x=da2[,names(da2)[1]],y=da2[,names(da2)[2]],color=factor(1:nrow(da2))),size=5,shape=3)+xlab(input$Col[1])+ylab(input$Col[2])}) })## Run the app shinyApp(ui = ui,server = server)
總結來說就是ui里確定了在哪里input和output,server里通過input里的value來轉換為output,調用的原則是inputid和outputid,通過設定的id來一一對應,跟R6的面向對象編程一個架構方式。
地圖
完成這個app還有一個要素就是地圖。在各種涉及到“位置”的數據分析中,地圖在可視化中都扮演著一類非常重要的角色。有時候即使是一個很簡單的分析,配上地圖可視化之后就會十分的高大上。雖然R語言中的ggplot2等包可以根據地圖邊界坐標來畫出來地圖,但是都是靜態的地圖,所以我們使用的是R語言中一個公共地圖的接口leaflet。只需要幾行代碼就可以創建一個基礎的地圖層
library(leaflet) m <- leaflet() m%>%addTiles()與ggplot2挺像的,先畫一個底,如果想diy的話,再自己往上加圖層,而且最重要的是地圖是動態的而且可交互!比如說下面這兩張圖。
如果我想將某個位置的坐標給標出來的話,就需要用額外的函數了
library(leaflet) m <- leaflet() m %>% addTiles() %>% ## 給某個經度和緯度做標記addPopus(lng=longtitude,lat=latitude)坐標數據
有了框架有了地圖,接下來還差坐標數據了。對于個人來講,一個涵蓋全球各地坐標的數據庫還是不現實的,所以就需要借用一些已有的成型的地圖數據庫,比如說百度地圖和谷歌地圖,可惜后者被墻了。這里再介紹一個R包,名字就叫作baidumap,可以通過調用百度地圖的API來獲取某個地址的經緯度以及路線,輸出的結果是json格式(可選),所以這意味著我們還需要通過調用rjson包來解析json格式的文件。示例如下
library(baidumap) library(rjson)## 獲取“北京大學”的坐標 m <- getCoordinate(address='北京大學')然后我們會獲得這樣格式的數據
{"status":0,"result":{"location":{"lng":116.31616663593383,"lat":39.997752940431137},"precise":0,"confidence":50,"level":"UNKNOWN"}}通過函數fromJSON(m)格式就會變的更合理一點,在R里面會以list形式表示。
$status [1] 0$result $result$location $result$location$lng [1] 116.3162$result$location$lat [1] 39.99775$result$precise [1] 0$result$confidence [1] 50$result$level [1] "UNKNOWN"這是一個list格式數據,我們可以直接用美元符號($)來調用里面的子元素,其中status表示反饋狀態(0表示成功,1表示找不到,2表示沒有輸入地點),lng和lat就不解釋了,level表示地點的等級,不過只局限于“城市,區縣”這些比較宏觀的。
該包還有另外一個強大的函數是getRoute(origin,destination)可以獲得兩點之間的路線的坐標,配合上前面leaflet中的一個addPolyline()函數,可以在地圖上標注出路線圖。
整合
所有要素都配齊了,接下來的任務是將他們幾個整合在一起了,直接上代碼。
library(shiny) library(leaflet) library(baidumap) library(rjson)ui <- shinyUI(fluidPage(## the area for titleheaderPanel(title = 'Simulated BaiduMap'), ## plot the leaflet in the whole pageleafletOutput(outputId = 'map',width = '1920px',height = '1080px'),## control inputs panel and buttonabsolutePanel(width = 430,top=200,left = 'auto',draggable = T,textInput(inputId = 'Loc',label = 'THE PLACE'),textInput(inputId = 'Start',label = 'FROM',width = "50%"),textInput(inputId = 'End',label = 'TO',width = "50%"),selectInput(inputId = 'selected',label = 'Route or Loc',choices = c('Loc','Route'),selected = 'Loc',multiple = F),textOutput(outputId = 'Request'),submitButton(text = "Submit")) ))server <- shinyServer(function(input, output) {## acquire the coordinate from rjson filegetcoord <- function(x){## x is a name of some placex <- fromJSON(getCoordinate(x))return(x)}## output leaflet map to the id:mapoutput$map <- renderLeaflet({m <- leaflet()m <- m%>%addTiles()if(input$selected == 'Loc'){temp <- getcoord(input$Loc)if(temp$status!=0){output$Request <- renderText({c('The location failed to be found')})m}else{output$Request <- renderText({c('The location is found successfully')})m %>% addMarkers(lng=temp$result$location$lng,lat=temp$result$location$lat,popup = paste0(input$Loc,'--',temp$result$level))}}else{temp1 <- getcoord(input$Start)temp2 <- getcoord(input$End)if(temp1$status==0&temp2$status==0){output$Request <- renderText({c('Both start point and end point are valid')})route <- getRoute(input$Start,input$End)m%>%addPolylines(route$lon,route$lat)%>%addMarkers(lng=route$lon[c(1,nrow(route))],lat=route$lat[c(1,nrow(route))],popup = c(paste0(input$Start,'--',temp1$result$level),paste0(input$End,'--',temp2$result$level)))}else{output$Request <- renderText({c('One or both of origin and destination is invalid')})}}}) })就不解釋代碼了,主要兩種功能
效果還是蠻好的,比如說我想找天安門到清華大學的路線:
總結
博客原文還是發在了個人網頁上Zhuifengmu,如果感興趣的話可以嘗試下我之前發布的一個粗糙版本的ChinaMap,由于是國外的網不一定登的上去。文章是水出來的并沒有注重細節,歡迎指正。
總結
以上是生活随笔為你收集整理的【Shiny】基于R-Shiny制作地图App(百度地图)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 许可不可用
- 下一篇: 摄像机、NVR公网IP不固定解决方案(J