1

I have a bunch of points that I'd like to assign zones to in a grid. My points are from -100:100 along the x-axis and -42.5:42.5 along the y-axis. I want to create an overall 10x7 grid, which means the individual boxes are 20x12.143. Below is a re-prex example of the data and with gridlines indicating how I want the data divvied up.

x <- seq(-100, 100, length.out = 50)
y <- seq(-42.5, 42.5, length.out = 50)
points <- merge(x, y)

points %>%
  ggplot() +
  geom_point(aes(x, y), color = "lightblue")  +
  theme_minimal() +
  #start of grid points
  geom_segment(aes(x = -100, xend = -100, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -80, xend = -80, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -60, xend = -60, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -40, xend = -40, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -20, xend = -20, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 0, xend = 0, y = -42.5, yend = 42.5))  +
  geom_segment(aes(x = 80, xend = 80, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 60, xend = 60, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 40, xend = 40, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 20, xend = 20, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 100, xend = 100, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -100, xend = 100, y = -30.357, yend = -30.357)) +
  geom_segment(aes(x = -100, xend = 100, y = -18.214, yend = -18.214)) +
  geom_segment(aes(x = -100, xend = 100, y = -6.071, yend = -6.071)) +
  geom_segment(aes(x = -100, xend = 100, y = 30.357, yend = 30.357)) +
  geom_segment(aes(x = -100, xend = 100, y = 18.214, yend = 18.214)) +
  geom_segment(aes(x = -100, xend = 100, y = 6.071, yend = 6.071)) +
  geom_segment(aes(x = -100, xend = 100, y = -42.5, yend = -42.5)) +
  geom_segment(aes(x = -100, xend = 100, y = 42.5, yend = 42.5))

What I'd like to do is assign each of those points in each zone a unique zone ID (like Zone 1 through Zone 70). I can probably write a massive ifelse function, but that's easy to mess up. I feel like there should be an easier way to do this, but I can't figure it out.

Any help is appreciated!

tjebo
  • 21,977
  • 7
  • 58
  • 94
benhowell71
  • 39
  • 1
  • 4
  • for the future reader - this way of creating a regular grid is very inefficient. Check https://stackoverflow.com/questions/33989595/overlay-grid-rather-than-draw-on-top-of-it for other options to create a regular grid. – tjebo Feb 20 '21 at 10:57

1 Answers1

2

There are 4 steps to take, first you define two sequences along the x and y axes for the grid. Second, you make a matrix that can be indexed by the seq_along() of the x and y sequences and returns an ID.

xbreaks <- seq(-100, 100, length.out = 10) 
ybreaks <- seq(-42.5, 42.5, length.out = 8)

id <- matrix(seq_len(length(xbreaks) * length(ybreaks)),
             length(xbreaks), length(ybreaks))

Subsequently we can use findInterval() to match the points to a position in the grid in the x and y direction. This position can then be used to index the id matrix defined above.

# Make points
x <- seq(-100, 100, length.out = 50)
y <- seq(-42.5, 42.5, length.out = 50)
points <- merge(x, y)

# Match points to grid location
xi <- findInterval(points$x, xbreaks)
yi <- findInterval(points$y, ybreaks)

# Subset with 2-column matrix
points$id <- id[cbind(xi, yi)]

And this is what the IDs look like.

library(ggplot2)

ggplot(points) +
  geom_point(aes(x, y, colour = as.factor(id)))  +
  theme_minimal() +
  #start of grid points
  geom_segment(aes(x = -100, xend = -100, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -80, xend = -80, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -60, xend = -60, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -40, xend = -40, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -20, xend = -20, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 0, xend = 0, y = -42.5, yend = 42.5))  +
  geom_segment(aes(x = 80, xend = 80, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 60, xend = 60, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 40, xend = 40, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 20, xend = 20, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = 100, xend = 100, y = -42.5, yend = 42.5)) +
  geom_segment(aes(x = -100, xend = 100, y = -30.357, yend = -30.357)) +
  geom_segment(aes(x = -100, xend = 100, y = -18.214, yend = -18.214)) +
  geom_segment(aes(x = -100, xend = 100, y = -6.071, yend = -6.071)) +
  geom_segment(aes(x = -100, xend = 100, y = 30.357, yend = 30.357)) +
  geom_segment(aes(x = -100, xend = 100, y = 18.214, yend = 18.214)) +
  geom_segment(aes(x = -100, xend = 100, y = 6.071, yend = 6.071)) +
  geom_segment(aes(x = -100, xend = 100, y = -42.5, yend = -42.5)) +
  geom_segment(aes(x = -100, xend = 100, y = 42.5, yend = 42.5))

Created on 2021-02-19 by the reprex package (v1.0.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • teunbrand this works really well! My next step is looking at how often there's a value in one zone then another, like going from zone 1 to zone 13. Using the `count` and `spread` functions, I can get how many times each zone followed the one in question, but is there an easy way to get the % of which zone followed? Other than manually mutating the 80 zones and their %? – benhowell71 Feb 19 '21 at 22:58
  • This vaguely reminds me of the `cumsum()` function, but I'm afraid I don't fully understand what you mean. Could you give an example calculation? – teunbrand Feb 19 '21 at 23:05