4

using the iris dataset as an example,

I am trying to create plots for Voronoi and Delaunay partitions.

I can do this just fine for Voronoi PLots using ggplot and ggforce packages

#voronoi plot with filled polygons
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
  geom_voronoi_tile(aes(fill = Petal.Length))

enter image description here Now I would like to do a similar plot but with Delaunay triangulation, where the triangles are also filled like the polygons in the Voronoi plot above, however, I can't work out how to fill/color the triangles by a third variable

# Delaunay triangles
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
  geom_delaunay_tile(aes(fill = Petal.Length))

enter image description here

tjebo
  • 21,977
  • 7
  • 58
  • 94
Myriad
  • 341
  • 1
  • 8
  • I think this is a bug. The data created in `StatDelaunayTile$compute_group` only has four columns - no fill or PANEL column - whereas the data created with `StatVoronoiTile$compute_group` has those columns. I guess somehow StatDelaunayTile does not inherit aesthetics in the same way and I am not sure if this is desired. – tjebo Dec 26 '22 at 16:58
  • FYI https://github.com/thomasp85/ggforce/issues/293 – tjebo Dec 26 '22 at 17:12
  • @tjebo yea I saw this too, but I have looked to other ways of plotting this without relying on ggforce, but could not yet find an alterative solution that works either – Myriad Dec 26 '22 at 17:12
  • @tjebo thanks I did also file an issue related to this on ggforce GitHub page a while ago, but did not get an answer https://github.com/thomasp85/ggforce/issues/292 – Myriad Dec 26 '22 at 17:15
  • 2
    I guess Thomas will be super busy with other stuff. I'm sure there must be a fairly straight forward fix as I feel this is related with required/default aesthetics that are set within the Stat and Geom. These are things that have very often cause me big headaches, and I'm usually hoping for wizards like AllanCameron or Teunbrand to show me where the problem is – tjebo Dec 26 '22 at 17:19
  • And there we go, Allan has spoken! – tjebo Dec 26 '22 at 17:20
  • 1
    @tjebo You are too kind. Actually, the method I have sketched out below should be easy enough to incorporate into ggforce. – Allan Cameron Dec 26 '22 at 17:22
  • @AllanCameron thanks so much for this, would it be possible to instead fill the triangle with a gradient that presents the color of each vertex, say if I had a color value for each vertice – Myriad Dec 26 '22 at 17:33

1 Answers1

4

In Voronoi tiling there is a 1:1 correspondence between the points and the tiles, so one can easily map a fill aesthetic to the tiles. Each row in your data frame will have its own tile and therefore can specify a fill, an alpha, etc.

This is not the case in Delaunay tiling, where each row in your data frame describes a single vertex, and each tile therefore requires 3 rows of data to describe. These 3 rows have different values of Petal Length, and there is not a 1:1 correspondence between rows and tiles.

The obvious option is to average the Petal Length of the three vertices, but it seems that ggforce does not have an option to interpolate the vertices this way. However, we can use the deldir package in the same way ggforce does to achieve this ourselves:

library(ggplot2)
library(deldir)

tri <- triang.list(deldir(iris$Sepal.Length, iris$Sepal.Width))
do.call(rbind, lapply(seq_along(tri), 
                      function(x) {
  data.frame(Sepal.Length = tri[[x]]$x, Sepal.Width = tri[[x]]$y, 
             Petal.Length = mean(iris$Petal.Length[tri[[x]]$ptNum]),
             tri = x)
  })) |>
  ggplot(aes(Sepal.Length, Sepal.Width)) +
  geom_polygon(aes(fill = Petal.Length, group = tri)) 

enter image description here


Additional

To gradient fill your triangles, probably best to draw blank triangles over a 2D interpolation:

library(interp)
library(ggforce)

interp(iris$Sepal.Length, iris$Sepal.Width, iris$Petal.Length, 
              duplicate = "mean", nx = 1000, ny = 1000) |>
  interp2xyz() |>
  as.data.frame() |>
  setNames(names(iris)[1:3]) |>
  ggplot(aes(Sepal.Length, Sepal.Width)) +
  geom_raster(aes(fill = Petal.Length)) +
  scale_fill_continuous(na.value = NA) +
  geom_delaunay_tile(data = iris, fill = NA, color = "#00000050")

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87