LKremer/ggpointdensity

Render point layer as raster

bjreisman opened this issue · 3 comments

Great work on this package! One challenge I often face is that I'll want to export a plot as an SVG for the final version, but each point is rendered as an individual object which makes the files unwieldy.

One solution to this problem is to render the the entire plot as vector graphics except for the point later which is rendered as a raster. This is implemented in the ggrasr, package.

Would you consider adding a raster option to stat_pointdensity? The ideal use scenario would be to call stat_pointdensity(geom = 'pointrastr'), but I'm not sure how to get that to get the pointrastr geom to export. Another solution would be to create a another geom, geom_pointdensity_rastr which would serve this purpose.

Here's my hacky solution for now (using @VPetukhov 's code from here)

> DrawGeomPointRast <- function(data, panel_params, coord, na.rm = FALSE, raster.width=NULL, raster.height=NULL, raster.dpi=300) {
+   if (is.null(raster.width)) {
+     raster.width <- par('fin')[1]
+   }
+   
+   if (is.null(raster.height)) {
+     raster.height <- par('fin')[2]
+   }
+   
+   prev_dev_id <- dev.cur()
+   
+   p <- ggplot2::GeomPoint$draw_panel(data, panel_params, coord)
+   dev_id <- Cairo::Cairo(type='raster', width=raster.width*raster.dpi, height=raster.height*raster.dpi, dpi=raster.dpi, units='px', bg="transparent")[1]
+   
+   grid::pushViewport(grid::viewport(width=1, height=1))
+   grid::grid.points(x=p$x, y=p$y, pch = p$pch, size = p$size,
+                     name = p$name, gp = p$gp, vp = p$vp, draw = T)
+   grid::popViewport()
+   cap <- grid::grid.cap()
+   dev.off(dev_id)
+   dev.set(prev_dev_id)
+   
+   grid::rasterGrob(cap, x=0, y=0, width = 1,
+                    height = 1, default.units = "native",
+                    just = c("left","bottom"))
+ }
> 
> GeomPointRast <- ggplot2::ggproto(
+   "GeomPointRast",
+   ggplot2::GeomPoint,
+   draw_panel = DrawGeomPointRast
+ )
> 
> diamonds %>%
+   ggplot(aes(x=carat, y = depth)) + 
+   stat_pointdensity(geom = GeomPointRast) + 
+   scale_color_viridis_c()
geom_pointdensity using method='kde2d' due to large number of points (>20k)

image

Hi @bjreisman,
I agree that this would be a very useful feature. I tried this with a similar raster package (scattermore) but it didn't quite work with the color gradient. Your solution seems to work well!
I think you don't even need to copy the code from ggrastr, you can use non-exported functions with the triple colon. This worked for me:

library(tidyverse)
library(ggrastr)

diamonds %>%
  ggplot(aes(x=carat, y = depth)) +
  rasterise(geom_pointdensity(), dpi=300) + 
  scale_color_viridis_c()

Let me know if it also works for you. I'll expand the readme / docs to include an example of this because it seems really useful. I'm thinking about adding a shortcut as you suggested, I think geom_pointdensity_rastr would be easiest to remember.

Ah, this works great! I was tried for a while to get that approach to work, but couldn't figure out how to access non-exported functions. That triple colon is a handy operator.

idot commented

Its now:

 ggrastr::rasterise(ggpointdensity::geom_pointdensity(size=0.1), dpi=300)