zoneparser zoneparser - 20 days ago 8
R Question

R, ggplot2: creating a single legend in a bubble chart with positive and negative values

Hi I'm trying to create a bubble plot for a data-set with both positive and negative values AND generate only one legend.

I want the size of the bubble to be scaled by the absolute value of data, but the colour to correspond to the 'sign'. Creating a plot with two legends is pretty straightforward as seen in this graph below.


Here is the code I've used.

# create data frame
x=sample(seq(1,50),50,T)
y=sample(seq(1,50),50,T)
plot_dat=data.frame(x=x,y=y,value=rnorm(50,0,20))

# plot
library(ggplot2)
ggplot(data=plot_dat, aes(x=x, y=y,colour=factor(sign(value)), size=abs(value))) +
geom_point() +
scale_size(range = c(1,5)) +
scale_colour_manual(values = c("orange", "blue")) +
guides(size = guide_legend(), colour = guide_legend())


But I want to create a single legend like in plot below, generated using sp::bubble().


For various reasons I want to duplicate this in ggplot2. It is mentioned somewhere that the last line of my code

guides(size = guide_legend(), colour = guide_legend())


should combine the two legends. Obviously it isnt working for me.

The closest I have gotten is to generate a single legend with scaled symbols, but the actual bubbles themselves arent scaled.


The above plot was created using the code below

ggplot(data=plot_dat, aes(x=x, y=y,colour=factor(sign(value)), size=value)) +
geom_point() +
scale_size(breaks = c(-40,-30,-20,-10,0,10,20,30,40,50), range = c(0.5,4)) +
scale_colour_manual(values = c("orange", "blue"), guide=F) +
guides(size = guide_legend(override.aes = list(colour = list("orange","orange","orange","orange","blue","blue","blue","blue","blue","blue"),size=c(3,2.5,2,1,0.5,1,2,2.5,3,4))))

Answer

For plotting use again absolute values of value and for color sign.

You can provide breaks= argument of scale_size_continuous() with double values of 10,20,... Then provide labels= as you really need. Using guides() function replace repeated sizes with your own order of values and colors.

ggplot(data=plot_dat, aes(x=x, y=y,colour=factor(sign(value)), size=abs(value))) +
      geom_point() +
      scale_color_manual(values=c("orange","blue"),guide=FALSE)+
      scale_size_continuous(breaks=c(10,10,20,20,30,30,40,40,50,50),labels=c(-50,-40,-30,-20,-10,10,20,30,40,50),range = c(1,5))+
      guides(size = guide_legend(override.aes = list(colour = list("orange","orange","orange","orange","orange","blue","blue","blue","blue","blue"),
                                               size=c(4.92,4.14,3.50,2.56,1.78,1.78,2.56,3.50,4.14,4.92))))

To exatly know which values to provide for the size= in the guides() function you can use function rescale() from the scales library to manualy rescale your values plus break points to range you will provide in scale_size_continuous().

set.seed(1234)
x=sample(seq(1,50),50,T)
y=sample(seq(1,50),50,T)
plot_dat=data.frame(x=x,y=y,value=rnorm(50,0,20))

library(scales)
rescale(c(abs(plot_dat$value),10,20,30,40,50),to=c(1,5))[51:55]
[1] 1.775906 2.562657 3.349409 4.136161 4.922912

enter image description here