R: Legend for geom_polygon() with single value - r

I'm using ggplot2 for map plots in R. How do I add a legend entry for a layer without a scale, just for a uniform color:
geom_polygon(data = watercourses, fill = "#0055aa", alpha = .5)
I just want to have the item title "Watercourses" and a color block representing the correct fill color. How does this work? So far, I only figured out how I can include scales to the legend.
Thank you!
EDIT: Here's an example with the NC dataset.
Map without centroids in legend
library(sf)
library(ggplot2)
demo(nc)
nc_centroids <- st_centroid(nc)
ggplot(nc) +
geom_sf(aes(fill = BIR74)) +
scale_fill_gradient(low = "white", high = "red") +
geom_sf(data = nc_centroids, color = "blue") +
coord_sf()
Wrong usage of aes() for legend
ggplot(nc) +
geom_sf(aes(fill = BIR74)) +
scale_fill_gradient(low = "white", high = "red") +
geom_sf(data = nc_centroids, aes(color = "blue")) +
coord_sf()
Trying to add the centroids to the legend (based on the answer of r2evans, https://stackoverflow.com/a/75346358/4921339)
ggplot(nc) +
geom_sf(aes(fill = BIR74)) +
scale_fill_gradient(low = "white", high = "red") +
geom_sf(data = nc_centroids, aes(color = "County centroids")) +
scale_fill_manual(name = "Centroids", values = c("County centroids" = "blue"))
coord_sf()
Throws the following messages and an error:
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
Error: Continuous value supplied to discrete scale
In my original case I use sp package instead of sf, but the messages and error thrown in the end are the same.
I think I did not yet understand how things work here, unfortunately. Any helping hints are highly appreciated.

If you place your fill in an aes(.), it will create a legend. Since you want a specific color, I suggest also adding scale_fill_manual:
ggplot(mtcars[-(1:3),], aes(mpg, disp)) +
geom_point() +
# placeholder for your `geom_polygon`:
geom_point(data = mtcars[1:3,], aes(fill = "something"), alpha = 0.5) +
scale_fill_manual(name = "something else", values = c("something" = "#0055aa"))
Perhaps this to add your blue points:
ggplot(nc) +
geom_sf(aes(fill = BIR74)) +
scale_fill_gradient(low = "white", high = "red") +
geom_sf(data = transform(nc_centroids, col = "County centroids"), aes(colour = col)) +
coord_sf() +
scale_colour_manual(name = NULL, values = c("County centroids" = "blue"))
EDIT by #winnewoerp: Explanation of how it works, for those who have problems understanding it all (like me until now...):
Add an extra column to the data frame with a unique value to be used within the legend, this can be done e.g. using the transform() function like in the given example or like df$col <- "Column unique value" prior to ggplot().
The (sole?) advantage to using transform is that there is no need to alter the original data, which might affect other processes on it (outside of this image). One disadvantage to doing it this way is that one must hard-code the "Column unique value" in both the transform and the scale_colour_manual, below.
Use scale_colour_manual() to add the legend item (blue colour example):
scale_colour_manual(
name = "Legend title",
values = c("Column unique value" = "blue")
)

Related

scale_fill_discrete with breaks and custom color scale?

I have an issue choosing the custom colouring of my plot, I am trying to add my own values to the plot but I can's seem to understand where should I put the custom color vector:
col <- c("#004d8d", "#cc2701", "#e5b400")
This is the plot code right now:
p1 <- ggplot(data = densdf1, mapping = aes(x = x, y = y)) +
geom_area(data = densdf1[densdf1$CI,],
aes(fill = Electrode, color = Electrode),
outline.type = "full", alpha = 0.3, size = 1) +
geom_line(aes(color = Electrode), size = 1) +
scale_fill_discrete(breaks=c("Fz","Cz","Pz")) +
guides(colour = "none") +
geom_vline(xintercept = 0) +
lims(x = c(-3, 2), y = c(0, 2.25)) +
labs(title="INTERVAL 225-275ms", x="VALUES", y="DENSITY") +
theme_bw() +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
plot.title=element_text(size=14))
This is the plot with default colours and it looks perfectly fine, but I'd like to customise the colours.
As you can see there is a contour line and the area from the density that need to be coloured.
I tried changing the aesthetics but I think I am not understanding the logic. I tried also using scale_manual_fill(values = col) removing scale_fill_discrete(breaks=c("Fz","Cz","Pz")) but it only works with the area inside.
Can any ggplot2 expert give me a hint? Thanks!
in the aes(...) section you define scales, and the color must be adjusted for each scale. In your case it would be the "fill" and the "color" scale, hence the following two lines must be added to adjust both scales:
scale_color_manual(values = col, breaks = c("Fz", "Cz", "Pz")) +
scale_fill_manual(values = col, breaks = c("Fz", "Cz", "Pz")) +
If you want to make sure, that a certain category gets a certain color, you have to specify the breaks, and the order the vector corresponds to the order of the color vector.

How to add custom legend in ggboxplot

I'm trying to create some boxplots in R. I've been using both ggboxplot and ggplot. This is my code and output so far:
ggboxplot:
ggboxplot(shp_PA#data, x = "hei_1998to2007_cat", y = "adjrate.2008to2017",
xlab = "Hazardous Exposure Index Jenks",
ylab = "Lung Cancer Incidence Rate",
color = "red",
add = c("jitter", "mean"),
add.params = list(color = "black", shape=20))
ggplot:
shp_PA#data %>%
ggplot(aes(x=hei_1998to2007_cat, y=adjrate.2008to2017)) +
geom_boxplot(colour = "red") +
geom_jitter(color="black", size=0.75) +
stat_summary(fun=mean, geom="point", shape=4, size=3, color="black") +
xlab("Hazardous Exposure Index Jenks") +
ylab("Lung Cancer Incidence Rate")
My main interest right now is in putting a legend on each boxplot that has the symbol used to depict the mean, and the word "Mean" next to it. In base R, its as simple as putting something like
legend("topright", legend=c("Mean"),pch=5, col="red")
but I can't figure it out in ggboxplot or ggplot. Most of the things I've seen online discuss modifying a legend that is already present.
One other thing I'm wondering how to do is specific to ggboxplot. I want to be able to make the color and shape of the jitter points different from the symbol for the mean. I've tried changing the add.params code to
add.params = list(color = c("black", "blue"), shape=c(20,4))
but I get the error
Error: Aesthetics must be either length 1 or the same as the data (213): shape and colour
Any help is greatly appreciated!
Edit: Add reproducible example using iris dataset in R
ggboxplot:
ggboxplot(iris, x = "Species", y = "Sepal.Length",
color = "red",
add = c("jitter", "mean"),
add.params = list(color = "black", shape=20))
ggplot:
ggplot(data=iris, aes(x=Species, y=Sepal.Length)) +
geom_boxplot(colour = "red") +
geom_jitter(color="black", size=0.75) +
stat_summary(fun=mean, geom="point", shape=4, size=3, color="black")
Again, I'd like to add a legend with the symbol used to depict the mean and the word "Mean", and be able to use ggboxplot to have the color and shape of the jitter and mean to be different.
Its a bit of a non-standard way to use ggplot, but you can do something like this.
add a legend with the symbol used to depict the mean and the word "Mean"
Map different shapes to geom_jitter and stat_summary using aes. Control those shapes using scale_shape_manual
have the color and shape of the jitter and mean to be different
Use color to change the colors for the jitter points and mean point, and use override.aes to change the colors in the legend.
ggplot(data=iris, aes(x=Species, y=Sepal.Length)) +
geom_boxplot(colour = "red") +
geom_jitter(size=1, color = 'green', aes(shape = 'all data')) +
stat_summary(fun=mean, geom="point", size=3, color = 'black', aes(shape = 'mean')) +
scale_shape_manual(values = c(20, 4)) +
guides(shape = guide_legend(override.aes = list(color = c('green', 'black'))))
Another similar answer here: https://stackoverflow.com/a/5179731/12400385
Welcome to SO!
Adding custom labels to ggplot2 is notoriously difficult, and I believe this is by design. All legends are controlled by the arguments placed in aes and scale_*_[continuoues|discrete|manual]. If we don't want to start learning how to grob (likely spending several hours) we can however achieve the desired output by
Adding are statistic to the data itself
Create a column indicating which is the statistic and which is data points
Abuse that we can subset the data directly in our geom_* function to create a specific layer for jitter and non-jittered points, and set the shape in the aestethics of these layers
Customize the marks using scale_shape_manual (or scale_shape_discrete).
Using the mtcars dataset as an example (and dplyr for piping) we can obtain something very similar to ggboxplot
library(ggplot2)
library(dplyr)
data(mtcars)
# Setup data with mean instead of using stat_summary
mtcars %>%
select(cyl, hp) %>%
group_by(cyl) %>%
summarize(hp = mean(hp)) %>%
bind_cols(stat = factor(rep('mean', 3))) %>%
bind_rows(mtcars %>%
select(cyl, hp) %>%
bind_cols(stat = rep('data', nrow(mtcars)))) %>%
# Create ggplot
ggplot(aes(x = factor(cyl), y = hp)) +
geom_boxplot(colour = 'red') +
# Jitter based on subset of data. Do the same for geom_point (means)
## Note that to only plot a subset I pass a function to data that "filters" the data.
geom_jitter(data = function(.data)filter(.data, stat == 'data'),
aes(shape = stat), color = 'black') +
# Add mean to the point and change shape into something we like.
geom_point(data = function(.data)filter(.data, stat == 'mean'),
aes(shape = stat), size = 2.5) +
## Use scale_shape_manual to change shape into something i like.
scale_shape_manual(values = c('mean' = 8, 'data' = 16)) +
# Fix the plot theme to be similar to ggboxplot
theme(panel.grid = element_line(colour = NA),
panel.background = element_rect(fill = "#00000000"),
axis.line.x = element_line(colour = 'black'),
axis.line.y = element_line(colour = 'black'),
axis.text = element_text(size = 11),
legend.position = 'bottom'
) +
# Remove label from the legend if wanted
labs(shape = NULL)

Problem: qqplot legend different linetypes

legend <- c("score" = "black", "answer" = "red")
plot <- df_l %>% ggplot(aes(date, score, color = "score")) + geom_line() +
geom_vline(aes(xintercept = getDate(df_all %>% filter(name == List[5])), color = "answer"), linetype = "dashed", size = 1,) +
scale_color_manual(name = "Legend", values = legend) +
scale_x_date(labels = date_format("%m/%y"), breaks = date_breaks("months")) +
theme(axis.text.x = element_text(angle=45)) +
labs(title = "", x = "", y = "", colors = "Legend")
I get the result above and could not figure out how to resolve the problem that in the legend always both lines are mixed up. One legend should of course show the slim black line only and the other the dashed black line. Thanks in advance!
The issue you have is that geom_vline results in a legend item that is a vertical line and geom_line gives you a horizontal line item. One solution is to create the legend kind of manually by specifying the color= aesthetic in geom_line... but not in geom_vline. You can then create a kind of "dummy" geom with geom_blank that serves as a holding object for the aesthetics of color=. You can then specify the colors for both of those items via scale_color_manual. Here's an example:
set.seed(12345)
df <- data.frame(x=1:100,y=rnorm(100))
ggplot(df, aes(x,y)) + theme_bw() +
geom_line(aes(color='score')) +
geom_vline(aes(xintercept=4), linetype=2, color='red', show.legend = FALSE) +
geom_blank(aes(color='my line')) +
scale_color_manual(name='Legend', values=c('my line'='red','score'='black'))
That creates the one legend for color... but unfortunately "my line" is solid red, when it should be dashed. To fix that, you just apply the linetype= aesthetic in the same way.
ggplot(df, aes(x,y)) + theme_bw() +
geom_line(aes(color='score', linetype='score')) +
geom_vline(aes(xintercept=4), linetype=2, color='red', show.legend = FALSE) +
geom_blank(aes(color='my line', linetype='my line')) +
scale_linetype_manual(name='Legend', values=c('my line'=2,'score'=1)) +
scale_color_manual(name='Legend', values=c('my line'='red','score'='black'))

geom_path is not drawing a line

I'm making depth profiles with ggplot. Some of the lines are drawn between the variable points using geom_path but some are not, even when I try adding "group=1" (which was the only solution I've found for this problem). I'm doing multiple plots for different lakes and for each lake there is one or multiple variables not getting a line by using geom_path. For the code below only the Chl.a variable is not drawing a line, all the others do. What could this depend on?
I also tried geom_line instead but this only worked for some variables since the it draws the line following the x-axis, but I want the line to go vertically following the y-axis. Can I achieve this using geom_line since geom_path doesn't seem to work for all variables?
gs <- ggplot(goodspirit, aes(y=goodspirit$Depth.m)) +
geom_point(aes(x=Temp, colour= "Temp")) +
geom_path(aes(x=Temp, color = "Temp"), size=1.5) +
geom_point(aes(x=zDOmg, color ="z(DO mg/L)")) +
geom_path(aes(x=zDOmg, color ="z(DO mg/L)"), size=1.5) +
geom_point(aes(x=Chl.a, color ="Chl.a"), na.rm = TRUE) +
geom_path(aes(x=Chl.a, color ="Chl.a"), na.rm = TRUE, size=1.5) +
geom_point(aes(x=zN2O, color ="z(N2O.nM)"), na.rm = TRUE) +
geom_line(aes(x=zN2O, color ="z(N2O.nM)"), na.rm = TRUE, size=1.5) +
geom_point(aes(x=Sal.ppt, color ="Salinity.ppt"), na.rm = TRUE) +
geom_line(aes(x=Sal.ppt, color ="Salinity.ppt"), na.rm = TRUE, size=1.5)+
geom_point(aes(x=zph, color ="z(pH)")) +
geom_path(aes(x=zph, color ="z(pH)"), size=1.5) +
scale_x_continuous(position = "top", limits=c(-3,5), expand = c(0,0))+
scale_y_reverse(expand = c(0.05,0))+
ylab("Depth (m)") + xlab("x") + ggtitle("Good spirit lake") + labs(colour
= "Parameters") +
theme(plot.title = element_text(hjust = 0.5)) + theme_light()
gs
enter image description here

Adding legend for combo bar and line graph -- ggplot ignoring commands

I am trying to make a bar chart with line plots as well. The graph has created fine but the legend does not want to add the line plots to the legend.
I have tried so many different ways of adding these to the legend including:
ggplot Legend Bar and Line in Same Graph
None of which have worked. show.legend also seems to have been ignored in the geom_line aes.
My code to create the graph is as follows:
ggplot(first_q, aes(fill = Segments)) +
geom_bar(aes(x= Segments, y= number_of_new_customers), stat =
"identity") + theme(axis.text.x = element_blank()) +
scale_y_continuous(expand = c(0, 0), limits = c(0,3000)) +
ylab('Number of Customers') + xlab('Segments') +
ggtitle('Number Customers in Q1 by Segments') +theme(plot.title =
element_text(hjust = 0.5)) +
geom_line(aes(x= Segments, y=count) ,stat="identity",
group = 1, size = 1.5, colour = "darkred", alpha = 0.9, show.legend =
TRUE) +
geom_line(aes(x= Segments, y=bond_count)
,stat="identity", group = 1, size = 1.5, colour = "blue", alpha =
0.9) +
geom_line(aes(x= Segments, y=variable_count)
,stat="identity", group = 1, size = 1.5, colour = "darkgreen",
alpha = 0.9) +
geom_line(aes(x= Segments, y=children_count)
,stat="identity", group = 1, size = 1.5, colour = "orange", alpha
= 0.9) +
guides(fill=guide_legend(title="Segments")) +
scale_color_discrete(name = "Prod", labels = c("count", "bond_count", "variable_count", "children_count)))
I am fairly new to R so if any further information is required or if this question could be better represented then please let me know.
Any help is greatly appreciated.
Alright, you need to remove a little bit of your stuff. I used the mtcars dataset, since you did not provide yours. I tried to keep your variable names and reduced the plot to necessary parts. The code is as follows:
first_q <- mtcars
first_q$Segments <- mtcars$mpg
first_q$val <- seq(1,nrow(mtcars))
first_q$number_of_new_costumers <- mtcars$hp
first_q$type <- "Line"
ggplot(first_q) +
geom_bar(aes(x= Segments, y= number_of_new_costumers, fill = "Bar"), stat =
"identity") + theme(axis.text.x = element_blank()) +
scale_y_continuous(expand = c(0, 0), limits = c(0,3000)) +
geom_line(aes(x=Segments,y=val, linetype="Line"))+
geom_line(aes(x=Segments,y=disp, linetype="next line"))
The answer you linked already gave the answer, but i try to explain. You want to plot the legend by using different properties of your data. So if you want to use different lines, you can declare this in your aes. This is what get's shown in your legend. So i used two different geom_lines here. Since the aes is both linetype, both get shown at the legend linetype.
the plot:
You can adapt this easily to your use. Make sure you using known keywords for the aesthetic if you want to solve it this way. Also you can change the title names afterwards by using:
labs(fill = "costum name")
If you want to add colours and the same line types, you can do customizing by using scale_linetype_manual like follows (i did not use fill for the bars this time):
library(ggplot2)
first_q <- mtcars
first_q$Segments <- mtcars$mpg
first_q$val <- seq(1,nrow(mtcars))
first_q$number_of_new_costumers <- mtcars$hp
first_q$type <- "Line"
cols = c("red", "green")
ggplot(first_q) +
geom_bar(aes(x= Segments, y= number_of_new_costumers), stat =
"identity") + theme(axis.text.x = element_blank()) +
scale_y_continuous(expand = c(0, 0), limits = c(0,3000)) +
geom_line(aes(x=Segments,y=val, linetype="solid"), color = "red", alpha = 0.4)+
geom_line(aes(x=Segments,y=disp, linetype="second"), color ="green", alpha = 0.5)+
scale_linetype_manual(values = c("solid","solid"),
guide = guide_legend(override.aes = list(colour = cols)))

Resources