Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract the coordinates of a rendered dot plot

Tags:

r

ggplot2

ggdist

Say I have a variable and create a dot plot of the distribution:

library(ggplot2)
library(ggdist)

data.frame(x = rchisq(500, df = 10)) |> 
  ggplot(aes(x = x)) +
  geom_dots(layout = "hex")

Plot rendered by included code showing dots in the shape of a chi-square distribution

The points are automatically arranged along the x- and y-axes. Is is possible to extract the x and y coordinates for each point, after they have been arranged?

I have tried using ggplot_build(), but when I extract the data, the value of y is always 0.

my_plot <- data.frame(x = rchisq(500, df = 10)) |> 
  ggplot(aes(x = x)) +
  geom_dots(layout = "hex")

head(ggplot_build(my_plot)$data[[1]])
#>           x PANEL group flipped_aes y datatype height ymin ymax thickness
#> 1  8.712773     1    -1        TRUE 0     slab      1    0    1         1
#> 2  4.223199     1    -1        TRUE 0     slab      1    0    1         1
#> 3  7.535543     1    -1        TRUE 0     slab      1    0    1         1
#> 4  9.253599     1    -1        TRUE 0     slab      1    0    1         1
#> 5 20.435195     1    -1        TRUE 0     slab      1    0    1         1
#> 6  9.940869     1    -1        TRUE 0     slab      1    0    1         1
#>   family     side scale
#> 1        topright   0.9
#> 2        topright   0.9
#> 3        topright   0.9
#> 4        topright   0.9
#> 5        topright   0.9
#> 6        topright   0.9

Created on 2025-06-17 with reprex v2.1.1

like image 601
Jake Thompson Avatar asked Dec 02 '25 21:12

Jake Thompson


1 Answers

Stefan's answer may be all you need, but I thought it would be worthwhile posting an answer to the question as asked, since someone searching for a method to extract point data from a geom_dot for reasons other than drawing hexagons is likely to come across this Q&A.

It's quite tricky to extract the dot locations, because they are recalculated every time the plotting window is resized. This means that they have to be drawn by a special grob with its own makeContent method - this is where the actual dot arrangement must be taking place.

The following function will take a ggplot and extract the dot positions by hijacking the makeContent method:

extract_dot_locations <- function(p) {
  p2 <- p |> ggplot2::ggplot_build() |> ggplot2::ggplot_gtable()
  
  pg <- p2$grobs[[6]]$children[[3]]$children[[1]]
  
  xvals <- numeric()
  yvals <- numeric()
  pg$make_points_grob <- function (x, y, pch, col, fill, fontfamily, 
                                   fontsize, lwd, lty,  ...) {
    xvals <<- x
    yvals <<- y
    grid::pointsGrob(x = x, y = y, pch = pch, 
               gp = grid::gpar(col = col, 
                         fill = fill, fontfamily = fontfamily, fontsize = fontsize, 
                         lwd = lwd, lty = lty))
  }
  
  p2$grobs[[6]]$children[[3]]$children[[1]] <- pg
  grid::grid.newpage()
  grid::grid.draw(p2)
  data.frame(x = xvals, y = yvals)
}

Now we can do:

library(ggplot2)
library(ggdist)

set.seed(1)

p <- data.frame(x = rchisq(500, df = 10)) |> 
  ggplot(aes(x = x)) +
  geom_dots(layout = "hex") 

point_data <- extract_dot_locations(p)

enter image description here

And we have our point data frame:

 head(point_data)
#>            x          y
#> 1 0.04939082 0.05674432
#> 2 0.05750770 0.07932387
#> 3 0.06916483 0.05674432
#> 4 0.06916483 0.10190342
#> 5 0.07728171 0.07932387
#> 6 0.09077930 0.05674432

So you can use the hexagons from ggstaras planned:

point_data |> 
  ggplot(aes(x = x, y = y)) +
  ggstar::geom_star(aes(fill = y), starshape = 6, size = 6) +
  scale_fill_viridis_c()

enter image description here

like image 103
Allan Cameron Avatar answered Dec 05 '25 13:12

Allan Cameron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!