Using sf package within a plumber api -- sf::st_as_sf seems to be failing

I am trying to create an API with the plumber package that leverages the sf package. The following function takes the x/y coordinates of a location in California and checks which electric provider's territory the coordinates fall under using the sf::st_intersects function. The function works when I run it interactively in my R session, but when I deploy with plumber

edu_mapping <- function(x,
                        y) {
  
  st_read_edu <- sf::st_read('https://services3.arcgis.com/bWPjFyq029ChCGur/arcgis/rest/services/California_Electric_Utility_Service_Areas/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=*&returnGeometry=true&returnCentroid=false&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pgeojson&token=')
  
  points <- data.frame(x = x,
                       y = y)
  
  points_sf <- sf::st_as_sf(points, coords = c('x', 'y'), crs = 4326)
  
  intersection <- sf::st_intersects(st_read_edu, points_sf, sparse = FALSE) %>%
    as.data.frame() %>%
    dplyr::mutate(edu = st_read_edu$Utility) %>%
    dplyr::rename(within_edu_territory = V1) %>%
    filter(within_edu_territory == TRUE)
  
  return(intersection)
}

edu_mapping(x = -118.240290,
            y = 34.072580)

  within_edu_territory                                     edu
1                 TRUE Los Angeles Department of Water & Power

However, when I run this same code within my api I get no cases returned as all values for within_edu_territory come back false:

[
  {
    "within_edu_territory": false,
    "edu": "PacifiCorp"
  },
  {
    "within_edu_territory": false,
    "edu": "Liberty Utilities"
  },
  {
    "within_edu_territory": false,
    "edu": "Surprise Valley Electrification Corporation"
  },
  {
    "within_edu_territory": false,
    "edu": "Plumas-Sierra Rural Electric Cooperative"
  },
  {
    "within_edu_territory": false,
    "edu": "Shelter Cove Resort Improvement District"
  },
  {
    "within_edu_territory": false,
    "edu": "Valley Electrical Association"
  },
  {
    "within_edu_territory": false,
    "edu": "Anza Electric Cooperative, Inc."
  },
  {
    "within_edu_territory": false,
    "edu": "Sonoma Clean Power"
  },
  {
    "within_edu_territory": false,
    "edu": "Morongo Band of Mission Indians"
  },
  {
    "within_edu_territory": false,
    "edu": "Aha Macav Power Service"
  },
  {
    "within_edu_territory": false,
    "edu": "Biggs Municipal Utilities"
  },
  {
    "within_edu_territory": false,
    "edu": "Imperial Irrigation District"
  },
  {
    "within_edu_territory": false,
    "edu": "Port of Stockton"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Pittsburg"
  },
  {
    "within_edu_territory": false,
    "edu": "Lathrop Irrigation District"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Riverside"
  },
  {
    "within_edu_territory": false,
    "edu": "Rancho Cucamonga Municipal Utility"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Industry"
  },
  {
    "within_edu_territory": false,
    "edu": "Lassen Municipal Utility District"
  },
  {
    "within_edu_territory": false,
    "edu": "Alameda Power & Telecom"
  },
  {
    "within_edu_territory": false,
    "edu": "Redding Electric Utility"
  },
  {
    "within_edu_territory": false,
    "edu": "Colton Electric Utility Department"
  },
  {
    "within_edu_territory": false,
    "edu": "Moreno Valley Utility"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Lompoc Electric Division"
  },
  {
    "within_edu_territory": false,
    "edu": "Port of Oakland"
  },
  {
    "within_edu_territory": false,
    "edu": "Modesto Irrigation District"
  },
  {
    "within_edu_territory": false,
    "edu": "Power and Water Resource Pooling Authority"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Healdsburg Electric Department"
  },
  {
    "within_edu_territory": false,
    "edu": "Roseville Electric"
  },
  {
    "within_edu_territory": false,
    "edu": "Pasadena Water & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "Turlock Irrigation District"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Palo Alto"
  },
  {
    "within_edu_territory": false,
    "edu": "Trinity Public Utilities District"
  },
  {
    "within_edu_territory": false,
    "edu": "Silicon Valley Power"
  },
  {
    "within_edu_territory": false,
    "edu": "Los Angeles Department of Water & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Needles"
  },
  {
    "within_edu_territory": false,
    "edu": "Sacramento Municipal Utility District"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Cerritos"
  },
  {
    "within_edu_territory": false,
    "edu": "Merced Irrigation District"
  },
  {
    "within_edu_territory": false,
    "edu": "Eastside Power Authority"
  },
  {
    "within_edu_territory": false,
    "edu": "Truckee Donner Public Utilities District"
  },
  {
    "within_edu_territory": false,
    "edu": "Azusa Light & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Corona Department of Water & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Banning Electric Department"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Anaheim Public Utilities Department"
  },
  {
    "within_edu_territory": false,
    "edu": "Lodi Electric Utility"
  },
  {
    "within_edu_territory": false,
    "edu": "Kirkwood Meadows Public Utility District"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Ukiah Electric Utilities Division"
  },
  {
    "within_edu_territory": false,
    "edu": "Gridley Electric Utility"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Vernon Municipal Light Department"
  },
  {
    "within_edu_territory": false,
    "edu": "Burbank Water & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "City and County of San Francisco - Hetch Hetchy Water and Power"
  },
  {
    "within_edu_territory": false,
    "edu": "Glendale Water & Power"
  },
  {
    "within_edu_territory": false,
    "edu": "City of Shasta Lake"
  },
  {
    "within_edu_territory": false,
    "edu": "Victorville Municipal Utilities Services"
  },
  {
    "within_edu_territory": false,
    "edu": "Southern California Edison"
  },
  {
    "within_edu_territory": false,
    "edu": "Pacific Gas & Electric Company"
  },
  {
    "within_edu_territory": false,
    "edu": "San Diego Gas & Electric"
  },
  {
    "within_edu_territory": false,
    "edu": "Bear Valley Electric Service"
  },
  {
    "within_edu_territory": false,
    "edu": "Western Area Power Administration"
  }
]

What appears to be happening is the points_sf object should return a geometry of (-118.2403 34.07258), and instead it is returning a value of (1,1) within the plumber API.

Any ideas why this happening?

My plumber file and session info are below:

#' Check which EDU territory encompasses an address
#' @param x longitude of the location
#' @param y latitude of the location
#' @get /intersection
#' @serializer json

function(x,
         y) {
  
  library(tidyverse)
  library(sf)
  
  st_read_edu <- sf::st_read('https://services3.arcgis.com/bWPjFyq029ChCGur/arcgis/rest/services/California_Electric_Utility_Service_Areas/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=*&returnGeometry=true&returnCentroid=false&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pgeojson&token=')
  
  points <- data.frame(x = x,
                       y = y)
  
  points_sf <- sf::st_as_sf(points, coords = c('x', 'y'), crs = 4326)
  
  intersection <- sf::st_intersects(st_read_edu, points_sf, sparse = FALSE) %>%
    as.data.frame() %>%
    dplyr::mutate(edu = st_read_edu$Utility) %>%
    dplyr::rename(within_edu_territory = V1) %>%
    filter(within_edu_territory == TRUE)
  
  return(intersection)

}
R version 3.6.2 (2019-12-12)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Catalina 10.15.3

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] sf_0.9-5        forcats_0.5.0   stringr_1.4.0   dplyr_1.0.0     purrr_0.3.4    
 [6] readr_1.3.1     tidyr_1.1.0     tibble_3.0.3    ggplot2_3.3.2   tidyverse_1.3.0

loaded via a namespace (and not attached):
 [1] webutils_1.1       tidyselect_1.1.0   haven_2.3.1        swagger_3.32.5    
 [5] colorspace_1.4-1   vctrs_0.3.4        generics_0.0.2     rlang_0.4.7       
 [9] e1071_1.7-3        later_1.1.0.1      pillar_1.4.6       glue_1.4.2        
[13] withr_2.2.0        DBI_1.1.0          dbplyr_1.4.2       modelr_0.1.5      
[17] readxl_1.3.1       lifecycle_0.2.0    munsell_0.5.0      gtable_0.3.0      
[21] cellranger_1.1.0   rvest_0.3.5        httpuv_1.5.4       class_7.3-15      
[25] fansi_0.4.1        broom_0.7.0        Rcpp_1.0.5         KernSmooth_2.23-16
[29] promises_1.1.1     scales_1.1.1       backports_1.1.9    classInt_0.4-3    
[33] jsonlite_1.7.1     fs_1.5.0           hms_0.5.3          packrat_0.5.0     
[37] stringi_1.5.3      plumber_0.4.7.9000 grid_3.6.2         cli_2.0.2         
[41] tools_3.6.2        magrittr_1.5       crayon_1.3.4       pkgconfig_2.0.3   
[45] ellipsis_0.3.1     rsconnect_0.8.16   xml2_1.3.2         reprex_0.3.0      
[49] lubridate_1.7.9    assertthat_0.2.1   httr_1.4.2         rstudioapi_0.11   
[53] R6_2.4.1           units_0.6-6        compiler_3.6.2    

How do call plumber? What is the actual API call.

1 Like

Be sure to call as.numeric() on your x and y values.

Query string parameters are always considered strings.

I don't know why it works locally. It shouldn't work in the first place... even though I could reprex the working (locally) and non-working (deployed) behavior.


Update your points definition to:

  points <- data.frame(x = as.numeric(x),
                       y = as.numeric(y))

Side note: Move your library() and sf::st_read statements outside of your endpoint. No need to always read a static file. Instead, just read it once when plumber starts up.

2 Likes

Awesome, this did the trick. Thanks for your help!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.