How can I delete the background in stat_density_2d?

1k views Asked by At

I am trying to make density maps in R using the function stat_density_2d, but I would like to remove the background color for which the density is null. I tried changing the limits for the density, but when moving the limits from [0,5] to [0.1, 5], the background becomes grey instead of dark blue. What can I do to have a transparent background, and colouring only the datapoints?

Here is my code :

ggplot(TEST, aes(x = X, y = Y)) +
  geom_point() +
  stat_density_2d(geom = "raster", aes(fill = ..density..*10e04), contour = F, 
                  h = c(5, 5),
                  n = 300) +
  ggtitle("7387")+ 
  theme(plot.title = element_text(lineheight=.8, face="bold"))+
  scale_y_reverse()+
  scale_fill_distiller(palette = 'Spectral', limits=c(0,5))

enter image description here

Thank you!

3

There are 3 answers

0
Allan Cameron On BEST ANSWER

You could map the density to the alpha scale so that lower values are transparent:

TEST <- data.frame(X = rnorm(10000, -700, 50),
                   Y = rnorm(10000, -450, 50))

ggplot(TEST, aes(x = X, y = Y)) +
  stat_density_2d(geom = "raster", 
                  aes(fill = ..density..*10e04, alpha = ..density..*10e04), 
                  contour = FALSE, 
                  h = c(7, 7),
                  n = 300) +
  scale_alpha_continuous(range = c(0, 1), limits = c(0, 3), 
                         guide = guide_none()) +
  ggtitle("7387") + 
  theme(plot.title = element_text(lineheight=.8, face="bold"))+
  scale_y_reverse() +
  scale_fill_viridis_c(limits = c(0, 12))

enter image description here

0
Patrick Sadil On

Building on the accepted answer -- the background goes grey when setting the limits because coordinates falling outside the limits receive a value of NA, and the default fill for NA is "grey50". To use a different color, specify na.value. For removing the background, set the lower limit to some value near 0 and then use "transparent"

library(ggplot2)

TEST <- data.frame(X = rnorm(10000, -700, 50),
                   Y = rnorm(10000, -450, 50))

ggplot(TEST, aes(x = X, y = Y)) +
  stat_density_2d(geom = "raster", 
                  aes(fill = ..density..*10e04), 
                  contour = FALSE, 
                  h = c(7, 7),
                  n = 300) +
  ggtitle("7387") + 
  theme(plot.title = element_text(lineheight=.8, face="bold"))+
  scale_y_reverse() +
  scale_fill_viridis_c(limits = c(0.001, 12), na.value = "transparent")

Created on 2022-05-22 by the reprex package (v2.0.1)

0
o.h On

I'd like to propose another possible solution here. The prior solutions either require you to use an alpha scale or require you to hard code some values that are relative to the range of your data. The alpha scale is hard to get right if you really only want the low values to be transparent but not the mid/high. The hardcoding is problematic if you are making multiple graphs or using different inputs (e.g. a lower bound of .01 might look good on one dataset, but cut off important values on another).

The solution is to create a custom color map that begins with 'transparent'. You can do this using existing color ramps like viridis.

Calling viridis::viridis_pal()(n) will give you a vector of colors from the viridis scale. You can also access others with something like viridis::viridis_pal(option='magma')(10) which will you give you 10 colors from the range of the magma palette .

To create your new color ramp, use scale_fill_gradientn() and concatenate 'transparent' in front of a range of colors from your desired scale:

scale_fill_gradientn(colors = c('transparent',viridis::viridis_pal()(10)))

Now you have a scale that is transparent on the smallest end of the range but then proceeds through the viridis color ramp. You can also choose your own colors here as desired rather than relying on a built-in scale.

TEST <- data.frame(X = rnorm(10000, -700, 50),
                   Y = rnorm(10000, -450, 50))

ggplot(TEST, aes(x = X, y = Y)) +
  stat_density_2d(geom = "raster", aes(fill = ..density..*10e04), contour = F, 
                  h = c(5, 5),
                  n = 300) +
  ggtitle("7387")+ 
  theme(plot.title = element_text(lineheight=.8, face="bold"))+
  scale_y_reverse()+
  scale_fill_gradientn(colors = c('transparent',viridis::viridis_pal()(10)))

example with n=10

You can also attenuate this effect by adjusting how many colors you use to build your ramp. The effect is subtle, but more colors means more of the "background" is filled in, while fewer colors will allow more of the background to fade away. The below compares viridis::viridis_pal()(5) and viridis::viridis_pal()(30):

enter image description here

This effect is independent of the scaling of your data--if you multiply density by 10, the result will be identical (which it would not be if you use the methods based on hard-coded limits).