1

I'm trying to use the "apply" function with the R "eleavatr" package. I'm getting an error message but I'm not sure if the problem is in my understanding of the apply function (perhaps the root of the problem?) or a wholly different problem. The function works if you just use it alone ie get_elev(temp_df) but using it in apply causes problem. This is my sample data & code:

> temp_df
           x        y
41 -74.67020 41.36181
42 -74.66993 41.36208
43 -74.66966 41.36235
44 -74.66939 41.36262
45 -74.66912 41.36289
46 -74.66885 41.36316
47 -74.66858 41.36343
48 -74.66831 41.36370
49 -74.66804 41.36397
50 -74.66777 41.36424

get_elev<-function(ll){
  temp_el<-elevatr::get_elev_point(locations = ll, src = "epqs", units="meters", 
         prj = ll_prj)
  return(temp_el)
}

sapply(temp_df, FUN=get_elev) #this should take the lat/lon coordinates of each row to search for elevation. 

Error message:

 Error in if (attributes(class(locations)) %in% c("raster", "sp")) { : 
argument is of length zero 
  • try sapply(temp_df, print) to see what each iteration is feeding to the function.... If you want to do things row-wise, use apply(temp_df, 1, FUN=something). – Spacedman Oct 23 at 17:30
  • @Spacedman When I tried that, I don't think both the lat and long are being read in properly, ie. [1] -74.67020 -74.66993 -74.66966 -74.66939 -74.66912 -74.66885 -74.66858 -74.66831 -74.66804 -74.66777 [1] 41.36181 41.36208 41.36235 41.36262 41.36289 41.36316 41.36343 41.36370 41.36397 41.36424 x y [1,] -74.67020 41.36181 [2,] -74.66993 41.36208 . (sorry I don't know how to format this better). Is there a way to feed both values into apply? – Tammy Oct 23 at 17:36
  • Is there a reason why you are using *apply? Why not call get_elev_point with the whole data frame? – Spacedman Oct 23 at 18:11
  • I'm trying to parallel my code ultimately and my understanding is that library(parallel) uses apply-like functions – Tammy Oct 23 at 18:13
1

The problem is that sapply works over columns in a data frame:

> tmp = sapply(temp_df, print)
 [1] -74.66463 -74.55881 -74.06158 -74.20245 -74.31204 -74.70192 -74.56885
 [8] -74.56009 -74.89815 -74.53474
 [1] 41.15452 41.51665 41.61388 41.48831 41.81899 41.89160 41.10157 41.57314
 [9] 41.48867 41.00771

that has called print twice, once for each column.

apply is meant to use over matrices, not data frames, so it fails when you try and run it over rows on a data frame:

> get_elev = function(ll){elevatr::get_elev_point(ll, src="epqs",prj="+init=epsg:4326")}
> tmp = apply(temp_df,1, get_elev)
Error in if (attributes(class(locations)) %in% c("raster", "sp")) { : 
  argument is of length zero

If you inspect ll when called like this you'll see its a vector of length two. So you can reconstruct a little data frame and use that:

> get_elev = function(ll){ll=data.frame(x=ll[1],y=ll[2]);elevatr::get_elev_point(ll, src="epqs",prj="+init=epsg:4326")}
> tmp = apply(temp_df,1, get_elev)
> 

which returns a list of elements like this:

> tmp[[1]]
            coordinates elevation elev_units
1 (-74.66463, 41.15452)    139.05     meters

I'm not sure doing this in order to parallelise it in order to speed it up is a good idea, or even will work. The speed will be determined by the response of the server, and running in parallel will thrash the server harder and possibly get you kicked off it faster.

  • thank you so much for sending and answering my question. I'm not sure that using parallel is the best way but when I had applied get_elev_point to the entire dataframe, the code would crash with: "API did not return json". My dataframe is large 10^6 so my understanding after searching this google message is the connection between the website is crashing mid-code. I thought with parallel, I shorten the time to the website. This is way beyond my understanding but does that seem possibly reasonable? – Tammy Oct 23 at 18:31
  • The help page says: "The "epqs" source is relatively slow for larger numbers of points (e.g. > 500)" - trying to do a million is probably pointless. I would very carefully read the terms and conditions on the API endpoint before proceeding. You might benefit from downloading SRTM rasters and querying them. – Spacedman Oct 23 at 18:57
  • I forgot that was a limitation with epqs--thanks for looking into that. I think finding an alternative method might be necessary and that seems pretty reasonable. Thanks again – Tammy Oct 23 at 19:00
  • It would seem that if your dataset is, in fact, that large it may be more prudent to just down DEM tiles and then pull the elevation values. – Jeffrey Evans Oct 23 at 19:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.