8

I'm trying to simulate some data for a project, and basically I need to draw an irregular oval-ish shape, then make a bunch of random points inside that shape, and I'm at a total loss for how to do this.

For now, I've made a spline shape, then plotted a bunch of points over it. Is there a way I can find the overlap? Or better, just generate random points in bounds of a pre-made shape?

(feel free to ditch my code if there is a better way to start - maybe it needs to be some kind of spatial object?)

set.seed(2)
shape <- data.frame(
  x     = c(2, 3, 2, 3, 2, 1, 0, 1),
  y     = c(1, 3, 5, 7, 9, 7, 5, 3 )
)

scatter = data.frame(
  x = rnorm(100, mean = 1.5, sd = .6),
  y = rnorm(100, mean = 5, sd = 2)
)


ggplot(data = shape, 
       aes(x=x,y=y)) +
  ggforce::geom_bspline_closed(fill = "transparent", color = "black") +
  geom_point(color = "blue") +
  coord_equal() +  
  geom_point(data = scatter, shape = "*", size=3)

enter image description here

Jake L
  • 987
  • 9
  • 21
  • I think you can coax more samples to `within` your ellipse by using `runif` to create your `xy` data.frame, setting the min and max for each, `?runif`. – Chris Aug 12 '21 at 17:02

2 Answers2

8

I would recommend the sf package because it is made for spatial data and performing spatial operation. Here is a small example of generating random points within a polygon:

library(ggplot2)

polygon =
  # The syntax for creating a polygon with sf is a little strange.
  # It has to be a list of matrices and the first point has to be 
  # repeated as the last point (2, 1).
  list(
    matrix(
      c(2, 1, 3, 3, 2, 5, 3, 7, 2, 9, 1, 7, 0, 5, 1, 3, 2, 1),
      ncol=2, byrow=T
    )
  ) 

# Create an sf polygon
polygon = sf::st_polygon(polygon)
# Sample 50 random points within the polygon
points = sf::st_sample(polygon, size=50)

# Plot using the ggplot geom_sf function.
ggplot() + 
  geom_sf(aes(), data=polygon) + 
  geom_sf(aes(), data=points)

enter image description here

If you need the coordinates of the points, you can simply convert the sf point object to a data.frame with points %>% sf::st_coordinates() %>% as.data.frame().

ColinB
  • 528
  • 3
  • 12
  • And for the ellipse part [ellipse](https://stackoverflow.com/questions/35841685/add-an-ellipse-on-raster-plot-in-r). – Chris Aug 12 '21 at 17:52
2

In spatstat polygons are used as observation windows for point patterns. You can do a lot of geometric operations with such objects (owin). Maybe something like this is useful:

library(spatstat)
#> Loading required package: spatstat.data
#> Loading required package: spatstat.geom
#> spatstat.geom 2.2-2.002
#> Loading required package: spatstat.core
#> Loading required package: nlme
#> Loading required package: rpart
#> spatstat.core 2.3-0.003
#> Loading required package: spatstat.linnet
#> spatstat.linnet 2.3-0
#> 
#> spatstat 2.2-0       (nickname: 'That's not important right now') 
#> For an introduction to spatstat, type 'beginner'
W1 <- ellipse(a=5, b=2, centre=c(2,7), phi=80*pi/180)
W2 <- ellipse(a=5, b=2, centre=c(2,3), phi=-80*pi/180)
W <- union.owin(W1, W2)
plot(W, lwd=3, main = "")

Wplus <- dilation(W, 1)
plot(Wplus, lwd=3, main = "")

There are many ways to sample points inside the window (see the section Creating and Manipulating Data in ?spatstat). E.g. completely random or very regularly spaced:

plot(runifpoint(50, win = Wplus))

plot(rSSI(r = 1, n = 50, win = Wplus))

Ege Rubak
  • 4,347
  • 1
  • 10
  • 18