├── src ├── .gitignore ├── Makevars ├── Makevars.win ├── load_namespaces.cpp ├── utils.cpp ├── baidugeo.h ├── RcppExports.cpp ├── coords.cpp └── addrs.cpp ├── .gitignore ├── tests ├── testthat.R └── testthat │ └── test-baidugeo.R ├── .Rbuildignore ├── inst └── extdata │ ├── address_cache.rda │ └── coordinate_cache.rda ├── .travis.yml ├── baidugeo.Rproj ├── NAMESPACE ├── man ├── bmap_get_cached_coord_data.Rd ├── bmap_get_cached_address_data.Rd ├── bmap_set_key.Rd ├── bmap_remaining_daily_queries.Rd ├── bmap_rate_limit_info.Rd ├── bmap_set_daily_rate_limit.Rd ├── bmap_clear_cache.Rd ├── bmap_get_location.Rd └── bmap_get_coords.Rd ├── R ├── utils.R ├── zzz.R ├── RcppExports.R ├── rate_limit.R ├── cache.R ├── get_location.R └── get_coords.R ├── DESCRIPTION ├── README.Rmd └── README.md /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | CXX_STD = CXX11 2 | PKG_CPPFLAGS=-DSTRICT_R_HEADERS 3 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | CXX_STD = CXX11 2 | PKG_CPPFLAGS=-DSTRICT_R_HEADERS 3 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(baidugeo) 3 | 4 | test_check("baidugeo") 5 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.travis\.yml$ 4 | ^README\.Rmd$ 5 | ^README-.*\.png$ 6 | -------------------------------------------------------------------------------- /inst/extdata/address_cache.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisMuir/baidugeo/HEAD/inst/extdata/address_cache.rda -------------------------------------------------------------------------------- /inst/extdata/coordinate_cache.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisMuir/baidugeo/HEAD/inst/extdata/coordinate_cache.rda -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | 7 | os: 8 | - linux 9 | - osx -------------------------------------------------------------------------------- /baidugeo.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(bmap_clear_cache) 4 | export(bmap_get_cached_address_data) 5 | export(bmap_get_cached_coord_data) 6 | export(bmap_get_coords) 7 | export(bmap_get_location) 8 | export(bmap_rate_limit_info) 9 | export(bmap_remaining_daily_queries) 10 | export(bmap_set_daily_rate_limit) 11 | export(bmap_set_key) 12 | importFrom(Rcpp,sourceCpp) 13 | useDynLib(baidugeo, .registration = TRUE) 14 | -------------------------------------------------------------------------------- /man/bmap_get_cached_coord_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{bmap_get_cached_coord_data} 4 | \alias{bmap_get_cached_coord_data} 5 | \title{Get Cached Coordinate Data} 6 | \usage{ 7 | bmap_get_cached_coord_data() 8 | } 9 | \value{ 10 | data frame 11 | } 12 | \description{ 13 | Return all cached coordinate data, as a tidy data frame. 14 | } 15 | \examples{ 16 | \dontrun{ 17 | df <- bmap_get_cached_coord_data() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /man/bmap_get_cached_address_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{bmap_get_cached_address_data} 4 | \alias{bmap_get_cached_address_data} 5 | \title{Get Cached Address Data} 6 | \usage{ 7 | bmap_get_cached_address_data() 8 | } 9 | \value{ 10 | data frame 11 | } 12 | \description{ 13 | Return all cached address data, as a tidy data frame. 14 | } 15 | \examples{ 16 | \dontrun{ 17 | df <- bmap_get_cached_address_data() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /man/bmap_set_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate_limit.R 3 | \name{bmap_set_key} 4 | \alias{bmap_set_key} 5 | \title{Set Baidu Map API Key} 6 | \usage{ 7 | bmap_set_key(key) 8 | } 9 | \arguments{ 10 | \item{key}{char string, valid Baidu Maps API key.} 11 | } 12 | \value{ 13 | Function does not return a value. 14 | } 15 | \description{ 16 | Function for setting a Baidu Map API key. Key will be used in all API calls. 17 | } 18 | \examples{ 19 | bmap_set_key("some_valid_key_str") 20 | 21 | } 22 | -------------------------------------------------------------------------------- /man/bmap_remaining_daily_queries.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate_limit.R 3 | \name{bmap_remaining_daily_queries} 4 | \alias{bmap_remaining_daily_queries} 5 | \title{Remaining Daily Queries} 6 | \usage{ 7 | bmap_remaining_daily_queries() 8 | } 9 | \value{ 10 | integer, number of queries 11 | } 12 | \description{ 13 | Get the number of daily queries left in the current 24 hour period, with 14 | the API key that is currently registered. 15 | } 16 | \examples{ 17 | bmap_remaining_daily_queries() 18 | 19 | } 20 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | 2 | #' Get URI for a coordinates API query 3 | #' 4 | #' @noRd 5 | get_coords_query_uri <- function(location) { 6 | paste0( 7 | "http://api.map.baidu.com/geocoder/v2/?address=", 8 | location, 9 | "&output=json&ak=", 10 | "%s" 11 | ) 12 | } 13 | 14 | 15 | #' Get URI for an address API query 16 | #' 17 | #' @noRd 18 | get_addr_query_uri <- function(lon, lat) { 19 | paste0( 20 | "http://api.map.baidu.com/geocoder/v2/?ak=", 21 | "%s", 22 | "&location=", 23 | lat, 24 | ",", 25 | lon, 26 | "&output=json&pois=0" 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: baidugeo 2 | Title: Interface to the Baidu Maps API Geocoding Services 3 | Version: 0.3.0 4 | Encoding: UTF-8 5 | Authors@R: person("Chris", "Muir", email = "chrismuirRVA@gmail.com", role = c("aut", "cre")) 6 | Description: Provides interface to the basic geocoding functions of the Baidu Maps API. 7 | Features forward and reverse geocoding. 8 | Depends: 9 | R (>= 3.0.0) 10 | Imports: 11 | digest, 12 | httr, 13 | methods, 14 | Rcpp 15 | License: GPL-3 16 | LazyData: true 17 | RoxygenNote: 6.1.0 18 | LinkingTo: Rcpp, rapidjsonr 19 | Suggests: knitr, 20 | testthat 21 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | ## Set up pkg environment to manage internal package data objects and rate 2 | ## limiting. 3 | bmap_env <- new.env() 4 | assign("bmap_key", NULL, envir = bmap_env) 5 | assign("bmap_daily_rate_limit", 5950L, envir = bmap_env) 6 | assign("queries_left_today", 5950L, envir = bmap_env) 7 | assign("next_limit_reset", NULL, envir = bmap_env) 8 | assign("time_of_last_query", Sys.time(), envir = bmap_env) 9 | 10 | # Initialize placeholders for package data within bmap_env. 11 | assign("coord_hash_map", NULL, envir = bmap_env) 12 | assign("addr_hash_map", NULL, envir = bmap_env) 13 | 14 | # Initialize global variables to keep R CMD Check happy. 15 | coord_hash_map <- NULL 16 | addr_hash_map <- NULL 17 | -------------------------------------------------------------------------------- /man/bmap_rate_limit_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate_limit.R 3 | \name{bmap_rate_limit_info} 4 | \alias{bmap_rate_limit_info} 5 | \title{Get Rate Limit Details} 6 | \usage{ 7 | bmap_rate_limit_info() 8 | } 9 | \value{ 10 | list of length four. 11 | } 12 | \description{ 13 | Function that will return rate limit details related to the current 14 | registered API key. Values are returned as a list. 15 | } 16 | \details{ 17 | Function returns a list containing the following info 18 | \itemize{ 19 | \item Current registered API key 20 | \item Daily query limit of the current key 21 | \item Number of daily queries remaining for the current 24 hour period 22 | \item Date-time in which the daily query limit will reset. 23 | } 24 | } 25 | \examples{ 26 | bmap_rate_limit_info() 27 | 28 | } 29 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | from_json_addrs_vector <- function(lng, lat, json_vect) { 5 | .Call(`_baidugeo_from_json_addrs_vector`, lng, lat, json_vect) 6 | } 7 | 8 | get_addrs_pkg_data <- function(addr_hash_map, keys) { 9 | .Call(`_baidugeo_get_addrs_pkg_data`, addr_hash_map, keys) 10 | } 11 | 12 | from_json_coords_vector <- function(location, json_vect) { 13 | .Call(`_baidugeo_from_json_coords_vector`, location, json_vect) 14 | } 15 | 16 | get_coords_pkg_data <- function(coord_hash_map, keys) { 17 | .Call(`_baidugeo_get_coords_pkg_data`, coord_hash_map, keys) 18 | } 19 | 20 | is_json_parsable <- function(json) { 21 | .Call(`_baidugeo_is_json_parsable`, json) 22 | } 23 | 24 | get_message_value <- function(json) { 25 | .Call(`_baidugeo_get_message_value`, json) 26 | } 27 | 28 | -------------------------------------------------------------------------------- /man/bmap_set_daily_rate_limit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rate_limit.R 3 | \name{bmap_set_daily_rate_limit} 4 | \alias{bmap_set_daily_rate_limit} 5 | \title{Set a daily rate limit for an API key.} 6 | \usage{ 7 | bmap_set_daily_rate_limit(num_limit) 8 | } 9 | \arguments{ 10 | \item{num_limit}{numeric value, number of daily API queries associated with 11 | the valid key currently being used.} 12 | } 13 | \value{ 14 | Function does not return a value. 15 | } 16 | \description{ 17 | This function will save the value passed to arg "num_limit" to the pkg 18 | environment value "bmap_daily_rate_limit", which is meant to be the number 19 | of daily queries allowed for the API key currently being used (default 20 | value for "bmap_daily_rate_limit" upon pkg load is 5950). Prior to using 21 | this function, a valid API key must be registered in the current R session, 22 | using function \code{\link{bmap_set_key}}. 23 | } 24 | \examples{ 25 | \dontrun{ 26 | bmap_set_daily_rate_limit(20000) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/testthat/test-baidugeo.R: -------------------------------------------------------------------------------- 1 | context("bmap_set_key") 2 | 3 | bmap_set_key("some_valid_key_str") 4 | test_that("setting key is successful", { 5 | expect_equal(get("bmap_key", envir = baidugeo:::bmap_env), 6 | "some_valid_key_str") 7 | }) 8 | 9 | 10 | context("bmap_set_rate_limit") 11 | 12 | bmap_set_daily_rate_limit(20000) 13 | test_that("setting rate limit is successful", { 14 | expect_equal(get("bmap_daily_rate_limit", envir = baidugeo:::bmap_env), 15 | 20000L) 16 | }) 17 | 18 | 19 | context("bmap_remaining_daily_queries") 20 | 21 | test_that("bmap_remaining_daily_queries is successful", { 22 | expect_equal(bmap_remaining_daily_queries(), 20000L) 23 | }) 24 | 25 | 26 | context("invalid_key_msg") 27 | 28 | test_that("invalid key msg is correct", { 29 | expect_equal( 30 | invalid_key_msg('{\"message\":\"len of str is 3 or fewer chars\"}'), 31 | paste0("API key is invalid. Current API key: some_valid_key_str\n ", 32 | "Response from the API:\n ", 33 | "len of str is 3 or fewer chars") 34 | ) 35 | }) 36 | -------------------------------------------------------------------------------- /src/load_namespaces.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "baidugeo.h" 3 | using namespace Rcpp; 4 | 5 | 6 | // Variables used by both coords and address functions. 7 | namespace global_vars { 8 | rapidjson::Document doc; 9 | NumericVector status; 10 | NumericVector lng; 11 | NumericVector lat; 12 | } 13 | 14 | // Variables used by the coords functions. 15 | namespace coord_vars { 16 | IntegerVector precise; 17 | IntegerVector confidence; 18 | NumericVector comprehension; 19 | String level; 20 | } 21 | 22 | // Variables used by the address functions. 23 | namespace addr_vars { 24 | double input_lng; 25 | double input_lat; 26 | String formatted_address; 27 | String business; 28 | String country; 29 | NumericVector country_code; 30 | String country_code_iso; 31 | String country_code_iso2; 32 | String province; 33 | String city; 34 | NumericVector city_level; 35 | String district; 36 | String town; 37 | std::string temp_str; 38 | IntegerVector ad_code; 39 | String street; 40 | String street_number; 41 | String direction; 42 | IntegerVector distance; 43 | String sematic_desc; 44 | NumericVector city_code; 45 | } 46 | -------------------------------------------------------------------------------- /man/bmap_clear_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{bmap_clear_cache} 4 | \alias{bmap_clear_cache} 5 | \title{Clear Cached Data Files} 6 | \usage{ 7 | bmap_clear_cache(coordinate_cache = FALSE, address_cache = FALSE) 8 | } 9 | \arguments{ 10 | \item{coordinate_cache}{logical, if TRUE, all data currently in 11 | coordinate_cache.rda will be cleared. Default value is FALSE.} 12 | 13 | \item{address_cache}{logical, if TRUE, all data currently in 14 | address_cache.rda will be cleared. Default value is FALSE.} 15 | } 16 | \value{ 17 | If both func args are set to FALSE, function will return NULL. 18 | Otherwise, function does not return a value. 19 | } 20 | \description{ 21 | This function gives the user the ability to clear one or both of the cached 22 | data sets on file. Doing so for either of the datasets will completely 23 | erase all data for the dataset specified. Do NOT run this function if you 24 | don't want to loose any of the cached data currently on file. 25 | } 26 | \examples{ 27 | \dontrun{ 28 | # Clear both cached data sets. 29 | bmap_clear_cache(coordinate_cache = TRUE, address_cache = TRUE) 30 | 31 | # Clear only the address cache. 32 | bmap_clear_cache(address_cache = TRUE) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "baidugeo.h" 3 | using namespace Rcpp; 4 | 5 | 6 | // [[Rcpp::export]] 7 | bool is_json_parsable(const char * json) { 8 | rapidjson::Document doc; 9 | doc.Parse(json); 10 | 11 | if(doc.HasParseError()) { 12 | return false; 13 | } 14 | 15 | return true; 16 | } 17 | 18 | 19 | // [[Rcpp::export]] 20 | std::string get_message_value(const char * json) { 21 | rapidjson::Document doc; 22 | doc.Parse(json); 23 | 24 | std::string out; 25 | if(doc.HasMember("message")) { 26 | out = doc["message"].GetString(); 27 | } else { 28 | out = ""; 29 | } 30 | 31 | return out; 32 | } 33 | 34 | 35 | // Extract lon and lat as doubles from a uri string. 36 | // Input uri's look like this: 37 | // "http://api.map.baidu.com/geocoder/v2/?ak=%s&location=30.61,114.27&output=json&pois=0" 38 | void get_coords_from_uri(std::string& uri) { 39 | size_t pos; 40 | std::string delim; 41 | 42 | // split by delim "location=", keep only the second half. 43 | // Result will look like this: 44 | // "30.61,114.27&output=json&pois=0" 45 | delim = "location="; 46 | pos = uri.find(delim); 47 | uri = uri.substr(pos + delim.size(), uri.size() - 1); 48 | 49 | // Split by delims "," and "&" to extract the lat and lon. 50 | delim = ","; 51 | pos = uri.find(delim); 52 | addr_vars::input_lat = atof(uri.substr(0, pos).c_str()); 53 | addr_vars::input_lng = atof(uri.substr(pos + delim.size(), uri.find("&")).c_str()); 54 | } 55 | -------------------------------------------------------------------------------- /src/baidugeo.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // [[Rcpp::depends(rapidjsonr)]] 4 | #include "rapidjson/document.h" 5 | 6 | using namespace Rcpp; 7 | 8 | 9 | #ifndef _ANAGRAMS_H 10 | #define _ANAGRAMS_H 11 | 12 | // Variables used by both coords and address functions. 13 | namespace global_vars { 14 | extern rapidjson::Document doc; 15 | extern NumericVector status; 16 | extern NumericVector lng; 17 | extern NumericVector lat; 18 | } 19 | 20 | // Variables used by the coords functions. 21 | namespace coord_vars { 22 | extern IntegerVector precise; 23 | extern IntegerVector confidence; 24 | extern NumericVector comprehension; 25 | extern String level; 26 | } 27 | 28 | // Variables used by the address functions. 29 | namespace addr_vars { 30 | extern double input_lng; 31 | extern double input_lat; 32 | extern String formatted_address; 33 | extern String business; 34 | extern String country; 35 | extern NumericVector country_code; 36 | extern String country_code_iso; 37 | extern String country_code_iso2; 38 | extern String province; 39 | extern String city; 40 | extern NumericVector city_level; 41 | extern String district; 42 | extern String town; 43 | extern std::string temp_str; 44 | extern IntegerVector ad_code; 45 | extern String street; 46 | extern String street_number; 47 | extern String direction; 48 | extern IntegerVector distance; 49 | extern String sematic_desc; 50 | extern NumericVector city_code; 51 | } 52 | 53 | 54 | bool is_json_parsable(const char * json); 55 | std::string get_message_value(const char * json); 56 | void get_coords_from_uri(std::string& uri); 57 | 58 | 59 | #endif /* _ANAGRAMS_H */ 60 | -------------------------------------------------------------------------------- /man/bmap_get_location.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_location.R 3 | \name{bmap_get_location} 4 | \alias{bmap_get_location} 5 | \title{Get Location for a Vector of lat/lon coordinates.} 6 | \usage{ 7 | bmap_get_location(lat, lon, type = c("data.frame", "json"), 8 | force = FALSE, cache_chunk_size = NULL) 9 | } 10 | \arguments{ 11 | \item{lat}{numeric vector, vector of latitude values.} 12 | 13 | \item{lon}{numeric vector, vector of longitude values.} 14 | 15 | \item{type}{string, dictates the return data type. Valid inputs are 16 | \code{data.frame}, which will return a data.frame, or \code{json}, which 17 | will return a vector of json strings.} 18 | 19 | \item{force}{logical, force online query, even if previously downloaded and 20 | saved to the data dictionary.} 21 | 22 | \item{cache_chunk_size}{integer, indicates how often you want the API return 23 | data to be saved to the package cache. Default value is NULL.} 24 | } 25 | \value{ 26 | char vector of json text objects. Each object contains the return 27 | value(s) from the Baidu Maps query, as well as the return value status 28 | code. 29 | } 30 | \description{ 31 | Takes a vector of lat/lon coordinates, or a list of lat/lon coordinates, 32 | sends them to the Baidu Maps API, output a char vector of addresses and 33 | address component info, as json text objects. This function also implements 34 | a data dictionary, saved as an rda object, to avoid sending the same query 35 | to Baidu twice. 36 | } 37 | \examples{ 38 | \dontrun{ 39 | lat <- c( 40 | 30.616167082550779, 41 | 30.39624844375698, 42 | 30.679942845419565 43 | ) 44 | 45 | lon <- c( 46 | 114.27287244473057, 47 | 119.87833669326516, 48 | 104.06792346330406 49 | ) 50 | 51 | bmap_get_location(lat, lon) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /man/bmap_get_coords.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_coords.R 3 | \name{bmap_get_coords} 4 | \alias{bmap_get_coords} 5 | \title{Get Coordinates for a Vector of Locations.} 6 | \usage{ 7 | bmap_get_coords(location, type = c("data.frame", "json"), 8 | force = FALSE, skip_short_str = FALSE, cache_chunk_size = NULL) 9 | } 10 | \arguments{ 11 | \item{location}{char vector, vector of locations.} 12 | 13 | \item{type}{string, dictates the return data type. Valid inputs are 14 | \code{data.frame}, which will return a data.frame, or \code{json}, which 15 | will return a vector of json strings.} 16 | 17 | \item{force}{logical, force online query, even if previously downloaded and 18 | saved to the data dictionary.} 19 | 20 | \item{skip_short_str}{logical, if TRUE then any input strings with length 21 | of three or less will not be queried in the Baidu API, and a json str with 22 | custom status code will be returned, indicating the str is too short to 23 | query. The idea is that if a str is three char's or less, then it's 24 | probably not an actual address, company/business name, or location. 25 | Default value is FALSE.} 26 | 27 | \item{cache_chunk_size}{integer, indicates how often you want the API return 28 | data to be saved to the package cache. Default value is NULL.} 29 | } 30 | \value{ 31 | char vector of json text objects. Each object contains the return 32 | value(s) from the Baidu Maps query, as well as the return value status 33 | code. 34 | } 35 | \description{ 36 | Takes a vector of locations (address, business names, etc), sends them to 37 | the Baidu Maps API, output a char vector of coordinates, as json text 38 | objects. This function also implements a data dictionary, saved as an rda 39 | object, to avoid sending the same query to Baidu twice. 40 | } 41 | \examples{ 42 | \dontrun{ 43 | locs <- c( 44 | "中百超市有限公司长堤街二分店", 45 | "浙江省杭州市余杭区径山镇小古城村", 46 | "成都高梁红餐饮管理有限公司" 47 | ) 48 | 49 | bmap_get_coords(locs) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | // from_json_addrs_vector 9 | List from_json_addrs_vector(NumericVector lng, NumericVector lat, std::vector json_vect); 10 | RcppExport SEXP _baidugeo_from_json_addrs_vector(SEXP lngSEXP, SEXP latSEXP, SEXP json_vectSEXP) { 11 | BEGIN_RCPP 12 | Rcpp::RObject rcpp_result_gen; 13 | Rcpp::RNGScope rcpp_rngScope_gen; 14 | Rcpp::traits::input_parameter< NumericVector >::type lng(lngSEXP); 15 | Rcpp::traits::input_parameter< NumericVector >::type lat(latSEXP); 16 | Rcpp::traits::input_parameter< std::vector >::type json_vect(json_vectSEXP); 17 | rcpp_result_gen = Rcpp::wrap(from_json_addrs_vector(lng, lat, json_vect)); 18 | return rcpp_result_gen; 19 | END_RCPP 20 | } 21 | // get_addrs_pkg_data 22 | List get_addrs_pkg_data(Environment& addr_hash_map, CharacterVector& keys); 23 | RcppExport SEXP _baidugeo_get_addrs_pkg_data(SEXP addr_hash_mapSEXP, SEXP keysSEXP) { 24 | BEGIN_RCPP 25 | Rcpp::RObject rcpp_result_gen; 26 | Rcpp::RNGScope rcpp_rngScope_gen; 27 | Rcpp::traits::input_parameter< Environment& >::type addr_hash_map(addr_hash_mapSEXP); 28 | Rcpp::traits::input_parameter< CharacterVector& >::type keys(keysSEXP); 29 | rcpp_result_gen = Rcpp::wrap(get_addrs_pkg_data(addr_hash_map, keys)); 30 | return rcpp_result_gen; 31 | END_RCPP 32 | } 33 | // from_json_coords_vector 34 | List from_json_coords_vector(CharacterVector location, std::vector json_vect); 35 | RcppExport SEXP _baidugeo_from_json_coords_vector(SEXP locationSEXP, SEXP json_vectSEXP) { 36 | BEGIN_RCPP 37 | Rcpp::RObject rcpp_result_gen; 38 | Rcpp::RNGScope rcpp_rngScope_gen; 39 | Rcpp::traits::input_parameter< CharacterVector >::type location(locationSEXP); 40 | Rcpp::traits::input_parameter< std::vector >::type json_vect(json_vectSEXP); 41 | rcpp_result_gen = Rcpp::wrap(from_json_coords_vector(location, json_vect)); 42 | return rcpp_result_gen; 43 | END_RCPP 44 | } 45 | // get_coords_pkg_data 46 | List get_coords_pkg_data(Environment& coord_hash_map, CharacterVector& keys); 47 | RcppExport SEXP _baidugeo_get_coords_pkg_data(SEXP coord_hash_mapSEXP, SEXP keysSEXP) { 48 | BEGIN_RCPP 49 | Rcpp::RObject rcpp_result_gen; 50 | Rcpp::RNGScope rcpp_rngScope_gen; 51 | Rcpp::traits::input_parameter< Environment& >::type coord_hash_map(coord_hash_mapSEXP); 52 | Rcpp::traits::input_parameter< CharacterVector& >::type keys(keysSEXP); 53 | rcpp_result_gen = Rcpp::wrap(get_coords_pkg_data(coord_hash_map, keys)); 54 | return rcpp_result_gen; 55 | END_RCPP 56 | } 57 | // is_json_parsable 58 | bool is_json_parsable(const char * json); 59 | RcppExport SEXP _baidugeo_is_json_parsable(SEXP jsonSEXP) { 60 | BEGIN_RCPP 61 | Rcpp::RObject rcpp_result_gen; 62 | Rcpp::RNGScope rcpp_rngScope_gen; 63 | Rcpp::traits::input_parameter< const char * >::type json(jsonSEXP); 64 | rcpp_result_gen = Rcpp::wrap(is_json_parsable(json)); 65 | return rcpp_result_gen; 66 | END_RCPP 67 | } 68 | // get_message_value 69 | std::string get_message_value(const char * json); 70 | RcppExport SEXP _baidugeo_get_message_value(SEXP jsonSEXP) { 71 | BEGIN_RCPP 72 | Rcpp::RObject rcpp_result_gen; 73 | Rcpp::RNGScope rcpp_rngScope_gen; 74 | Rcpp::traits::input_parameter< const char * >::type json(jsonSEXP); 75 | rcpp_result_gen = Rcpp::wrap(get_message_value(json)); 76 | return rcpp_result_gen; 77 | END_RCPP 78 | } 79 | 80 | static const R_CallMethodDef CallEntries[] = { 81 | {"_baidugeo_from_json_addrs_vector", (DL_FUNC) &_baidugeo_from_json_addrs_vector, 3}, 82 | {"_baidugeo_get_addrs_pkg_data", (DL_FUNC) &_baidugeo_get_addrs_pkg_data, 2}, 83 | {"_baidugeo_from_json_coords_vector", (DL_FUNC) &_baidugeo_from_json_coords_vector, 2}, 84 | {"_baidugeo_get_coords_pkg_data", (DL_FUNC) &_baidugeo_get_coords_pkg_data, 2}, 85 | {"_baidugeo_is_json_parsable", (DL_FUNC) &_baidugeo_is_json_parsable, 1}, 86 | {"_baidugeo_get_message_value", (DL_FUNC) &_baidugeo_get_message_value, 1}, 87 | {NULL, NULL, 0} 88 | }; 89 | 90 | RcppExport void R_init_baidugeo(DllInfo *dll) { 91 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 92 | R_useDynamicSymbols(dll, FALSE); 93 | } 94 | -------------------------------------------------------------------------------- /R/rate_limit.R: -------------------------------------------------------------------------------- 1 | 2 | #' Set Baidu Map API Key 3 | #' 4 | #' Function for setting a Baidu Map API key. Key will be used in all API calls. 5 | #' 6 | #' @param key char string, valid Baidu Maps API key. 7 | #' 8 | #' @return Function does not return a value. 9 | #' @export 10 | #' 11 | #' @examples 12 | #' bmap_set_key("some_valid_key_str") 13 | #' 14 | bmap_set_key <- function(key) { 15 | stopifnot(is.character(key)) 16 | assign("bmap_key", key, envir = bmap_env) 17 | } 18 | 19 | 20 | #' Set a daily rate limit for an API key. 21 | #' 22 | #' This function will save the value passed to arg "num_limit" to the pkg 23 | #' environment value "bmap_daily_rate_limit", which is meant to be the number 24 | #' of daily queries allowed for the API key currently being used (default 25 | #' value for "bmap_daily_rate_limit" upon pkg load is 5950). Prior to using 26 | #' this function, a valid API key must be registered in the current R session, 27 | #' using function \code{\link{bmap_set_key}}. 28 | #' 29 | #' @param num_limit numeric value, number of daily API queries associated with 30 | #' the valid key currently being used. 31 | #' 32 | #' @return Function does not return a value. 33 | #' @export 34 | #' 35 | #' @examples \dontrun{ 36 | #' bmap_set_daily_rate_limit(20000) 37 | #' } 38 | #' 39 | bmap_set_daily_rate_limit <- function(num_limit) { 40 | if (num_limit != as.integer(num_limit) || num_limit < 1) { 41 | stop("arg 'num_limit' must be a whole number greater than zero") 42 | } 43 | num_limit <- as.integer(num_limit) 44 | 45 | # Check to make sure an API key has been registered. 46 | if (is.null(get("bmap_key", envir = bmap_env))) { 47 | stop( 48 | paste0("cannot set rate limit without first setting an API key.\n", 49 | missing_key_msg()), 50 | call. = FALSE 51 | ) 52 | } 53 | 54 | # Assign the input rate limit to the pkg environment. 55 | assign("bmap_daily_rate_limit", num_limit, envir = bmap_env) 56 | assign("queries_left_today", num_limit, envir = bmap_env) 57 | } 58 | 59 | 60 | #' Get Rate Limit Details 61 | #' 62 | #' Function that will return rate limit details related to the current 63 | #' registered API key. Values are returned as a list. 64 | #' 65 | #' @details Function returns a list containing the following info 66 | #' \itemize{ 67 | #' \item Current registered API key 68 | #' \item Daily query limit of the current key 69 | #' \item Number of daily queries remaining for the current 24 hour period 70 | #' \item Date-time in which the daily query limit will reset. 71 | #' } 72 | #' 73 | #' @return list of length four. 74 | #' @export 75 | #' 76 | #' @examples 77 | #' bmap_rate_limit_info() 78 | #' 79 | bmap_rate_limit_info <- function() { 80 | # Initialize the output list. 81 | out <- list() 82 | 83 | out$current_key <- get("bmap_key", envir = bmap_env) 84 | out$daily_query_limit <- get("bmap_daily_rate_limit", envir = bmap_env) 85 | out$daily_queries_remaining <- bmap_remaining_daily_queries() 86 | reset <- get_limit_reset_time() 87 | if (is.null(reset)) { 88 | out$daily_limit_reset_time <- Sys.time() + 24*60*60 89 | } else { 90 | out$daily_limit_reset_time <- reset 91 | } 92 | 93 | out 94 | } 95 | 96 | 97 | #' Remaining Daily Queries 98 | #' 99 | #' Get the number of daily queries left in the current 24 hour period, with 100 | #' the API key that is currently registered. 101 | #' 102 | #' @return integer, number of queries 103 | #' @export 104 | #' 105 | #' @examples 106 | #' bmap_remaining_daily_queries() 107 | #' 108 | bmap_remaining_daily_queries <- function() { 109 | get("queries_left_today", envir = bmap_env) 110 | } 111 | 112 | 113 | #' Get date-time in which the current 24 hour query limit will be reset 114 | #' 115 | #' @noRd 116 | get_limit_reset_time <- function() { 117 | get("next_limit_reset", envir = bmap_env) 118 | } 119 | 120 | 121 | #' Get timestamp of the last API query 122 | #' 123 | #' @noRd 124 | timestamp_of_last_query <- function() { 125 | get("time_of_last_query", envir = bmap_env) 126 | } 127 | 128 | 129 | #' Query Limit Reset 130 | #' 131 | #' Reset the values for "next_limit_reset" and "bmap_daily_rate_limit". 132 | #' 133 | #' @noRd 134 | limit_reset <- function() { 135 | assign("next_limit_reset", Sys.time() + 24*60*60, envir = bmap_env) 136 | assign( 137 | "queries_left_today", 138 | get("bmap_daily_rate_limit", envir = bmap_env), 139 | envir = bmap_env 140 | ) 141 | } 142 | 143 | 144 | #' Missing API key message 145 | #' 146 | #' @noRd 147 | missing_key_msg <- function() { 148 | paste0("Apply for an application key here: ", 149 | "http://lbsyun.baidu.com/apiconsole/key", 150 | "\nThen register your key by running `bmap_set_key('valid_key_str')`") 151 | } 152 | 153 | 154 | #' Invalid API key message 155 | #' 156 | #' @noRd 157 | invalid_key_msg <- function(api_res) { 158 | # If api_res is not a valid json string, pass it unedited to the error msg. 159 | if (!is_json_parsable(api_res)) { 160 | msg <- api_res 161 | } else { 162 | # Get value from the "message" key in api_res. 163 | msg <- get_message_value(api_res) 164 | if (!nzchar(msg)) { 165 | # If "message" value is empty, make msg "unknown". 166 | msg <- "unknown" 167 | } 168 | } 169 | 170 | Encoding(msg) <- "UTF-8" 171 | 172 | sprintf( 173 | "API key is invalid. Current API key: %s 174 | Response from the API: 175 | %s", 176 | get("bmap_key", envir = bmap_env), msg 177 | ) 178 | } 179 | -------------------------------------------------------------------------------- /src/coords.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "baidugeo.h" 3 | using namespace Rcpp; 4 | 5 | 6 | // Get coords data from the json of a single API request. 7 | void from_json_coords(std::string& json) { 8 | if(json != "") { 9 | global_vars::doc.Parse(json.c_str()); 10 | } else { 11 | global_vars::doc.Parse("{\"empty\":\"json\"}"); 12 | } 13 | 14 | if(global_vars::doc.HasParseError()) { 15 | Rcerr << "parse error for json string: '"<< json << "'" << std::endl; 16 | } 17 | 18 | // status 19 | if(global_vars::doc.HasMember("status")) { 20 | global_vars::status[0] = global_vars::doc["status"].GetDouble(); 21 | } else { 22 | global_vars::status[0] = NA_REAL; 23 | } 24 | 25 | // longitude 26 | if(global_vars::doc["result"]["location"].HasMember("lng")) { 27 | global_vars::lng[0] = global_vars::doc["result"]["location"]["lng"].GetDouble(); 28 | } else { 29 | global_vars::lng[0] = NA_REAL; 30 | } 31 | 32 | // latitude 33 | if(global_vars::doc["result"]["location"].HasMember("lat")) { 34 | global_vars::lat[0] = global_vars::doc["result"]["location"]["lat"].GetDouble(); 35 | } else { 36 | global_vars::lat[0] = NA_REAL; 37 | } 38 | 39 | // precise 40 | if(global_vars::doc["result"].HasMember("precise")) { 41 | coord_vars::precise[0] = global_vars::doc["result"]["precise"].GetInt(); 42 | } else { 43 | coord_vars::precise[0] = NA_INTEGER; 44 | } 45 | 46 | // confidence 47 | if(global_vars::doc["result"].HasMember("confidence")) { 48 | coord_vars::confidence[0] = global_vars::doc["result"]["confidence"].GetInt(); 49 | } else { 50 | coord_vars::confidence[0] = NA_INTEGER; 51 | } 52 | 53 | // comprehension 54 | if(global_vars::doc["result"].HasMember("comprehension")) { 55 | coord_vars::comprehension[0] = global_vars::doc["result"]["comprehension"].GetDouble(); 56 | } else { 57 | coord_vars::comprehension[0] = NA_REAL; 58 | } 59 | 60 | // level 61 | if(global_vars::doc["result"].HasMember("level")) { 62 | coord_vars::level = global_vars::doc["result"]["level"].GetString(); 63 | } else { 64 | coord_vars::level = NA_STRING; 65 | } 66 | } 67 | 68 | 69 | // [[Rcpp::export]] 70 | List from_json_coords_vector(CharacterVector location, 71 | std::vector json_vect) { 72 | int json_len = json_vect.size(); 73 | NumericVector status(json_len); 74 | NumericVector lng(json_len); 75 | NumericVector lat(json_len); 76 | IntegerVector precise(json_len); 77 | IntegerVector confidence(json_len); 78 | NumericVector comprehension(json_len); 79 | CharacterVector level(json_len); 80 | 81 | for(int i = 0; i < json_len; ++i) { 82 | // Parse json, assign values from the parsed json. 83 | from_json_coords(json_vect[i]); 84 | status[i] = global_vars::status[0]; 85 | lng[i] = global_vars::lng[0]; 86 | lat[i] = global_vars::lat[0]; 87 | precise[i] = coord_vars::precise[0]; 88 | confidence[i] = coord_vars::confidence[0]; 89 | comprehension[i] = coord_vars::comprehension[0]; 90 | level[i] = coord_vars::level; 91 | } 92 | 93 | // Create List output that has the necessary attributes to make it a 94 | // data.frame object. 95 | List out = List::create( 96 | Named("location") = location, 97 | Named("lon") = lng, 98 | Named("lat") = lat, 99 | Named("status") = status, 100 | Named("precise") = precise, 101 | Named("confidence") = confidence, 102 | Named("comprehension") = comprehension, 103 | Named("level") = level 104 | ); 105 | 106 | out.attr("class") = "data.frame"; 107 | out.attr("row.names") = seq(1, json_len); 108 | 109 | return out; 110 | } 111 | 112 | 113 | // [[Rcpp::export]] 114 | List get_coords_pkg_data(Environment& coord_hash_map, 115 | CharacterVector& keys) { 116 | int cache_len = Rf_length(coord_hash_map); 117 | CharacterVector location(cache_len); 118 | NumericVector status(cache_len); 119 | NumericVector lng(cache_len); 120 | NumericVector lat(cache_len); 121 | IntegerVector precise(cache_len); 122 | IntegerVector confidence(cache_len); 123 | NumericVector comprehension(cache_len); 124 | CharacterVector level(cache_len); 125 | 126 | CharacterVector curr_res; 127 | String curr_key; 128 | std::string curr_json; 129 | 130 | for(int i = 0; i < cache_len; ++i) { 131 | 132 | curr_key = keys[i]; 133 | curr_res = coord_hash_map[curr_key]; 134 | 135 | //location 136 | location[i] = curr_res[0]; 137 | 138 | // Parse json, assign values from the parsed json. 139 | curr_json = as(curr_res[1]); 140 | from_json_coords(curr_json); 141 | status[i] = global_vars::status[0]; 142 | lng[i] = global_vars::lng[0]; 143 | lat[i] = global_vars::lat[0]; 144 | precise[i] = coord_vars::precise[0]; 145 | confidence[i] = coord_vars::confidence[0]; 146 | comprehension[i] = coord_vars::comprehension[0]; 147 | level[i] = coord_vars::level; 148 | } 149 | 150 | // Create List output that has the necessary attributes to make it a 151 | // data.frame object. 152 | List out = List::create( 153 | Named("location") = location, 154 | Named("lon") = lng, 155 | Named("lat") = lat, 156 | Named("status") = status, 157 | Named("precise") = precise, 158 | Named("confidence") = confidence, 159 | Named("comprehension") = comprehension, 160 | Named("level") = level 161 | ); 162 | 163 | out.attr("class") = "data.frame"; 164 | if(cache_len > 0) { 165 | out.attr("row.names") = seq(1, cache_len); 166 | } else { 167 | out.attr("row.names") = 0; 168 | } 169 | 170 | return out; 171 | } 172 | -------------------------------------------------------------------------------- /R/cache.R: -------------------------------------------------------------------------------- 1 | 2 | #' Addr Hash Map Lookup 3 | #' 4 | #' @noRd 5 | in_addr_hash_map <- function(key) { 6 | exists(key, envir = bmap_env$addr_hash_map, inherits = FALSE) 7 | } 8 | 9 | 10 | #' Coord Hash Map Insert 11 | #' 12 | #' @noRd 13 | insert_coord_hash_map <- function(key, value) { 14 | bmap_env$coord_hash_map[[digest::digest(key)]] <- c(key, value) 15 | } 16 | 17 | 18 | #' Addr Hash Map Insert 19 | #' 20 | #' @noRd 21 | insert_addr_hash_map <- function(key, value) { 22 | bmap_env$addr_hash_map[[key]] <- value 23 | } 24 | 25 | 26 | #' Load Coordinate Cache 27 | #' 28 | #' @noRd 29 | load_coord_cache <- function() { 30 | if (is.null(bmap_env$coord_hash_map)) { 31 | coord_hash_map <- system.file("extdata", 32 | "coordinate_cache.rda", 33 | package = "baidugeo") 34 | if (file.exists(coord_hash_map)) { 35 | load(coord_hash_map, envir = bmap_env) 36 | if (is.null(bmap_env$coord_hash_map)) { 37 | assign("coord_hash_map", new.env(), envir = bmap_env) 38 | } 39 | } else { 40 | warning("Cannot identify package data file 'coordinate_cache.rda'") 41 | } 42 | } 43 | } 44 | 45 | 46 | #' Load Address Cache 47 | #' 48 | #' @noRd 49 | load_address_cache <- function() { 50 | if (is.null(bmap_env$addr_hash_map)) { 51 | addr_hash_map <- system.file("extdata", 52 | "address_cache.rda", 53 | package = "baidugeo") 54 | if (file.exists(addr_hash_map)) { 55 | load(addr_hash_map, envir = bmap_env) 56 | if (is.null(bmap_env$addr_hash_map)) { 57 | assign("addr_hash_map", new.env(), envir = bmap_env) 58 | } 59 | } else { 60 | warning("Cannot identify package data file 'address_cache.rda'") 61 | } 62 | } 63 | } 64 | 65 | 66 | #' Save updated cache data set to inst/extdata as package data. 67 | #' 68 | #' @noRd 69 | update_cache_data <- function(coordinate_cache = FALSE, 70 | address_cache = FALSE) { 71 | if (coordinate_cache) { 72 | # Save coord_hash_map to file.. 73 | save( 74 | coord_hash_map, 75 | file = paste0(system.file("extdata", package = "baidugeo"), 76 | "/coordinate_cache.rda"), 77 | compress = "bzip2", 78 | envir = bmap_env 79 | ) 80 | } 81 | if (address_cache) { 82 | # Save addr_hash_map to file.. 83 | save( 84 | addr_hash_map, 85 | file = paste0(system.file("extdata", package = "baidugeo"), 86 | "/address_cache.rda"), 87 | compress = "bzip2", 88 | envir = bmap_env 89 | ) 90 | } 91 | } 92 | 93 | 94 | #' Clear Cached Data Files 95 | #' 96 | #' This function gives the user the ability to clear one or both of the cached 97 | #' data sets on file. Doing so for either of the datasets will completely 98 | #' erase all data for the dataset specified. Do NOT run this function if you 99 | #' don't want to loose any of the cached data currently on file. 100 | #' 101 | #' @param coordinate_cache logical, if TRUE, all data currently in 102 | #' coordinate_cache.rda will be cleared. Default value is FALSE. 103 | #' @param address_cache logical, if TRUE, all data currently in 104 | #' address_cache.rda will be cleared. Default value is FALSE. 105 | #' 106 | #' @return If both func args are set to FALSE, function will return NULL. 107 | #' Otherwise, function does not return a value. 108 | #' @export 109 | #' 110 | #' @examples \dontrun{ 111 | #' # Clear both cached data sets. 112 | #' bmap_clear_cache(coordinate_cache = TRUE, address_cache = TRUE) 113 | #' 114 | #' # Clear only the address cache. 115 | #' bmap_clear_cache(address_cache = TRUE) 116 | #' } 117 | bmap_clear_cache <- function(coordinate_cache = FALSE, 118 | address_cache = FALSE) { 119 | stopifnot(is.logical(coordinate_cache)) 120 | stopifnot(is.logical(address_cache)) 121 | 122 | if (!coordinate_cache && !address_cache) { 123 | message(paste0("No cached datasets were cleared.\nSet function args to ", 124 | "TRUE in order to clear one or both of the cached ", 125 | "datasets.")) 126 | return(NULL) 127 | } 128 | 129 | if (coordinate_cache && address_cache) { 130 | clear_coord_cache() 131 | clear_addr_cache() 132 | message("Both cached datasets were cleared.") 133 | } else if (coordinate_cache) { 134 | clear_coord_cache() 135 | message("The coordinates dataset was cleared.") 136 | } else if (address_cache) { 137 | clear_addr_cache() 138 | message("The addresses dataset was cleared.") 139 | } else { 140 | message(paste0("No cached datasets were cleared.\nSet function args to ", 141 | "TRUE in order to clear one or both of the cached ", 142 | "datasets.")) 143 | } 144 | } 145 | 146 | 147 | #' Clear Coordinates Cached Data 148 | #' 149 | #' @noRd 150 | clear_coord_cache <- function() { 151 | coord_hash_map <- new.env() 152 | save( 153 | coord_hash_map, 154 | file = paste0(system.file("extdata", package = "baidugeo"), 155 | "/coordinate_cache.rda"), 156 | compress = "bzip2", 157 | envir = bmap_env 158 | ) 159 | } 160 | 161 | 162 | #' Clear Address Cache Data 163 | #' 164 | #' @noRd 165 | clear_addr_cache <- function() { 166 | addr_hash_map <- new.env() 167 | save( 168 | addr_hash_map, 169 | file = paste0(system.file("extdata", package = "baidugeo"), 170 | "/address_cache.rda"), 171 | compress = "bzip2", 172 | envir = bmap_env 173 | ) 174 | } 175 | 176 | 177 | #' Get Cached Coordinate Data 178 | #' 179 | #' Return all cached coordinate data, as a tidy data frame. 180 | #' 181 | #' @return data frame 182 | #' @export 183 | #' 184 | #' @examples \dontrun{ 185 | #' df <- bmap_get_cached_coord_data() 186 | #' } 187 | bmap_get_cached_coord_data <- function() { 188 | # Load the cache coordinates data set. 189 | load_coord_cache() 190 | 191 | get_coords_pkg_data(bmap_env$coord_hash_map, 192 | names(bmap_env$coord_hash_map)) 193 | } 194 | 195 | #' Get Cached Address Data 196 | #' 197 | #' Return all cached address data, as a tidy data frame. 198 | #' 199 | #' @return data frame 200 | #' @export 201 | #' 202 | #' @examples \dontrun{ 203 | #' df <- bmap_get_cached_address_data() 204 | #' } 205 | bmap_get_cached_address_data <- function() { 206 | # Load the cache address data set. 207 | load_address_cache() 208 | 209 | get_addrs_pkg_data(bmap_env$addr_hash_map, 210 | names(bmap_env$addr_hash_map)) 211 | } 212 | -------------------------------------------------------------------------------- /R/get_location.R: -------------------------------------------------------------------------------- 1 | #' Get Location for a Vector of lat/lon coordinates. 2 | #' 3 | #' Takes a vector of lat/lon coordinates, or a list of lat/lon coordinates, 4 | #' sends them to the Baidu Maps API, output a char vector of addresses and 5 | #' address component info, as json text objects. This function also implements 6 | #' a data dictionary, saved as an rda object, to avoid sending the same query 7 | #' to Baidu twice. 8 | #' 9 | #' @param lat numeric vector, vector of latitude values. 10 | #' @param lon numeric vector, vector of longitude values. 11 | #' @param type string, dictates the return data type. Valid inputs are 12 | #' \code{data.frame}, which will return a data.frame, or \code{json}, which 13 | #' will return a vector of json strings. 14 | #' @param force logical, force online query, even if previously downloaded and 15 | #' saved to the data dictionary. 16 | #' @param cache_chunk_size integer, indicates how often you want the API return 17 | #' data to be saved to the package cache. Default value is NULL. 18 | #' 19 | #' @return char vector of json text objects. Each object contains the return 20 | #' value(s) from the Baidu Maps query, as well as the return value status 21 | #' code. 22 | #' @export 23 | #' 24 | #' @examples \dontrun{ 25 | #' lat <- c( 26 | #' 30.616167082550779, 27 | #' 30.39624844375698, 28 | #' 30.679942845419565 29 | #' ) 30 | #' 31 | #' lon <- c( 32 | #' 114.27287244473057, 33 | #' 119.87833669326516, 34 | #' 104.06792346330406 35 | #' ) 36 | #' 37 | #' bmap_get_location(lat, lon) 38 | #' } 39 | bmap_get_location <- function(lat, lon, type = c("data.frame", "json"), 40 | force = FALSE, cache_chunk_size = NULL) { 41 | # Input validation. 42 | stopifnot(is.numeric(lat)) 43 | stopifnot(is.numeric(lon)) 44 | type <- match.arg(type) 45 | stopifnot(is.logical(force)) 46 | stopifnot(is.integer(cache_chunk_size) || is.null(cache_chunk_size)) 47 | 48 | if (!identical(length(lat), length(lon))) { 49 | stop("length of 'lat' and 'lon' must match") 50 | } 51 | 52 | # Check to make sure key is not NULL. 53 | if (is.null(bmap_env$bmap_key)) { 54 | stop(missing_key_msg(), call. = FALSE) 55 | } 56 | 57 | # Load address cache data (if it's not already loaded). 58 | load_address_cache() 59 | 60 | # Record number of observations in addr_hash_map. 61 | cache_len <- length(bmap_env$addr_hash_map) 62 | 63 | # Iterate over "location". If obj exists in addr_hash_map, return 64 | # its json object. Otherwise, perform Baidu query, write the result to the 65 | # addr_hash_map, and return the result. 66 | out <- vector(length = length(lat), mode = "character") 67 | for (x in seq_len(length(lat))) { 68 | 69 | # If last api query was less than 1 seconds ago, delay code by 1 seconds. 70 | if (Sys.time() < timestamp_of_last_query() + 1) { 71 | Sys.sleep(1) 72 | } 73 | 74 | # Check to make sure we're not over the daily query limit. 75 | if (bmap_remaining_daily_queries() == 0) { 76 | # If any obs were added to addr_hash_map, write the changes to file. 77 | if (length(bmap_env$addr_hash_map) > cache_len) { 78 | update_cache_data(address_cache = TRUE) 79 | } 80 | out_msg <- paste("rate limit has been reached for the day for key:", 81 | bmap_env$bmap_key) 82 | out <- out[1:(x - 1)] 83 | break 84 | } 85 | 86 | # Check to see if the 24 hour daily query limit timer needs to be reset. 87 | # If it does, then reset the daily numeric rate limit as well. 88 | if (is.null(get_limit_reset_time()) || 89 | get_limit_reset_time() < Sys.time()) { 90 | limit_reset() 91 | } 92 | 93 | # Generate query uri. 94 | uri <- get_addr_query_uri(lon[x], lat[x]) 95 | 96 | # If lon_x or lat_x is NA, return NA. 97 | if (any(is.na(c(lon[x], lat[x])))) { 98 | out[x] <- NA 99 | 100 | # elif lon/lat in addr_hash_map & force == FALSE, return json obj from 101 | # addr_hash_map. 102 | } else if (!force && in_addr_hash_map(uri)) { 103 | out[x] <- bmap_env$addr_hash_map[[uri]] 104 | 105 | # else sent query to Baidu Maps API to get coordinates. Result will be 106 | # returned as a json text obj, and saved to addr_hash_map. 107 | } else { 108 | # Time stamp the current api query. 109 | assign("time_of_last_query", Sys.time(), envir = bmap_env) 110 | 111 | # Perform API query. 112 | res <- baidu_location_query(uri) 113 | 114 | # Edit cache variable "queries_left_today" to be one less. 115 | assign("queries_left_today", bmap_remaining_daily_queries() - 1L, 116 | envir = bmap_env) 117 | 118 | # If API key is invalid, throw error. 119 | if (grepl("message", res) && !grepl('\"lng\"', res)) { 120 | stop(invalid_key_msg(res), call. = FALSE) 121 | } 122 | 123 | # Assign res to output vector. 124 | out[x] <- res 125 | 126 | # If there was a connection error or http status code 302, do not cache 127 | # the result to addr_hash_map. 128 | if (grepl('con error:|"status\\":302', res)) { 129 | next 130 | } 131 | 132 | # If force == TRUE and uri already exists in addr_hash_map, do not cache 133 | # the resutls to addr_hash_map. 134 | if (force && in_addr_hash_map(uri)) { 135 | next 136 | } 137 | 138 | # Cache result to addr_hash_map. 139 | insert_addr_hash_map(uri, res) 140 | } 141 | 142 | # If cache_chunk_size is not NULL, and current iteration is evenly dvisible 143 | # by cache_chunk_size, write current API data to the package cache. 144 | if (!is.null(cache_chunk_size) && x %% cache_chunk_size == 0) { 145 | if (length(bmap_env$addr_hash_map) > cache_len) { 146 | update_cache_data(address_cache = TRUE) 147 | } 148 | } 149 | } 150 | 151 | # If any obs were added to addr_hash_map, write the changes to file. 152 | if (length(bmap_env$addr_hash_map) > cache_len) { 153 | update_cache_data(address_cache = TRUE) 154 | } 155 | 156 | # If "out_msg" doesn't exist, create it. 157 | if (!exists("out_msg", inherits = FALSE)) { 158 | out_msg <- "all queries completed" 159 | } 160 | 161 | # If input arg "type" is data.frame, parse the vector of json strings, 162 | # extract data into a data frame. 163 | if (type == "data.frame") { 164 | out <- from_json_addrs_vector(lon, lat, out) 165 | } 166 | 167 | # Assign attributes to the output object. 168 | attributes(out)$msg <- out_msg 169 | attributes(out)$daily_queries_remaining <- bmap_remaining_daily_queries() 170 | attributes(out)$key_used <- bmap_env$bmap_key 171 | return(out) 172 | } 173 | 174 | 175 | #' Send lat/lon query to Baidu Maps API, return full address of the lat/lon 176 | #' 177 | #' @param uri char string, uri to query 178 | #' 179 | #' @return json obj (as char string) containing the address API return data. 180 | #' 181 | #' @noRd 182 | baidu_location_query <- function(uri) { 183 | # Add API key to the query uri. 184 | uri <- sprintf(uri, get("bmap_key", envir = bmap_env)) 185 | 186 | # Query 187 | res <- tryCatch(httr::GET(uri), error = function(e) e) 188 | 189 | # Check return for error, then return the value. 190 | if (methods::is(res, "error")) { 191 | res <- "con error: err" 192 | } else if (httr::status_code(res) != 200) { 193 | res <- paste("con error:", httr::status_code(res)) 194 | } else { 195 | res <- httr::content(res, as = "text", encoding = "UTF-8") 196 | } 197 | 198 | return(res) 199 | } 200 | -------------------------------------------------------------------------------- /R/get_coords.R: -------------------------------------------------------------------------------- 1 | #' Get Coordinates for a Vector of Locations. 2 | #' 3 | #' Takes a vector of locations (address, business names, etc), sends them to 4 | #' the Baidu Maps API, output a char vector of coordinates, as json text 5 | #' objects. This function also implements a data dictionary, saved as an rda 6 | #' object, to avoid sending the same query to Baidu twice. 7 | #' 8 | #' @param location char vector, vector of locations. 9 | #' @param type string, dictates the return data type. Valid inputs are 10 | #' \code{data.frame}, which will return a data.frame, or \code{json}, which 11 | #' will return a vector of json strings. 12 | #' @param force logical, force online query, even if previously downloaded and 13 | #' saved to the data dictionary. 14 | #' @param skip_short_str logical, if TRUE then any input strings with length 15 | #' of three or less will not be queried in the Baidu API, and a json str with 16 | #' custom status code will be returned, indicating the str is too short to 17 | #' query. The idea is that if a str is three char's or less, then it's 18 | #' probably not an actual address, company/business name, or location. 19 | #' Default value is FALSE. 20 | #' @param cache_chunk_size integer, indicates how often you want the API return 21 | #' data to be saved to the package cache. Default value is NULL. 22 | #' 23 | #' @return char vector of json text objects. Each object contains the return 24 | #' value(s) from the Baidu Maps query, as well as the return value status 25 | #' code. 26 | #' @export 27 | #' 28 | #' @examples \dontrun{ 29 | #' locs <- c( 30 | #' "中百超市有限公司长堤街二分店", 31 | #' "浙江省杭州市余杭区径山镇小古城村", 32 | #' "成都高梁红餐饮管理有限公司" 33 | #' ) 34 | #' 35 | #' bmap_get_coords(locs) 36 | #' } 37 | #' @useDynLib baidugeo, .registration = TRUE 38 | #' @importFrom Rcpp sourceCpp 39 | bmap_get_coords <- function(location, type = c("data.frame", "json"), 40 | force = FALSE, skip_short_str = FALSE, 41 | cache_chunk_size = NULL) { 42 | # Input validation. 43 | stopifnot(is.character(location)) 44 | type <- match.arg(type) 45 | stopifnot(is.logical(force)) 46 | stopifnot(is.logical(skip_short_str)) 47 | stopifnot(is.integer(cache_chunk_size) || is.null(cache_chunk_size)) 48 | 49 | # Check to make sure key is not NULL. 50 | if (is.null(bmap_env$bmap_key)) { 51 | stop(missing_key_msg(), call. = FALSE) 52 | } 53 | 54 | # Load coord cache data (if it's not already loaded). 55 | load_coord_cache() 56 | 57 | # Record number of observations in coord_hash_map. 58 | cache_len <- length(bmap_env$coord_hash_map) 59 | 60 | # Iterate over "location". If obj exists in coord_hash_map, return 61 | # its json object. Otherwise, perform Baidu query, write the result to 62 | # coord_hash_map, and return the result. 63 | out <- vector(length = length(location), mode = "character") 64 | for (x in seq_len(length(location))) { 65 | 66 | # If last api query was less than 1 seconds ago, delay code by 1 seconds. 67 | if (Sys.time() < timestamp_of_last_query() + 1) { 68 | Sys.sleep(1) 69 | } 70 | 71 | # Check to make sure we're not over the daily query limit. 72 | if (bmap_remaining_daily_queries() == 0) { 73 | # If any obs were added to coord_hash_map, write the changes to file. 74 | if (length(bmap_env$coord_hash_map) > cache_len) { 75 | update_cache_data(coordinate_cache = TRUE) 76 | } 77 | out_msg <- paste("rate limit has been reached for the day for key:", 78 | bmap_env$bmap_key) 79 | out <- out[1:(x - 1)] 80 | break 81 | } 82 | 83 | # Check to see if the 24 hour daily query limit timer needs to be reset. 84 | # If it does, then reset the daily numeric rate limit as well. 85 | if (is.null(get_limit_reset_time()) || 86 | get_limit_reset_time() < Sys.time()) { 87 | limit_reset() 88 | } 89 | 90 | # Look up current location in coord_hash_map. 91 | curr_hash <- bmap_env$coord_hash_map[[digest::digest(location[x])]] 92 | 93 | # If the current location is NA or NULL, return "NA". 94 | if (is.null(location[x]) || is.na(location[x])) { 95 | out[x] <- NA 96 | 97 | # if x in saved_coords & force == FALSE, look up x in coord_hash_map 98 | # and return json obj. 99 | } else if (!force && !is.null(curr_hash)) { 100 | out[x] <- curr_hash[2] 101 | 102 | # elif skip_short_str == TRUE & nchar(x) <= 3, return custom json obj. 103 | } else if (skip_short_str && nchar(location[x]) <= 3) { 104 | res <- paste0('{\"status\":6,\"msg\":\"len of str is 3 or', 105 | ' fewer chars\",\"results\":[]}') 106 | out[x] <- res 107 | insert_coord_hash_map(location[x], res) 108 | 109 | # else sent query to Baidu Maps API to get coordinates. Result will be 110 | # returned as a json text obj, and saved to the data dictionary. 111 | } else { 112 | # Time stamp the current api query. 113 | assign("time_of_last_query", Sys.time(), envir = bmap_env) 114 | 115 | # Perform API query. 116 | res <- baidu_coord_query(location[x]) 117 | 118 | # Edit cache variable "queries_left_today" to be one less. 119 | assign("queries_left_today", (bmap_remaining_daily_queries() - 1L), 120 | envir = bmap_env) 121 | 122 | # If API key is invalid, throw error. 123 | if (grepl("message", res) && !grepl('\"lng\"', res)) { 124 | stop(invalid_key_msg(res), call. = FALSE) 125 | } 126 | 127 | # Assign res to output vector. 128 | out[x] <- res 129 | 130 | # If API key is invalid, throw error. 131 | if (grepl("message", res) && !grepl('\"lng\"', res)) { 132 | stop(invalid_key_msg(res), call. = FALSE) 133 | } 134 | 135 | # If there was a connection error or http status code 302, do not cache 136 | # the result to addr_hash_map. 137 | if (grepl('con error:|"status\\":302', res)) { 138 | next 139 | } 140 | 141 | # If force == TRUE and uri already exists in addr_hash_map, do not cache 142 | # the resutls to addr_hash_map. 143 | if (force && !is.null(curr_hash)) { 144 | next 145 | } 146 | 147 | # Cache result to coord_hash_map. 148 | insert_coord_hash_map(location[x], res) 149 | 150 | } 151 | 152 | # If cache_chunk_size is not NULL, and current iteration is evenly dvisible 153 | # by cache_chunk_size, write current API data to the package cache. 154 | if (!is.null(cache_chunk_size) && x %% cache_chunk_size == 0) { 155 | if (length(bmap_env$coord_hash_map) > cache_len) { 156 | update_cache_data(coordinate_cache = TRUE) 157 | } 158 | } 159 | } 160 | 161 | # If any obs were added to coord_hash_map, write the changes to file. 162 | if (length(bmap_env$coord_hash_map) > cache_len) { 163 | update_cache_data(coordinate_cache = TRUE) 164 | } 165 | 166 | # If "out_msg" doesn't exist, create it. 167 | if (!exists("out_msg", inherits = FALSE)) { 168 | out_msg <- "all queries completed" 169 | } 170 | 171 | # If input arg "type" is data.frame, parse the vector of json strings, 172 | # extract data into a data frame. 173 | if (type == "data.frame") { 174 | out <- from_json_coords_vector(location, out) 175 | } 176 | 177 | # Assign attributes to the output object. 178 | attributes(out)$msg <- out_msg 179 | attributes(out)$daily_queries_remaining <- bmap_remaining_daily_queries() 180 | attributes(out)$key_used <- bmap_env$bmap_key 181 | return(out) 182 | } 183 | 184 | 185 | #' Send address/location query to Baidu Maps API, return a lat/lon 186 | #' 187 | #' @param location char string, location name or address to query. 188 | #' 189 | #' @return json obj (as char string) containing the lat/lon return data. 190 | #' @noRd 191 | baidu_coord_query <- function(location) { 192 | # Check for presence of chars " " and "#", as either will produce errors 193 | # if sent to the Baidu Maps API. Find and eliminate them. 194 | if (any(grepl(' |#', location))) { 195 | location <- gsub(' |#', '', location) 196 | } 197 | 198 | # Compile query URL. 199 | uri <- sprintf( 200 | get_coords_query_uri(location), get("bmap_key", envir = bmap_env) 201 | ) 202 | 203 | # query 204 | res <- tryCatch(httr::GET(uri), error = function(e) e) 205 | 206 | # Check return for error, then return the value. 207 | if (methods::is(res, "error")) { 208 | res <- "con error: err" 209 | } else if (httr::status_code(res) != 200) { 210 | res <- paste("con error:", httr::status_code(res)) 211 | } else { 212 | res <- httr::content(res, as = "text", encoding = "UTF-8") 213 | } 214 | 215 | return(res) 216 | } 217 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: default 4 | html_document: default 5 | --- 6 | 7 | 8 | 9 | ```{r, echo = FALSE} 10 | knitr::opts_chunk$set(collapse = TRUE, comment = "#>") 11 | ``` 12 | 13 | # baidugeo 14 | 15 | [![Travis-CI Build Status](https://travis-ci.org/ChrisMuir/baidugeo.svg?branch=master)](https://travis-ci.org/ChrisMuir/baidugeo) 16 | 17 | R interface for the Baidu Maps API geocoding services. API docs can be found [here](http://lbsyun.baidu.com/index.php?title=jspopular), [here](http://developer.baidu.com/map/skins/MySkin/resources/iframs/webapi-geocoding.html), and [here](http://lbsyun.baidu.com/index.php?title=car/api/geocoding). Functions are provided for both forward and reverse geocoding. The Baidu Maps API is useful for geolocation of Chinese strings (addresses, business names, locations, etc). 18 | 19 | This project initially started as a fork of the [baidumap](https://github.com/badbye/baidumap) package by [Yalei Du](https://github.com/badbye). This package is meant to be a stripped down, simplified version of that package, useful for when all you need is geocoding from Baidu, and with a couple additional features built in. Major differences include: 20 | 21 | - All API return data is cached as internal package data. The cache is persistent across R sessions. 22 | - API rate limiting is handled automatically. 23 | - Removes multicore processing, so no parallel API calls. 24 | - Fewer dependencies. 25 | - Uses the [rapidjson](https://github.com/Tencent/rapidjson) C++ header files (via the R packge [rapidjsonr](https://github.com/SymbolixAU/rapidjsonr)) for fast parsing of JSON API return data. 26 | 27 | For geolocation of Chinese terms using basic string parsing (no API required), check out my package [geolocChina](https://github.com/ChrisMuir/geolocChina). 28 | 29 | ## Install from this repo 30 | 31 | ```{r, eval=FALSE} 32 | #install.packages("devtools") 33 | devtools::install_github("ChrisMuir/baidugeo") 34 | ``` 35 | 36 | ## Usage and API Credentialing 37 | 38 | A valid key is required to make queries with this package. Apply for an application key from [lbsyun.baidu.com](http://lbsyun.baidu.com/apiconsole/key). Then register your key using function `bmap_set_key()`. 39 | ```{r} 40 | library(baidugeo) 41 | bmap_set_key("some_valid_key_str") 42 | ``` 43 | The Baidu Maps API features daily rate limits. By default, any key registered using `bmap_set_key()` will be assigned a daily rate limit of 5950. This can be adjusted using function `bmap_set_daily_rate_limit()` 44 | ```{r} 45 | bmap_set_daily_rate_limit(20000) 46 | ``` 47 | 48 | The function `bmap_rate_limit_info()` can be used to get info related to the currently registered key. 49 | ```{r} 50 | bmap_rate_limit_info() 51 | ``` 52 | 53 | ## Geocoding 54 | Use function `bmap_get_coords()` to get lat and lon coordinates given a vector of strings. 55 | 56 | ```{r, echo=FALSE} 57 | res_df <- data.frame( 58 | "location" = c("中百超市有限公司长堤街二分店", "浙江省杭州市余杭区径山镇小古城村", "成都高梁红餐饮管理有限公司"), 59 | "lon" = c(114.2729, 119.8783, 104.0679), 60 | "lat" = c(30.61617, 30.39625, 30.67994), 61 | "status" = c(0, 0, 0), 62 | "precise" = c(1, 0, 0), 63 | "confidence" = c(80, 30, 12), 64 | "comprehension" = c(95, 100, 29), 65 | "level" = c("UNKNOWN", "乡镇", "城市") 66 | ) 67 | 68 | res_json <- c( 69 | "{\"status\":0,\"result\":{\"location\":{\"lng\":114.27287244473057,\"lat\":30.616167082550779},\"precise\":1,\"confidence\":80,\"comprehension\":95,\"level\":\"UNKNOWN\"}}", 70 | "{\"status\":0,\"result\":{\"location\":{\"lng\":119.87833669326516,\"lat\":30.39624844375698},\"precise\":0,\"confidence\":30,\"comprehension\":100,\"level\":\"乡镇\"}}", 71 | "{\"status\":0,\"result\":{\"location\":{\"lng\":104.06792346330406,\"lat\":30.679942845419565},\"precise\":0,\"confidence\":12,\"comprehension\":29,\"level\":\"城市\"}}" 72 | ) 73 | ``` 74 | 75 | ```{r} 76 | locs <- c( 77 | "中百超市有限公司长堤街二分店", 78 | "浙江省杭州市余杭区径山镇小古城村", 79 | "成都高梁红餐饮管理有限公司" 80 | ) 81 | ``` 82 | `bmap_get_coords()` returns a data frame by default. 83 | ```{r, eval=FALSE} 84 | coords_df <- bmap_get_coords(locs) 85 | knitr::kable(coords_df) 86 | ``` 87 | 88 | ```{r, echo=FALSE} 89 | knitr::kable(res_df) 90 | ``` 91 | 92 | Use arg `type` to return a vector of json strings. 93 | ```{r, eval=FALSE} 94 | bmap_get_coords(locs, type = "json") 95 | ``` 96 | 97 | ```{r, echo=FALSE} 98 | print(res_json) 99 | ``` 100 | 101 | 102 | ## Reverse Geocoding 103 | Use function `bmap_get_location()` to get full address details given vectors of lat/lon coordinate pairs. 104 | 105 | ```{r, echo=FALSE} 106 | res_df <- data.frame( 107 | "input_lon" = c(114.2729, 119.8783, 104.0679), 108 | "input_lat" = c(30.61617, 30.39625, 30.67994), 109 | "return_lon" = c(114.2729, 119.8783, 104.0679), 110 | "return_lat" = c(30.61617, 30.39625, 30.67994), 111 | "status" = c(0, 0, 0), 112 | "formatted_address" = c("湖北省武汉市江汉区新华路630号", "浙江省杭州市余杭区潘金线", "四川省成都市青羊区王家塘街84号"), 113 | "business" = c("汉口火车站,常青路,北湖", NA, "骡马市,新华西路,八宝街"), 114 | "country" = c("中国", "中国", "中国"), 115 | "country_code" = c(0, 0, 0), 116 | "country_code_iso" = c("CHN", "CHN", "CHN"), 117 | "country_code_iso2" = c("CN", "CN", "CN"), 118 | "province" = c("湖北省", "浙江省", "四川省"), 119 | "city" = c("武汉市", "杭州市", "成都市"), 120 | "city_level" = c(2, 2, 2), 121 | "district" = c("江汉区", "余杭区", "青羊区"), 122 | "town" = c(NA_character_, NA_character_, NA_character_), 123 | "ad_code" = c(420103, 330110, 510105), 124 | "street" = c("新华路", "潘金线", "王家塘街"), 125 | "street_number" = c("630号", NA, "84号"), 126 | "direction" = c("附近", NA, "附近"), 127 | "distance" = c(9, NA, 6), 128 | "city_code" = c(218, 179, 75) 129 | ) 130 | 131 | res_json <- c( 132 | "{\"status\":0,\"result\":{\"location\":{\"lng\":114.27287244473092,\"lat\":30.61616696729939},\"formatted_address\":\"湖北省武汉市江汉区新华路630号\",\"business\":\"汉口火车站,常青路,北湖\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"湖北省\",\"city\":\"武汉市\",\"city_level\":2,\"district\":\"江汉区\",\"town\":\"\",\"adcode\":\"420103\",\"street\":\"新华路\",\"street_number\":\"630号\",\"direction\":\"附近\",\"distance\":\"9\"},\"pois\":[],\"roads\":[],\"poiRegions\":[],\"sematic_description\":\"锦江之星酒店(武汉菱角湖万达店)南53米\",\"cityCode\":218}}", 133 | "{\"status\":0,\"result\":{\"location\":{\"lng\":119.87833669326493,\"lat\":30.39624841472855},\"formatted_address\":\"浙江省杭州市余杭区潘金线\",\"business\":\"\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"浙江省\",\"city\":\"杭州市\",\"city_level\":2,\"district\":\"余杭区\",\"town\":\"\",\"adcode\":\"330110\",\"street\":\"潘金线\",\"street_number\":\"\",\"direction\":\"\",\"distance\":\"\"},\"pois\":[],\"roads\":[],\"poiRegions\":[],\"sematic_description\":\"阳坞山西北444米\",\"cityCode\":179}}", 134 | "{\"status\":0,\"result\":{\"location\":{\"lng\":104.06792346330394,\"lat\":30.67994271533221},\"formatted_address\":\"四川省成都市青羊区王家塘街84号\",\"business\":\"骡马市,新华西路,八宝街\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"四川省\",\"city\":\"成都市\",\"city_level\":2,\"district\":\"青羊区\",\"town\":\"\",\"adcode\":\"510105\",\"street\":\"王家塘街\",\"street_number\":\"84号\",\"direction\":\"附近\",\"distance\":\"6\"},\"pois\":[],\"roads\":[],\"poiRegions\":[{\"direction_desc\":\"内\",\"name\":\"青羊区政府\",\"tag\":\"政府机构;各级政府\",\"uid\":\"96b672aa58335874cf04ef80\"}],\"sematic_description\":\"青羊区政府内,成都华氏陶瓷艺术博物馆附近1米\",\"cityCode\":75}}" 135 | ) 136 | ``` 137 | 138 | `bmap_get_location()` returns a data frame by default. 139 | ```{r, eval=FALSE} 140 | addrs_df <- bmap_get_location(coords_df$lat, coords_df$lon) 141 | knitr::kable(addrs_df) 142 | ``` 143 | 144 | ```{r, echo=FALSE} 145 | knitr::kable(res_df) 146 | ``` 147 | 148 | Use arg `type` to return a vector of json strings. 149 | ```{r, eval=FALSE} 150 | bmap_get_location(coords_df$lat, coords_df$lon, type = "json") 151 | ``` 152 | 153 | ```{r, echo=FALSE} 154 | print(res_json) 155 | ``` 156 | 157 | ## Package Data 158 | Functions `bmap_get_coords()` and `bmap_get_location()` both cache API return data. The functions will first look for the return data in the cached package datasets, if it's not found there they will execute an API request. 159 | 160 | Use function `bmap_clear_cache()` to clear either of the package cache data sets (or both at once). 161 | ```{r, eval=FALSE} 162 | bmap_clear_cache(coordinate_cache = TRUE, address_cache = TRUE) 163 | ``` 164 | 165 | Use function `bmap_get_cached_coord_data()` to load all of the cached lat/lon return data as a tidy data frame. 166 | ```{r, eval=FALSE} 167 | df <- bmap_get_cached_coord_data() 168 | ``` 169 | 170 | Use function `bmap_get_cached_address_data()` to load the cached address return data as a tidy data frame. 171 | ```{r, eval=FALSE} 172 | df <- bmap_get_cached_address_data() 173 | ``` 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | baidugeo 4 | ======== 5 | 6 | [![Travis-CI Build Status](https://travis-ci.org/ChrisMuir/baidugeo.svg?branch=master)](https://travis-ci.org/ChrisMuir/baidugeo) 7 | 8 | R interface for the Baidu Maps API geocoding services. API docs can be found [here](http://lbsyun.baidu.com/index.php?title=jspopular), [here](http://developer.baidu.com/map/skins/MySkin/resources/iframs/webapi-geocoding.html), and [here](http://lbsyun.baidu.com/index.php?title=car/api/geocoding). Functions are provided for both forward and reverse geocoding. The Baidu Maps API is useful for geolocation of Chinese strings (addresses, business names, locations, etc). 9 | 10 | This project initially started as a fork of the [baidumap](https://github.com/badbye/baidumap) package by [Yalei Du](https://github.com/badbye). This package is meant to be a stripped down, simplified version of that package, useful for when all you need is geocoding from Baidu, and with a couple additional features built in. Major differences include: 11 | 12 | - All API return data is cached as internal package data. The cache is persistent across R sessions. 13 | - API rate limiting is handled automatically. 14 | - Removes multicore processing, so no parallel API calls. 15 | - Fewer dependencies. 16 | - Uses the [rapidjson](https://github.com/Tencent/rapidjson) C++ header files (via the R packge [rapidjsonr](https://github.com/SymbolixAU/rapidjsonr)) for fast parsing of JSON API return data. 17 | 18 | For geolocation of Chinese terms using basic string parsing (no API required), check out my package [geolocChina](https://github.com/ChrisMuir/geolocChina). 19 | 20 | Install from this repo 21 | ---------------------- 22 | 23 | ``` r 24 | #install.packages("devtools") 25 | devtools::install_github("ChrisMuir/baidugeo") 26 | ``` 27 | 28 | Usage and API Credentialing 29 | --------------------------- 30 | 31 | A valid key is required to make queries with this package. Apply for an application key from [lbsyun.baidu.com](http://lbsyun.baidu.com/apiconsole/key). Then register your key using function `bmap_set_key()`. 32 | 33 | ``` r 34 | library(baidugeo) 35 | bmap_set_key("some_valid_key_str") 36 | ``` 37 | 38 | The Baidu Maps API features daily rate limits. By default, any key registered using `bmap_set_key()` will be assigned a daily rate limit of 5950. This can be adjusted using function `bmap_set_daily_rate_limit()` 39 | 40 | ``` r 41 | bmap_set_daily_rate_limit(20000) 42 | ``` 43 | 44 | The function `bmap_rate_limit_info()` can be used to get info related to the currently registered key. 45 | 46 | ``` r 47 | bmap_rate_limit_info() 48 | #> $current_key 49 | #> [1] "some_valid_key_str" 50 | #> 51 | #> $daily_query_limit 52 | #> [1] 20000 53 | #> 54 | #> $daily_queries_remaining 55 | #> [1] 20000 56 | #> 57 | #> $daily_limit_reset_time 58 | #> [1] "2018-10-20 20:49:27 EDT" 59 | ``` 60 | 61 | Geocoding 62 | --------- 63 | 64 | Use function `bmap_get_coords()` to get lat and lon coordinates given a vector of strings. 65 | 66 | ``` r 67 | locs <- c( 68 | "中百超市有限公司长堤街二分店", 69 | "浙江省杭州市余杭区径山镇小古城村", 70 | "成都高梁红餐饮管理有限公司" 71 | ) 72 | ``` 73 | 74 | `bmap_get_coords()` returns a data frame by default. 75 | 76 | ``` r 77 | coords_df <- bmap_get_coords(locs) 78 | knitr::kable(coords_df) 79 | ``` 80 | 81 | | location | lon| lat| status| precise| confidence| comprehension| level | 82 | |:---------------------------------|---------:|---------:|-------:|--------:|-----------:|--------------:|:--------| 83 | | 中百超市有限公司长堤街二分店 | 114.2729| 30.61617| 0| 1| 80| 95| UNKNOWN | 84 | | 浙江省杭州市余杭区径山镇小古城村 | 119.8783| 30.39625| 0| 0| 30| 100| 乡镇 | 85 | | 成都高梁红餐饮管理有限公司 | 104.0679| 30.67994| 0| 0| 12| 29| 城市 | 86 | 87 | Use arg `type` to return a vector of json strings. 88 | 89 | ``` r 90 | bmap_get_coords(locs, type = "json") 91 | ``` 92 | 93 | #> [1] "{\"status\":0,\"result\":{\"location\":{\"lng\":114.27287244473057,\"lat\":30.616167082550779},\"precise\":1,\"confidence\":80,\"comprehension\":95,\"level\":\"UNKNOWN\"}}" 94 | #> [2] "{\"status\":0,\"result\":{\"location\":{\"lng\":119.87833669326516,\"lat\":30.39624844375698},\"precise\":0,\"confidence\":30,\"comprehension\":100,\"level\":\"乡镇\"}}" 95 | #> [3] "{\"status\":0,\"result\":{\"location\":{\"lng\":104.06792346330406,\"lat\":30.679942845419565},\"precise\":0,\"confidence\":12,\"comprehension\":29,\"level\":\"城市\"}}" 96 | 97 | Reverse Geocoding 98 | ----------------- 99 | 100 | Use function `bmap_get_location()` to get full address details given vectors of lat/lon coordinate pairs. 101 | 102 | `bmap_get_location()` returns a data frame by default. 103 | 104 | ``` r 105 | addrs_df <- bmap_get_location(coords_df$lat, coords_df$lon) 106 | knitr::kable(addrs_df) 107 | ``` 108 | 109 | | input\_lon| input\_lat| return\_lon| return\_lat| status| formatted\_address | business | country | country\_code| country\_code\_iso | country\_code\_iso2 | province | city | city\_level| district | town | ad\_code| street | street\_number | direction | distance| city\_code| 110 | |-----------:|-----------:|------------:|------------:|-------:|:-------------------------------|:-----------------------|:--------|--------------:|:-------------------|:--------------------|:---------|:-------|------------:|:---------|:-----|---------:|:---------|:---------------|:----------|---------:|-----------:| 111 | | 114.2729| 30.61617| 114.2729| 30.61617| 0| 湖北省武汉市江汉区新华路630号 | 汉口火车站,常青路,北湖 | 中国 | 0| CHN | CN | 湖北省 | 武汉市 | 2| 江汉区 | NA | 420103| 新华路 | 630号 | 附近 | 9| 218| 112 | | 119.8783| 30.39625| 119.8783| 30.39625| 0| 浙江省杭州市余杭区潘金线 | NA | 中国 | 0| CHN | CN | 浙江省 | 杭州市 | 2| 余杭区 | NA | 330110| 潘金线 | NA | NA | NA| 179| 113 | | 104.0679| 30.67994| 104.0679| 30.67994| 0| 四川省成都市青羊区王家塘街84号 | 骡马市,新华西路,八宝街 | 中国 | 0| CHN | CN | 四川省 | 成都市 | 2| 青羊区 | NA | 510105| 王家塘街 | 84号 | 附近 | 6| 75| 114 | 115 | Use arg `type` to return a vector of json strings. 116 | 117 | ``` r 118 | bmap_get_location(coords_df$lat, coords_df$lon, type = "json") 119 | ``` 120 | 121 | #> [1] "{\"status\":0,\"result\":{\"location\":{\"lng\":114.27287244473092,\"lat\":30.61616696729939},\"formatted_address\":\"湖北省武汉市江汉区新华路630号\",\"business\":\"汉口火车站,常青路,北湖\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"湖北省\",\"city\":\"武汉市\",\"city_level\":2,\"district\":\"江汉区\",\"town\":\"\",\"adcode\":\"420103\",\"street\":\"新华路\",\"street_number\":\"630号\",\"direction\":\"附近\",\"distance\":\"9\"},\"pois\":[],\"roads\":[],\"poiRegions\":[],\"sematic_description\":\"锦江之星酒店(武汉菱角湖万达店)南53米\",\"cityCode\":218}}" 122 | #> [2] "{\"status\":0,\"result\":{\"location\":{\"lng\":119.87833669326493,\"lat\":30.39624841472855},\"formatted_address\":\"浙江省杭州市余杭区潘金线\",\"business\":\"\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"浙江省\",\"city\":\"杭州市\",\"city_level\":2,\"district\":\"余杭区\",\"town\":\"\",\"adcode\":\"330110\",\"street\":\"潘金线\",\"street_number\":\"\",\"direction\":\"\",\"distance\":\"\"},\"pois\":[],\"roads\":[],\"poiRegions\":[],\"sematic_description\":\"阳坞山西北444米\",\"cityCode\":179}}" 123 | #> [3] "{\"status\":0,\"result\":{\"location\":{\"lng\":104.06792346330394,\"lat\":30.67994271533221},\"formatted_address\":\"四川省成都市青羊区王家塘街84号\",\"business\":\"骡马市,新华西路,八宝街\",\"addressComponent\":{\"country\":\"中国\",\"country_code\":0,\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"四川省\",\"city\":\"成都市\",\"city_level\":2,\"district\":\"青羊区\",\"town\":\"\",\"adcode\":\"510105\",\"street\":\"王家塘街\",\"street_number\":\"84号\",\"direction\":\"附近\",\"distance\":\"6\"},\"pois\":[],\"roads\":[],\"poiRegions\":[{\"direction_desc\":\"内\",\"name\":\"青羊区政府\",\"tag\":\"政府机构;各级政府\",\"uid\":\"96b672aa58335874cf04ef80\"}],\"sematic_description\":\"青羊区政府内,成都华氏陶瓷艺术博物馆附近1米\",\"cityCode\":75}}" 124 | 125 | Package Data 126 | ------------ 127 | 128 | Functions `bmap_get_coords()` and `bmap_get_location()` both cache API return data. The functions will first look for the return data in the cached package datasets, if it's not found there they will execute an API request. 129 | 130 | Use function `bmap_clear_cache()` to clear either of the package cache data sets (or both at once). 131 | 132 | ``` r 133 | bmap_clear_cache(coordinate_cache = TRUE, address_cache = TRUE) 134 | ``` 135 | 136 | Use function `bmap_get_cached_coord_data()` to load all of the cached lat/lon return data as a tidy data frame. 137 | 138 | ``` r 139 | df <- bmap_get_cached_coord_data() 140 | ``` 141 | 142 | Use function `bmap_get_cached_address_data()` to load the cached address return data as a tidy data frame. 143 | 144 | ``` r 145 | df <- bmap_get_cached_address_data() 146 | ``` 147 | -------------------------------------------------------------------------------- /src/addrs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "baidugeo.h" 3 | using namespace Rcpp; 4 | 5 | 6 | // Get address data from the json of a single API request. 7 | void from_json_addrs(std::string& json, std::string& key) { 8 | if(json != "") { 9 | global_vars::doc.Parse(json.c_str()); 10 | } else { 11 | global_vars::doc.Parse("{\"empty\":\"json\"}"); 12 | } 13 | 14 | if(global_vars::doc.HasParseError()) { 15 | Rcerr << "parse error for json string: '"<< json << "'" << std::endl; 16 | } 17 | 18 | // Input lon and input lat (if "key" is not "NA"). 19 | if(key != "NA") { 20 | get_coords_from_uri(key); 21 | } 22 | 23 | // Return lon. 24 | if(global_vars::doc["result"]["location"].HasMember("lng")) { 25 | global_vars::lng[0] = global_vars::doc["result"]["location"]["lng"].GetDouble(); 26 | } else { 27 | global_vars::lng[0] = NA_REAL; 28 | } 29 | 30 | // Return lat. 31 | if(global_vars::doc["result"]["location"].HasMember("lat")) { 32 | global_vars::lat[0] = global_vars::doc["result"]["location"]["lat"].GetDouble(); 33 | } else { 34 | global_vars::lat[0] = NA_REAL; 35 | } 36 | 37 | // status 38 | if(global_vars::doc.HasMember("status")) { 39 | global_vars::status[0] = global_vars::doc["status"].GetDouble(); 40 | } else { 41 | global_vars::status[0] = NA_REAL; 42 | } 43 | 44 | // formatted_address. 45 | if(global_vars::doc["result"].HasMember("formatted_address")) { 46 | addr_vars::temp_str = global_vars::doc["result"]["formatted_address"].GetString(); 47 | if(addr_vars::temp_str != "") { 48 | addr_vars::formatted_address = addr_vars::temp_str; 49 | } else { 50 | addr_vars::formatted_address = NA_STRING; 51 | } 52 | } else { 53 | addr_vars::formatted_address = NA_STRING; 54 | } 55 | 56 | // business. 57 | if(global_vars::doc["result"].HasMember("business")) { 58 | addr_vars::temp_str = global_vars::doc["result"]["business"].GetString(); 59 | if(addr_vars::temp_str != "") { 60 | addr_vars::business = addr_vars::temp_str; 61 | } else { 62 | addr_vars::business = NA_STRING; 63 | } 64 | } else { 65 | addr_vars::business = NA_STRING; 66 | } 67 | 68 | // country. 69 | if(global_vars::doc["result"]["addressComponent"].HasMember("country")) { 70 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["country"].GetString(); 71 | if(addr_vars::temp_str != "") { 72 | addr_vars::country = addr_vars::temp_str; 73 | } else { 74 | addr_vars::country = NA_STRING; 75 | } 76 | } else { 77 | addr_vars::country = NA_STRING; 78 | } 79 | 80 | // country_code. 81 | if(global_vars::doc["result"]["addressComponent"].HasMember("country_code")) { 82 | addr_vars::country_code[0] = global_vars::doc["result"]["addressComponent"]["country_code"].GetDouble(); 83 | } else { 84 | addr_vars::country_code[0] = NA_REAL; 85 | } 86 | 87 | // country_code_iso. 88 | if(global_vars::doc["result"]["addressComponent"].HasMember("country_code_iso")) { 89 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["country_code_iso"].GetString(); 90 | if(addr_vars::temp_str != "") { 91 | addr_vars::country_code_iso = addr_vars::temp_str; 92 | } else { 93 | addr_vars::country_code_iso = NA_STRING; 94 | } 95 | } else { 96 | addr_vars::country_code_iso = NA_STRING; 97 | } 98 | 99 | // country_code_iso2. 100 | if(global_vars::doc["result"]["addressComponent"].HasMember("country_code_iso2")) { 101 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["country_code_iso2"].GetString(); 102 | if(addr_vars::temp_str != "") { 103 | addr_vars::country_code_iso2 = addr_vars::temp_str; 104 | } else { 105 | addr_vars::country_code_iso2 = NA_STRING; 106 | } 107 | } else { 108 | addr_vars::country_code_iso2 = NA_STRING; 109 | } 110 | 111 | // province. 112 | if(global_vars::doc["result"]["addressComponent"].HasMember("province")) { 113 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["province"].GetString(); 114 | if(addr_vars::temp_str != "") { 115 | addr_vars::province = addr_vars::temp_str; 116 | } else { 117 | addr_vars::province = NA_STRING; 118 | } 119 | } else { 120 | addr_vars::province = NA_STRING; 121 | } 122 | 123 | // city. 124 | if(global_vars::doc["result"]["addressComponent"].HasMember("city")) { 125 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["city"].GetString(); 126 | if(addr_vars::temp_str != "") { 127 | addr_vars::city = addr_vars::temp_str; 128 | } else { 129 | addr_vars::city = NA_STRING; 130 | } 131 | } else { 132 | addr_vars::city = NA_STRING; 133 | } 134 | 135 | // city_level. 136 | if(global_vars::doc["result"]["addressComponent"].HasMember("city_level")) { 137 | addr_vars::city_level[0] = global_vars::doc["result"]["addressComponent"]["city_level"].GetDouble(); 138 | } else { 139 | addr_vars::city_level[0] = NA_REAL; 140 | } 141 | 142 | // district. 143 | if(global_vars::doc["result"]["addressComponent"].HasMember("district")) { 144 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["district"].GetString(); 145 | if(addr_vars::temp_str != "") { 146 | addr_vars::district = addr_vars::temp_str; 147 | } else { 148 | addr_vars::district = NA_STRING; 149 | } 150 | } else { 151 | addr_vars::district = NA_STRING; 152 | } 153 | 154 | // town. 155 | if(global_vars::doc["result"]["addressComponent"].HasMember("town")) { 156 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["town"].GetString(); 157 | if(addr_vars::temp_str != "") { 158 | addr_vars::town = addr_vars::temp_str; 159 | } else { 160 | addr_vars::town = NA_STRING; 161 | } 162 | } else { 163 | addr_vars::town = NA_STRING; 164 | } 165 | 166 | // adcode. 167 | if(global_vars::doc["result"]["addressComponent"].HasMember("adcode")) { 168 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["adcode"].GetString(); 169 | if(addr_vars::temp_str != "") { 170 | addr_vars::ad_code[0] = stoi(addr_vars::temp_str); 171 | } else { 172 | addr_vars::ad_code[0] = NA_INTEGER; 173 | } 174 | } else { 175 | addr_vars::ad_code[0] = NA_INTEGER; 176 | } 177 | 178 | // street. 179 | if(global_vars::doc["result"]["addressComponent"].HasMember("street")) { 180 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["street"].GetString(); 181 | if(addr_vars::temp_str != "") { 182 | addr_vars::street = addr_vars::temp_str; 183 | } else { 184 | addr_vars::street = NA_STRING; 185 | } 186 | } else { 187 | addr_vars::street = NA_STRING; 188 | } 189 | 190 | // street_number. 191 | if(global_vars::doc["result"]["addressComponent"].HasMember("street_number")) { 192 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["street_number"].GetString(); 193 | if(addr_vars::temp_str != "") { 194 | addr_vars::street_number = addr_vars::temp_str; 195 | } else { 196 | addr_vars::street_number = NA_STRING; 197 | } 198 | } else { 199 | addr_vars::street_number = NA_STRING; 200 | } 201 | 202 | // direction. 203 | if(global_vars::doc["result"]["addressComponent"].HasMember("direction")) { 204 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["direction"].GetString(); 205 | if(addr_vars::temp_str != "") { 206 | addr_vars::direction = addr_vars::temp_str; 207 | } else { 208 | addr_vars::direction = NA_STRING; 209 | } 210 | } else { 211 | addr_vars::direction = NA_STRING; 212 | } 213 | 214 | // distance. 215 | if(global_vars::doc["result"]["addressComponent"].HasMember("distance")) { 216 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["distance"].GetString(); 217 | if(addr_vars::temp_str != "") { 218 | addr_vars::distance = stoi(addr_vars::temp_str); 219 | } else { 220 | addr_vars::distance = NA_INTEGER; 221 | } 222 | } else { 223 | addr_vars::distance = NA_INTEGER; 224 | } 225 | 226 | // sematic_description. 227 | if(global_vars::doc["result"]["addressComponent"].HasMember("sematic_description")) { 228 | addr_vars::temp_str = global_vars::doc["result"]["addressComponent"]["sematic_description"].GetString(); 229 | if(addr_vars::temp_str != "") { 230 | addr_vars::sematic_desc = addr_vars::temp_str; 231 | } else { 232 | addr_vars::sematic_desc = NA_STRING; 233 | } 234 | } else { 235 | addr_vars::sematic_desc = NA_STRING; 236 | } 237 | 238 | // city_code. 239 | if(global_vars::doc["result"].HasMember("cityCode")) { 240 | addr_vars::city_code[0] = global_vars::doc["result"]["cityCode"].GetDouble(); 241 | } else { 242 | addr_vars::city_code[0] = NA_REAL; 243 | } 244 | } 245 | 246 | 247 | // [[Rcpp::export]] 248 | List from_json_addrs_vector(NumericVector lng, NumericVector lat, 249 | std::vector json_vect) { 250 | int json_len = json_vect.size(); 251 | NumericVector input_lng(json_len); 252 | NumericVector input_lat(json_len); 253 | NumericVector return_lng(json_len); 254 | NumericVector return_lat(json_len); 255 | NumericVector status(json_len); 256 | CharacterVector formatted_address(json_len); 257 | CharacterVector business(json_len); 258 | CharacterVector country(json_len); 259 | NumericVector country_code(json_len); 260 | CharacterVector country_code_iso(json_len); 261 | CharacterVector country_code_iso2(json_len); 262 | CharacterVector province(json_len); 263 | CharacterVector city(json_len); 264 | NumericVector city_level(json_len); 265 | CharacterVector district(json_len); 266 | CharacterVector town(json_len); 267 | IntegerVector ad_code(json_len); 268 | CharacterVector street(json_len); 269 | CharacterVector street_number(json_len); 270 | CharacterVector direction(json_len); 271 | IntegerVector distance(json_len); 272 | CharacterVector sematic_desc(json_len); 273 | NumericVector city_code(json_len); 274 | 275 | rapidjson::Document doc; 276 | std::string na_str = "NA"; 277 | 278 | for(int i = 0; i < json_len; ++i) { 279 | from_json_addrs(json_vect[i], na_str); 280 | 281 | input_lng[i] = lng[i]; 282 | input_lat[i] = lat[i]; 283 | return_lng[i] = global_vars::lng[0]; 284 | return_lat[i] = global_vars::lat[0]; 285 | status[i] = global_vars::status[0]; 286 | formatted_address[i] = addr_vars::formatted_address; 287 | business[i] = addr_vars::business; 288 | country[i] = addr_vars::country; 289 | country_code[i] = addr_vars::country_code[0]; 290 | country_code_iso[i] = addr_vars::country_code_iso; 291 | country_code_iso2[i] = addr_vars::country_code_iso2; 292 | province[i] = addr_vars::province; 293 | city[i] = addr_vars::city; 294 | city_level[i] = addr_vars::city_level[0]; 295 | district[i] = addr_vars::district; 296 | town[i] = addr_vars::town; 297 | ad_code[i] = addr_vars::ad_code[0]; 298 | street[i] = addr_vars::street; 299 | street_number[i] = addr_vars::street_number; 300 | direction[i] = addr_vars::direction; 301 | distance[i] = addr_vars::distance[0]; 302 | sematic_desc[i] = addr_vars::sematic_desc; 303 | city_code[i] = addr_vars::city_code[0]; 304 | } 305 | 306 | // Create List output that has the necessary attributes to make it a 307 | // data.frame object. 308 | List out(23); 309 | out[0] = input_lng; 310 | out[1] = input_lat; 311 | out[2] = return_lng; 312 | out[3] = return_lat; 313 | out[4] = status; 314 | out[5] = formatted_address; 315 | out[6] = business; 316 | out[7] = country; 317 | out[8] = country_code; 318 | out[9] = country_code_iso; 319 | out[10] = country_code_iso2; 320 | out[11] = province; 321 | out[12] = city; 322 | out[13] = city_level; 323 | out[14] = district; 324 | out[15] = town; 325 | out[16] = ad_code; 326 | out[17] = street; 327 | out[18] = street_number; 328 | out[19] = direction; 329 | out[20] = distance; 330 | out[21] = sematic_desc; 331 | out[22] = city_code; 332 | 333 | CharacterVector names(23); 334 | names[0] = "input_lon"; 335 | names[1] = "input_lat"; 336 | names[2] = "return_lon"; 337 | names[3] = "return_lat"; 338 | names[4] = "status"; 339 | names[5] = "formatted_address"; 340 | names[6] = "business"; 341 | names[7] = "country"; 342 | names[8] = "country_code"; 343 | names[9] = "country_code_iso"; 344 | names[10] = "country_code_iso2"; 345 | names[11] = "province"; 346 | names[12] = "city"; 347 | names[13] = "city_level"; 348 | names[14] = "district"; 349 | names[15] = "town"; 350 | names[16] = "ad_code"; 351 | names[17] = "street"; 352 | names[18] = "street_number"; 353 | names[19] = "direction"; 354 | names[20] = "distance"; 355 | names[21] = "sematic_desc"; 356 | names[22] = "city_code"; 357 | 358 | out.attr("names") = names; 359 | out.attr("class") = "data.frame"; 360 | out.attr("row.names") = seq(1, json_len); 361 | 362 | return out; 363 | } 364 | 365 | 366 | // [[Rcpp::export]] 367 | List get_addrs_pkg_data(Environment& addr_hash_map, 368 | CharacterVector& keys) { 369 | int cache_len = keys.size(); 370 | NumericVector input_lng(cache_len); 371 | NumericVector input_lat(cache_len); 372 | NumericVector return_lng(cache_len); 373 | NumericVector return_lat(cache_len); 374 | NumericVector status(cache_len); 375 | CharacterVector formatted_address(cache_len); 376 | CharacterVector business(cache_len); 377 | CharacterVector country(cache_len); 378 | NumericVector country_code(cache_len); 379 | CharacterVector country_code_iso(cache_len); 380 | CharacterVector country_code_iso2(cache_len); 381 | CharacterVector province(cache_len); 382 | CharacterVector city(cache_len); 383 | NumericVector city_level(cache_len); 384 | CharacterVector district(cache_len); 385 | CharacterVector town(cache_len); 386 | IntegerVector ad_code(cache_len); 387 | CharacterVector street(cache_len); 388 | CharacterVector street_number(cache_len); 389 | CharacterVector direction(cache_len); 390 | IntegerVector distance(cache_len); 391 | CharacterVector sematic_desc(cache_len); 392 | NumericVector city_code(cache_len); 393 | 394 | std::string curr_key; 395 | std::string curr_json; 396 | 397 | for(int i = 0; i < cache_len; ++i) { 398 | curr_key = as(keys[i]); 399 | curr_json = as(addr_hash_map[curr_key]); 400 | 401 | from_json_addrs(curr_json, curr_key); 402 | 403 | input_lng[i] = addr_vars::input_lng; 404 | input_lat[i] = addr_vars::input_lat; 405 | return_lng[i] = global_vars::lng[0]; 406 | return_lat[i] = global_vars::lat[0]; 407 | status[i] = global_vars::status[0]; 408 | formatted_address[i] = addr_vars::formatted_address; 409 | business[i] = addr_vars::business; 410 | country[i] = addr_vars::country; 411 | country_code[i] = addr_vars::country_code[0]; 412 | country_code_iso[i] = addr_vars::country_code_iso; 413 | country_code_iso2[i] = addr_vars::country_code_iso2; 414 | province[i] = addr_vars::province; 415 | city[i] = addr_vars::city; 416 | city_level[i] = addr_vars::city_level[0]; 417 | district[i] = addr_vars::district; 418 | town[i] = addr_vars::town; 419 | ad_code[i] = addr_vars::ad_code[0]; 420 | street[i] = addr_vars::street; 421 | street_number[i] = addr_vars::street_number; 422 | direction[i] = addr_vars::direction; 423 | distance[i] = addr_vars::distance[0]; 424 | sematic_desc[i] = addr_vars::sematic_desc; 425 | city_code[i] = addr_vars::city_code[0]; 426 | } 427 | 428 | // Create List output that has the necessary attributes to make it a 429 | // data.frame object. 430 | List out(23); 431 | out[0] = input_lng; 432 | out[1] = input_lat; 433 | out[2] = return_lng; 434 | out[3] = return_lat; 435 | out[4] = status; 436 | out[5] = formatted_address; 437 | out[6] = business; 438 | out[7] = country; 439 | out[8] = country_code; 440 | out[9] = country_code_iso; 441 | out[10] = country_code_iso2; 442 | out[11] = province; 443 | out[12] = city; 444 | out[13] = city_level; 445 | out[14] = district; 446 | out[15] = town; 447 | out[16] = ad_code; 448 | out[17] = street; 449 | out[18] = street_number; 450 | out[19] = direction; 451 | out[20] = distance; 452 | out[21] = sematic_desc; 453 | out[22] = city_code; 454 | 455 | CharacterVector names(23); 456 | names[0] = "input_lon"; 457 | names[1] = "input_lat"; 458 | names[2] = "return_lon"; 459 | names[3] = "return_lat"; 460 | names[4] = "status"; 461 | names[5] = "formatted_address"; 462 | names[6] = "business"; 463 | names[7] = "country"; 464 | names[8] = "country_code"; 465 | names[9] = "country_code_iso"; 466 | names[10] = "country_code_iso2"; 467 | names[11] = "province"; 468 | names[12] = "city"; 469 | names[13] = "city_level"; 470 | names[14] = "district"; 471 | names[15] = "town"; 472 | names[16] = "ad_code"; 473 | names[17] = "street"; 474 | names[18] = "street_number"; 475 | names[19] = "direction"; 476 | names[20] = "distance"; 477 | names[21] = "sematic_desc"; 478 | names[22] = "city_code"; 479 | 480 | out.attr("names") = names; 481 | out.attr("class") = "data.frame"; 482 | if(cache_len > 0) { 483 | out.attr("row.names") = seq(1, cache_len); 484 | } else { 485 | out.attr("row.names") = 0; 486 | } 487 | 488 | return out; 489 | } 490 | --------------------------------------------------------------------------------