Change line type of border - r

I would like to change the line type of the panel border from solid line to dashed line in my graph. I tried to use panel.border and panel_border in theme, but R keep telling me it cannot find these two functions in theme.

I think this will be very difficult to do with theme options. Even when the panel spacing is 0, I'm pretty sure it's using element_rect to draw the panel borders. Getting the plot you want with theme modifications would require modifying 1 or 2 lines of each panel border with awareness of whether the facet is a left, right, or central facet.
To get around this we can use hline and vline instead. Hacky, but it works:
hline_df = expand.grid(visit = unique(df$visit), yint = c(-Inf, Inf))
vline_df = expand.grid(visit = unique(df$visit), xint = c(-Inf, Inf)) %>%
mutate(no_dash = !(
(xint == Inf & visit == tail(levels(visit), 1)) |
(xint == -Inf & visit == head(levels(visit), 1))
))
ggplot(df, aes(x=avisit, y=mean, group=Type, color=Type, shape=Type)) +
scale_y_continuous(breaks=seq(0,18,2), limits=c(0, 18)) +
geom_point(position=pd, cex=2) +
xlab("") +
ylab("Mean") +
scale_colour_manual(values=c("blue", "red")) +
scale_shape_manual(values=c("triangle", "circle")) +
coord_cartesian(ylim = c(0, 18)) +
facet_grid(.~factor(visit), scales = "free_x", space ="free_x",switch = "both") +
geom_hline(data = hline_df, aes(yintercept = yint)) +
geom_vline(data = vline_df, aes(xintercept = xint, linetype = no_dash), show.legend = FALSE) +
theme_bw() +
theme(axis.text.y = element_text(margin = margin(r = 0)),
panel.spacing = unit(0, "mm"),
strip.background = element_blank(),
legend.title=element_blank(),
strip.placement = "outside",
legend.background = element_rect(color="black", fill="white", size=0.5, linetype="solid"),
legend.direction = "horizontal",
panel.grid.minor = element_line(colour="white", linetype="dashed"),
panel.grid.major = element_line(colour = "white",linetype="dashed"),
panel.border = element_blank())

element_rect takes a linetype argument. It might draw the axis line on top of the border or vice versa, so you can modify axis.line too. This theme should give you what you want and will be a little more elegant:
ggplot() + theme(axis.line = element_line(linetype = 3), panel.border = element_rect(linetype =3)

Related

R ggplot 2 legend border issue

I know this is minor, but it's for a publication and will drive me crazy. The bottom of the P0688 box is like 1-2 pixels thinner than the rest. I don't want to make the borders thicker because then it doesn't match the rest of the bar chart.
plot<- ggplot(tukey_letters, aes(x = variable, y = value.x,
fill = L1)) +
theme(panel.background=element_rect(fill="#ffffff", color
="#000000"), panel.grid.major=element_blank(),
panel.grid.minor=element_blank()) +
geom_bar(stat = "identity", position=position_dodge(),color="black")+ scale_fill_manual(values=c("#FFFFFF", "#999999"))+ guides(fill=guide_legend(title="Genotype", title.position = "left")) +
geom_errorbar(aes(ymin=value.x-se, ymax=value.x+se), width=.1,size=.5,position=position_dodge(0.9), color="black")+
theme(
axis.title = element_text(size =12, face="bold"),
axis.text = element_text(angle=30, vjust=0.5,hjust=0.6,size=8,face="bold", color="#000000"),
axis.ticks = element_line(size = rel(1)),
axis.ticks.length = unit(0.3, "cm"),
legend.position = c(0.2, 0.9)
)+
labs(
x="Treatment",
y="ARI1"
)+
#facet_wrap(~L1)+ ## You can use face_wrap function only if you need it+
geom_text(data =tukey_letters,
aes(x=xpos, y=ymax+offset_asterisk,label=groups),
size = 4,position=position_dodge(0.9) , vjust=-0.5
)
Thanks in advance. Let me know if there is anything else needed to help solve this.
This is due to the filling behaviour of the legend keys. It's a known issue, see this GitHub thread https://github.com/tidyverse/ggplot2/issues/2844. There is also a fix suggested on this site, let me show this here.
library(tidyverse)
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.key = element_rect(color="white") +
legend.position = c(0.2, 0.7))
Enlarged, the legend will look now like this:
Now let's do the fix.
draw_key_polygon3 <- function(data, params, size) {
lwd <- min(data$size, min(size) / 4)
grid::rectGrob(
width = grid::unit(0.7, "npc"),
height = grid::unit(0.7, "npc"),
gp = grid::gpar(
col = data$colour,
fill = alpha(data$fill, data$alpha),
lty = data$linetype,
lwd = lwd * .pt,
linejoin = "mitre"
))
}
GeomBar$draw_key = draw_key_polygon3
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.key = element_rect(color="white", fill = 'white'),
legend.position = c(0.2, 0.7))
But what is actually going on here? Let's see!
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.position = c(0.2, 0.7),
legend.key = element_rect(color="black", fill = 'white'))
The legend has two borders! One for the legend glyph, the other for the key. You draw the border for the key with the call to theme, and the border around the glyph is created with your color argument in geom_bar
Created on 2020-04-04 by the reprex package (v0.3.0)

Unable to customize strip in facet_grid

I am trying to customize the strip in facet_grid function.
My graph currently looks like:
I successfully changed the background of strip to purple, however, I could not change the border color to black, even though I set the color to 'black' in the function.
Also, I want the space between text and the rectangle to be larger so that it will looks nicer. How should I achieve this?
My codes looks like:
plot.density <- ggplot(df_densityWindow, aes(x = idx, y = density, color = factor(location))) +
geom_bar(stat = 'identity', fill = 'white') +
facet_grid(marker ~ case, scales = 'free') +
theme(strip.background = element_rect(colour="red", fill="#CCCCFF")) +
scale_color_manual(name = 'Regions',values = c("#F26969", "#02f527",'#F2F2C6')) +
background_grid(major = 'y', minor = "none") + # add thin horizontal lines
xlab('Index') +
ylab(expression(paste('Density/', mm^2, ))) +
theme(axis.title = element_text(size = 28)) +
theme(axis.text = element_text(size = 26)) +
theme(legend.text = element_text(size = 16)) +
theme(legend.title = element_text(size = 18)) +
panel_border() # and a border around each panel
plot(plot.density)
If necessary, the data could be downloaded here:
data
Thank you!
Your colour specification for strips works without error for me. The spacing between the strip text and box can be increased by setting the margin argument at the strip.text theme:
ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
geom_point() +
facet_grid(Species ~ rev(Species)) +
theme(strip.background = element_rect(colour="red", fill="#CCCCFF"),
strip.text = element_text(margin = margin(10, 10, 10, 10)))
Possible debug strategy:
Reproduce code above
1A. If that doesn't work, check if your ggplot versions is ~3.2-ish
1B. If that does work, proceed to 2.
Try to remove and place back lines of plotting to see where the error occurs
I'm particularly unfamiliar with panel_border() and background_grid(), so you could try those first.
EDIT: Plot based on data and code provided
ggplot(data, aes(x = idx, y = density, colour = factor(location))) +
geom_col(fill = "white") +
scale_color_manual(name = 'Regions',values = c("#F26969", "#02f527",'#F2F2C6')) +
facet_grid(marker ~ case, scales = "free") +
xlab('Index') +
ylab(expression(paste('Density/', mm^2, ))) +
theme(strip.background = element_rect(colour = "red", fill = "#CCCCFF"),
strip.text = element_text(margin = margin(10, 10, 10, 10)),
axis.title = element_text(size = 28),
axis.text = element_text(size = 26),
legend.text = element_text(size = 16),
legend.title = element_text(size = 18),
# Improvised based on missing functions
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_line(colour = "grey90"),
panel.background = element_rect(fill = "white", colour = NA),
panel.border = element_rect(colour = "grey90", fill = NA))

Applying a continuous scale while using geom_label_repel based off separate dataframe

Based off the approach outline in the answer here I have a plot which draws it labels off a separate dataframe. However I was wondering if there would be a way to use geom_label_repel instead of geom_text but have a continuous colour scale applied to the label?
So the original plot would be:
df %>%
ggplot(aes(variable, value, width =.7)) +
geom_col(col="black",aes(fill=X1)) + #Black border around the bars
expand_limits(y = 0) +
scale_y_continuous(limits = c(0,70),
breaks=c(0,10,20, 30,40, 50,60,70),
expand = c(0.02, 0.02))+
geom_label_repel(data = df_max,
aes(label = max, y = max))+ #Here the text is added
scale_fill_brewer(palette="Dark2") + #Changes the colour scale
labs(x="Breed",
y="Weighted score",
fill="") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.direction="vertical", legend.position=c(0.9, 0.85),
legend.text=element_text(size=11),
legend.key = element_rect(size = 4),
legend.key.size = unit(1.5, 'lines'))
My guess, if it's possible, its going to include a variation of scale_fill_gradient but I haven't found a way to make it work?
If I include a scale_fill_gradient like this:
df %>%
ggplot(aes(variable, value, width =.7)) +
geom_col(col="black",aes(fill=X1)) + #Black border around the bars
expand_limits(y = 0) +
scale_fill_gradient2(data=df_max, aes(y=max),
fill=max,
low='blue', mid='green', high='red', midpoint = 10)+
scale_y_continuous(limits = c(0,70),
breaks=c(0,10,20, 30,40, 50,60, 70),
expand = c(0.02, 0.02))+
geom_label_repel(data = df_max,
aes(label = max, y = max))+ #Here the text is added
scale_fill_brewer(palette="Dark2") + #Changes the colour scale
labs(x="Breed",
y="Weighted score",
fill="") +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.direction="vertical",
legend.position=c(0.9, 0.85),
legend.text=element_text(size=11),
legend.key = element_rect(size = 4),
legend.key.size = unit(1.5, 'lines')) # Ensures spacing between the
# different lines on the legend.
I get the following error:
Error in continuous_scale("fill", "gradient2", div_gradient_pal(low, mid, :
unused arguments (data = list(variable = 1:4, max = c(15, 14.7, 9.7, 4.1)),
fill = .Primitive("max"))

Change one line in the ggplot graph with scale_linetype_manual

I am trying to change one of the lines in my ggplot from dash to dotted but I fail, the function scale_linetype_manual doesn't do the work. Can anyone help me to solve this problem?
ggplot(d, aes(a,value)) +
geom_line(aes(color = series), size=2)+
scale_y_continuous(breaks=seq(-2.5, 2.5, 2.5)) +
coord_cartesian(ylim=c(-2.5, 2.5))+
scale_x_continuous(breaks=seq(-200, 2000, 1000)) +
scale_color_manual(values=c("#E69F00","#56B4E9", "#56B4E9")) +
scale_linetype_manual(values=c("twodash", "dotted", "dotted")) +
theme(legend.direction = 'vertical',
legend.position = 'right',
legend.key = element_rect(size = 7),
legend.key.size = unit(3, 'lines'))+
theme(panel.grid.major = element_blank(), text = element_text(size=30),
panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour =
"black"))+
geom_vline(xintercept=c(0), linetype="dotted", size=1.5)+
geom_rect(data=rect, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax),
color="gray55",
alpha=0.4,
inherit.aes = FALSE)+
labs(x = "time [ms]",
y = "Amplitude [µV]",
color = "")
The 'problem' with your plot was that you didn't map the aesthetic linetyppe
to a variable. Hence, your call to scale_linetype_manual had no effect. You should change your code to be
ggplot(d, aes(a,value)) +
geom_line(aes(color = series, linetype = series), size = 2) +
...

Make the faceted x-axis text be the grouping factor in R using ggplot2 when plotting boxplots

I am creating faceted box plots that are grouped by a variable. Instead of having the x-axis text be the factors for the x-axis variable I'd like the x-axis text to be the grouping variable.
However, I don't just want to use the grouping variable as my x-axis variable because I'd like the boxplots to cluster. Its hard to explain well. But I think its clear from the code and comments below.
Let me know if you have any suggestions or can help and thanks in advance!
library(ggplot2)
library(scales)
ln_clr <- "black"
bk_clr <- "white"
set.seed(1)
# Creates variables for a dataset
donor = rep(paste0("Donor",1:3), each=40)
machine = sample(rep(rep(paste0("Machine",1:4), each=1),30))
gene = rep(paste0("Gene",LETTERS[1:5]), each=24)
value = rnorm(24*5, mean=rep(c(0.5,10,1000,25000,8000), each=24),
sd=rep(c(0.5,8,900,9000,3000), each=24))
# Makes all values positive
for(m in 1:length(value)){
if(value[m]<0){
value[m] <- sqrt(value[m]*value[m])
}
}
# Creates a data frame from variables
df = data.frame(donor, machine, gene, value)
# Adds a clone variable
clns <- LETTERS[1:4]
k=1
for(i in 1:nrow(df)/4){
for(j in 1:length(clns)){
df$clone[k] <- paste(df$donor[k],clns[j],sep="")
k = k+1
}
}
df$clone <- as.factor(df$clone)
#*************************************************************************************************************************************
# Creates the facet of the machine but what I want on the x-axis is clone, not donor.
# However, if I set x to clone it doesn't group the boxplots and its harder to read
# the graph.
bp1 <- ggplot(df, aes(x=donor, y=value, group=clone)) +
stat_boxplot(geom ='errorbar', position = position_dodge(width = .83),
width = 0.25, size = 0.7, coef = 1) +
geom_boxplot(coef=1, outlier.shape = NA, position = position_dodge(width = .83),
lwd = 0.3, alpha = 1, colour = ln_clr) +
geom_point(position = position_dodge(width = 0.83), size = 1.8, alpha = 0.9,
mapping=aes(group=clone)) +
facet_wrap(~ machine, ncol=2, scales="free_x")
bp1 + scale_y_log10(expand = c(0, 0)) +
theme(axis.text.x= element_text(size=rel(1), colour = "black", angle=45, hjust=1),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1))
# Creates the facet of the Donor and clusters the clones but doesn't facet the
# machine. This could be okay if I could put spaces in between the different
# machine values but not the donors and could remove the donor facet labels, and
# only have the machine values show up once.
bp2 <- ggplot(df, aes(x=clone, y=value)) +
stat_boxplot(geom ='errorbar', position = position_dodge(width = .83),
width = 0.25, size = 0.7, coef = 1) +
geom_boxplot(coef=1, outlier.shape = NA, position = position_dodge(width = .83),
lwd = 0.3, alpha = 1, colour = ln_clr) +
geom_point(position = position_dodge(width = 0.83), size = 1.8, alpha = 0.9) +
facet_wrap(machine ~ donor, scales="free_x", ncol=6)
bp2 + scale_y_log10(expand = c(0, 0)) +
theme(axis.text.x= element_text(size=rel(1), colour = "black", angle=45, hjust=1),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1),
panel.spacing = unit(0, "lines"))
Below is an example comparing what I'd like in an ideal world (Top two facets) as compared to what I'm getting (bottom two facets).
I'm not sure I understand exactly what you're trying to do, so let me know if this is on the right track:
library(dplyr)
pd = position_dodge(width=0.83)
ggplot(df %>% mutate(clone=gsub("Donor[1-3]","",clone),
donor=gsub("Donor", "", donor)),
aes(x=clone, y=value, color=donor, group=interaction(clone,donor))) +
geom_boxplot(coef=1, outlier.shape=NA, position=pd, lwd=0.3) +
geom_point(position=pd, size=1.8, alpha=0.9) +
facet_wrap(~ machine, ncol=2, scales="free_x") +
scale_y_log10(expand = c(0.02, 0)) +
theme(strip.background=element_rect(colour=ln_clr, fill=bk_clr, size=1))
How about this:
ggplot(df, aes(x=clone, y=value, group=interaction(clone,donor))) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3) +
geom_point(size=1.8, alpha=0.9) +
facet_wrap(~ machine, ncol=2, scales="free_x") +
scale_y_log10(expand = c(0.02, 0)) +
theme(axis.text.x= element_text(size=rel(1), colour = "black", angle=45, hjust=1),
strip.background=element_rect(colour=ln_clr, fill=bk_clr, size=1))
I found a work around for this problem but its not very elegant. I'd be super happy if some one came up with a better solution. Using the code to create a function for a "multiplot" found here and adding the code below I was able to do what I wanted. However, This is a slightly wonky solution in that I can't really format my titles with boxes around them and there are still two "clone" titles on the x axis that I can't replace easily with a single x-axis title. Also, had I of had many "machines" in my example this solution would have been painful to scale. All-in-all not ideal but passible for what I need. Special thanks to Eipi10 for their help, I appreciate it.
# Creates a multi-plot function for use in the graphs below
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
# Call multiplot function after storing each of the below plots as variables
ln_clr <- "black"
bk_clr <- "white"
bp3 <- ggplot(df[df$machine=="Machine1",], aes(x=clone, y=value)) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3) +
geom_point(size=1.8, alpha=0.9) +
ggtitle("Machine 1") +
expand_limits(y=c(0.001,10^5)) +
facet_wrap(~ donor, nrow=1, scales="free_x") + scale_y_log10(expand = c(0, 0)) +
theme(axis.text.x= element_text(size=rel(1), color = ln_clr, angle=45, hjust=1),
panel.spacing = unit(0.25, "lines"), axis.title.x= element_blank(),
plot.title = element_text(hjust=0.5),
strip.text.x = element_text(size=rel(1), face="bold", colour = ln_clr),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1),
axis.line.x= element_line(size = 1.25, colour = ln_clr),
axis.line.y= element_line(size = 1.25, colour = ln_clr),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = bk_clr),
panel.border = element_blank(),
plot.background = element_rect(fill = bk_clr))
bp4 <- ggplot(df[df$machine=="Machine2",], aes(x=clone, y=value)) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3) +
geom_point(size=1.8, alpha=0.9) +
ggtitle("Machine 2") +
expand_limits(y=c(0.001,10^5)) +
facet_wrap(~ donor, nrow=1, scales="free_x") + scale_y_log10(expand = c(0, 0)) +
theme(axis.text.x= element_text(size=rel(1), colour = ln_clr, angle=45, hjust=1),
panel.spacing = unit(0.25, "lines"), plot.title = element_text(hjust=0.5),
strip.text.x = element_text(size=rel(1), face="bold", colour = ln_clr),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1),
axis.line.x= element_line(size = 1.25, colour = ln_clr),
axis.line.y= element_line(size = 1.25, colour = ln_clr),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = bk_clr),
panel.border = element_blank(),
plot.background = element_rect(fill = bk_clr))
bp5 <- ggplot(df[df$machine=="Machine3",], aes(x=clone, y=value)) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3) +
geom_point(size=1.8, alpha=0.9) +
ggtitle("Machine 3") +
expand_limits(y=c(0.001,10^5)) +
facet_wrap(~ donor, nrow=1, scales="free_x") + scale_y_log10(expand = c(0, 0)) +
theme(panel.spacing = unit(0.25, "lines"), axis.title.y= element_blank(),
axis.title.x= element_blank(),axis.line.y= element_blank(),
axis.text.y=element_blank(),
axis.text.x= element_text(size=rel(1), colour = ln_clr, angle=45, hjust=1),
axis.ticks.y=element_blank(), plot.title = element_text(hjust=0.5),
strip.text.x = element_text(size=rel(1), face="bold", colour = ln_clr),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1),
axis.line.x= element_line(size = 1.25, colour = ln_clr),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = bk_clr),
panel.border = element_blank(),
plot.background = element_rect(fill = bk_clr))
bp6 <- ggplot(df[df$machine=="Machine4",], aes(x=clone, y=value)) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3) +
geom_point(size=1.8, alpha=0.9) +
ggtitle("Machine 4") +
expand_limits(y=c(0.001,10^5)) +
facet_wrap(~ donor, nrow=1, scales="free_x") + scale_y_log10(expand = c(0, 0)) +
theme(axis.text.x= element_text(size=rel(1), colour = ln_clr, angle=45, hjust=1),
panel.spacing = unit(0.25, "lines"), plot.title = element_text(hjust=0.5),
strip.text.x = element_text(size=rel(1), face="bold", colour = ln_clr),
strip.background = element_rect(colour = ln_clr, fill = bk_clr, size = 1),
axis.line.x= element_line(size = 1.25, colour = ln_clr),
axis.line.y= element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.title.y= element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = bk_clr),
panel.border = element_blank(),
plot.background = element_rect(fill = bk_clr))
# Plot all 4 graphs and saves them as a output file
png(filename="graph3.png", width= 9, height= 7.5, units = "in", res=600)
multiplot(bp3, bp4, bp5, bp6, cols=2)
dev.off()
Alternatively, if I set the "strip.text.x = " and the "strip.background =" as element_blank(). I can generate the below:

Resources