Adding a manual right-hand-side y-axis in ggplot2 - r

I am wondering if there is any way to get a manual right-side y-axis label when there is no scale, only facet headings.
Here's an example
library(dplyr)
library(Hmisc)
# Plot power vs. n for various odds ratios (base prob.=.1)
(n <- seq(10, 1000, by=10)) # candidate sample sizes
(OR <- as.numeric(sort(c(seq(1/0.90,1/0.13,length.out = 9),2.9)))) # candidate odds ratios, spanning the 95% CI centered around an odds ratio of 2.9
alpha <- c(.001, .01, .05)
# put all of these into a dataset and calculate power
powerDF <- data.frame(expand.grid(OR, n, alpha)) %>%
rename(OR = Var1, num = Var2, alph = Var3) %>%
arrange(OR) %>%
mutate(power = as.numeric(bpower(p1=.29, odds.ratio=OR, n=num, alpha = alph))) %>%
transform(OR = factor(format(round(OR,2),nsmall=2)))
# now plot
pPower <- ggplot(powerDF, aes(x = num, y = power, colour = factor(OR))) +
geom_line() +
facet_grid(factor(alph)~.) +
labs(x = "sample size") +
scale_colour_discrete(name = "Odds Ratio") +
scale_x_continuous(breaks = seq(0,1000,100)) +
scale_y_continuous(breaks = seq(0,1,.1)) +
theme_light() +
theme(axis.title.x = element_text(size = 12, face = "bold"),
axis.title.y = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(colour = "gray95"),
panel.grid.major.x = element_line(colour = "gray95"),
strip.text = element_text(colour = 'black', face = 'bold', size = 12),
legend.text = element_text(size = 12),
legend.title = element_text(size = 12, face = "bold"))
(Please forgive the cluttered axes labels, I had to reduce the size of the image to allow it to be uploaded).
I was wondering if there was any way to have an axis label saying 'significance level' down the right hand side of the graph?

Adding the following to scale_y_continuous seems one way to go (although a bunch of warnings)
sec.axis = sec_axis(trans=I, breaks=NULL, name="Significance")
Alternatively, you can add an additional strip that spans all the panels:
library(grid)
library(gtable)
g <- ggplotGrob(pPower)
rect <- grobTree(rectGrob(gp = gpar(fill = "grey70", col="grey70")),
textGrob("Significance", rot=-90, gp = gpar(col="black")))
g <- gtable_add_cols(g, g$widths[6], 6)
g <- gtable_add_grob(g, rect, l=7, t=7, b=11)
grid.newpage() ; grid.draw(g)

Related

Overlaying two lines with confidence interval on the same graph

I have plotted a line plot with confidence interval as below:
Here is the code I used:
Data_prob = read.table("group1.csv", header=TRUE, sep=",", na.strings="NA", dec=".", strip.white=TRUE)
p<-ggplot(Data_prob, aes(x=Trial, y=Data)) + theme_bw() + xlim(1, 49) + ylim(0.3, .95) +
theme(plot.title = element_text(color="black", size=14, face="bold.italic"), # plot title
axis.title.x = element_text(color="Black", size=25), # x label
axis.title.y = element_text(color="Black", size=25), # y label
axis.text.x = element_text(color = "black",face = "bold", # text style for x axis (removed face = "bold")
size = 22, angle = 0),
axis.text.y = element_text( color = "black",face = "bold", # text style for y axis
size = 22, angle = 0),
axis.line = element_line(color = "black", # line for x and y axis
size = 1, linetype = "solid"),
plot.caption = element_text(color = "black", size =11, face = "bold.italic"), # text style for caption
axis.ticks.length=unit(.25, "cm")
#axis.ticks = element_blank()
) +
theme(panel.border = element_blank(), # remove grid and background color
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
geom_ribbon(aes(ymin=Data-CI, ymax=Data+CI),
alpha=0.2, fill = "gold",color = "gray35", size = 0.1) +
geom_line(size=2, color="black")
print(p)
# Change axis labels
p <- p + labs(x = "Trial", y = "Go probability")
p
Here is what the data look like:
structure(list(Trial = 1:20, Data = c(0.500000027777778, 0.529220307827301,
0.519090892380421, 0.532167908861151, 0.598987738691911, 0.631452312399153,
0.669892859606973, 0.649994605133695, 0.675688232680895, 0.708304011267941,
0.720449809771278, 0.748081634160322, 0.761387966998141, 0.784275979741743,
0.786897508201414, 0.794196638795235, 0.785998558171792, 0.766138054176142,
0.790409435001615, 0.778745578955544), CI = c(5.44644605948509e-08,
0.073455696656296, 0.080875149623623, 0.073926617913334, 0.085753364225061,
0.068666346495005, 0.079656617789649, 0.077652237751934, 0.070180261163008,
0.071432599780653, 0.064943477844168, 0.064645277387821, 0.065096219183598,
0.065766579701286, 0.064325292909355, 0.066878706963396, 0.067698913200129,
0.07105300711211, 0.067063389995005, 0.069931673037628)), row.names = c(NA,
20L), class = "data.frame")
I would like to plot data from another group (group2.csv), so basically another line with confidence interval on the same graph to visually compare the two groups, ideally with a different line color. I've seen some examples on here but I couldn't get it to work. Could anyone help? Thank you!
Suppose you read your data up to two tibble from csv files.
library(tidyverse)
Data_prob1 =tibble(
Trial = 1:50,
Data = c(seq(0.5,0.8, length.out = 20), rep(0.8, 30))+rnorm(50,0,0.05),
CI = 0.1,
)
Data_prob2 =tibble(
Trial = 1:50,
Data = c(seq(0.8,1.2, length.out = 25), rep(1.2, 25))+rnorm(50,0,0.05),
CI = 0.08
)
You can combine such data like this
Data_prob = Data_prob1 %>% mutate(probe = "1") %>%
bind_rows(Data_prob2 %>% mutate(probe = "2")) %>%
mutate(probe = probe %>% fct_inorder())
Finally, create a chart
Data_prob %>% ggplot(aes(Trial, Data, fill=probe, color = probe))+
geom_line()+
geom_ribbon(aes(ymin=Data-CI, ymax=Data+CI, color=NULL), alpha=0.2)

Adjusting font size within a grob using textGrob() and ggplot2

I am trying to increase the fontsize for a second axis title added as a grob (for reasons that will become apparent). Here is some toy data to graph
library(Hmisc)
library(dplyr)
# Plot power vs. n for various odds ratios
(n <- seq(10, 1000, by=10)) # candidate sample sizes
(OR <- as.numeric(sort(c(seq(1/0.90,1/0.13,length.out = 9), 2.9)))) # candidate odds ratios, spanning the 95% CI centered around what we got (OR=2.9)
alpha <- c(.001, .01, .05)
# put all of these into a dataset and calculate power
powerDF <- data.frame(expand.grid(OR, n, alpha)) %>%
rename(OR = Var1, num = Var2, alph = Var3) %>%
arrange(OR) %>%
mutate(power = as.numeric(bpower(p1=.29, odds.ratio=OR, n=num, alpha = alph))) %>%
transform(OR = factor(format(round(OR,2),nsmall=2)),
alph = factor(ifelse(alph == 0.001, "p=0.001",
ifelse(alph == 0.01, "p=0.01", "p=0.05"))))
Now for the figure
library(grid)
library(gtable)
p2 <- ggplot(powerDF, aes(x = num, y = power, colour = factor(OR))) +
geom_line() +
facet_grid(factor(alph)~.) +
labs(x = "sample size") +
scale_colour_discrete(name = "Odds Ratio") +
scale_x_continuous(breaks = seq(0,1000,100)) +
scale_y_continuous(breaks = seq(0,1,.1)) +
theme_light() +
theme(axis.title.x = element_text(size = 12, face = "bold"),
axis.title.y = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(colour = "gray95"),
panel.grid.major.x = element_line(colour = "gray95"),
strip.text = element_text(colour = 'black', face = 'bold', size = 12),
legend.text = element_text(size = 12),
legend.title = element_text(size = 12, face = "bold"))
p2
Now to add the second axis title as a grob.
g <- ggplotGrob(p2)
rect <- grobTree(rectGrob(gp = gpar(fill = "white", col = "white")),
textGrob(expression(bold("Significance Level")), rot = -90, gp = gpar(col = "black")))
g <- gtable_add_cols(x = g, widths = g$widths[6], pos = 6) # add a column g$widths[6] wide to the right of horizontal position 6
g <- gtable_add_grob(x = g, grobs = rect, l=7, t=7, b=11) # now add the rect grob at the new column position to the right of position 6 (i.e. left-most position y, or l= 7, spanning the whole graph)
grid.newpage()
grid.draw(g)
All good. But how do I increase the font size of the second axis within textGrob()?
I have tried fontsize =, cex =, face = to no avail, and the textGrob() documentation makes no reference to font size.
Font size is set via the fontsize argument in gpar().
g <- ggplotGrob(p2)
rect <- grobTree(
rectGrob(gp = gpar(fill = "white", col = "white")),
textGrob(
expression(bold("Significance Level")), rot = -90,
gp = gpar(col = "black", fontsize = 20)
)
)
g <- gtable_add_cols(x = g, widths = g$widths[6], pos = 6) # add a column g$widths[6] wide to the right of horizontal position 6
g <- gtable_add_grob(x = g, grobs = rect, l=7, t=7, b=11) # now add the rect grob at the new column position to the right of position 6 (i.e. left-most position y, or l= 7, spanning the whole graph)
grid.newpage()
grid.draw(g)

Partial italics in facet headings of ggplot

I am wondering if there is any way to rename facet titles so that they contain partial italics and partial non-italics.
Here is some toy data
library(Hmisc)
library(dplyr)
# Plot power vs. n for various odds ratios
n <- seq(10, 1000, by=10) # candidate sample sizes
OR <- as.numeric(sort(c(seq(1/0.90,1/0.13,length.out = 9),2.9))) # candidate ORs
alpha <- c(.001, .01, .05) # alpha significance levels
# put all of these into a dataset and calculate power
powerDF <- data.frame(expand.grid(OR, n, alpha)) %>%
rename(OR = Var1, num = Var2, alph = Var3) %>%
arrange(OR) %>%
mutate(power = as.numeric(bpower(p1=.29, odds.ratio=OR, n=num, alpha = alph))) %>%
transform(OR = factor(format(round(OR,2),nsmall=2)),
alph = factor(ifelse(alph == 0.001, "p=0.001",
ifelse(alph == 0.01, "p=0.01", "p=0.05"))))
pPower <- ggplot(powerDF, aes(x = num, y = power, colour = factor(OR))) +
geom_line() +
facet_grid(factor(alph)~.) +
labs(x = "sample size") +
scale_colour_discrete(name = "Odds Ratio") +
scale_x_continuous(breaks = seq(0,1000,100)) +
scale_y_continuous(breaks = seq(0,1,.1), sec.axis = sec_axis(trans=I, breaks=NULL, name="Significance Level")) + # this is the second axis label
theme_light() +
theme(axis.title.x = element_text(size = 12, face = "bold"),
axis.title.y = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(colour = "gray95"),
panel.grid.major.x = element_line(colour = "gray95"),
strip.text = element_text(colour = 'black', face = 'bold', size = 12),
legend.text = element_text(size = 12),
legend.title = element_text(size = 12, face = "bold"))
pPower
Is there any way to get the facet headings to read "p=0.001", "p=0.01" etc, instead of "p=0.001", i.e. to get partial italics and partial non-italics?

ggMarginal ignores choord_cartesian. How to change marginal scales?

I'm trying to plot a 2D density plot with ggplot, with added marginal histograms. Problem is that the polygon rendering is stupid and needs to be given extra padding to render values outside your axis limits (e.g. in this case I set limits between 0 and 1, because values outside this range have no physical meaning). I still want the density estimate though, because often it's much cleaner than a blocky 2D heatmap.
Is there a way around this problem, besides scrapping ggMarginal entirely and spending another 50 lines of code trying to align histograms?
Unsightly lines:
Now rendering works, but ggMarginal ignores choord_cartesian(), which demolishes the plot:
Data here:
http://pasted.co/b581605a
dataset <- read.csv("~/Desktop/dataset.csv")
library(ggplot2)
library(ggthemes)
library(ggExtra)
plot_center <- ggplot(data = dataset, aes(x = E,
y = S)) +
stat_density2d(aes(fill=..level..),
bins= 8,
geom="polygon",
col = "black",
alpha = 0.5) +
scale_fill_continuous(low = "yellow",
high = "red") +
scale_x_continuous(limits = c(-1,2)) + # Render padding for polygon
scale_y_continuous(limits = c(-1,2)) + #
coord_cartesian(ylim = c(0, 1),
xlim = c(0, 1)) +
theme_tufte(base_size = 15, base_family = "Roboto") +
theme(axis.text = element_text(color = "black"),
panel.border = element_rect(colour = "black", fill=NA, size=1),
legend.text = element_text(size = 12, family = "Roboto"),
legend.title = element_blank(),
legend.position = "none")
ggMarginal(plot_center,
type = "histogram",
col = "black",
fill = "orange",
margins = "both")
You can solve this problem by using xlim() and ylim() instead of coord_cartesian.
dataset <- read.csv("~/Desktop/dataset.csv")
library(ggplot2)
library(ggthemes)
library(ggExtra)
plot_center <- ggplot(data = dataset, aes(x = E,
y = S)) +
stat_density2d(aes(fill=..level..),
bins= 8,
geom="polygon",
col = "black",
alpha = 0.5) +
scale_fill_continuous(low = "yellow",
high = "red") +
scale_x_continuous(limits = c(-1,2)) + # Render padding for polygon
scale_y_continuous(limits = c(-1,2)) + #
xlim(c(0,1)) +
ylim(c(0,1)) +
theme_tufte(base_size = 15, base_family = "Roboto") +
theme(axis.text = element_text(color = "black"),
panel.border = element_rect(colour = "black", fill=NA, size=1),
legend.text = element_text(size = 12, family = "Roboto"),
legend.title = element_blank(),
legend.position = "none")
ggMarginal(plot_center,
type = "histogram",
col = "black",
fill = "orange",
margins = "both")

How to set legend height to be the same as the height of the plot area?

I have arranged two plots: a line chart on top and a heatmap below.
I want the heatmap legend to have the same height as the plot area of the heatmap, i.e. the same length as the y-axis. I know that I can change the height and size of the legend using theme(legend.key.height = unit(...)), but this would take many trial and errors before I find an adequate setting.
Is there a way to specify the height of the legend so that it is exactly the same height of the plot area of the heatmap and would retain that ratio when plotting to a pdf?
A reproducible example with code I have tried:
#Create some test data
pp <- function (n, r = 4) {
x <- seq(1:100)
df <- expand.grid(x = x, y = 1:10)
df$z <- df$x*df$y
df
}
testD <- pp(20)
#Define groups
colbreaks <- seq(min(testD[ , 3]), max(testD[ , 3] + 1), length = 5)
library(Hmisc)
testD$group <- cut2(testD[ , 3], cuts = c(colbreaks))
detach(package:Hmisc, unload = TRUE)
#Create data for the top plot
testD_agg <- aggregate(.~ x, data=testD[ , c(1, 3)], FUN = sum)
#Bottom plot (heatmap)
library(ggplot2)
library(gtable)
p <- ggplot(testD, aes(x = x, y = y)) +
geom_tile(aes(fill = group)) +
scale_fill_manual(values = c("red", "orange", "yellow", "lightgreen")) +
coord_cartesian(xlim = c(0, 100), ylim = c(0.5, 10.5)) +
theme_bw() +
theme(legend.position = "right",
legend.key = element_blank(),
legend.text = element_text(colour = "black", size = 12),
legend.title = element_blank(),
axis.text.x = element_text(size = 12, angle = 45, vjust = +0.5),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 14),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(0, 0, 0, 0), "line"))
#Top plot (line)
p2 <- ggplot(testD_agg, aes(x = x, y = z)) +
geom_line() +
xlab(NULL) +
coord_cartesian(xlim = c(0, 100), ylim = c(0, max(testD_agg$z))) +
theme_bw() +
theme(legend.position = "none",
legend.key = element_blank(),
legend.text = element_text(colour = "black", size = 12),
legend.title = element_text(size = 12, face = "plain"),
axis.text.x = element_blank(),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 14),
axis.ticks.x = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(0.5, 0.5, 0, 0), "line"))
#Create gtables
gp <- ggplotGrob(p)
gp2 <- ggplotGrob(p2)
#Add space to the right of the top plot with width equal to the legend of the bottomplot
legend.width <- gp$widths[7:8] #obtain the width of the legend in pff2
gp2 <- gtable_add_cols(gp2, legend.width, 4) #add a colum to pff with with legend.with
#combine the plots
cg <- rbind(gp2, gp, size = "last")
#set the ratio of the plots
panels <- cg$layout$t[grep("panel", cg$layout$name)]
cg$heights[panels] <- unit(c(2,3), "null")
#remove white spacing between plots
cg <- gtable_add_rows(cg, unit(0, "npc"), pos = nrow(gp))
pdf("test.pdf", width = 8, height = 7)
print(grid.draw(cg))
dev.off()
#The following did not help solve my problem but I think I got close
old.height <- cg$grobs[[16]]$heights[2]
#It seems the height of the legend is given in "mm", change to "npc"?
gp$grobs[[8]]$grobs[[1]]$heights <- c(rep(unit(0, "npc"), 3), rep(unit(1/4, "npc"), 4), rep(unit(0, "mm"),1))
#this does allow for adjustment of the heights but not the exact control I need.
My actual data has some more categories, but the gist is the same.
Here is an image produced with the code above and annotated with what I would like to do.
Thanks in advance!
Maarten
It seems there are two sets of heights that need adjustment: the heights of the legend keys, and the overall height of the legend. Picking up from your cg grob, I extract the legend, make the adjustments to the heights, then insert the legend grob back into the layout.
leg = gtable_filter(cg, "guide-box")
library(grid)
# Legend keys
leg[[1]][[1]][[1]][[1]]$heights = unit.c(rep(unit(0, "mm"), 3),
rep(unit(1/4, "npc"), 4),
unit(0, "mm"))
# Legend
leg[[1]][[1]]$heights[[3]] = sum(rep(unit(0, "mm"), 3),
rep(unit(1/4, "npc"), 4),
unit(0, "mm"))
# grid.draw(leg) # Check that heights are correct
cg.new = gtable_add_grob(cg, leg, t = 17, l = 8)
grid.newpage()
grid.draw(cg.new)

Resources