Adding a dotted line between two categorical points in R - r

I'm new to R and I've scripted the interaction plot below, for which I want two dotted lines connecting both "coral" and both "darkgoldenrod2" points respectively:
df <- tibble::tribble(~Proportion, ~Lower,~Upper, ~Area,~Time,
invlogit(-0.033886), invlogit(-0.517223067), invlogit(0.449451067), "SNP", "Day",
(invlogit(-0.9231219)+invlogit(-0.3786)), 0.5727 ,0.8087, "SNP", "Night",
invlogit(-0.9231219), invlogit(-1.406458967), invlogit(-0.439784833),"LGCA", "Day",
invlogit(-0.1604356), invlogit(-0.643772667) ,invlogit(0.322901467), "LGCA","Night")
df
dfnew <- df %>%
mutate(ymin = Proportion - Lower,
ymax = Proportion + Upper)
p <- ggplot(data = dfnew, aes(x = Time, y = Proportion, color=Area)) +
geom_point(size = 6, stroke = 0, shape = 16,
position = position_dodge(width = 0.1))+
geom_errorbar(aes(y=Proportion, ymin = Lower, ymax = Upper),width=0.1,size=1,
position = position_dodge(width = 0.1)) +
theme(axis.text=element_text(size=15),
axis.title=element_text(size=20)) +
scale_color_manual(values = c("SNP" = "coral",
"LGCA" = "darkgoldenrod2"))
p
Reading other posts here on SO, I've used the command line: +geom_line(aes(group = 1),size=2)
This however isn't producing the desired plot as you can see below:
Any help with this is truly appreciated!

You should add group=Area to your ggplot mapping and then you just need to call geom_line. You also don't need y=Position in geom_errorbar.
p <- ggplot(data = dfnew, aes(x = Time, y = Proportion, color=Area, group=Area)) +
geom_point(size = 6, stroke = 0, shape = 16,
position = position_dodge(width = 0.1))+
geom_errorbar(aes(ymin = Lower, ymax = Upper), width=0.1, size=1,
position = position_dodge(width = 0.1)) +
theme(axis.text=element_text(size=15),
axis.title=element_text(size=20)) +
scale_color_manual(values = c("SNP" = "coral",
"LGCA" = "darkgoldenrod2")) +
geom_line(size=2)
p

Related

Reordering Groups in Raincloud Plot [duplicate]

This question already has answers here:
Change stacked bar order when aesthetic fill is based on the interaction of two factors
(1 answer)
ggplot legends - change labels, order and title
(1 answer)
Closed 2 years ago.
Currently, I have a plot that looks like this:
library(ggplot2)
df <- ToothGrowth
df %>%
ggplot(aes(x = supp, y = len, fill = supp)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = supp),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "ToothGrowth Length by Supplement",
y = "Length") +
theme_classic() +
raincloud_theme
I'd like to change the order so that OJ appears above VC. I've tried adding scale_x_discrete before coord_flip(), but that seems to mess up my plot as this is a raincloud plot -- I'd have to move not only the violin plot, but also the points and the box plot. I've also tried adding rev(), which also messed up my plot. What is the best way to reorder this?
EDIT
Thank you for the comment! How do I change the orders in an interaction plot?
df %>%
mutate(Supplement = ifelse(supp == "VC",
"VC",
"OJ"),
Dose = ifelse(dose == "0.5",
"0.5",
"1.0"),
Interaction = factor(str_replace(interaction(Supplement, Dose),
'\\.', '\n'),
ordered=TRUE)) %>%
ggplot(aes(x = Interaction, y = len, fill = Interaction)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = Dose),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "Effect of Supplement and Dose on Length",
y = "Growth Length") +
scale_fill_discrete(guide = guide_legend(override.aes = list(shape = c(".", ".")))) +
scale_shape_discrete(guide = guide_legend(override.aes = list(size = 3))) +
theme_classic() +
raincloud_theme
ggplot2 will interpret the supp factor and the order in the plot correspond to the levels of the factor.
You will need to change the levels of the supp factor.
df <- ToothGrowth
df$supp
df$supp <- relevel(ToothGrowth$supp,ref = "VC")
df$supp
df %>%
ggplot(aes(x = supp, y = len, fill = supp)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = supp),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "ToothGrowth Length by Supplement",
y = "Length") +
theme_classic() +
raincloud_theme

Increase the margin of every second x-axis tick ggplot2

I'm looking for a way to move every second x-axis tick downwards and have the tick line go down with it.
I can change the general margin and tick length for all ticks with:
#MWE
library(ggplot2)
ggplot(cars, aes(dist, speed))+
geom_point()+
theme(
axis.ticks.length.x = unit(15, "pt")
)
But, I would like the x-axis ticks 0, 50, and 100 (i.e., every second tick) to be without the added top margin.
A generalized answer is preferred as my x-axis is categorical and not numerical (and contains 430 ticks, so nothing I can set by hand).
Any ideas?
Edit:
Output should be:
Edit2:
A more intricate example would be:
#MWE
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge')+
theme(
axis.ticks.length.x = unit(15, "pt")
)
Edit -- added categorical approach at bottom.
Here's a hack. Hope there's a better way!
ticks <- data.frame(
x = 25*0:5,
y = rep(c(-0.2, -2), 3)
)
ggplot(cars, aes(dist, speed))+
geom_point()+
geom_rect(fill = "white", xmin = -Inf, xmax = Inf,
ymin = 0, ymax = -5) +
geom_segment(data = ticks,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks,
aes(x = x, y = y, label = x), vjust = 1.5) +
theme(axis.ticks.x = element_blank()) +
scale_x_continuous(breaks = 25*0:5, labels = NULL, name = "") +
coord_cartesian(clip = "off")
Here's a similar approach used with a categorical x.
cats <- sort(as.character(unique(diamonds$cut)))
ticks <- data.frame(x = cats)
ticks$y = ifelse(seq_along(cats) %% 2, -500, -2000)
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge') +
annotate("rect", fill = "white",
xmin = 0.4, xmax = length(cats) + 0.6,
ymin = 0, ymax = -3000) +
geom_segment(data = ticks, inherit.aes = F,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks, inherit.aes = F,
aes(x = x, y = y, label = x), vjust = 1.5) +
scale_x_discrete(labels = NULL, name = "cut") +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.05))) +
theme(axis.ticks.x = element_blank()) +
coord_cartesian(clip = "off")

how to put mean lines in ggplot?

I am try to do a plot whith means lines by group (in ggplot), and i have my code like this
ggplot(gama, aes(x = distancia, y= glipidoscmtejido, colour= estado)) +
geom_point(position=position_dodge(.5), alpha= 1, size=3) +
geom_crossbar(data=gama,aes(x=distancia,ymin=mean(glipidoscmtejido),
ymax=mean(glipidoscmtejido),y=mean(glipidoscmtejido),colour=estado), width = 0.5)
and I get this
but i need the mean line by distancia and by estado. how can i make it?
thanks.
How about this using stat_summary to plot the means per estado per distancia:
# Generate some sample data
set.seed(2017);
df <- cbind.data.frame(
x = rnorm(100),
estado = sample(c("sana", "lesionada"), 100, replace = T),
distancia = sample(c("0-1", "2.5-3.5", "5.6"), 100, replace = T));
require(ggplot2);
ggplot(df, aes(x = distancia, y = x, colour = estado)) +
geom_point(position = position_dodge(width = 0.3)) +
stat_summary(
fun.y = mean,
geom = "errorbar",
aes(ymax = ..y.., ymin = ..y..),
position = position_dodge(width = 0.3),
width = 0.25);

customize two legends inside one graph in ggplot2

I wanted to comment on the following doubt.
Using this code:
Plot<-data.frame(Age=c(0,0,0,0,0),Density=c(0,0,0,0,0),Sensitivity=c(0,0,0,0,0),inf=c(0,0,0,0,0),sup=c(0,0,0,0,0),tde=c(0,0,0,0,0))
Plot[1,]<-c(1,1,0.857,0.793,0.904,0.00209834)
Plot[2,]<-c(1,2,0.771 ,0.74,0.799,0.00348286)
Plot[3,]<-c(1,3,0.763 ,0.717,0.804,0.00577784)
Plot[4,]<-c(1,4,0.724 ,0.653,0.785,0.00504161)
Plot[5,]<-c(2,1,0.906,0.866,0.934,0.00365742)
Plot[6,]<-c(2,2,0.785 ,0.754,0.813,0.00440399)
Plot[7,]<-c(2,3,0.660,0.593,0.722,0.00542849)
Plot[8,]<-c(2,4,0.544,0.425,0.658,0.00433052)
names(Plot)<-c("Age","Mammographyc density","Sensitivity","inf","sup","tde")
Plot$Age<-c("50-59","50-59","50-59","50-59","60-69","60-69","60-69","60-69")
Plot$Density<-c("Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense","Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense")
levels(Plot$Age)<-c("50-59","60-69")
levels(Plot$Density)<-c("Almost entirely fat","Scattered fibroglandular density","Heterogeneously dense","Extremely dense")
pd <- position_dodge(0.2) #
Plot$Density <- reorder(Plot$Density, 1-Plot$Sensitivity)
ggplot(Plot, aes(x = Density, y = 100*Sensitivity, colour=Age)) +
geom_errorbar(aes(ymin = 100*inf, ymax = 100*sup), width = .1, position = pd) +
geom_line(position = pd, aes(group = Age), linetype = c("dashed")) +
geom_point(position = pd, size = 4)+
scale_y_continuous(expand = c(0, 0),name = 'Sensitivity (%)',sec.axis = sec_axis(~./5, name = 'Breast cancer detection rate (per 1000 mammograms)', breaks = c(0,5,10,15,20),
labels = c('0‰',"5‰", '10‰', '15‰', '20‰')), limits = c(0,100)) +
geom_line(position = pd, aes(x = Density, y = tde * 5000, colour = Age, group = Age), linetype = c("dashed"), data = Plot) +
geom_point(shape=18,aes(x = Density, y = tde * 5000, colour = Age, group = Age), position = pd, size = 4) +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
theme(legend.position="bottom") + guides(colour = guide_legend(), size = guide_legend(),
shape = guide_legend())
I have made the following graph,
in which the axis on the left is the scale of the circles and the axis on the right is the scale of the diamonds. The fact is that I would like to have a legend approximately like this:
But it is impossible for me, I have tried suggestions of other threads like scale_shape and different commands in guides but I have not got success. I just want to make clear the difference in what shape and color represent.
Would someone know how to help me?
Best regards,
What you should do is a panel plot to avoid the confusion of double axes:
library(dplyr)
library(tidyr)
Plot %>%
gather(measure, Result, Sensitivity, tde) %>%
ggplot(aes(x = Density, y = Result, colour=Age)) +
geom_errorbar(aes(ymin = inf, ymax = sup), width = .1, position = pd,
data = . %>% filter(measure == "Sensitivity")) +
geom_line(aes(group = Age), position = pd, linetype = "dashed") +
geom_point(position = pd, size = 4)+
# scale_y_continuous(expand = c(0, 0), limits = c(0, 1)) +
scale_y_continuous(labels = scales::percent) +
facet_wrap(~measure, ncol = 1, scales = "free_y") +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
theme(legend.position="bottom")
But to do what you asked, you problem is that you have only 1 non-positional aesthetic mapped so you cannot get more than one legend. To force a second legend, you need to add a second mapping. It can be a dummy mapping that has no effect, as below we map alpha but then manually scale both levels to 100%. This solution is not advisable because, as you have done in your example of a desired legend, it is easy to mix up the mappings and have your viz tell a lie by mislabeling which points are sensitivity and which are detection rate.
ggplot(Plot, aes(x = Density, y = 100*Sensitivity, colour=Age, alpha = Age)) +
geom_errorbar(aes(ymin = 100*inf, ymax = 100*sup), width = .1, position = pd) +
geom_line(position = pd, aes(group = Age), linetype = c("dashed")) +
geom_point(position = pd, size = 4)+
scale_y_continuous(expand = c(0, 0),name = 'Sensitivity (%)',sec.axis = sec_axis(~./5, name = 'Breast cancer detection rate (per 1000 mammograms)', breaks = c(0,5,10,15,20),
labels = c('0‰',"5‰", '10‰', '15‰', '20‰')), limits = c(0,100)) +
geom_line(position = pd, aes(x = Density, y = tde * 5000, colour = Age, group = Age), linetype = c("dashed"), data = Plot) +
geom_point(shape=18,aes(x = Density, y = tde * 5000, colour = Age, group = Age), position = pd, size = 4) +
theme_light() +
scale_color_manual(name="Age (years)",values = c("50-59"= "grey55", "60-69" = "grey15")) +
scale_alpha_manual(values = c(1, 1)) +
guides(alpha = guide_legend("Sensitivity"),
color = guide_legend("Detection Rate", override.aes = list(shape = 18))) +
theme(legend.position="bottom")

stacked bar *bringing labels to the graph *

I'm plotting a stacked bar graph and use geom_text to insert the value and name of each stack. The problem is some stacks are very small/narrow, so that the text of two stacks overlap each other and hence is not very readable. How can I modify the code to solve this issue.
Type<-c("ddddddddddd","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd","eeeeeeeeeeeeee","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd",
"eeeeeeeeeeeeee","mmmmmmmmmmmmmmmmmmm","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","eeeeeeeeeeeeee")
Category<-c("mmmmm","mmmmm","gggggggggggggggggg","ffffffffffff","ffffffffffff","ffffffffffff","sanddddddddd","sanddddddddd","yyyyyyyyyyy",
"yyyyyyyyyyy","yyyyyyyyyyy","sssssssssssssss","sssssssssssssss","sssssssssssssss","ttttttttttttt")
Frequency<-c(4,1,30,7,127,11,1,1,6,9,1,200,3,4,5)
Data <- data.frame(Type, Category, Frequency)
p <- ggplot(Data, aes(x = Type, y = Frequency)) +
geom_bar(aes(fill = Category), stat="identity", show.legend = FALSE) +
geom_text(aes(label = Frequency), size = 3) +
geom_text(aes(label = Category), size = 3)
Considering your data, a facetted plot might be a better approach:
# summarise your data
library(dplyr)
d1 <- Data %>%
mutate_each(funs(substr(.,1,2)),Type,Category) %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq)) # create a label by pasting the 'Category' and the 'Freq' variables together
# plot
ggplot(d1, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(label = lbl), angle = 90, size = 5, hjust = -0.1, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14)
which gives:
In the above plot I shortened the labels on purpose. If you don't want to do that, you could consider this:
d2 <- Data %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq))
ggplot(d2, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(y = 5, label = lbl), alpha = 0.6, angle = 90, size = 5, hjust = 0, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
which gives:

Resources