-
Notifications
You must be signed in to change notification settings - Fork 292
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
adds runifpoint #1204
adds runifpoint #1204
Conversation
This looks attractive, but still needs a bit of thought. Pinging @rubak.
for very good reasons, but we should catch that earlier. Actually, type "random" (sf native) does "proper" sampling on the sphere in that case, can spatstat can do that too somehow, Ege?
|
Further thoughts: spatstat doesn't do anything fancy for uniform random sampling, we want it for the special cases, like |
Indeed, spatstat doesn't do anything special for uniform sampling, and we don't handle geographic coordinates at all. This has all been postponed to For a list of the random point generators in spatstat see the spatstat package help (p. 3-4 in this pdf). |
@edzer |
Having a return() on line 146 is entirely against the logic of the whole if/else block, that's why I didn't see it. R |
Yes, a simple solution would be using
which would avoid writing an interface for each and every method. But this would require that the functions share a common interface (at least: parameter names).Each of them seems to have Also: all |
I think it should be a curated list of simulation functions from spatstat with a direct interface from sf since it otherwise maybe difficult for the user to find relevant functions. Then we also have the option of including a unit test for each function we claim to interface. The sketched way of calling these by @edzer is great. Sometimes I like to start with the documentation when thinking such an interface through:
|
This list is not complete, but a starting point. Most simulation functions in spatstat generate a random number of sampling points, so I thought it was better to explicitly say that |
I think this is a good approach: making clear where the docs are to be found. I'm hesitant to add unit tests to sf, because it would test spatstat functionality really; a change in spatstat would then cause a breaking sf. |
I see your point about the unit tests. What about examples? Are you OK with having an example of some of the spatstat sampling types at the end of the help page? |
Yes, that makes sense. |
OK. With the proposal by @edzer I think the spatstat part of the function can be written simply as (plus some checking etc. for geographic coordinates etc.): st_sample_poly_spatstat <- function(x, ..., type){
spatstat_fun <- try(get(paste0("r", type), asNamespace("spatstat")), silent = TRUE)
if(inherits(spatstat_fun, "try-error")){
stop(paste0("r", type), " is not an exported function from spatstat.")
}
rslt <- try(spatstat_fun(..., win = maptools::as.owin.SpatialPolygons(as(x, "Spatial"))), silent = TRUE)
if(inherits(rslt, "try-error")){
stop("The spatstat function ", paste0("r", type),
" did not return a valid result. Consult the help file.\n",
"Error message from spatstat:\n", rslt)
}
return(rslt)
}
x <- sf::st_sfc(sf::st_polygon(list(rbind(c(0,0),c(10,0),c(10,10),c(0,0)))))
pts <- st_sample_poly_spatstat(x, type = "thomas")
#> Error in st_sample_poly_spatstat(x, type = "thomas"): rthomas is not an exported function from spatstat.
pts <- st_sample_poly_spatstat(x, kappa = 1, mu = 10, type = "Thomas")
#> Error in st_sample_poly_spatstat(x, kappa = 1, mu = 10, type = "Thomas"): The spatstat function rThomas did not return a valid result. Consult the help file.
#> Error message from spatstat:
#> Error : 'scale' should be a single number
pts <- st_sample_poly_spatstat(x, kappa = 1, mu = 10, scale = 0.1, type = "Thomas")
plot(pts) This also allows the advanced user to call any random generator from spatstat which has argument |
@edzer, I have tried to add spatstat sampling to be inside of the library(sf)
#> Linking to GEOS 3.7.1, GDAL 2.3.2, PROJ 5.2.0
x <- sf::st_sfc(sf::st_polygon(list(rbind(c(0, 0), c(10, 0), c(10, 10), c(0, 0)))))
plot(x) # error expected
pts <- st_sample(x, type = "thomas")
#> Error in st_poly_sample(x, ..., size, type = type): sampling type thomas not implemented for polygons
# error expected
pts <- st_sample(x, kappa = 1, mu = 10, type = "Thomas")
#> Error in st_poly_sample(x, ..., size, type = type): The spatstat function rThomas did not return a valid result. Consult the help file.
#> Error message from spatstat:
#> Error : 'scale' should be a single number
# points expected
pts <- st_sample(x, kappa = 1, mu = 10, scale = 0.1, type = "Thomas")
#> Error in st_poly_sample(x, ..., size, type = type): The spatstat function rThomas did not return a valid result. Consult the help file.
#> Error message from spatstat:
#> Error in st_poly_sample(x, ..., size, type = type) :
#> argument "size" is missing, with no default
plot(pts)
#> Error in plot(pts): object 'pts' not found Created on 2019-12-08 by the reprex package (v0.3.0) |
Alternative approach would be to add a new function st_sample_spatstat = function(x, ..., type){
if (!requireNamespace("spatstat", quietly = TRUE)){
stop("package spatstat required, please install it first")
}
spatstat_fun = try(get(paste0("r", type), asNamespace("spatstat")), silent = TRUE)
if(inherits(spatstat_fun, "try-error")){
stop(paste0("r", type), " is not an exported function from spatstat.")
}
if (!requireNamespace("maptools", quietly = TRUE)){
stop("package maptools required, please install it first")
}
spatstat_fun = try(get(paste0("r", type), asNamespace("spatstat")), silent = TRUE)
rslt = try(spatstat_fun(..., win = maptools::as.owin.SpatialPolygons(as(x, "Spatial"))), silent = TRUE)
if(inherits(rslt, "try-error")){
stop("The spatstat function ", paste0("r", type),
" did not return a valid result. Consult the help file.\n",
"Error message from spatstat:\n", rslt)
}
return(rslt)
}
library(sf)
#> Linking to GEOS 3.7.1, GDAL 2.3.2, PROJ 5.2.0
x <- sf::st_sfc(sf::st_polygon(list(rbind(c(0, 0), c(10, 0), c(10, 10), c(0, 0)))))
plot(x) # error expected
pts <- st_sample_spatstat(x, type = "thomas")
#> Error in st_sample_spatstat(x, type = "thomas"): rthomas is not an exported function from spatstat.
# error expected
pts <- st_sample_spatstat(x, kappa = 1, mu = 10, type = "Thomas")
#> Error in st_sample_spatstat(x, kappa = 1, mu = 10, type = "Thomas"): The spatstat function rThomas did not return a valid result. Consult the help file.
#> Error message from spatstat:
#> Error : 'scale' should be a single number
# points expected
pts <- st_sample_spatstat(x, kappa = 1, mu = 10, scale = 0.1, type = "Thomas")
plot(pts) Created on 2019-12-08 by the reprex package (v0.3.0) |
I like the idea of simply having an exported function |
I don't think that the missing library(sf)
# Linking to GEOS 3.8.0, GDAL 3.0.2, PROJ 6.2.1
#> Linking to GEOS 3.7.1, GDAL 2.3.2, PROJ 5.2.0
x <- sf::st_sfc(sf::st_polygon(list(rbind(c(0, 0), c(10, 0), c(10, 10), c(0, 0)))))
s = st_sample(x, 10)
# error expected
try(pts <- st_sample(x, type = "thomas"))
# Error in st_poly_sample(x, size = size, ..., type = type) :
# rthomas is not an exported function from spatstat.
# error expected
try(pts <- st_sample(x, kappa = 1, mu = 10, type = "Thomas"))
# Error in st_poly_sample(x, size = size, ..., type = type) :
# The spatstat function rThomas did not return a valid result. Consult the help file.
# Error message from spatstat:
# Error : ‘scale’ should be a single number
# points expected
pts <- st_sample(x, kappa = 1, mu = 10, scale = 0.1, type = "Thomas")
plot(x)
plot(pts, add = TRUE) giving the plot generated above by @Nowosad . There's a couple of things to do or to discuss:
|
For many people it would indeed be convenient to specify the average number of points they want rather than the intensity. I considered this at some point, but I don't think it is worth the effort. The problem is that many methods don't have a single concept of intensity, and it may be difficult for us to do the conversion in a generic fashion:
So rather than have a list of spatstat models where
That would indeed make sense, but I won't get around to it in the near future.
Nice to have, but it could also be postponed. I have no strong opinion about this right now. |
I now (manually) merged this into master. Thanks! |
* remove maptools dependency * namespace issues * test results
Removed maptools dependency. |
@edzer this PR adds the spatstat::runifpoint function's support to sf. Please take a look at the code and let me know if this implementation is ok. If so, I can add some documentation, etc.
The second thing is to decide which sampling types from spatstat are worth adding - see pages 3 and 4 at https://spatstat.org/resources/spatstatQuickref.pdf for the complete list.
Example of use:
Created on 2019-11-24 by the reprex package (v0.3.0)