ggplot lwd overriding legend - r

I have a bit of a coding issue. I have a MWE below:
df <- data.frame(year=seq(1961,2013,1), group1=rnorm(53), group2=rnorm(53))
p <- ggplot(df, aes(x=year)) +
geom_line(aes(y=group1, linetype="group1")) +
geom_line(aes(y=group2, linetype="group2"))
p1 <- ggplot(df, aes(x=year)) +
geom_line(aes(y=group1, linetype="group1"), lwd=1.5) +
geom_line(aes(y=group2, linetype="group2"))
p produces a very standard looking graph with no issues:
However, when I try to change the linewidth in p1, of one of the geom_line, this distorts the legend as such:
The dotted aspect of the line remains the same but the lined segment is being affected by the lwd=1.5 from the first line.
Is there an error/shortcoming in my approach to this problem or a larger issue at play here?

If you want a nice legend with different linetypes and linewidths then you should convert your data to long format, map group on both linetype and lwd aestehtics and set the lwd manually using scale_size_manual.
library(ggplot2)
library(dplyr)
library(tidyr)
df <- data.frame(year=seq(1961,2013,1), group1=rnorm(53), group2=rnorm(53))
df %>%
pivot_longer(-year, names_to = "group") %>%
ggplot(aes(x=year)) +
geom_line(aes(y=value, linetype = group, lwd = group)) +
scale_size_manual(values = c(1.5, .5))
Created on 2020-05-27 by the reprex package (v0.3.0)

Related

r ggplot: multiple geoms and scales (which scale overides which geom?)

I intended to color lines in pink, and points in yellow. I don't want to use colour argument in respective geom(), I want to use scale to change colour.
p3 <- ggplot(dfcc,aes(x = yr, y = mean)) +
geom_line(aes(color = '')) +
geom_point(aes(color = ''))
p3 + scale_colour_manual(values =c('pink', 'yellow'))
This gives this plot, both lines and points are not in the right colours.
Hence, I have two questions
can I use "scale_colour_manual" to change the line and point colors in one go?
if having multiple geoms and multiple scales, how does the system know which scale applies to which geom?
Any help and explanation would be much appreciated!
Use package ggnewscale.
set.seed(2022)
df1 <- data.frame(x = 1:20, y = cumsum(rnorm(20, 2)))
library(ggplot2)
ggplot(df1, aes(x, y)) +
geom_line(color = "pink", linewidth = 2) +
ggnewscale::new_scale_color() +
geom_point(color = "yellow", size = 3) +
theme_classic()
Created on 2022-12-25 with reprex v2.0.2

How do I get my legend dots blue and red instead that both are red?

I am trying to get a red and a blue dot in my legend, this is not the data that I am using but a reproducible example,
The graph exits of two dataset, example is one of them and example1.
here is my code:
if (!require("pacman")) install.packages("pacman")
pacman::p_load_gh("trinker/wakefield")
example <- r_data_frame(
n = 100,
id,
iq,
age,
height
)
example1 <- r_data_frame(
n = 100,
id,
iq,
age,
height)
library(ggplot2)
color_names <- c("example", "example1")
color_values <- c("blue", "red")
names(color_values) <- color_names
ggplot() +
#These points need to be blue and in the legend as well.
geom_point(data=example, aes(x=ID, y=Height,
fill ="example"),
colour="darkblue", size=1) +
#These points need to be red and red in the legend
geom_point(data=example1, aes(x=ID, y=Height,
fill ="example1"), colour = "red"
, size=1) +
# plot configuration scales, theme, etc...
scale_colour_manual(values = color_values) +
scale_fill_manual(values = color_values) +
theme_bw()
The main issue here is that you are setting the colour using the color names for the points but also overwriting these settings with scale_colour_manual and scale_fill_manual.
As you are using geom_point() it is not necessary to change the fill unless you use a different point type.
I would suggest labelling the colours in aes() with the examples (not just fill). My solution removes all excess scales I can add these back in if you need them in your actual implementation (not the reprex as it is unneccessary here).
I have additionally modified the colour_values variable to contain the name and the colour in one line (rather than your implementation).
if (!require("pacman")) install.packages("pacman")
pacman::p_load_gh("trinker/wakefield")
example <- r_data_frame(
n = 100,
id,
iq,
age,
height
)
#> Warning: `tbl_df()` was deprecated in dplyr 1.0.0.
#> Please use `tibble::as_tibble()` instead.
example1 <- r_data_frame(
n = 100,
id,
iq,
age,
height)
library(ggplot2)
color_values <- c("example" = "darkblue", "example1" = "red")
ggplot() +
#These points need to be blue and in the legend as well.
geom_point(data=example, aes(x=ID, y=Height,color = "example"), size=1) +
#These points need to be red and red in the legend
geom_point(data=example1, aes(x=ID, y=Height,
color = "example1"), size=1) +
# plot configuration scales, theme, etc...
scale_colour_manual(name = "colour", values = color_values) +
theme_bw()
Created on 2021-04-07 by the reprex package (v2.0.0)
Taking Joel Kandiah's answer a step further (+1), I'd use a more natural way for ggplot2 to make use of their fantastic aesthetics - use a long format if your data frames contain the same variables. Just bind them together.
Avoids headaches and hard coding, and also reduces your code.
library(wakefield)
library(tidyverse)
example <- r_data_frame(n = 100, id, iq, age, height)
#> Warning: `tbl_df()` was deprecated in dplyr 1.0.0.
#> Please use `tibble::as_tibble()` instead.
example1 <- r_data_frame(n = 100, id, iq, age, height)
color_values <- c(example = "darkblue", example1 = "red")
bind_rows(mget(ls(pattern = "^example")), .id = "example") %>%
ggplot() +
geom_point(aes(x=ID, y=Height,color = example), size=1) +
scale_colour_manual(name = "colour", values = color_values) +
theme_bw()
Created on 2021-04-07 by the reprex package (v1.0.0)

Horizontal alignment of colour scales in patchwork

I'm using the package patchwork to combine multiple ggplot2 plots vertically. I'd like the scales for each plot to be directly above one another, regardless of the length of the scale name. At the moment, the scales are not aligned above one another.
I'm open to using ggpubr or facet_grid() if they would make it possible, but I've seen that facets doesn't allow multiple scales, and I haven't found any solution using ggpubr
library(ggplot2)
library(patchwork)
set.seed(0)
testdata <- data.frame(x=1:10, y=1:10, col=runif(10))
g1 <- ggplot(testdata, aes(x=x,y=y,col=col)) + geom_point() +
scale_color_gradient(name="Short")
g2 <- ggplot(testdata, aes(x=x,y=y,col=col)) + geom_point() +
scale_color_gradient(name="A rather longer name")
g1/g2
ggsave("testfile.tiff", units = "mm", device="tiff",
width=100, height=100, dpi = 100)
Ideal output:
With plot_layout you can "collect" the legends. This uses as default theme(legend.position = 'right'). You can add this after plot_layout with & theme(legend.position = 'right') and adjust the position if you want to change the location of the legends.
g1/g2 + plot_layout(guides = 'collect') # & theme(legend.position = 'right') <- adjust position here!
ggsave("testfile.tiff", units = "mm", device="tiff",
width=100, height=100, dpi = 100)
I'd also be curious to learn of a patchwork parameter than could fix this, but I don't think there is one (please correct me if I'm wrong). You may have noticed that Hadley's answer is more than 10 years old and people have been working on ggplot2 since then. The ggnewscale package solves the problem of having multiple scales per plot. Here is a facetted approach using multiple colourscales:
library(ggplot2)
library(ggnewscale)
set.seed(0)
testdata <- data.frame(x=1:10, y=1:10, col=runif(10))
ggplot(mapping = aes(x = x, y, y)) +
geom_point(data = transform(testdata,
facet = factor("Top", c("Top", "Bottom"))),
aes(colour = col)) +
scale_colour_continuous(name = "Short") +
new_scale_colour() +
geom_point(data = transform(testdata,
facet = factor("Bottom", c("Top", "Bottom"))),
aes(colour = col)) +
scale_colour_continuous(name = "A rather longer name") +
facet_wrap(~ facet, ncol = 1)

ggplot2 add colored shapes on top of colored lines and combine both into one legend

I have gotten the following graph in ggplot2, and it is almost exactly what I want. The one detail that I want to change is to put different shapes on the lines, just in case someone is colorblind and unable to distinguish whatever two colors I ultimately choose.
library(ggplot2)
color1 = "red"
color2 = "blue"
DF1.grp1 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(1,2,3,4,5,6),grp=rep("grp1",6))
DF1.grp2 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(2,3,4,4,5,9),grp=rep("grp2",6))
DF1 <- rbind(DF1.grp1,DF1.grp2)
ggplot(shape=DF1$grp) + #
geom_line(data=DF1,aes(x=X,y=Y,color=grp),size=1)+
geom_point(data=DF1,aes(x=X,y=Y,color=grp),size=3)+
xlab("x variable") +
ylab("y variable") +
scale_colour_manual(values=c(color1,color2)) +
labs(color="") +
geom_density(alpha = 0.5) + theme_bw()+theme(legend.position="bottom")
In the geom_point line, I have tried by including shape=grp, and that does give me different shapes on each line and in the right color. However, the legend gives the colors and shapes separately and puts the shapes in black.
library(ggplot2)
color1 = "red"
color2 = "blue"
DF1.grp1 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(1,2,3,4,5,6),grp=rep("grp1",6))
DF1.grp2 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(2,3,4,4,5,9),grp=rep("grp2",6))
DF1 <- rbind(DF1.grp1,DF1.grp2)
ggplot(shape=DF1$grp) + #
geom_line(data=DF1,aes(x=X,y=Y,color=grp),size=1)+
geom_point(data=DF1,aes(x=X,y=Y,color=grp,shape=grp),size=3)+
xlab("x variable") +
ylab("y variable") +
scale_colour_manual(values=c(color1,color2)) +
labs(color="") +
geom_density(alpha = 0.5) + theme_bw()+theme(legend.position="bottom")
The ideal plot for me would be to change the first image by just putting a blue triangle on the blue part of the legend and a red circle on the red part of the legend, replacing the circles that are there.
What would be the appropriate change to my first block of code to accomplish this?
For legends to be combined, they must have the same title. In your second example, set both titles to "" with labs(color="", shape="") and you will get a single legend with over-plotted symbol and line.
Here is a simple solution
library(ggplot2)
DF1.grp1 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(1,2,3,4,5,6),grp=rep("grp1",6))
DF1.grp2 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(2,3,4,4,5,9),grp=rep("grp2",6))
DF1 <- rbind(DF1.grp1,DF1.grp2)
ggplot(DF1, aes(X, Y, color = grp, shape = grp)) +
geom_point() +
geom_line() +
scale_colour_manual(values=c('red','blue'))+
scale_shape_manual(values = c(24,25))+
theme_bw()+theme(legend.position="bottom")
Created on 2020-02-07 by the reprex package (v0.3.0)
To your extended question
The shapes I have used are already ones which can be filled. If you put out the aesthetics into the individual geoms you have the possibility to change them individually. That is what I did in the following code and I have used fill instead of color.
The legend of a specific geom can be switched off by guide = 'none' in the scale_.
library(ggplot2)
DF1.grp1 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(1,2,3,4,5,6),grp=rep("grp1",6))
DF1.grp2 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(2,3,4,4,5,9),grp=rep("grp2",6))
DF1 <- rbind(DF1.grp1,DF1.grp2)
ggplot(DF1, aes(X, Y)) +
geom_point(aes(fill = grp, shape = grp)) +
geom_line(aes(color = grp)) +
scale_colour_manual(values=c('red','blue'), guide = 'none')+
scale_shape_manual(values = c(24,25))+
theme_bw()+theme(legend.position="bottom")
Created on 2020-02-08 by the reprex package (v0.3.0)
To your further extended question
library(ggplot2)
DF1.grp1 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(1,2,3,4,5,6),grp=rep("grp1",6))
DF1.grp2 <- data.frame(X=c(5,10,15,20,25,30),
Y=c(2,3,4,4,5,9),grp=rep("grp2",6))
DF1 <- rbind(DF1.grp1,DF1.grp2)
ggplot(DF1, aes(X, Y)) +
geom_point(aes(fill = grp, shape = grp), stroke =0, size =5) +
geom_line(aes(color = grp)) +
scale_colour_manual(values=c('red','blue'), guide = 'none')+
scale_fill_manual(values=c('red','blue'))+
scale_shape_manual(values = c(24,25))+
theme_bw()+
theme(legend.position="bottom")
Created on 2020-02-08 by the reprex package (v0.3.0)
I have added scale_fill_ and have set the stroke of geom_point to zero. I have also made the points larger, so you can see better.

Adding Space between my geom_histogram bars-not barplot

Let's say I want to make a histogram
So I use the following code
v100<-c(runif(100))
v100
library(ggplot2)
private_plot<-ggplot()+aes(v100)+geom_histogram(binwidth = (0.1),boundary=0
)+scale_x_continuous(breaks=seq(0,1,0.1), lim=c(0,1))
private_plot
How do I separate my columns so that the whole thing is more pleasing to the eye?
I tried this but it somehow doesn't work:
Adding space between bars in ggplot2
Thanks
You could set the line color of the histogram bars with the col parameter, and the filling color with the fill parameter. This is not really adding space between the bars, but it makes them visually distinct.
library(ggplot2)
set.seed(9876)
v100<-c(runif(100))
### use "col="grey" to set the line color
ggplot() +
aes(v100) +
geom_histogram(binwidth = 0.1, fill="black", col="grey") +
scale_x_continuous(breaks = seq(0,1,0.1), lim = c(0,1))
Yielding this graph:
Please let me know whether this is what you want.
If you want to increase the space for e.g. to indicate that values are discrete, one thing to do is to plot your histogram as a bar plot. In that case, you have to summarize the data yourself, and use geom_col() instead of geom_histogram(). If you want to increase the space further, you can use the width parameter.
library(tidyverse)
lambda <- 1:6
pois_bar <-
map(lambda, ~rpois(1e5, .x)) %>%
set_names(lambda) %>%
as_tibble() %>%
gather(lambda, value, convert = TRUE) %>%
count(lambda, value)
pois_bar %>%
ggplot() +
aes(x = value, y = n) +
geom_col(width = .5) +
facet_wrap(~lambda, scales = "free", labeller = "label_both")
Just use color and fill options to distinguish between the body and border of bins:
library(ggplot2)
set.seed(1234)
df <- data.frame(sex=factor(rep(c("F", "M"), each=200)),
weight=round(c(rnorm(200, mean=55, sd=5), rnorm(200, mean=65, sd=5))))
ggplot(df, aes(x=weight)) +
geom_histogram(color="black", fill="white")
In cases where you are creating a "histogram" over a range of integers, you could use:
ggplot(data) + geom_bar(aes(x = value, y = ..count..))
I just came across this issue. My solution was to add vertical lines at the points separating my bins. I use "theme_classic" and have a white background. I set my bins to break at 10, 20, 30, etc. So I just added 9 vertical lines with:
geom_vline(xintercept=10, linetype="solid", color = "white", size=2)+
geom_vline(xintercept=20, linetype="solid", color = "white", size=2)+
etc
A silly hack, but it works.

Resources