Home > Mobile >  How to recursively create squares, based on previous squares?
How to recursively create squares, based on previous squares?

Time:05-14

I have a df that contains coordinates to create a square:

library(ggplot2)

df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15)

ggplot(df)  
        geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), fill = "green")

enter image description here

Now, I want to have a function, when it is given df, it adds new rows to the df, with 5 scaled versions of the original square, showing like this:

enter image description here

This means, the area of the green coloured squares in the new square(s) corresponds to the 5/9 of the original square.

I also want to make it recursively, so that, given the df with scaled version (5 squares, like in the second image) it gives:

enter image description here

and so on.

CodePudding user response:

Using a recursive approach you could do:

square5 <- function(xmin, xmax, ymin, ymax) {
  x <- data.frame(
    xmin = c(0, rep(1/3, 3), 2/3),
    xmax = c(0, rep(1/3, 3), 2/3)   1/ 3,
    ymin = c(1/3, 0, 1/3, 2/3, 1/3),
    ymax = c(1/3, 0, 1/3, 2/3, 1/3)   1/ 3
  )
  
  x[c("xmin", "xmax")] <- lapply(x[c("xmin", "xmax")], scales::rescale, to = c(xmin, xmax), from = c(0, 1))
  x[c("ymin", "ymax")] <- lapply(x[c("ymin", "ymax")], scales::rescale, to = c(ymin, ymax), from = c(0, 1))
  
  return(x)
}

df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15)

df1 <- purrr::reduce(seq(5), function(x, n) purrr::pmap_df(x, square5), .init = df)

library(ggplot2)

ggplot(df1)  
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), fill = "green", color = "darkgreen", size = .5)

CodePudding user response:

With these three functions:

generate_rects <- function(x1, x2, y1, y2, depth = 1) {
  wid <- x2 - x1
  hgt <- y2 - y1
  data.frame(xmin = x1   c(0, wid/3, wid/3, wid/3, wid * 2/3),
             xmax = x2 - c(2/3 * wid, wid/3, wid/3, wid/3, 0),
             ymin = y1   c(hgt/3, 0, hgt/3, hgt * 2/3, hgt/3),
             ymax = y2 - c(hgt/3, hgt * 2/3, hgt/3, 0, hgt/3),
             depth = depth   1)
}

expand_rects <- function(df) {
  d <- max(df$depth)
  rbind(df, do.call(rbind,
          apply(df[which(df$depth == d), ], 1, function(x) {
            generate_rects(x[1], x[2], x[3], x[4], d)
          })))
}

branch_rects <- function(df, depth) {
  while(max(df$depth) < depth) df <- expand_rects(df)
  df[df$depth == depth,]
}

We can plot any level of branching we want (in practice more than 8 levels of branching is difficult to see and takes too long to calculate), but it is extremely straightforward to use

Depth 2

df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15, depth = 1)

ggplot(branch_rects(df, 2))  
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
            fill = "green", color = "green4")

enter image description here

Depth 3

ggplot(branch_rects(df, 3))  
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
            fill = "green", color = "green4")

enter image description here

Depth 4

ggplot(branch_rects(df, 4))  
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
            fill = "green", color = "green4")

enter image description here

Depth 8

ggplot(branch_rects(df, 8))  
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), 
            fill = "green", color = "green4")

enter image description here

CodePudding user response:

I inserted a column scale that indicates the scaling level:

library(data.table) # mostly for rbindlist

fScale <- function(dt) {
  dt2 <- dt[scale == last(dt$scale)]
  xscale <- (dt2$xmax[1] - dt2$xmin[1])/3
  yscale <- (dt2$ymax[1] - dt2$ymin[1])/3
  xmin <- rep(dt2$xmin, each = 5)   c(0, rep(xscale, 3), 2*xscale)
  ymin <- rep(dt2$ymin, each = 5)   c(yscale, 0, yscale, 2*yscale, yscale)
  rbindlist(
    list(
      dt,
      data.table(
        scale = dt2$scale[1]   1,
        xmin = xmin,
        xmax = xmin   xscale,
        ymin = ymin,
        ymax = ymin   yscale
      )
    )
  )
}

df <- data.table(scale = 1, xmin = 1, xmax = 3, ymin = 10, ymax = 15)
for (i in 1:3) print(df <- fScale(df))
#>    scale     xmin     xmax     ymin     ymax
#> 1:     1 1.000000 3.000000 10.00000 15.00000
#> 2:     2 1.000000 1.666667 11.66667 13.33333
#> 3:     2 1.666667 2.333333 10.00000 11.66667
#> 4:     2 1.666667 2.333333 11.66667 13.33333
#> 5:     2 1.666667 2.333333 13.33333 15.00000
#> 6:     2 2.333333 3.000000 11.66667 13.33333
#>     scale     xmin     xmax     ymin     ymax
#>  1:     1 1.000000 3.000000 10.00000 15.00000
#>  2:     2 1.000000 1.666667 11.66667 13.33333
#>  3:     2 1.666667 2.333333 10.00000 11.66667
#>  4:     2 1.666667 2.333333 11.66667 13.33333
#>  5:     2 1.666667 2.333333 13.33333 15.00000
#>  6:     2 2.333333 3.000000 11.66667 13.33333
#>  7:     3 1.000000 1.222222 12.22222 12.77778
#>  8:     3 1.222222 1.444444 11.66667 12.22222
#>  9:     3 1.222222 1.444444 12.22222 12.77778
#> 10:     3 1.222222 1.444444 12.77778 13.33333
#> 11:     3 1.444444 1.666667 12.22222 12.77778
#> 12:     3 1.666667 1.888889 10.55556 11.11111
#> 13:     3 1.888889 2.111111 10.00000 10.55556
#> 14:     3 1.888889 2.111111 10.55556 11.11111
#> 15:     3 1.888889 2.111111 11.11111 11.66667
#> 16:     3 2.111111 2.333333 10.55556 11.11111
#> 17:     3 1.666667 1.888889 12.22222 12.77778
#> 18:     3 1.888889 2.111111 11.66667 12.22222
#> 19:     3 1.888889 2.111111 12.22222 12.77778
#> 20:     3 1.888889 2.111111 12.77778 13.33333
#> 21:     3 2.111111 2.333333 12.22222 12.77778
#> 22:     3 1.666667 1.888889 13.88889 14.44444
#> 23:     3 1.888889 2.111111 13.33333 13.88889
#> 24:     3 1.888889 2.111111 13.88889 14.44444
#> 25:     3 1.888889 2.111111 14.44444 15.00000
#> 26:     3 2.111111 2.333333 13.88889 14.44444
#> 27:     3 2.333333 2.555556 12.22222 12.77778
#> 28:     3 2.555556 2.777778 11.66667 12.22222
#> 29:     3 2.555556 2.777778 12.22222 12.77778
#> 30:     3 2.555556 2.777778 12.77778 13.33333
#> 31:     3 2.777778 3.000000 12.22222 12.77778
#>     scale     xmin     xmax     ymin     ymax
#>      scale     xmin     xmax     ymin     ymax
#>   1:     1 1.000000 3.000000 10.00000 15.00000
#>   2:     2 1.000000 1.666667 11.66667 13.33333
#>   3:     2 1.666667 2.333333 10.00000 11.66667
#>   4:     2 1.666667 2.333333 11.66667 13.33333
#>   5:     2 1.666667 2.333333 13.33333 15.00000
#>  ---                                          
#> 152:     4 2.777778 2.851852 12.40741 12.59259
#> 153:     4 2.851852 2.925926 12.22222 12.40741
#> 154:     4 2.851852 2.925926 12.40741 12.59259
#> 155:     4 2.851852 2.925926 12.59259 12.77778
#> 156:     4 2.925926 3.000000 12.40741 12.59259
  • Related