I've created a ggplot2 graph using the basic code below:
my_df %>%
ggplot(aes(conv_norm, vot_norm, color = language:poa)) +
geom_smooth(method = "glm", se=FALSE) +
theme(
...
)
[I've left out the formatting commands from the theme() layer]
And I got a graph that looks like this:
Now, my question is: how can I add extra space only in between two legend items? I've looked online and have found ways to increase the spacing between all items in the legend, but I only want extra spacing between the English items and the Spanish items. Is there a way to add a 1-in distance between these language groups?
Well, I don't know of an elegant, simple solution to do what you are asking to do... but by working with how legends are drawn and adjusting some of the elements, we can come up with a really "hacky" solution. ;)
Here's a sample dataset that kind of simulates what you shared, along with the plot:
set.seed(12345)
my_df <- data.frame(
lang = rep(c(paste('English',1:3), paste('Spanish',1:3)),2),
x = c(rep(0,6), rep(1,6)),
y = rnorm(12, 10,2))
library(ggplot2)
p <- ggplot(my_df, aes(x,y, color=lang)) + geom_line()
p
The approach here is going to be to combine all the following individual steps:
Add a "blank" legend entry. We do this by refactoring and specifying the levels of the column mydf$lang to include a blank entry in the correct position. This will be the final order of the items in the legend.
Use scale_color_manual() to set the colors of the legend items manually. I make sure to use "NA" for the blank entry.
Within scale_color_manual() I use the drop=FALSE setting. This includes all levels for a factor, even if there is no data on the plot to show. This makes our blank entry show on the legend.
Use the legend.background theme element to draw transparent boxes for the legend key items. This is so that you don't have a white or gray box for that blank entry.
Putting it all together you get this:
my_df$lang <- factor(my_df$lang, levels=c(paste('English',1:3), '', paste('Spanish',1:3)))
ggplot(my_df, aes(x,y, color=lang)) +
geom_line() +
scale_color_manual(
values=c(rainbow(6)[1:3], 'NA', rainbow(6)[4:6]),
drop=FALSE) +
theme( legend.key = element_rect(fill='NA') )
Alternatively, you could use guides(color=guide_legend(override.aes... to set the colors, but you need the drop=FALSE part within scale_color_manual() get the blank level to draw in the legend anyway.
Another option would be to create two separate legends. Either by using two different aesthetics, or you can use color twice, e.g with ggnewscale - thanks to user chemdork123 for the fake data +1.
library(tidyverse)
library(ggnewscale)
set.seed(12345)
my_df <- data.frame(
lang = rep(c(paste('English',1:3), paste('Spanish',1:3)),2),
x = c(rep(0,6), rep(1,6)),
y = rnorm(12, 10,2))
ggplot(mapping = aes(x,y)) +
geom_line(data = filter(my_df, grepl("English", lang)), aes(color=lang)) +
scale_color_brewer(NULL, palette = "Dark2") +
new_scale_colour() +
geom_line(data = filter(my_df, grepl("Spanish", lang)), aes(color=lang)) +
scale_color_brewer(palette = "Set1") +
guides(color = guide_legend(order = 1))
Created on 2021-04-11 by the reprex package (v1.0.0)
Related
I am trying to create a plot containing two lines with different shapes and colour.
I have checked a number of similar questions online but I have not been successful. I have been able to do the following so far
library(reshape2)
library(ggplot2)
library(latex2exp)
v1 <-c(0.000120,-0.000085,-0.000018,0.000005)
v2 <- c(0.000164,0.000041,-0.000032,0.000031)
v3 <- c(500,1000,5000,10000)
dfr <- data.frame(rate1=v1,rate2=v2,quantity=v3)
dfr <- melt(dfr,id='quantity',value.name="res")
ggplot(dfr, aes(x=quantity, y=res,group=variable,shape=variable)) +
geom_line(size=1, aes(linetype=variable,colour=variable)) +
geom_point( size=4,aes(colour=variable))+ coord_cartesian(ylim = c(-0.0001,0.0002)) +
scale_x_continuous(breaks=c(500,1000,5000,10000))+
scale_linetype_manual(values=c("solid", "longdash"))+
geom_hline(yintercept = 0,linetype="dotted",size=1)
However, I want to do the following:
Replace the legend texts/labels: rate1 and rate2 with two Greek lambda symbols.
Finally, hide the legend title variable.
When I try to include this: scale_colour_manual( values=c('#F8766D','#00BFC4'),labels = unname(TeX(c(" $\\lambda_1$", "$\\lambda_2$")))), so as to change the legend text, I get an extra legend below:
Please how can I fix this? Thanks!
The issue is that by changing the labels in scale_linetype but not for the other scales (color and shape) ggplot2 will no longer merge them into one legend. Hence you have the change the labels for the other scales as well. However, using Tex() I did not manage to make this work. But following this post using bquote worked fine. Finally, to get rid of the legend title simply use labs() to set the title for all three scales to NULL
EDIT Thanks to #mischva for checking and pointing out that using labels <- unname(TeX(c(" $\\lambda_1$", "$\\lambda_2$"))) will also work fine. Interestingly it does not work if one puts it directly into the three scales functions. That's what I tried.
library(reshape2)
library(ggplot2)
library(latex2exp)
v1 <-c(0.000120,-0.000085,-0.000018,0.000005)
v2 <- c(0.000164,0.000041,-0.000032,0.000031)
v3 <- c(500,1000,5000,10000)
dfr <- data.frame(rate1=v1,rate2=v2,quantity=v3)
dfr <- melt(dfr,id='quantity',value.name="res")
labels <- c(bquote(lambda[1]), bquote(lambda[2]))
ggplot(dfr, aes(x=quantity, y=res,group=variable,shape=variable)) +
geom_line(size=1, aes(linetype=variable,colour=variable)) +
geom_point( size=4,aes(colour=variable))+ coord_cartesian(ylim = c(-0.0001,0.0002)) +
scale_x_continuous(breaks=c(500,1000,5000,10000))+
scale_linetype_manual(values=c("solid", "longdash"), labels = labels)+
scale_shape_discrete(labels = labels)+
scale_colour_discrete(labels = labels) +
labs(color = NULL, linetype = NULL, shape = NULL) +
geom_hline(yintercept = 0,linetype="dotted",size=1)
I'm making many plots and want to set a default color for the data labels without having to pass the color argument to every geom_text call. I can do it for the plot titles and axes, but not the data labels.
# Example of how to set default color for other text elements
library(ggplot2)
theme_set(theme_bw() + theme(text = element_text(color = "red"),
axis.text = element_text(color = "red")))
ggplot(mtcars, aes(x = cyl, label = ..count..)) +
geom_bar() +
geom_text(stat = "count") +
labs(title = "title")
Unfortunately, I believe theme elements are only intended to apply to non-data-related elements of the plot, meaning the theme does not cover the text in geom_text. The default color "black" is hard-coded in the source of geom_text, so as far as I know, there's not a simple way to override it. (Though, if someone cares to correct me, excellent!)
However, one simple solution that may help streamline things is to create a wrapper function that will return a geom_text with all the defaults that you will be passing over and over. For example:
geom_text_wrap <- function(col="red", ...) {
geom_text(col=col, ...)
}
can be used in place of geom_text directly, and will, by default, create red text. So the following will create red text without you having to specify it directly in the plot creation.
ggplot(mtcars, aes(x = cyl, label = ..count..)) +
geom_bar() +
geom_text_wrap(stat="count") +
labs(title = "title")
Note: If you really are creating a ton of similar plots to the point that you are tiring of specifying repetitive arguments, you may consider writing a function that will create the complete graph objects programmatically. That will depend on your specific use-case.
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))
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 can I get a single legend that captures both colour and size?
I was under the impression that a common legend is default if a common variable is used, but the following example shows I am missing something.
library(ggplot2)
input <- as.data.frame(matrix(runif(60),nrow=20,ncol=3))
colnames(input) <- c("A","B","C")
p <- ggplot(input,aes(A,B,size=C,color=C)) + geom_point()
Thanks to Arun for a comment that prompted this edit. So, if one just uses size (and forgets color) one gets a legend that depicts three sizes but many more sizes are depicted in the plot.
So what I would be after is similar behaviour - a legend that shows some values of the common variable and depicts the corresponding sizes and colors.
The colorbar cannot be merged, but a normal legend can,
p + guides(colour = guide_legend())
I needed to make the labels for size and color the same, and make sure it's working with the same information combined with the guides line.
p+geom_jitter(data=df, aes(x=x, y=y, color=value, size = value))
+scale_size_continuous(name = "Legend Name", breaks= c(.25, .50,.75), labels=c(".25",".50",".75"))+scale_colour_gradient(name = "Legend Name", breaks= c(.25, .50,.75), labels=c(".25", ".50",".75"))+
guides(colour = guide_legend())