How to supress/combine the legend for two geoms in R - r

Im making a scatterplot which shows a value plotted against the date since symptom onset. These patients are categorised based on disease severity, and i wanted to show how the values change over time in each severity category. I have coloured the dots based on severity score, but i prefer to use shape =21 so i can have a border. I also draw a line to see the trend, and i want that coloured in the same way, however, this has added another legend and it looks complicated. This issue doesnt happen if use a different shape that isnt filled, because scale_colour_manual can be used for both the lines and the dots, but i dont think it looks as nice. Any idea how i can fix this?
IC50SymObySS <- ggplot(data = isaric) +
geom_point(mapping = aes(x = Days_since_onset, y = log2IC50, fill = Severity_score), size = 2, colour = "black", shape = 21)+
geom_smooth(mapping = aes(x = Days_since_onset, y = log2IC50, colour = Severity_score), se = FALSE)+
scale_fill_manual(breaks=c("1","2","3","4","5"),
values=c("1" = "lightblue1","2" = "lightblue3","3" = "lightblue4","4" = "lightcoral","5" = "firebrick2"),
labels=c("1","2","3","4","5"),
name = "Severity Score")+
scale_colour_manual(values=c("1" = "lightblue1","2" = "lightblue3","3" = "lightblue4","4" = "lightcoral","5" = "firebrick2"))+
theme_minimal()+
JTheme+
ylab("Serum Log2 IC50")+
xlab("Days Since Symptom Onset")+
guides(colour = guide_legend(title.position = "top", title.hjust = 0.5))
IC50SymObySS

As per this answer, you need to use identical name and labels values for both fill and colour scale.
library(ggplot2)
library(dplyr)
isaric <- transmute(iris,
Days_since_onset = (Sepal.Length - 4)^3,
log2IC50 = Sepal.Width * 3,
Severity_score = cut(Petal.Length, breaks = quantile(Petal.Length, prob = 0:5 / 5), labels = 1:5))
ggplot(data = isaric) +
geom_smooth(mapping = aes(x = Days_since_onset, y = log2IC50, colour = Severity_score), se = FALSE)+
geom_point(mapping = aes(x = Days_since_onset, y = log2IC50, fill = Severity_score), size = 2, colour = "black", shape = 21)+
scale_colour_manual(
name = "Severity Score",
values=c("1" = "lightblue1","2" = "lightblue3","3" = "lightblue4","4" = "lightcoral","5" = "firebrick2"),
labels=c("1","2","3","4","5"))+
scale_fill_manual(
name = "Severity Score",
breaks=c("1","2","3","4","5"),
values=c("1" = "lightblue1","2" = "lightblue3","3" = "lightblue4","4" = "lightcoral","5" = "firebrick2"),
labels=c("1","2","3","4","5"))+
theme_minimal()+
ylab("Serum Log2 IC50")+
xlab("Days Since Symptom Onset")+
guides(colour = guide_legend(title.position = "top", title.hjust = 0.5))

Related

ggplot line graph with multiple lines by groups

So my data set is to analyse the effect of predation on salmon selected for growth.
Basically I have a start and ending point, 3 different strains and 2 environments (with and without predator). Does anyone knows the best way to do this?
I was thinking of something like this drawing enter image description here
I have been trying but I can only come up either with the separated time points, in which I would have to do 2 graphs, or with and average of both.
The data set is available here.
https://dryad-assetstore-merritt-west.s3.us-west-2.amazonaws.com/ark%3A/13030/m55q9wc8%7C1%7Cproducer/Salmon_Size_Data.txt?response-content-type=text%2Fplain&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEgaCXVzLXdlc3QtMiJIMEYCIQD%2FrxcoA78DX5N86nFNROptzvNB%2Bo82OubnJESH4AQF5wIhALF9AuZuZMgV6Ik7EBd9Pje07bsANAT%2BB5R%2BBh24rjJYKswECEEQABoMNDUxODI2OTE0MTU3Igxdeqv51kC67yp3Gr0qqQTdXAWYho6s5Xrf3UFxy0BvZ%2Fm1OUwz%2BSvZS2jSWam%2BcFwyEk2gVOvcZis5PLf%2BAUk43X0wn4S5%2FpXkunbyWiWWlwoV1d%2BOlt8M%2FiyuGrg%2Bzydv2d%2FT6l5zdQ2dxa5ISKLmLHvpl5CzfCB2aChuWTwruTMsssEPZQUyxZy2ihgpbPpjV%2FM5LOfOxcunwJXrMBL4BUk6PCqZQYMpe5NiIOvv7mO58trcPKL5hQ0W4HECtiPtoslFn5Gv5v6KWG4A9VDAfgZwc0TxVmqzzbd6xnb57i6bbfgOyX7PkwFXTuNswa1VJL8Zai08%2BmlmvCXYZyhENYuVTk7K9g3N2aUWlP0nSSMyUKoJPgW45fldrgMMfl7uAH5Budh8EfoFUMQMStuse9gR0qiCHWMbohDao0YcOImNYmoCO5znwTbuDerPsGEzQbrK9YFPKbTpFtm%2Fqc5pAPWw4wWPWcj0PmG2FvNphT3IV8M8jL5Nc%2BNkCM2SbKf82XY2sBar43Xn%2BhPFlsaU%2FkeaFINCSRf29FY6mFNgoKWHfcGbiFoS6gegiFc4iyK7zMjReIFjJ9%2Bsur6HpwWVLG%2Br2JZ8OZjjwg1Uy6tWZ5LxUk%2Fm00fhjIuJyYe6vb%2BL98gKyzL9YXEOEDoEbQ6C%2FCGPsYzKs2mEJSic%2FRxGHIt7%2B4wI7ilcdVnpmoBxiQDYIjD5EYF1UYX2RzXCAb%2Ba4Feb5Y%2FnLv5Wd9lZH67KnrCl%2F%2FP80n%2FUMLmNqJsGOqgBUH4Uc6%2BmRqbTXPRp0NF%2BL6Ieni3hFJbOhhF33xQvrX0R75mGpFCUGSh15B1V%2F%2BQyoPJSJ6KpjBbmhvByzaUNzp9Tu9IRVbrAYaQjU1msReCU7%2B8T6NQnphj%2FizbzJsYEAPxVesRFiGfoH%2FcqjfDSIXDWiJU4pzwyaITjlPe2qawZ06sxXaP%2BxkrgINQ93FHpFTh6DX7kcYUG0dXkwGsDVXYln3pXlXTG&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20221108T081734Z&X-Amz-SignedHeaders=host&X-Amz-Expires=14400&X-Amz-Credential=ASIAWSMX3SNW4W5FR7N3%2F20221108%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=8ab2326025376f5c9b96f2b4e31c51ba5fe15a96743794ac8d6cc48a75efe7e0
I am using this code:
ggplot(data = aqua, mapping = aes(x = Env, y = mass, group = Strain, color = Strain))+
geom_line(stat = "summary", fun = mean, size = 1, linetype = 2)+
geom_point(stat = "summary", fun = mean, size = 3)+
stat_summary(geom = "errorbar", fun.data = mean_se, width = 0.1, size = .5)+
labs(x = "Environment", y = "Body mass (g)")+
theme(axis.title.x.bottom = element_text(size = 20), axis.title.y.left = element_text(size = 20))
Since you have not given any data, I made up an example data for you. Next time please include a reproducible example data with your code.
example_data <- tibble(
strain = rep(c("A", "B", "C"), each = 3),
env = rep(c("x", "y", "z"), times = 3),
mass = c(1,4,7,2,6,9,3,8,10)
)
ggplot(example_data, mapping = aes(x = env, y = mass, group = strain, color = strain))+
geom_line(size = 1, linetype = 2)+
geom_point(size = 3) +
labs(x = "Environment", y = "Body mass (g)")+
theme(axis.title.x.bottom = element_text(size = 20), axis.title.y.left = element_text(size = 20))

How to have a factor outside the axis for an arrow in ggplot

I want to make an annotation with an arrow that goes outside a plot in ggplot. Using geom_curve changes the order of the factor, and I do not understand why.
Here is the example: let's consider the following plot:
df <- data.frame(ID = factor(c("A","B","C"),level = c("AA","B","C","A")),
y = 1:3)
ggplot(df,aes(ID,y,color = ID))+
geom_point()+
coord_flip(clip = "off")+
scale_x_discrete(breaks = c("B","C","A"))
I want to keep the order of the vertical axis (B,C,A), and have an arrow pointing at the first point but from above the plot. I thus want to ass a factor before A that goes outside the plot:
ggplot(df,aes(ID,y,color = ID))+
geom_point()+
geom_curve(data = data.frame(ID = factor("AA",level = c("AA","B","C","A")),
ID_end = "A",
y = 2,y_end = 1),
aes(x = ID,xend = ID_end,
y = y ,yend = y_end),
curvature = -.1,
arrow =arrow(length = unit(2, "mm"),type = "closed"),
color = "grey20" ,size = .2)+
coord_flip(clip = "off")+
scale_x_discrete(breaks = c("B","C","A"))
Here the vertical axis has the factors reordered, although I specified the same order in geom_curve. My arrow lies in the middle instead of being on the top/outside the plot.
How can I solve this problem?
Does this help you? The arrow is not really "outside" the plot, but the order on the axis is maintained the way you want
df <- data.frame(
ID = factor(c(1,2,3), labels=c("B","C","A")),
y =c(2,3,1)
)
curvedata = data.frame(
ID = 4,
ID_end = 3,
y = 2,y_end = 1)
ggplot(df,aes(ID,y,color = ID))+
geom_point()+
geom_curve(data=curvedata,
aes(x = ID,xend = ID_end,
y = y ,yend = y_end),
curvature = -.1,
arrow =arrow(length = unit(2, "mm"),type = "closed"),
color = "grey20" ,size = .2)+
coord_flip(clip = "off")
If you want to manually add a few things to a graph, use annotate(geom = "XXX") rather than geom_XXX with a custom data =.
Also, factor levels get converted to integers. It is easier to specify the integer value, rather than forcing the factor levels.
ggplot(df,aes(ID,y,color = ID))+
geom_point()+
annotate(geom = "curve", x = -1L, xend = 1, y = 2, yend = 1,
curvature = -.1,
arrow =arrow(length = unit(2, "mm"),type = "closed"),
color = "grey20" ,size = .2) +
coord_flip(clip = "off")+
scale_x_discrete(breaks = c("B","C","A"))

Break legend in two columns while keeping shape override

I have a ggplot problem. Here is the example data:
df <- data.frame(x = rep(1:5,5),
type2 = c(rep(letters[1:2],each = 10),rep("c",5)),
type1 = rep(LETTERS[1:5],each = 5),
value = unlist(lapply(-2:2,function(a){rnorm(5,mean = a, sd = 1)})))
library(ggplot2)
plotcolor <- c( "#99d8c9","#2ca25f","#cbc9e2","#9e9ac8","#e34a33")
p <- ggplot(df,aes(x,value,color = type1,fill = type1,shape = type2))+
geom_point(size = 5)+
theme_light()+
labs(title = "",
color = "Method",
fill = "Method",
shape = "")+
geom_hline(yintercept = 0)+
guides(colour = guide_legend(override.aes = list(shape = c(21,21,24,24,22),
linetype = c(rep("blank",5)),
fill = plotcolor,
color = plotcolor)))+
scale_shape(guide = FALSE)+
scale_colour_manual(values = plotcolor)
p
which gives
Now I want to split the legend into two columns, for space reasons. I tried
p + guides(color=guide_legend(ncol=2))
but it remove the override part of my legend, letting just points:
p + guides(color=guide_legend(ncol=2),
fill =guide_legend(ncol=2) ,
shape = guide_legend(ncol=2))
didn't work either. Does anyone have an idea on how to deal with this particular problem?
You can specify ncol within the existing guide_legend (do not use it multiple times):
guides(colour = guide_legend(override.aes = list(shape = c(24,24,22,22,21),
linetype = c(rep("blank",5)),
fill = plotcolor,
color = plotcolor),
ncol = 2))+

ggplot2's line legends appear "crossed-out"

I'm creating a ggplot with two lines, each from separate geoms. As an example:
df = data.frame(
x.v = seq(0, 1, 0.025),
y.v = runif(41)
)
straight.line = data.frame(
Inter = c(0),
Slope = c(1)
)
p = ggplot() +
geom_point(
mapping = aes(
x = x.v,
y = y.v
),
data = df,
colour = "blue"
) +
geom_smooth(
mapping = aes(
x = x.v,
y = y.v,
colour = "line of best fit"
),
data = df,
method = "lm",
show.legend = NA
) +
geom_abline(
mapping = aes(
intercept = Inter,
slope = Slope,
colour = "y = x"
),
data = straight.line,
show.legend = NA
) +
guides(
fill = "none",
linetype = "none",
shape = "none",
size = "none"
)
This gives the output:
As you can see, the legend has weird diagonal lines through it. An answer to a similar question says this can be fixed by using show.legend = NA. However, as you can see in the code above, I did this and it did not change the result.
Does anybody know what is adding the diagonal lines in the legend and how else I can fix it please? Thanks.
EDIT: A question of if this is a duplicate of this. This may be the answer but how do I apply this when the answer in the link uses fill, and I use colour, please?
If I try
+ guides(colour = guide_legend(override.aes = list(colour = NULL)))
I get the error
Error in check.length("col") : 'gpar' element 'col' must not be length 0
and if I try
+ guides(colour = guide_legend(override.aes = listfill = NULL)))
I get the error
Error in `$<-.data.frame`(`*tmp*`, "fill", value = character(0)) :
replacement has 0 rows, data has 1
The following works:
library(ggplot2)
ggplot() +
geom_point(mapping = aes(x = x.v, y = y.v),
data = df, colour = "blue") +
geom_smooth(mapping = aes(x = x.v, y = y.v, colour = "line of best fit"),
data = df, method = "lm", show.legend = NA) +
geom_abline(mapping = aes(intercept = Inter, slope = Slope, colour = "y = x"),
data = straight.line, show.legend = FALSE) +
guides(fill = "none", linetype = "none", shape = "none", size = "none")
The code can be made a little bit less repetitive and we can leave out some things (liek the guide-call):
ggplot(data = df, mapping = aes(x = x.v, y = y.v)) +
geom_point(colour = "blue") +
geom_smooth(aes(colour = "line of best fit"), method = "lm") +
geom_abline(mapping = aes(intercept = Inter, slope = Slope, colour = "y = x"),
data = straight.line, show.legend = FALSE)
Why do we need to use show.legend = FALSE here and not show.legend = NA?
From the documentation:
show.legend
logical. Should this layer be included in the legends? NA, the default, includes if any aesthetics are mapped. FALSE never includes, and TRUE always includes. It can also be a named logical vector to finely select the aesthetics to display
This means that is we use show.legend = NA for the geom_abline-call we use this layer in the legend. However, we don't want to use this layer and therefore need show.legend = FALSE. You can see that this does not influence, which colors are included in the legend, only the layer.
Data
set.seed(42) # For reproducibilty
df = data.frame(x.v = seq(0, 1, 0.025),
y.v = runif(41))
straight.line = data.frame(Inter = 0, Slope = 1)

Replace the mapping text in ggplotly() plot without breaking the plot

I am creating a stacked bar chart below using ggplot and I convert it to interactive using ggplotly(). As you can see in the screenshot below the pop up text when I hover over a bar shows as "Name" the correct "Name" of the relative bar-in that case- DCH. I tried to replace that with a name of my choice but then the whole chart breaks down. So basically I would like to know if I can use "Name" in the background in order to display the chart but display another Name instead. The same for all of the 5 bars.
The code chunk which is related with this is:
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
#DATA
Name<-c("DCH","DCH","DCH","DGI","DGI","DGI","LDP","LDP","LDP","RH","RH","RH","TC","TC","TC")
Class<-c("Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap","Class1","Class2","Overlap")
count<-c(2077,1642,460,1971,5708,566,2316,810,221,2124,3601,413,2160,1097,377)
FinalDF<-data.frame(Name, Class,count)
#PLOT
ggplotly(ggplot(data = FinalDF) +
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
annotate('text', size = 5, x = (5+1)/2, y = -0.1, label = c('A'), angle = 90) +
coord_flip() +
scale_fill_manual(values = c('lemonchiffon', 'palegreen3', 'deepskyblue2'),breaks=c("Class1", "Overlap", "Class2"), labels = c(paste("Unique to","DB"), "Overlap", "Unique to Comparison Dataset "),
guide = guide_legend(label.position = 'left', label.hjust = 0, label.vjust = 0.5)) )
The tooltip argument might be in the right direction.
library(sf)
library(plotly)
# Create the stacked bar plot using ggplot()
stackedBarPlot<- ggplot(data = FinalDF) +
geom_col(mapping = aes(x = Name, y = count, fill = Class), width = rep(0.9,5),
color = "black", position = position_fill(reverse = T)) +
geom_text(size = 4, position = position_fill(reverse = T, vjust = 0.50), color = "black",
mapping = aes(x = Name, y = count, group = Class, label = round(count))) +
annotate('text', size = 5, x = (5+1)/2, y = -0.1, label = c('A'), angle = 90) +
coord_flip() +
scale_fill_manual(values = c('lemonchiffon', 'palegreen3', 'deepskyblue2'),breaks=c("Class1", "Overlap", "Class2"), labels = c(paste("Unique to","DB"), "Overlap", "Unique to Comparison Dataset "),
guide = guide_legend(label.position = 'left', label.hjust = 0, label.vjust = 0.5))+
geom_sf(aes(fill=Class,text=paste(Name,"DB")))
stackedBarPlot%>%
ggplotly(tooltip = "text")

Resources