New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API de Sakbé #13

Open
Eflores89 opened this Issue Aug 11, 2016 · 8 comments

Comments

Projects
None yet
2 participants
@Eflores89
Owner

Eflores89 commented Aug 11, 2016

INEGI publicó un nuevo API que parece interesante para trazar rutas.

Hasta ahora solo eh podido incluir el de búsqueda de id's de destinos, (ver la función inegi_destiny).

Le heche un vistazo también a la de líneas y tengo un avance:

#' Returns INEGI line ID
#'
#' Returns data.frame with id's that match coordinates. 
#'
#' @param latitud latitud vector in decimals
#' @param longitud longitud vector in decimals
#' @param scale scale of map visualization (1:scale)
#' @param keep_trying if TRUE the function will start from scale downwards by a degree of 10 until a line is reached
#' @param token API token supplied by INEGI
#' 
#' @return Data.frame
#'
#' @author Eduardo Flores 
#' 
#' @examples
#' # All id's in Monterrey, Mex.
#' \dontrun{
#' token <- "webservice_token"
#' line_ids <- inegi_lines(latitud, longitud, token = token)
#' }
#'
#' @importFrom jsonlite fromJSON
#' @importFrom XML xmlToList
#' @importFrom plyr ldply
#' @export
inegi_lines <- function(latitud, longitud, scale = 100000, keep_trying = TRUE, token){

  if(keep_trying){
  d <- NULL
   while(is.null(d$linea)){
    print(paste0("Using scale: ", scale))
     if(scale<1){d$linea <- NA # if already extended all attempts
     }else{ 
    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=IL",
                "&x=", latitud,
                "&y=", longitud, 
                "&escala=", scale, 
                "&type=xml&key=", token)

    d <- XML::xmlToList(q)
    scale <- scale/10
     }
   }
  }else{
    print(paste0("Using scale: ", scale))
    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=IL",
                "&x=", latitud,
                "&y=", longitud, 
                "&escala=", scale, 
                "&type=xml&key=", token)

    d <- XML::xmlToList(q)
  }

  if(is.null(d$linea)){stop("Nothing returned. Try with different scale or keep_trying = true")}
  if(suppressWarnings(is.na(d$linea))){stop("Nothing returned. Try with different scale or keep_trying = true")}

  df <- as.data.frame(d$linea)
  print(df)
  #geolist <- apply(X = df$geojson, 
   #                MARGIN = 1, inegiR::ext_geo)
  #df$GEO_TYPE <- ldply(geolist, "[")['TYPE']
  #df$LAT <- ldply(geolist, "[")['LAT']
  #df$LONG <- ldply(geolist, "[")['LONG']

  df
}

Y la documentación del INEGI me trae vuelto loco con el trace de rutas. Pareciera que tiene muchas opciones y muchas no están explicadas correctamente. Llevo un avance en una funcionsita así...

inegi_route <- function(from, to, route_type = 2, vehicle = 1, axis = 0, type = 1, token){
  if(type == 1){
    # linea a linea
    if(length(from)==2){}else{stop("Length of from parameter must be 2. A vector with source id and target id, in that order")}
    if(length(to)==2){}else{stop("Length of to parameter must be 2. A vector with source id and target id, in that order")}

    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR
                &id_i=1
                &source_i=", 
                from[1], 
                "&target_i=",
                from[2],
                "&id_f=", from[2],
                "&source_f=", to[1],
                "&target_f=", to[2],
                "&p=", route_type,
                "&v=", vehicle,
                "&e=", axis,
                "&type=xml
                  &key=", token)
    m <- "line to line"
  }else{
    if(type == 2){
      q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR",
                  "&dest_i=",from, 
                  "&dest_f=", to, 
                  "&p=", route_type, 
                  "&v=", vehicle, 
                  "&e=", axis,
                  "&type=xml&key=",token)
      m <- "destiny to destiny"
    }else{

      if(type == 3){

      }else{
        if(type == 4){

        }else{stop("Type of query unrecognized. Use 1 through 4.")}
      }
    }
  }
  d <- XML::xmlToList(q)
  df <- data.frame("ROUTE_STRING" = paste0("Route, ", m, 
                                           " id: ", from[1], 
                                           " to id: ", to[1]),
                   "SQL_STRING" = ifelse(is.null(d$ruta$sql), NA, as.character(d$ruta$sql)), 
                   "ROUTE_LENGTH" = ifelse(is.null(d$ruta$long_km), NA, as.numeric(d$ruta$long_km)), 
                   "ROUTE_TIME" = ifelse(is.null(d$ruta$tiempo_min), NA, as.numeric(d$ruta$tiempo_min)),
                   "ROUTE_TOLL" = ifelse(is.null(d$ruta$peaje), NA, 
                                         ifelse(as.character(d$ruta$peaje)=="t", TRUE,FALSE)),
                   "ROUTE_COST" = ifelse(is.null(d$ruta$costo_caseta), NA, as.numeric(d$ruta$costo_caseta)),
                   "ROUTE_EXCEED" = ifelse(is.null(d$ruta$eje_excedente), NA, as.numeric(d$ruta$eje_excedente))
                   )
  l <- list("METADATA" = df, 
            "GEO" = jsonlite::fromJSON(as.character(d$ruta$geojson)))
  return(l)
}

@arturocm crees que podrías ayudarme a darle carpetazo al tema? Siento que ya tengo ceguera de taller y tal vez tengas ideas nuevas. Quiero sacar una versión 2.0 con este nuevo API, te pongo como coauthor, que ya haz hecho bastante también del DENUE.

@arturocm

This comment has been minimized.

arturocm commented Aug 11, 2016

Justamente estaba buscando algo así con el API de Google, pero tiene limite de 2500 consultas diarias y no me es suficiente. Lo veo en estos días

@arturocm

This comment has been minimized.

arturocm commented Aug 17, 2016

Ya empecé a jugar con el código, y tengo dos observaciones/dudas iniciales:

1)los siguientes parámetros de entrada no están nada claro:

  • id_i: identificador de la línea de inicio. *
  • source_i: valor del source de la línea de inicio. *
  • target_i: valor del target de la línea de inicio. *
  • id_f: identificador de la línea final. *
  • source_f: valor del source de la línea final. *
  • target_f: valor del target de la línea final. *
  • dest_i: identificador del destino de inicio. **
  • dest_f: identificador del destino final. **
  1. Al cambiar el layout de lo que hay en la funcion paste0 pude hacer funcionar el codigo (me estaba arrojando error con los \n)
from <- c(82233,82234,633281) #copie los valores del ejemplo del API
to <- c(218261,113968)

inegi_route <- function(from, to, route_type = 2, vehicle = 1, axis = 0, type = 1, token){
  if(type == 1){
    # linea a linea
    if(length(from)==2){}else{stop("Length of from parameter must be 2. A vector with source id and target id, in that order")}
    if(length(to)==2){}else{stop("Length of to parameter must be 2. A vector with source id and target id, in that order")}

    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR&id_i=1&source_i=", 
                from[1], 
                "&target_i=",
                from[2],
                "&id_f=", from[3],
                "&source_f=", to[1],
                "&target_f=", to[2],
                "&p=", route_type,
                "&v=", vehicle,
                "&e=", axis,
                "&type=xml&key=", token)
    m <- "line to line"
  }else{
    if(type == 2){
      q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR",
                  "&dest_i=",from, 
                  "&dest_f=", to, 
                  "&p=", route_type, 
                  "&v=", vehicle, 
                  "&e=", axis,
                  "&type=xml&key=",token)
      m <- "destiny to destiny"
    }else{

      if(type == 3){

      }else{
        if(type == 4){

        }else{stop("Type of query unrecognized. Use 1 through 4.")}
      }
    }
  }
  d <- XML::xmlToList(q)
  df <- data.frame("ROUTE_STRING" = paste0("Route, ", m, 
                                           " id: ", from[1], 
                                           " to id: ", to[1]),
                   "SQL_STRING" = ifelse(is.null(d$ruta$sql), NA, as.character(d$ruta$sql)), 
                   "ROUTE_LENGTH" = ifelse(is.null(d$ruta$long_km), NA, as.numeric(d$ruta$long_km)), 
                   "ROUTE_TIME" = ifelse(is.null(d$ruta$tiempo_min), NA, as.numeric(d$ruta$tiempo_min)),
                   "ROUTE_TOLL" = ifelse(is.null(d$ruta$peaje), NA, 
                                         ifelse(as.character(d$ruta$peaje)=="t", TRUE,FALSE)),
                   "ROUTE_COST" = ifelse(is.null(d$ruta$costo_caseta), NA, as.numeric(d$ruta$costo_caseta)),
                   "ROUTE_EXCEED" = ifelse(is.null(d$ruta$eje_excedente), NA, as.numeric(d$ruta$eje_excedente))
  )
  l <- list("METADATA" = df, 
            "GEO" = jsonlite::fromJSON(as.character(d$ruta$geojson)))
  return(l)
}

Continuaré con esto...

@Eflores89

This comment has been minimized.

Owner

Eflores89 commented Aug 17, 2016

Exactamente!! Traté de encontrar por todos lados, pero no se preocupan NADA por dejar claro que son los parámetros...

@arturocm

This comment has been minimized.

arturocm commented Aug 17, 2016

Segun http://antares.inegi.org.mx/analisis/red_hidro/SIATL/ cuando deseas trazar una ruta te sale el siguiente aviso:
screen shot 2016-08-17 at 1 08 57 pm

Encontré un poco más de información en el siguiente documento:

http://www.inegi.org.mx/saladeprensa/aproposito/2015/caminero0.pdf

@arturocm

This comment has been minimized.

arturocm commented Aug 17, 2016

Ok... aquí va lo que llevo.

inegi_lines <- function(latitud, longitud, scale = 100000, keep_trying = TRUE, token){
  options(scipen = 999)
  if(keep_trying){
    d <- NULL
    while(is.null(d$linea)){
      print(paste0("Using scale: ", scale))
      if(scale<1){d$linea <- NA # if already extended all attempts
      }else{ 
        q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=IL",
                    "&x=", longitud,
                    "&y=", latitud, 
                    "&escala=", scale, 
                    "&type=xml&key=", token)
        d <- XML::xmlToList(q)
        scale <- scale/10
      }
    }
  }else{
    print(paste0("Using scale: ", scale))
    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=IL",
                "&x=", longitud,
                "&y=", latitud, 
                "&escala=", scale, 
                "&type=xml&key=", token)
    d <- XML::xmlToList(q)
  }
  if(is.null(d$linea)){stop("Nothing returned. Try with different scale or keep_trying = true")}
  if(suppressWarnings(is.na(d$linea))){stop("Nothing returned. Try with different scale or keep_trying = true")}
  df <- as.data.frame(d$linea)
  print(df)
  return(df)
}

Unica modificación que hice a la función inegi_lines() es la del formato de los números para evitar que se utilicen notaciones científicas (esto me generó problemas al tratar de correr la formula en mi computadora)

En cuanto a inegi_route() aquí empieza lo interesante:

  1. Las variables from_io y to_io deben de ser coordenadas en el formato lat/lon
  2. Se hace uso de la función inegi_lines() para obtener los valores de id, source y target de las coordenadas mencionadas en 1
  3. Hasta el momento solo hice uso de type==1
inegi_route <- function(from_io, to_io, route_type = 2, vehicle = 1, axis = 0, type = 1, token){
  #use inegi_lines() to obtain id, source and target for the routes
  from <- inegi_lines(latitud=from_io[1],longitud=from_io[2],scale=10000000,keep_trying = TRUE, token = token)
  to <- inegi_lines(latitud=to_io[1],longitud=to_io[2],scale=10000000,keep_trying = TRUE, token = token)
  if(type == 1){
    # linea a linea
    if(length(from)==5){}else{stop("Length of from parameter must be 2. A vector with source id and target id, in that order")}
    if(length(to)==5){}else{stop("Length of to parameter must be 2. A vector with source id and target id, in that order")}
    q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR&",
                "id_i=",from[1,1], #need this [1,1] to specifiy the correct value from the variable
                "&source_i=", from[1,2], 
                "&target_i=",from[1,2],
                "&id_f=", to[1,2],
                "&source_f=", to[1,2],
                "&target_f=", to[1,2],
                "&p=", route_type,
                "&v=", vehicle,
                "&e=", axis,
                "&type=xml&key=", token)
    m <- "line to line"
  }else{
    if(type == 2){
      q <- paste0("http://gaia.inegi.org.mx/sakbe/wservice?make=CR",
                  "&dest_i=",from, 
                  "&dest_f=", to, 
                  "&p=", route_type, 
                  "&v=", vehicle, 
                  "&e=", axis,
                  "&type=xml&key=",token)
      m <- "destiny to destiny"
    }else{
      # pending
      if(type == 3){
      # pending  
      }else{
        if(type == 4){
        # pending
        }else{stop("Type of query unrecognized. Use 1 through 4.")}
      }
    }
  }
  d <- XML::xmlToList(q)
  df <- data.frame("ROUTE_STRING" = paste0("Route, ", m, 
                                           " id: ", from[1,1], 
                                           " to id: ", to[1,1]),
                   "SQL_STRING" = ifelse(is.null(d$ruta$sql), NA, as.character(d$ruta$sql)), 
                   "ROUTE_LENGTH" = ifelse(is.null(d$ruta$long_km), NA, as.numeric(d$ruta$long_km)), 
                   "ROUTE_TIME" = ifelse(is.null(d$ruta$tiempo_min), NA, as.numeric(d$ruta$tiempo_min)),
                   "ROUTE_TOLL" = ifelse(is.null(d$ruta$peaje), NA, 
                                         ifelse(as.character(d$ruta$peaje)=="t", TRUE,FALSE)),
                   "ROUTE_COST" = ifelse(is.null(d$ruta$costo_caseta), NA, as.numeric(d$ruta$costo_caseta)),
                   "ROUTE_EXCEED" = ifelse(is.null(d$ruta$eje_excedente), NA, as.numeric(d$ruta$eje_excedente))
  )
  l <- list("METADATA" = df, 
            "GEO" = jsonlite::fromJSON(as.character(d$ruta$geojson)))
  return(l)
}

A manera de prueba, busque la ruta desde el TEC de Monterrey hasta el Museo de Historia del Barrio Antiguo (Monterrey)

p1=c(25.671528, -100.306492) #museo de historia mexicano (monterrey)
p2=c(25.650443,-100.289725) #tec de monterrey
p3=c(29.081782, -110.961874) #centro hermosillo

test <- inegi_route(p1,p2,token=token)
mapa <- test$GEO$coordinates

library(leaflet)
map <- leaflet() %>%
  addTiles() %>%
  setView(p1[2], p1[1], zoom = 10) %>%
  addCircleMarkers(lat = mapa[,2],
                   lng = mapa[,1],
                   radius = 3,
                   stroke = TRUE, fillOpacity = 0.5) %>%
  addProviderTiles("CartoDB.Positron") 
map

En caso de querer generar una función para "mapear" las coordenadas de distancias más largas, es necesario usar un do.call(). El siguiente ejemplo es la ruta desde el Tec de Monterrey hasta el centro de Hermosillo

p1=c(25.671528, -100.306492) #museo de historia mexicano (monterrey)
p2=c(25.650443,-100.289725) #tec de monterrey
p3=c(29.081782, -110.961874) #centro hermosillo

test <- inegi_route(p2,p3,token=token)
mapa <- do.call("rbind",test$GEO$coordinates)

library(leaflet)
map <- leaflet() %>%
  addTiles() %>%
  setView(p1[2], p1[1], zoom = 10) %>%
  addCircleMarkers(lat = mapa[,2],
                   lng = mapa[,1],
                   radius = 3,
                   stroke = TRUE, fillOpacity = 0.5) %>%
  addProviderTiles("CartoDB.Positron") 
map

Espero que vayamos en la dirección correcta.

Comentarios?

@Eflores89

This comment has been minimized.

Owner

Eflores89 commented Aug 17, 2016

O sea, como lo entiendo, la más directa es type == 1 que es coordenada a coordenada? Las demás podríamos simplemente omitir, ¿no? Por que en teoría con un "search" ya sale la coordenada...

@arturocm

This comment has been minimized.

arturocm commented Aug 17, 2016

Tengo pendiente trabajar en el "error handling" de estas dos funciones. Y también tengo interés en el detalle de ruta

@Eflores89

This comment has been minimized.

Owner

Eflores89 commented Dec 21, 2016

duda, en qué quedó todo esto? ajaja

estaría bien acabarlo estos días que tengo vacaciones para ya publicarlo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment