7
votes

I have two smoothScatter plots and hope to subtract them. See Below:

par(mfrow=c(1,2))
set.seed(3)
x1 = rnorm(1000)
y1 = rnorm(1000)
smoothScatter(x1,y1,nrpoints=length(x1),cex=3)

x2 = rnorm(200)
y2 = rnorm(200)
smoothScatter(x2,y2,nrpoints=length(x2),cex=3,colramp=colorRampPalette(c("white","red")))

enter image description here My hope is that I can produce a 3rd plot which is a colorful subtraction of the 1st plot from the 2nd plot. That is, there will be areas which are blue, red, and then if possible I'd like to make the overlapped areas gray. But I'd like the colors to be consistent with the new densities. For instance, the center of the new plot would be almost fully gray, whereas the outsides may have some gray but also patches of blue and red. Note that the two plots have different numbers of points. How could I do such a thing?

The only way I can think of doing this is to go pixel by pixel and subtract the colors from one plot to another. The problem is, I don't know how to grab the color intensities at each pixel to do this. However, even if I were to achieve this, white minus white would probably give black, which I wouldn't want.

Thanks in advance!

1
From ?smoothScatter it looks like these are generated with the bkde2D function, and from ?bkde2D it looks like you can grab the pixel-by-pixel data using the x1, x2, and fhat elements of the output of that function.josliber
Right but I'm not sure how to then grab the color value given a specific (x1,x2) positionCodeGuy

1 Answers

10
votes

You might consider using slightly transparent colors

#helper function to make transparent ramps
alpharamp<-function(c1,c2, alpha=128) {stopifnot(alpha>=0 & alpha<=256);function(n) paste(colorRampPalette(c(c1,c2))(n), format(as.hexmode(alpha), upper.case=T), sep="")}

And then we can overplot the two graphs with

smoothScatter(x1,y1,nrpoints=length(x1),cex=3, colramp=alpharamp("white",blues9))
par(new=T)
smoothScatter(x2,y2,nrpoints=length(x2),cex=3,colramp= alpharamp("white","red"), axes=F, ann=F)

Here's that this code produces.

sample plot with transparency

If, you still want to get to the actual color values in the plot, that's actually a bit tricky. You'd have to call grDevices:::.smoothScatterCalcDensity directly with your data. Then you'd have to transform the returned fhat values by taking 4th root and rescaling to 0-1. Then you convert to color by taking those values and then those values (let's call them z are converted to indexes using the formula floor((256 - 1e-05) * z + 1e-07)+1. Then those indexes are used to find a value from the 256 colors generated from the ramp you supply. It's all a bit crazy but you can read the source to smoothScatter and image.default to see how it really happens.