ggpointdensity icon indicating copy to clipboard operation
ggpointdensity copied to clipboard

Render point layer as raster

Open bjreisman opened this issue 4 years ago • 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

bjreisman avatar Dec 02 '19 00:12 bjreisman

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:

diamonds %>%
  ggplot(aes(x=carat, y = depth)) +
  stat_pointdensity(geom = ggrastr:::GeomPointRast) + 
  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.

LKremer avatar Dec 21 '19 00:12 LKremer

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.

bjreisman avatar Jan 25 '20 15:01 bjreisman

Its now:

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

idot avatar Feb 09 '23 11:02 idot