`fill` scale is not shown in the legend - r

Here is my dummy code:
set.seed(1)
df <- data.frame(xx=sample(10,6),
yy=sample(10,6),
type2=c('a','b','a','a','b','b'),
type3=c('A','C','B','A','B','C')
)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c('green', 'red'))
Resulting plot has a legend but it's 'type2' section doesn't reflect scale of fill value - is it by design?

I know this is an old thread, but I ran into this exact problem and want to post this here for others like me. While the accepted answer works, the less risky, cleaner method is:
library(ggplot2)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c(a='green',b='red'))+
guides(fill=guide_legend(override.aes=list(shape=21)))
The key is to change the shape in the legend to one of those that can have a 'fill'.

Here's a different workaround.
library(ggplot2)
ggplot(data=df, mapping = aes(x=xx, y=yy)) +
geom_point(aes(shape=type3, fill=type2), size=5) +
scale_shape_manual(values=c(24,25,21)) +
scale_fill_manual(values=c(a='green',b='red'))+
guides(fill=guide_legend(override.aes=list(colour=c(a="green",b="red"))))
Using guide_legend(...) with override_aes is a way to influence the appearance of the guide (the legend). The hack is that here we are "overriding" the fill colors in the guide with the colors they should have had in the first place.

I played with the data and came up with this idea. I first assigned shape in the first geom_point. Then, I made the shapes empty. In this way, outlines stayed in black colour. Third, I manually assigned specific shape. Finally, I filled in the symbols.
ggplot(data=df, aes(x=xx, y=yy)) +
geom_point(aes(shape = type3), size = 5.1) + # Plot with three types of shape first
scale_shape(solid = FALSE) + # Make the shapes empty
scale_shape_manual(values=c(24,25,21)) + # Assign specific types of shape
geom_point(aes(color = type2, fill = type2, shape = type3), size = 4.5)

I'm not sure if what you want looks like this?
ggplot(df,aes(x=xx,y=yy))+
geom_point(aes(shape=type3,color=type2,fill=type2),size=5)+
scale_shape_manual(values=c(24,25,21))

Related

Add black outline geom_point and fill independent variable different from others [duplicate]

I'd like to place a black border around points on a scatterplot that are filled based on data, using ggplot2. Also, I would like to avoid having a legend entry for the black border since it will be on each point. Basically I'm looking for this plot, but with a black border around each point.
df <- data.frame(id=runif(12), x=1:12, y=runif(12))
ggplot(df, aes(x=x, y=y))+geom_point(aes(colour=id), size=12)
As a bonus, I'd like to not have a legend entry for the black border. My best try is:
df <- data.frame(id=runif(12), x=1:12, y=runif(12))
ggplot(df, aes(x=x, y=y))+geom_point(aes(fill=id, colour="black"), size=12)
Which gives:
I don't understand why that doesn't give me what I want, and worse (for my education in ggplot2) I don't understand why it doesn't seem to map fill color to anything! Any help?
Perhaps if I can get the outline and fill mapping right I can use a hack like the one in hte last set of figures here to turn off the legend.
It's a bit obscure, but you have to use pch>20 (I think 21:25 are the relevant shapes): fill controls the interior colo(u)ring and colour controls the line around the edge.
(g0 <- ggplot(df, aes(x=x, y=y))+geom_point(aes(fill=id),
colour="black",pch=21, size=5))
update: with recent ggplot2 versions (e.g. 2.0.0, don't know how far back it goes) the default guide is a colourbar. Need g0 + guides(fill="legend") to get a legend with points as in the plot shown here. The default breaks have changed, too: to exactly replicate this plot you need g0 + scale_fill_continuous(guide="legend",breaks=seq(0.2,0.8,by=0.1)) ...
Related but not identical: how to create a plot with customized points in R? . The accepted answer to that question uses the layering technique shown in #joran's answer, but (IMO) the answer by #jbaums, which uses the pch=21 technique, is superior. (I think shape=21 is an alternative, and perhaps even preferred, to pch=21.)
PS you should put colour outside the mapping (aes bit) if you want to set it absolutely and not according to the value of some variable ...
The first question's a gimme:
ggplot(df, aes(x=x, y=y)) +
geom_point(aes(colour=id), size=12) +
geom_point(shape = 1,size = 12,colour = "black")
And, oh, you don't want an extra legend. I think that does it then:
I had the same issue, but I needed a solution that allows for jitter, too. For this you do need to use a pch that is a filled shape with a border and a grid.edit function from gridExtra package. Using your example:
df <- data.frame(id=runif(12), x=1:12, y=runif(12))
ggplot(df, aes(x=x, y=y, fill=id))+geom_point(pch=21, colour="Black", size=12)
library(gridExtra)
grid.edit("geom_point.points", grep = TRUE, gp = gpar(lwd = 3))
I had the same question, but perhaps since I was using geom_map with latitudes and longitudes, the other answers as of January 2020 didn't work for me.
Restating the question, where the following does not have a black outline around the points:
df <- data.frame(id=runif(12), x=1:12, y=runif(12))
ggplot(df, aes(x=x, y=y))+geom_point(aes(colour=id), size=12)
If I declared both the color and fill in the aesthetic and then used shape 21, problem solved.
ggplot(df, aes(x=x, y=y)) +
geom_point(aes(colour=id, fill=id),
shape = 21,size = 12,colour = "black")
If you want more control (for example, borders on points with various shapes and transparencies), use the fill aesthetic with shapes 21:25
ggplot(aes(x = Sepal.Length, y = Petal.Width, fill = Species, shape = Species), data = iris) + # notice: fill
geom_point(size = 4, alpha = 0.5) + # transparent point
geom_point(size = 4, fill = NA, colour = "black") + # black border
scale_shape_manual(values = c(21:23)) + # enable fill aesthetic
theme_classic()

Customising legend size-symbol items in ggplot2

I'm mapping size to a variable with something like a log distribution - mostly small values but a few very large ones. How can I make the legend display custom values in the low-value range? For example:
df = data.frame(x=rnorm(2000), y=rnorm(2000), v=abs(rnorm(2000)^5))
p = ggplot(df, aes(x, y)) +
geom_point(aes(col=v, size=v), alpha=0.75) +
scale_size_area(max_size = 10)
print(p)
I've tried p + guides(shape=guide_legend(override.aes=list(size=8))) solution posted in this SO question, but it makes no difference in my plot. In any case I'd like to use specific legend size values e.g. v = c(10,25,50,100,250,500) instead of the default range e.g. c(100,200,300,400)..
Grateful for assistance.
To get different break points of size in legend, modify scale_size_area() by adding argument breaks=. With breaks= you can set breakpoints at positions you need.
ggplot(df, aes(x, y)) +
geom_point(aes(col=v, size=v), alpha=0.75) +
scale_size_area(max_size = 10,breaks=c(10,25,50,100,250,500))

Changing the color in the legend with ggplot2 in R

I'm having two different problems with specifying the colors in my legends in ggplot. I've tried to make a simplified examples that shows my problem:
df <- data.frame(x=rep(1:9, 10), y=as.vector(t(aaply(1:10, 1, .fun=function(x){x:(x+8)}))), method=factor(rep(1:9, each=10)), DE=factor(rep(1:9, each=10)))
ggplot(df, aes(x, y, color=method, group=DE, linetype=DE)) + geom_smooth(stat="identity")
For some reason, the line types shown in the legend under the title DE are all blue. I'd like them to be black, but I have no idea why they're blue in the first place, so I'm not sure how to change them.
For my other problem, I'm trying to use both point color and point shape to show two different distinctions in my data. I'd like to have legends for both of these. Here's what I have:
classifiers <- c("KNN", "RF", "NB", "LR", "Tree")
des <- c("Uniform", "Gaussian", "KDE")
withoutDE <- c(.735, .710, .706, .628, .614, .720, .713, .532, .523, .557, .677, .641, .398, .507, .538)
withDE <- c(.769, .762, .758, .702, .707, .752, .745, .655, .721, .733, .775, .772, .749, .756, .759)
df <- data.frame(WithoutDE=withoutDE, WithDE=withDE, DE=rep(des, each=5), Classifier=rep(classifiers, 3))
df <- cbind(df, Method=paste(df$DE, df$Classifier, sep=""))
ggplot() + geom_point(data=df, aes(x=WithoutDE, y=WithDE, shape=Classifier, fill=DE), size=3) + ylim(0,1) + xlim(0,1) + xlab("AUC without DE") + ylab("AUC with DE") + scale_shape_manual(values=21:25) + scale_fill_manual(values=c("pink", "blue", "white"), labels=c("Uniform", "KDE", "Gaussian")) + theme(legend.position=c(.85,.3))
If I change the color to change as well as the fill (by putting color=DE into the aes), then those are visible in the legend. I like having the black border around the points, though. I'd just like to have the inside of the points in the legend reflect the point fill in the plot. (I'd also like to position the two legends side-by-side, but I really just want to get the color to work right now)
I've spent way too long googling about both of these problems and trying various solutions without any success. Does anyone have any idea what I'm doing wrong?
For question 1:
Give the legend for line type and the legend for colour the same name.
ggplot(df, aes(x, y, color=method, group=DE, linetype=DE)) +
geom_smooth(stat="identity") +
scale_color_discrete("Line") +
scale_linetype_discrete("Line")
For question 2:
I do not think your fills are matching your data. You should assign the name of the value to each colour in the scale_x_manual calls.
I couldn't get the black border for the points. Here is what I was able to get, though:
ggplot() +
geom_point(data=df, aes(x=WithoutDE, y=WithDE, shape=Classifier,
fill=DE, colour=DE), size=3) +
ylim(0,1) + xlim(0,1) +
xlab("AUC without DE") +
ylab("AUC with DE") +
scale_shape_manual(values=21:25) +
scale_fill_manual(values=c("Uniform"="pink", "KDE"="blue", "Gaussian"="white"),
guide="none") +
scale_colour_manual(values=c("Uniform"="pink", "KDE"="blue", "Gaussian"="white"),
labels=c("Uniform", "KDE", "Gaussian")) +
theme(legend.position=c(.85,.3))
I don't know if you can control the point type inside the legends. Maybe someone else with more knowledge of ggplot2 can figure it out.

how to distinguish 4 factors in ggplot2?

How does one distinguish 4 different factors (not using size)? Is it possible to use hollow and solid points to distinguish a variable in ggplot2?
test=data.frame(x=runif(12,0,1),
y=runif(12,0,1),
siteloc=as.factor(c('a','b','a','b','a','b','a','b','a','b','a','b')),
modeltype=as.factor(c('q','r','s','q','r','s','q','r','s','q','r','s')),
mth=c('Mar','Apr','May','Mar','Apr','May','Mar','Apr','May','Mar','Apr','May'),
yr=c(2010,2011,2010,2011,2010,2011,2010,2011,2010,2011,2010,2011))
where x are observations and y are modeling results and I want to compare different model versions across several factors. Thanks!
I think , it very difficult visually to distinguish/compare x and y values according to 4 factors. I would use faceting and I reduce the number of factors using interaction for example.
Here an example using geom_bar:
set.seed(10)
library(reshape2)
test.m <- melt(test,measure.vars=c('x','y'))
ggplot(test.m)+
geom_bar(aes(x=interaction(yr,mth),y=value,
fill=variable),stat='identity',position='dodge')+
facet_grid(modeltype~siteloc)
I really like using interaction by agstudy - I would probably try this first. But if keeping things unchanged then:
4 factors could be accomodated with faceting and 2 axes. Then there are 2 metrics x and y: one option is a bubble chart with both metrics distinguishing by color or shape or both (added jitter to make shapes less overlapping):
testm = melt(test, id=c('siteloc', 'modeltype', 'mth', 'yr'))
# by color
ggplot(testm, aes(x=siteloc, y=modeltype, size=value, colour=variable)) +
geom_point(shape=21, position="jitter") +
facet_grid(mth~yr) +
scale_size_area(max_size=40) +
scale_shape(solid=FALSE) +
theme_bw()
#by shape
testm$shape = as.factor(with(testm, ifelse(variable=='x', 21, 25)))
ggplot(testm, aes(x=siteloc, y=modeltype, size=value, shape=shape)) +
geom_point(position="jitter") +
facet_grid(mth~yr) +
scale_size_area(max_size=40) +
scale_shape(solid=FALSE) +
theme_bw()
# by shape and color
ggplot(testm, aes(x=siteloc, y=modeltype, size=value, colour=variable, shape=shape)) +
geom_point(position="jitter") +
facet_grid(mth~yr) +
scale_size_area(max_size=40) +
scale_shape(solid=FALSE) +
theme_bw()
UPDATE:
This is attempt based on 1st comment by Dominik to show if (x,y) is above or below 1:1 line and how big is the ratio x/y or y/x - blue triangle is if x/y>1, red circle otherwise (no need in melt in this case):
test$shape = as.factor(with(test, ifelse(x/y>1, 25, 21)))
test$ratio = with(test, ifelse(x/y>1, x/y, y/x))
ggplot(test, aes(x=siteloc, y=modeltype, size=ratio, colour=shape, shape=shape)) +
geom_point() +
facet_grid(mth~yr) +
scale_size_area(max_size=40) +
scale_shape(solid=FALSE) +
theme_bw()
You can use hollow and solid points, but only with certain shapes as described in this answer.
So, that leaves you with fill, colour, shape, and alpha as your aesthetic mappings. It looks ugly, but here it is:
ggplot(test, aes(x, y,
fill=modeltype,
shape=siteloc,
colour=mth,
alpha=factor(yr)
)) +
geom_point(size = 4) +
scale_shape_manual(values=21:25) +
scale_alpha_manual(values=c(0.35,1))
Ugly, but I guess it is what you asked for. (I haven't bothered to figure out what is happening with the legend -- it obviously isn't displaying the borders right.)
If you want to map a variable to a kind of custom aesthetic (hollow and solid), you'll have to go a little further:
test$fill.type<-ifelse(test$yr==2010,'other',as.character(test$mth))
cols<-c('red','green','blue')
ggplot(test, aes(x, y,
shape=modeltype,
alpha=siteloc,
colour=mth,
fill=fill.type
)) +
geom_point(size = 10) +
scale_shape_manual(values=21:25) +
scale_alpha_manual(values=c(1,0.5)) +
scale_colour_manual(values=cols) +
scale_fill_manual(values=c(cols,NA))
Still ugly, but it works. I don't know a cleaner way of mapping both the yr to one colour if it is 2010 and the mth if not; I'd be happy if someone showed me a cleaner way to do that. And now the guides (legend) is totally wrong, but you can fix that manually.

Remove and alter legend in ggplot2

I have the following plot but do not want the legend for point size to show. Also how can I change the title for the factor(grp)? Sorry I know this should be an easy one but I am stuck.
df1<-data.frame(x=c(3,4,5),y=c(15,20,25),grp=c(1,2,2))
p<-ggplot(df1,aes(x,y))
p<-p+ geom_point(aes(colour=factor(grp),size=4))
p
df2<-data.frame(x=c(3.5,4.5,5.5),y=c(15.5,20.5,25.5))
p<-p + geom_path(data=df2,aes(x=x,y=y))
p
To change the legend title, it's easier (I find) to just change the data frame title:
df1$grp = factor(df1$grp)
colnames(df1)[3] = "Group"
The reason why size appears in the legend, is because you have made it an aesthetic - it's not! An aesthetic is something that varies with data. Here size is fixed:
p = ggplot(df1,aes(x,y))
p = p+ geom_point(aes(colour=Group), size=4)
You can also change the name of the legend in ggplot itself:
p = p + scale_colour_discrete(name="Group")
Leave the size out of the aesthetics.
ggplot(df1,aes(x,y)) + geom_point(aes(colour = factor(grp)), size=4) +
scale_colour_discrete(name = "Grp")

Resources