ggplot2 - remove part of legend [duplicate] - r

Suppose I have a ggplot with more than one legend.
mov <- subset(movies, length != "")
(p0 <- ggplot(mov, aes(year, rating, colour = length, shape = mpaa)) +
geom_point()
)
I can turn off the display of all the legends like this:
(p1 <- p0 + theme(legend.position = "none"))
Passing show_guide = FALSE to geom_point (as per this question) turns off the shape legend.
(p2 <- ggplot(mov, aes(year, rating, colour = length, shape = mpaa)) +
geom_point(show_guide = FALSE)
)
But what if I want to turn off the colour legend instead? There doesn't seem to be a way of telling show_guide which legend to apply its behaviour to. And there is no show_guide argument for scales or aesthetics.
(p3 <- ggplot(mov, aes(year, rating, colour = length, shape = mpaa)) +
scale_colour_discrete(show_guide = FALSE) +
geom_point()
)
# Error in discrete_scale
(p4 <- ggplot(mov, aes(year, rating, shape = mpaa)) +
aes(colour = length, show_guide = FALSE) +
geom_point()
)
#draws both legends
This question suggests that the modern (since ggplot2 v0.9.2) way of controlling legends is with the guides function.
I want to be able to do something like
p0 + guides(
colour = guide_legend(show = FALSE)
)
but guide_legend doesn't have a show argument.
How do I specify which legends get displayed?

You can use guide = "none" in scale_..._...() to suppress legend.
For your example you should use scale_colour_continuous() because length is continuous variable (not discrete).
(p3 <- ggplot(mov, aes(year, rating, colour = length, shape = mpaa)) +
scale_colour_continuous(guide = "none") +
geom_point()
)
Or using function guides() you should set "none" for that element/aesthetic that you don't want to appear as legend, for example, fill, shape, colour.
p0 <- ggplot(mov, aes(year, rating, colour = length, shape = mpaa)) +
geom_point()
p0+guides(colour = "none")
UPDATE
Both provided solutions work in new ggplot2 version 3.3.5 but movies dataset is no longer present in this library. Instead you have to use new package ggplot2movies to check those solutions.
library(ggplot2movies)
data(movies)
mov <- subset(movies, length != "")

You can simply add show.legend=FALSE to geom to suppress the corresponding legend

Related

ggplot2 unable to color legend icons

I'm trying to use ggplot2 to make some sort of timeline using values from a dataframe (df). I've managed to plot the data exactly how I want it (the different colored line segments connecting the x-marks in this exact order, i.e., from left to right: 'early', 'unknown', 'late', 'sub'). The startpoint and endpoint columns in the dataframe are used to define the positions of the points and line segments.
The problem is that the legend doesn't show the color of the 'x' icons, they are just grey. I've tried adding scale_color_manual() and scale_fill_manual() commands but they don't seem to change anything. The legend does display the correct color when I change the shape to shape = 21, however, I really want the shape to be 4 (x icons). I don't care about the shape of the legend though but scale_shape_manual() again didn't change anything about the legend.
I have also tried placing different color arguments inside and outside the aes() argument of ggplot(), geom_segment() and/or geom_point().
How can I make the icons from the legend show the correct color?
Below I added a piece of code to reproduce the problem.
library(ggplot2)
library(RColorBrewer)
## Define dataframe
df <- data.frame(Var = c("sub","late","unknown","early"),
Time = c(10,267,0,1256),
Endpoint = c(1533,1523,1256,1256),
Startpoint = c(1523,1256,1256,0))
colorscheme <- RColorBrewer::brewer.pal(9, "Set1")[c(1,4,2,3)]
## Make plot
ggplot(df, aes(x="", y=Endpoint, fill=Var), color =colorscheme) +
geom_segment( aes(x="", xend="", y=Startpoint, yend=Endpoint), color = colorscheme) +
geom_point(aes(x="", y=Endpoint),size=5, shape=4 , color = colorscheme) +
coord_flip()
Thanks in advance for any suggestions!
You should use color instead of fill. To remove the line from the legend, use guides(color = guide_legend(override.aes = list(linetype = 0))) or use show.legend = F in geom_segment.
Also, arguments passed in ggplot need not to be repeated afterward.
ggplot(df, aes(x="", y=Endpoint, color=Var), colorscheme) +
geom_segment(aes(xend="", y=Startpoint, yend=Endpoint)) +
geom_point(size=5, shape=4) +
coord_flip() +
guides(color = guide_legend(override.aes = list(linetype = 0)))
#or
ggplot(df, aes(x="", y=Endpoint, color=Var), colorscheme) +
geom_segment(aes(xend="", y=Startpoint, yend=Endpoint)) +
geom_point(size=5, shape=4) +
coord_flip()
Try this:
ggplot(df, aes(x = "", y = Endpoint, color = Var), colorscheme) +
geom_segment(aes(x = "", xend = "", y = Startpoint, yend = Endpoint), show.legend = FALSE) +
geom_point(aes(x = "", y = Endpoint), size = 5, shape = 4) +
coord_flip()
In this way legend will show only X

R: ggplot2 density plot shows wrong fill colors

I would like to plot densities of two variables ("red_variable", "green_variable") from two independent dataframes on one density plot, using red and green color for the two variables.
This is my attempt at coding:
library(ggplot2)
### Create dataframes
red_dataframe <- data.frame(red_variable = c(10,11,12,13,14))
green_dataframe <- data.frame(green_variable = c(6,7,8,9,10))
mean(red_dataframe$red_variable) # mean is 12
mean(green_dataframe$green_variable) # mean is 8
### Set colors
red_color= "#FF0000"
green_color= "#008000"
### Trying to plot densities with correct colors and correct legend entries
ggplot() +
geom_density(aes(x=red_variable, fill = red_color, alpha=0.5), data=red_dataframe) +
geom_density(aes(x=green_variable, fill = green_color, alpha=0.5), data=green_dataframe) +
scale_fill_manual(labels = c("Density of red_variable", "Density of green_variable"), values = c(red_color, green_color)) +
xlab("X value") +
ylab("Density") +
labs(fill = "Legend") +
guides(alpha=FALSE)
Result: The legend shows correct colors, but the colors on the plot are wrong: The "red" variable is plotted with green color, the "green" variable with red color. The "green" density (mean=8) should appear left and the "red" density (mean=12) on the right on the x-axis. This behavior of the plot doesn't make any sense to me.
I can in fact get the desired result by switching red and green in the code:
### load ggplot2
library(ggplot2)
### Create dataframes
red_dataframe <- data.frame(red_variable = c(10,11,12,13,14))
green_dataframe <- data.frame(green_variable = c(6,7,8,9,10))
mean(red_dataframe$red_variable) # mean is 12
mean(green_dataframe$green_variable) # mean is 8
### Set colors
red_color= "#FF0000"
green_color= "#008000"
### Trying to plot densities with correct colors and correct legend entries
ggplot() +
geom_density(aes(x=red_variable, fill = green_color, alpha=0.5), data=red_dataframe) +
geom_density(aes(x=green_variable, fill = red_color, alpha=0.5), data=green_dataframe) +
scale_fill_manual(labels = c("Density of red_variable", "Density of green_variable"), values = c(red_color, green_color)) +
xlab("X value") +
ylab("Density") +
labs(fill = "Legend") +
guides(alpha=FALSE)
... While the plot makes sense now, the code doesn't. I cannot really trust code doing the opposite of what I would expect it to do. What's the problem here? Am I color blind?
On your code, in order to have color at the right position, you need to specify fill = red_color or fill = green_color (as well as alpha as it is a constant - as pointed out by #Gregor) outside of the aes such as:
...+
geom_density(aes(x=red_variable), alpha=0.5, fill = red_color, data=red_dataframe) +
geom_density(aes(x=green_variable), alpha=0.5, fill = green_color, data=green_dataframe) + ...
Alternatively, you can bind your dataframes together, reshape them into a longer format (much more appropriate to ggplot) and then add color column that you can use with scale_fill_identity function (https://ggplot2.tidyverse.org/reference/scale_identity.html):
df <- cbind(red_dataframe,green_dataframe)
library(tidyr)
library(ggplot2)
library(dplyr)
df <- df %>% pivot_longer(.,cols = c(red_variable,green_variable), names_to = "var",values_to = "val") %>%
mutate(Color = ifelse(grepl("red",var),red_color,green_color))
ggplot(df, aes(val, fill = Color))+
geom_density(alpha = 0.5)+
scale_fill_identity(guide = "legend", name = "Legend", labels = levels(as.factor(df$var)))+
xlab("X value") +
ylab("Density")
Does it answer your question ?
You're trying to use ggplot as if it's base graphics... the mindset shift can take a little while to get used to. dc37's answer shows how you should do it. I'll try to explain what goes wrong in your attempt:
When you put fill = green_color inside aes(), because it's inside aes() ggplot essentially creates a new column of data filled with the green_color values in your green_data_frame, i.e., "#008000", "#008000", "#008000", .... Ditto for the red color values in the red data frame. We can see this if we modify your plot by simply deleting your scale:
ggplot() +
geom_density(aes(x = red_variable, fill = green_color, alpha = 0.5), data =
red_dataframe) +
geom_density(aes(x = green_variable, fill = red_color, alpha = 0.5), data =
green_dataframe) +
xlab("X value") +
ylab("Density") +
labs(fill = "Legend") +
guides(alpha = FALSE)
We can actually get what you want by putting the identity scale, which is designed for the (common in base, rare in ggplot2) case where you actually put color values in the data.
ggplot() +
geom_density(aes(x = red_variable, fill = green_color, alpha = 0.5), data =
red_dataframe) +
geom_density(aes(x = green_variable, fill = red_color, alpha = 0.5), data =
green_dataframe) +
scale_fill_identity() +
xlab("X value") +
ylab("Density") +
labs(fill = "Legend") +
guides(alpha = FALSE)
When you added your scale_fill_manual, ggplot was like "okay, cool, you want to specify colors and labels". But you were thinking in the order that you added the layers to the plot (much like base graphics), whereas ggplot was thinking of these newly created variables "#FF0000" and "#008000", which it ordered alphabetically by default (just as if they were factor or character columns in a data frame). And since you happened to add the layers in reverse alphabetical order, it was switched.
dc37's answer shows a couple better methods. With ggplot you should (a) work with a single, long-format data frame whenever possible (b) don't put constants inside aes() (constant color, constant alpha, etc.), (c) set colors in a scale_fill_* or scale_color_* function when they're not constant.

How to correctly represent both hline and abline in a legend in ggplot2?

I am trying to create a legend in ggplot2 for hlines and ablines using clues from other similar questions. I am close to getting what I need with the following code (and example image) but I can't seem to get rid of the extra lines crossing the legend icons.
p <- ggplot(mtcars, aes(x = wt, y=mpg, col = factor(cyl))) + geom_point()
p + geom_hline(aes(lty="foo",yintercept=20)) +
geom_hline(aes(lty="bar",yintercept=25)) +
geom_hline(aes(lty="bar",yintercept=30)) +
geom_abline(aes(lty = "regression", intercept = 10 , slope = 1)) +
scale_linetype_manual(name="",values=c(2,3,1))
This behavior in the legend only appears when I include the abline. Without it, both hline appear as intended in the legend.
What am I missing here?
As a secondary point: both hlines (labelled "bar" here) here use the exact same configuration, but have different values for yintercept. I wasn't able to draw both of them with the same command, receiving an error (Error: Aesthetics must be either length 1 or the same as the data (32): linetype, yintercept).
Whenever I copy&paste a command like this, it feels like I'm not doing it right. Is it possible to set two yintercepts, while manually defining the linetype to create a legend?
You can use argument show.legend in the geom_abline:
ggplot() +
geom_point(aes(x = mtcars$wt, y=mtcars$mpg, col = factor(mtcars$cyl))) +
geom_hline(aes(lty=c("foo", "bar","bar"),yintercept=c(20,25,30))) +
geom_abline(aes(lty = "regression", intercept = 10 , slope = 1), show.legend = F) +
scale_linetype_manual(name="",values=c(2,3,1) )
If you not define the data on the ggplot command you can define all the hlines in just one command:
ggplot(mtcars, aes(x = wt, y=mpg, col = factor(cyl))) + geom_point() +
geom_hline(aes(lty="foo",yintercept=20)) +
geom_hline(aes(lty="bar",yintercept=25)) +
geom_hline(aes(lty="bar",yintercept=30)) +
geom_abline(aes(lty = "regression", intercept = 10 , slope = 1), show.legend = F) +
scale_linetype_manual(name="",values=c(2,3,1) )

Change color and add shape to lines on ggplot2 geom_freqpoly

I'm trying to add shapes on the lines plotted using geom_freqpoly to give more visibility to them if the plot is printed b/w on paper.
data <- data.frame(time=runif(1000,0,20000),
class=c("a","b","c","d"))
ggplot(data, aes(time, colour = class)) + geom_freqpoly(binwidth = 1000) + geom_point(aes(shape=class))
but this generates this error:
'Error: geom_point requires the following missing aesthetics: y'
How can I solve this error?
Another thing is that I want to use a single colour (eg. blue) to draw the lines
but with scale_colour_brewer() I can't change the colour scale, I want to change it because the lightest colour is nearly white and you can barely see it.
How can I add a custom min and max for the colours?
How about this? The error you are getting is being produced by geom_point which needs x and y, so I removed it.
ggplot(data, aes(x = time, color = class)) +
geom_freqpoly(binwidth = 1000) +
scale_color_brewer(palette = "Blues") +
theme_dark()
If you don't want the dark background, pass manual values from RColorBrewer. The following example uses every second color to increase the contrast.
p1 <- ggplot(data, aes(x = time, color = class)) +
geom_freqpoly(binwidth = 1000) +
scale_color_manual(values = RColorBrewer::brewer.pal(9, name = "Blues")[c(3, 5, 7, 9)])
EDIT
You can extract summarised data from a ggplot object using layer_data function.
xy <- layer_data(p1)
ggplot(xy, aes(x = x, y = count, color = colour)) +
theme_bw() +
geom_line() +
geom_point() +
scale_color_manual(values = RColorBrewer::brewer.pal(9, name = "Blues")[c(3, 5, 7, 9)])

change colors to black in existing ggplots

This is a question about the ggplot2 package (author: Hadley Wickham). I have existing ggplot objects with distinct colors (resp shapes, linetype, fill...) that I would like to map to a single color, e.g. black. What is the recommended approach?
Clarification: I have to work with these ggplot objects: I cannot re-make them
A ggplot with variables grouped as factors: this is the plot object p I need to work with
p <- ggplot(mtcars, aes(x = mpg, y = wt, group = factor(cyl), colour = factor(cyl))) +
geom_point(size = 5)
Several approaches I know of:
1. scale_colour_grey hack
p + scale_colour_grey(start = 0, end = 0) + # gives correct, useless legend
guides(color = FALSE)
The shorter p + scale_colour_grey(0,0) does not work, you have to be explicit about start and end.
2. scale_colour_manual with rep() hack
p + scale_colour_manual(values = rep("black",3)) # gives correct, useless legend
The simpler scale_colour_manual(values = "black") does not work. This was probably the most intuitive approach. Having to specify the length of the vector makes it less attractive an approach.
3. geom_point() recalled
p + geom_point(colour = "black") + # gives incorrect legend
guides(color = FALSE)
It is well documented that the following is not allowed:
p + scale_colour_manual(colour = "black")
Error in discrete_scale(aesthetic, "manual", pal, ...) :
unused argument (colour = "black")
Removing the color mapping directly seems to work:
p_bw = p
p_bw$mapping$colour = NULL
gridExtra::grid.arrange(p, p_bw)
If you just want to set the points to black and get rid of the color legend, I think you can just to this:
p + scale_colour_manual(values=rep("black",length(unique(mtcars$cyl))),
guide=FALSE)

Resources