rggplot2mathtidyversevoronoi

How to add polygons to your data for a voronoi treemap in R?


I have a data frame that looks like this. It contains the sunflower seed productivity of each country. I want to add next to this data polygon data so I can plot it with ggplot2.

I was told to use this site: https://observablehq.com/@ladataviz/wip-voronoi-data-generator, I want to understand how I can create polygons and plot a circular voronoi diagram.

I have created a similar post in the past, but my question here is very different. I want to find a way to create the polygon data

df <- data.frame(country = c("Ukraine", "Russia", "Argentina", "China", "Romania", "Other"),
                 prod = c(11.0, 10.6, 3.1, 2.4, 2.1, 15.3))
df
#>     country prod
#> 1   Ukraine 11.0
#> 2    Russia 10.6
#> 3 Argentina  3.1
#> 4     China  2.4
#> 5   Romania  2.1
#> 6     Other 15.3

Created on 2023-01-20 with reprex v2.0.2

If add polygons to my data should look like this:

       x            y path   split   group value
1   472.0117 220.08122253    0 Ukraine Ukraine    11
2   471.8336 217.18476868    1 Ukraine Ukraine    11
3   471.6556 214.28833008    2 Ukraine Ukraine    11
4   471.4776 211.39187622    3 Ukraine Ukraine    11
5   471.2996 208.49542236    4 Ukraine Ukraine    11
6   471.1216 205.59896851    5 Ukraine Ukraine    11

I want my data to look like this.

enter image description here


Solution

  • Having become hooked by this problem, I have written a small package to address it which you can install via

    devtools::install_github("AllanCameron/VoronoiPlus")
    

    It can deal with Voronoi maps (as in the question on this page) with a call to voronoi_map, which takes the weights and group labels. It can also take an arbitrary shape to act as the boundary of the tiles, though defaults to the unit circle if this is missing.

    library(VoronoiPlus)
    
    res <- voronoi_map(values = df$prod, groups = df$country)
    
    plot(res)
    

    enter image description here

    You can extract the polygons as a data frame from this object with:

    polys <- get_polygons(res)
    
    head(polys)
    #>   geom          x          y   group value
    #> 1    1 -0.6436006 -0.7649495 Ukraine    11
    #> 2    1 -0.6691306 -0.7431448 Ukraine    11
    #> 3    1 -0.7071068 -0.7071068 Ukraine    11
    #> 4    1 -0.7431448 -0.6691306 Ukraine    11
    #> 5    1 -0.7771460 -0.6293204 Ukraine    11
    #> 6    1 -0.8090170 -0.5877853 Ukraine    11
    

    The package can also handle arbitrarily nested groups to produce a genuine treemap via the voronoi_treemap function, which employs a formula interface (the weights on the left and grouping variables on the right)

    df$region <- c("Europe", "Europe", "Other", "Other", "Europe", "Other")
    
    dat <- voronoi_treemap(prod ~ region + country, data = df)
    
    head(dat)
    #>           x          y  group value parent level
    #> 1 0.6657716 -0.7460137 Europe  23.7   root     1
    #> 2 0.6293204 -0.7771460 Europe  23.7   root     1
    #> 3 0.5877853 -0.8090170 Europe  23.7   root     1
    #> 4 0.5446390 -0.8386706 Europe  23.7   root     1
    #> 5 0.5000000 -0.8660254 Europe  23.7   root     1
    #> 6 0.4539905 -0.8910065 Europe  23.7   root     1
    

    This allows a nested treemap as follows:

    library(tidyverse)
    
    ggplot(dat[dat$level == 2,], aes(x, y, label = group)) +
      geom_polygon(aes(fill = parent)) +
      geom_polygon(fill = "white", aes(group = group, alpha = group), 
                   color = "black") +
      geom_text(data = . %>% group_by(group) %>% 
                  summarize(x = mean(x), y = mean(y))) +
      scale_alpha_discrete(guide = "none") +
      coord_equal() +
      theme_void()
    

    enter image description here

    The algorithm used is also a brute-force method at present, though a little different to the one demonstrated by Robert Hijmans. I am working on a more directed method to improve convergence times.

    A major caveat is that the package is in a nascent stage and has not been properly tested or documented at the time of writing.