Difficulty in arranging plots - ggplot2

I have total 7 plots.
Six of them are line charts which are to be aligned and arranged one below each other such that there is no space between them - to make one composite plot.
Here is the data and ggplot2 code and I am using the same line chart 6 times just to explain my problem
x<- 1:10
y<- rnorm(10)
data <- data.frame(x,y)
library(ggplot2)
k<- ggplot(data, aes(x= x, y= y)) + geom_line() + theme(panel.background=element_blank()) + theme(aspect.ratio = 0.15) + theme(panel.grid.minor = element_blank(), panel.grid.major = element_blank(), axis.line.x = element_line(colour = "black", size= 0.5), axis.line.y = element_line(colour = "black", size= 0.5), axis.ticks.y = element_line(colour = "black", size= 0.5), axis.ticks.x = element_blank()) + xlab(label = "")+ ylab(label = "") + scale_x_continuous(label= NULL) +theme(plot.margin = unit(c(-0.25, 2, -0.25, 2), "cm"))
k
Seventh is scatter plot with regression line
a<- 1:10
a
b<- 11:20
b
data1 <- data.frame(a,b)
data1
library(ggplot2)
k3<-ggplot(data1, aes(x=a, y=b))+ geom_point(shape=1, fill ="black", alpha= 1, color= "black", size=3) + geom_smooth(method = lm, size = 0.5, linetype ="dotted", fill ="black", color= "black", alpha = 0.3)
k3
k3<- k3 + expand_limits(x = c(0.5, 10.5), y = c(10.5,20.5)) + scale_x_continuous(expand = c(0, 0), breaks = c(2,4, 6, 8, 10)) + scale_y_continuous(expand = c(0, 0),breaks = c(10, 12, 14, 16, 18, 20))
k3
k3 <- k3 + theme(panel.background=element_blank())+ theme(aspect.ratio = 1) + theme(panel.grid.minor = element_blank(), panel.grid.major = element_blank(), axis.line.x = element_line(colour = "black"), axis.line.y = element_line(colour = "black", size= 0.5), axis.ticks.y = element_line(colour = "black", size= 0.5), axis.ticks.x = element_line(colour = "black", size= 0.5))
k3
k3<- k3 + scale_x_reverse(expand = c(0, 0))
k3
#Flip axes
k3<- k3 + coord_flip()
k3<- k3 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm"))
k3
I want to arrange (1) composite plot (on left) and (2) scatter plot (on right)side by side. So I tried arranging that way using (1) ggarrange() [in ggpubr] and (2) plot_grid()[in cowplot], but I couldn't.
Could anybody help? Thankyou!
I want the layout to look like this

I really hope, that I've understand you correctly. To be honest your code is a mess, so I was using a default iris dataset.
The hint is to use plot_grid twice:
library(ggplot2)
library(cowplot)
k <- iris %>%
ggplot(aes(x = Sepal.Length, y = Petal.Length)) +
geom_line() +
labs(x = "", y = "") +
theme_classic() +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank())
k3 <- iris %>%
ggplot(aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
labs(x = "", y = "") +
theme_classic()
grid1 <- cowplot::plot_grid(
k, k, k, k, k, k,
ncol = 1,
align = "hv"
)
cowplot::plot_grid(grid1, k3,
align = "hv",
rel_widths = c(1.5, 1), # you can control the relative width and height
nrow = 1)

Found solution! Got desired result with package 'patchwork' in combination with some changes in plot margins.
Here is the code and result
library(ggplot2)
iris
# Line charts
k <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length)) +
geom_line() +
labs(x = "", y = "") +
theme_classic() +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()) +
theme(plot.margin = unit(c(-0.25,-3,-0.25,0), "cm")) +
theme(aspect.ratio = 0.15)
# Line chart (k4) with y-axis label
k4 <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length)) +
geom_line() +
labs(x = "", y = "") +
theme_classic() +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()) +
theme(axis.title.y = element_text(
vjust = 2,
color = "black",
size = 10,
face = "bold"
))+
theme(plot.margin = unit(c(-0.25,-3,-0.25,0), "cm"))+
theme(aspect.ratio = 0.15)
# scatter plot
sc <-ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
labs(x = "", y = "") +
theme_classic()+
theme(plot.margin = unit(c(0,0,0,-0.5), "cm"))+
theme(aspect.ratio = 0.7)
sc
library(patchwork)
p<- (k/k/k/k4/k/k)| sc
p

Related

Mismatch when using ggplot2 with a geom_point conditional fill

I am trying to have a white fill, for models where the p.fdr variable is <0.05.
However, the code I have written, is not modifying the correct point (the blue estimate should have a white fill not the pink estimate, as pictured below).
Example code:
conf.low <- sort(runif(6, min = 0, max = 1))
conf.high <- sort(runif(6, min = conf.low[1], max = 1))
estimate <- (conf.low + conf.high) / 2
forestplot <- data.frame(
outcome = c("mean_ssrt_0","mean_ssrt_0", "strp_scr_mnrt_congr", "strp_scr_mnrt_congr", "nihtbx_picvocab_theta_0","nihtbx_picvocab_theta_0"),
measure = c("Stop-Signal Task", "Stop-Signal Task","Emotional Word-Emotional Face Stroop", "Emotional Word-Emotional Face Stroop","NIH Toolbox® Cognition Battery", "NIH Toolbox® Cognition Battery" ),
a_model = c("1", "2", "1", "2", "1", "2"),
conf.low = conf.low,
conf.high = conf.high,
estimate = estimate,
p.fdr = runif(6, min = 0.05 / 1.3, max = 0.1))
forestplot$outcome <- factor(forestplot$outcome, levels=c('mean_ssrt_0', 'strp_scr_mnrt_congr', 'nihtbx_picvocab_theta_0'),
labels=c("Mean SSRT", "RT", "PVT \n (Theta)"))
forestplot$measure <- factor(forestplot$measure, levels=c('Stop-Signal Task',
'Emotional Word-Emotional Face Stroop',
'NIH Toolbox® Cognition Battery'))
forestplot$a_model <- factor(forestplot$a_model , levels=c("1","2"))
forestplot <- forestplot %>% arrange(measure, outcome,a_model, estimate, conf.low, conf.high)
plots <- forestplot %>%
split(.$measure) %>%
map2(.,names(.), ~ggplot(.x, aes(x = outcome, y =estimate, ymin =conf.low, ymax = conf.high,fill = as.factor(measure))) +
geom_pointrange(aes(color=a_model, shape = a_model), size=0.5, position=position_dodge2(width=0.5, reverse = TRUE), show.legend = F)+ # add group
geom_point(aes(shape = a_model), size=1.5, alpha = ifelse(.x$p.fdr < 0.05, 1, 0), position=position_dodge2(width=0.5, reverse = TRUE), show.legend = F, color="white") +
geom_hline(yintercept = 0, linetype = 'dashed', col = 'black') +
scale_y_continuous(limits = c(-0.1, 1))+
coord_flip() +
xlab('')+
ylab(expression(atop("Est. mean change (in SD units with 95% CI)", paste("per 1 SD increase in gPFS"^"lowDA"))))+
ggtitle(.y)+
theme_minimal(base_size = 11)+
guides(fill = "none") +
scale_color_manual(labels = c("Model 1", "Model 2"), values = c("#00B8E7", "#F8766D")) +
labs(color="Model")+
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.title.position = "plot",
plot.title = element_text(size = 10,face="bold"), text = element_text(size = 10)))
plot <-plot_grid(plots$`Stop-Signal Task`+ ggtitle(bquote(bold(~ "Stop-Signal Task" ~ '')))+ theme(legend.position = "none", axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank(),axis.line.y = element_line(color="black", size = 0.5)),
plots$`Emotional Word-Emotional Face Stroop` + ggtitle(bquote(bold(~ 'Stroop - EWEFS' ~ ''))) + theme(legend.position = "none", axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank(),axis.line.y = element_line(color="black", size = 0.5)),
plots$`NIH Toolbox® Cognition Battery` + ggtitle(bquote(bold(~ "NIH Toolbox\U00AE" ~ ''))) + theme(legend.position = "none", axis.ticks.x = element_line(color="black", size = 0.5), axis.line.x = element_line(color="black", size = 0.5),axis.line.y = element_line(color="black", size = 0.5)),
ncol = 1, nrow=3, rel_heights = c(1,1,1), align = 'v') # add 1 col and then the number of rows = to number of plots
plot
I have tried arranging the ordering the original dataframe but, it doesn't solve the problem.
forestplot <- forestplot %>% arrange(measure, outcome, a_model, estimate, conf.low, conf.high)
Is it okay if instead of white fill, it's just transparent? You can control that through the shape argument. It also simplifies the code a little bit. This is how you would modify your plots object:
plots <- forestplot %>%
mutate(
shape = if_else(a_model == 1 & p.fdr < 0.05, "hollow_circle",
if_else(a_model == 1 & p.fdr >= 0.05, "filled_circle",
if_else(a_model == 2 & p.fdr < 0.05, "hollow_triangle", "filled_triangle")))
) %>%
split(.$measure) %>%
map2(.,names(.), ~ggplot(.x, aes(x = outcome, y = estimate, ymin = conf.low, ymax = conf.high, shape = shape, color = a_model)) +
geom_pointrange(size = 0.5, position = position_dodge2(width = 0.5, reverse = TRUE), show.legend = F) + # add group
geom_hline(yintercept = 0, linetype = 'dashed', col = 'black') +
scale_y_continuous(limits = c(-0.1, 1)) +
scale_shape_manual(values = c("filled_circle" = 16, "hollow_triangle" = 2, "hollow_circle" = 1, "filled_triangle" = 17)) +
coord_flip() +
xlab('')+
ylab(expression(atop("Est. mean change (in SD units with 95% CI)", paste("per 1 SD increase in gPFS"^"lowDA"))))+
ggtitle(.y)+
theme_minimal(base_size = 11)+
guides(fill = "none") +
scale_color_manual(values = c("1" = "#00B8E7", "2" = "#F8766D")) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
plot.title.position = "plot",
plot.title = element_text(size = 10,face="bold"), text = element_text(size = 10)))

Facet title left alignment using facet_grid

I'm making a plot with facets where the length of facet titles vary quite a bit. I am trying to left-align the facet/strip title with hjust, but it seems like hjust adjust differently depending on length of each facet title. Ideally, I would like to align each facet title with the 0 on the axis.
library(ggplot2)
data <- data.frame(q = c(rep("q1", 16), rep("question mucher longer and longer and longer", 16)),
cat = c(rep(paste0("cat", 1:4), times = 8)),
p = rep(25, 32),
group = c(rep(paste0("group", 1:4), each = 4),
c(rep(paste0("group", 1:4), each = 4))))
ggplot(data = data,
aes(x = group, y = p, fill = cat, label = p)) +
geom_bar(stat="identity", position = position_stack(), width=0.6) +
facet_grid(col = vars(q)) +
coord_flip() +
geom_text(position = position_stack(vjust = 0.5), size = 3.5, color= "black") +
xlab("") +
ylab("") +
theme_minimal(base_size=12) +
theme(
legend.position="bottom",
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line( size=.1, color="gray"),
panel.grid.minor.x = element_line( size=.1, color="gray"),
strip.text = element_text(face="bold", hjust=0.03)) +
guides(fill = guide_legend(reverse=TRUE)) +
scale_y_continuous(labels=c("0","25","50","75","100 %")) +
geom_hline(yintercept = 0, color = "gray23") +
geom_hline(yintercept = 100, color = "gray23") +
theme(legend.title=element_blank(),
legend.margin=margin(0,0,0,0),
legend.box.margin=margin(-10,0,0,0))
The issue is the expansion of the y scale. Hence, the strip text box expands over the 0 line. To fix your issue use hjust=0 for the strip box text and remove the default expansion on the left (or bottom in your case) of the y scale. To show this clearer I added a red box around the strip text boxes:
library(ggplot2)
ggplot(
data = data,
aes(x = group, y = p, fill = cat, label = p)
) +
geom_bar(stat = "identity", position = position_stack(), width = 0.6) +
facet_grid(col = vars(q)) +
coord_flip() +
geom_text(position = position_stack(vjust = 0.5), size = 3.5, color = "black") +
xlab("") +
ylab("") +
theme_minimal(base_size = 12) +
theme(
legend.position = "bottom",
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(size = .1, color = "gray"),
panel.grid.minor.x = element_line(size = .1, color = "gray"),
strip.text = element_text(face = "bold", hjust = 0, margin = margin(0, 0, 0, 0, "pt")),
strip.background.x = element_rect(color = "red")
) +
guides(fill = guide_legend(reverse = TRUE)) +
scale_y_continuous(labels = c("0", "25", "50", "75", "100 %"), expand = c(0, 0, .05, 0)) +
geom_hline(yintercept = 0, color = "gray23") +
geom_hline(yintercept = 100, color = "gray23") +
theme(
legend.title = element_blank(),
legend.margin = margin(0, 0, 0, 0),
legend.box.margin = margin(-10, 0, 0, 0)
)

Start ggplot continuous axis with a squiggly line break? [duplicate]

I have a dataframe (dat) with two columns 1) Month and 2) Value. I would like to highlight that the x-axis is not continuous in my boxplot by interrupting the x-axis with two angled lines on the x-axis that are empty between the angled lines.
Example Data and Boxplot
library(ggplot2)
set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)
ggplot(data = dat, aes(x = factor(Month), y = Value)) +
geom_boxplot() +
labs(x = "Month") +
theme_bw() +
theme(panel.grid = element_blank(),
text = element_text(size = 16),
axis.text.x = element_text(size = 14, color = "black"),
axis.text.y = element_text(size = 14, color = "black"))
The ideal figure would look something like below. How can I make this discontinuous axis in ggplot?
You could make use of the extended axis guides in the ggh4x package. Alas, you won't easily be able to create the "separators" without a hack similar to the one suggested by user Zhiqiang Wang
guide_axis_truncated accepts vectors to define lower and upper trunks. This also works for units, by the way, then you have to pass the vector inside the unit function (e.g., trunc_lower = unit(c(0,.45), "npc") !
library(ggplot2)
library(ggh4x)
set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)
# this is to make it slightly more programmatic
x1end <- 3.45
x2start <- 3.55
p <-
ggplot(data = dat, aes(x = factor(Month), y = Value)) +
geom_boxplot() +
labs(x = "Month") +
theme_classic() +
theme(axis.line = element_line(colour = "black"))
p +
guides(x = guide_axis_truncated(
trunc_lower = c(-Inf, x2start),
trunc_upper = c(x1end, Inf)
))
Created on 2021-11-01 by the reprex package (v2.0.1)
The below is taking user Zhiqiang Wang's hack a step further. You will see I am using simple trigonometry to calculate the segment coordinates. in order to make the angle actually look as it is defined in the function, you would need to set coord_equal.
# a simple function to help make the segments
add_separators <- function(x, y = 0, angle = 45, length = .1){
add_y <- length * sin(angle * pi/180)
add_x <- length * cos(angle * pi/180)
## making the list for your segments
myseg <- list(x = x - add_x, xend = x + add_x,
y = rep(y - add_y, length(x)), yend = rep(y + add_y, length(x)))
## this function returns an annotate layer with your segment coordinates
annotate("segment",
x = myseg$x, xend = myseg$xend,
y = myseg$y, yend = myseg$yend)
}
# you will need to set limits for correct positioning of your separators
# I chose 0.05 because this is the expand factor by default
y_sep <- min(dat$Value) -0.05*(min(dat$Value))
p +
guides(x = guide_axis_truncated(
trunc_lower = c(-Inf, x2start),
trunc_upper = c(x1end, Inf)
)) +
add_separators(x = c(x1end, x2start), y = y_sep, angle = 70) +
# you need to set expand to 0
scale_y_continuous(expand = c(0,0)) +
## to make the angle look like specified, you would need to use coord_equal()
coord_cartesian(clip = "off", ylim = c(y_sep, NA))
I think it is possible to get what you want. It may take some work.
Here is your graph:
library(ggplot2)
set.seed(321)
dat <- data.frame(matrix(ncol = 2, nrow = 18))
x <- c("Month", "Value")
colnames(dat) <- x
dat$Month <- rep(c(1,2,3,10,11,12),3)
dat$Value <- rnorm(18,20,2)
p <- ggplot(data = dat, aes(x = factor(Month), y = Value)) +
geom_boxplot() +
labs(x = "Month") +
theme_bw() +
theme(panel.grid = element_blank(),
text = element_text(size = 16),
axis.text.x = element_text(size = 14, color = "black"),
axis.text.y = element_text(size = 14, color = "black"))
Here is my effort:
p + annotate("segment", x = c(3.3, 3.5), xend = c(3.6, 3.8), y = c(14, 14), yend = c(15, 15))+
coord_cartesian(clip = "off", ylim = c(15, 25))
Get something like this:
If you want to go further, it may take several tries to get it right:
p + annotate("segment", x = c(3.3, 3.5), xend = c(3.6, 3.8), y = c(14, 14), yend = c(15, 15))+
annotate("segment", x = c(0, 3.65), xend = c(3.45, 7), y = c(14.55, 14.55), yend = c(14.55, 14.55)) +
coord_cartesian(clip = "off", ylim = c(15, 25)) +
theme_classic()+
theme(axis.line.x = element_blank())
Just replace axis with two new lines. This is a rough idea, it may take some time to make it perfect.
You could use facet_wrap. If you assign the first 3 months to one group, and the other months to another, then you can produce two plots that are side by side and use a single y axis.
It's not exactly what you want, but it will show the data effectively, and highlights the fact that the x axis is not continuous.
dat$group[dat$Month %in% c("1", "2", "3")] <- 1
dat$group[dat$Month %in% c("10", "11", "12")] <- 2
ggplot(data = dat, aes(x = factor(Month), y = Value)) +
geom_boxplot() +
labs(x = "Month") +
theme_bw() +
theme(panel.grid = element_blank(),
text = element_text(size = 16),
axis.text.x = element_text(size = 14, color = "black"),
axis.text.y = element_text(size = 14, color = "black")) +
facet_wrap(~group, scales = "free_x")
* Differences in the plot are likely due to using different versions of R where the set.seed gives different result

Using a ggplot raster basemap with draw_plot and ggdraw seems to result in a blurred pdf

I need to produce a high resolution (1200dpi) image for a journal. However, using cowplot::draw_plot to overlay some insets seems to lower the resolution of the basemap (see resolution of "basemap_test.pdf" vs "cowplot_test.pdf"). There is a similar question here:
The draw_image() function from cowplot results in blurred pdfs
but that one is to do with bringing in outside images; this seems more straightforward, working with a ggplot object in the R environment. Is there a way I can stop the basemap blurring?
snip from basemap pdf
snip from ggdraw pdf
Sorry for the length of the reprex - wanted it as close as possible to my plot
if (!require(pacman)) install.packages('pacman')
library(pacman)
pacman::p_load(tidyverse,cowplot,raster,sf,maptools,fasterize)
eckIV = st_crs("ESRI:54012")
data("wrld_simpl")
wrld = st_as_sf(wrld_simpl) %>%
st_transform(eckIV)
#inset a
a_lims <- c(-9266960,-7503720,4725508,5796774)
a_sf <- st_bbox(extent(a_lims)) %>% st_as_sfc %>% st_sf
#inset b
b_lims <- c(-5203519,-3440279,-3705917,-2634651)
b_sf <- st_bbox(extent(b_lims)) %>% st_as_sfc %>% st_sf
#inset c
c_lims <- c(-43965.2,1719274.8,5759670.1,6830936.1)
c_sf <- st_bbox(extent(c_lims)) %>% st_as_sfc %>% st_sf
#inset d
d_lims <- c(9213988,10977228,3481996,4553262)
d_sf <- st_bbox(extent(d_lims)) %>% st_as_sfc %>% st_sf
insetBoxes <- rbind(a_sf,b_sf,c_sf,d_sf) %>%
st_set_crs(eckIV)
#dummy raster data
rst = raster(ext=extent(wrld),res=30000,crs=eckIV$proj4string)
values(rst) <- runif(n=ncell(rst),0,1)
rst = mask(rst,fasterize(wrld,rst))
rst_df = as.data.frame(rst, xy=TRUE)
#basemap
map <- ggplot() +
geom_sf(data=wrld, col=NA) +
geom_raster(data = rst_df, aes(fill = layer, x = x, y = y)) +
geom_sf(data=insetBoxes, fill=NA, size=0.5) +
scale_fill_gradientn(colours=terrain.colors(100),na.value = "transparent") +
theme_void() +
theme(legend.position = "none")
#insets
theme_inset <- theme_void() +
theme(legend.position="none",
panel.border = element_rect(colour = "black", fill = NA))
inset1 <- ggplot() +
geom_sf(data=wrld, col=NA) +
geom_raster(data = rst_df, aes(fill = layer, x = x, y = y)) +
scale_fill_gradientn(colours=terrain.colors(100),na.value = "transparent") +
geom_sf(data=wrld, fill=NA, size=0.1) +
theme_inset +
coord_sf(xlim = c(c_lims[[1]], c_lims[[2]]),
ylim = c(c_lims[[3]], c_lims[[4]]),
expand = FALSE)
inset2 <- ggplot() +
geom_sf(data=wrld, col=NA) +
geom_raster(data = rst_df, aes(fill = layer, x = x, y = y)) +
scale_fill_gradientn(colours=terrain.colors(100),na.value = "transparent") +
geom_sf(data=wrld, fill=NA, size=0.1) +
theme_inset +
coord_sf(xlim = c(d_lims[[1]], d_lims[[2]]),
ylim = c(d_lims[[3]], d_lims[[4]]),
expand = FALSE)
inset3 <- ggplot() +
geom_sf(data=wrld, col=NA) +
geom_raster(data = rst_df, aes(fill = layer, x = x, y = y)) +
scale_fill_gradientn(colours=terrain.colors(100),na.value = "transparent") +
geom_sf(data=wrld, fill=NA, size=0.1) +
theme_inset +
coord_sf(xlim = c(a_lims[[1]], a_lims[[2]]),
ylim = c(a_lims[[3]], a_lims[[4]]),
expand = FALSE)
inset4 <- ggplot() +
geom_sf(data=wrld, col=NA) +
geom_raster(data = rst_df, aes(fill = layer, x = x, y = y)) +
scale_fill_gradientn(colours=terrain.colors(100),na.value = "transparent") +
geom_sf(data=wrld, fill=NA, size=0.1) +
theme_inset +
coord_sf(xlim = c(b_lims[[1]], b_lims[[2]]),
ylim = c(b_lims[[3]], b_lims[[4]]),
expand = FALSE)
#combine
world_map = map %>%
cowplot::ggdraw() +
cowplot::draw_plot(inset1 + theme(plot.background = element_rect(fill = "white", colour = NA)),
width = 0.25,
height = 0.25,
x = 0.75,
y = 0.7) +
cowplot::draw_plot(inset2 + theme(plot.background = element_rect(fill = "white", colour = NA)),
width = 0.25,
height = 0.25,
x = 0.75,
y = 0.4) +
cowplot::draw_plot(inset3 + theme(plot.background = element_rect(fill = "white", colour = NA)),
width = 0.25,
height = 0.25,
x = 0,
y = 0.7) +
cowplot::draw_plot(inset4 + theme(plot.background = element_rect(fill = "white", colour = NA)),
width = 0.25,
height = 0.25,
x = 0,
y = 0.4)
rtn.plot = cowplot::plot_grid(world_map,world_map,ncol=1, labels = letters[1:2])
ggsave(plot=rtn.plot,
filename="cowplot_test.pdf",
width=22,height=18,unit="cm",device="pdf", dpi=1200)
ggsave(plot=map,
filename="basemap_test.pdf",
width=22,height=18,unit="cm",device="pdf", dpi=1200)

Create a ggplot2 survival curve with censored table

I am trying to create a Kaplan-Meier plot with 95% confidence bands plus having the censored data in a table beneath it. I can create the plot, but not the table. I get the error message: Error in grid.draw(both) : object 'both' not found.
library(survival)
library(ggplot2)
library(GGally)
library(gtable)
data(lung)
sf.sex <- survfit(Surv(time, status) ~ sex, data = lung)
pl.sex <- ggsurv(sf.sex) +
geom_ribbon(aes(ymin=low,ymax=up,fill=group),alpha=0.3) +
guides(fill=guide_legend("sex"))
pl.sex
tbl <- ggplot(df_nums, aes(x = Time, y = factor(variable), colour = variable,+
label=value)) +
geom_text() +
theme_bw() +
theme(panel.grid.major = element_blank(),+
legend.position = "none",+
plot.background = element_blank(), +
panel.grid.major = element_blank(),+
panel.grid.minor = element_blank(),+
panel.border = element_blank(),+
legend.position="none",+
axis.line = element_blank(),+
axis.text.x = element_blank(),+
axis.text.y = element_text(size=15, face="bold", color = 'black'),+
axis.ticks=element_blank(),+
axis.title.x = element_blank(),+
axis.title.y = element_blank(),+
plot.title = element_blank()) +
scale_y_discrete(breaks=c("Group.A", "Group.B"), labels=c("Group A", "Group B"))
both = rbind(ggplotGrob(g), ggplotGrob(tbl), size="last")
panels <- both$layout$t[grep("panel", both$layout$name)]
both$heights[panels] <- list(unit(1,"null"), unit(2, "lines"))
both <- gtable_add_rows(both, heights = unit(1,"line"), 8)
both <- gtable_add_grob(both, textGrob("Number at risk", hjust=0, x=0), t=9, l=2, r=4)
grid.newpage()
grid.draw(both)
I solved the problem by using the Rcmdrplugin KMggplot2 The code is generated by the plugin after selecting the data and variables.
library(survival, pos=18)
data(lung, package="survival")
lung <- within(lung, {
sex <- factor(sex, labels=c('male','female'))
})
ggthemes_data <- ggthemes::ggthemes_data
require("ggplot2")
.df <- na.omit(data.frame(x = lung$time, y = lung$status, z = lung$sex))
.df <- .df[do.call(order, .df[, c("z", "x"), drop = FALSE]), , drop = FALSE]
.fit <- survival::survfit(survival::Surv(time = x, event = y, type = "right") ~ z,
.df)
.pval <- plyr::ddply(.df, plyr::.(),
function(x) {
data.frame(
x = 0, y = 0, df = 1,
chisq = survival::survdiff(
survival::Surv(time = x, event = y, type = "right") ~ z, x
)$chisq
)})
.pval$label <- paste0(
"paste(italic(p), \" = ",
signif(1 - pchisq(.pval$chisq, .pval$df), 3),
"\")"
)
.fit <- data.frame(x = .fit$time, y = .fit$surv, nrisk = .fit$n.risk, nevent =
.fit$n.event, ncensor= .fit$n.censor, upper = .fit$upper, lower = .fit$lower)
.df <- .df[!duplicated(.df[,c("x", "z")]), ]
.df <- .fit <- data.frame(.fit, .df[, c("z"), drop = FALSE])
.med <- plyr::ddply(.fit, plyr::.(z), function(x) {
data.frame(
median = min(subset(x, y < (0.5 + .Machine$double.eps^0.5))$x)
)})
.df <- .fit <- rbind(unique(data.frame(x = 0, y = 1, nrisk = NA, nevent = NA,
ncensor = NA, upper = 1, lower = 1, .df[, c("z"), drop = FALSE])), .fit)
.cens <- subset(.fit, ncensor == 1)
.tmp1 <- data.frame(as.table(by(.df, .df[, c("z"), drop = FALSE], function(d)
max(d$nrisk, na.rm = TRUE))))
.tmp1$x <- 0
.nrisk <- .tmp1
for (i in 1:9) {.df <- subset(.fit, x < 100 * i); .tmp2 <-
data.frame(as.table(by(.df, .df[, c("z"), drop = FALSE], function(d) if
(all(is.na(d$nrisk))) NA else min(d$nrisk - d$nevent - d$ncensor, na.rm = TRUE))));
.tmp2$x <- 100 * i; .tmp2$Freq[is.na(.tmp2$Freq)] <- .tmp1$Freq[is.na(.tmp2$Freq)];
.tmp1 <- .tmp2; .nrisk <- rbind(.nrisk, .tmp2)}
.nrisk$y <- rep(seq(0.075, 0.025, -0.05), 10)
.plot <- ggplot(data = .fit, aes(x = x, y = y, colour = z)) +
RcmdrPlugin.KMggplot2::geom_stepribbon(data = .fit, aes(x = x, ymin = lower, ymax =
upper, fill = z), alpha = 0.25, colour = "transparent", show.legend = FALSE, kmplot
= TRUE) + geom_step(size = 1.5) +
geom_linerange(data = .cens, aes(x = x, ymin = y,
ymax = y + 0.02), size = 1.5) +
geom_text(data = .pval, aes(y = y, x = x, label =
label), colour = "black", hjust = 0, vjust = -0.5, parse = TRUE, show.legend =
FALSE, size = 14 * 0.282, family = "sans") +
geom_vline(data = .med, aes(xintercept
= median), colour = "black", lty = 2) + scale_x_continuous(breaks = seq(0, 900, by
= 100), limits = c(0, 900)) +
scale_y_continuous(limits = c(0, 1), expand = c(0.01,0)) + scale_colour_brewer(palette = "Set1") + scale_fill_brewer(palette = "Set1") +
xlab("Time from entry") + ylab("Proportion of survival") + labs(colour = "sex") +
ggthemes::theme_calc(base_size = 14, base_family = "sans") + theme(legend.position
= c(1, 1), legend.justification = c(1, 1))
.nrisk$y <- ((.nrisk$y - 0.025) / (max(.nrisk$y) - 0.025) + 0.5) * 0.5
.plot2 <- ggplot(data = .nrisk, aes(x = x, y = y, label = Freq, colour = z)) +
geom_text(size = 14 * 0.282, family = "sans") + scale_x_continuous(breaks = seq(0,900, by = 100), limits = c(0, 900)) +
scale_y_continuous(limits = c(0, 1)) +
scale_colour_brewer(palette = "Set1") + ylab("Proportion of survival") +
RcmdrPlugin.KMggplot2::theme_natrisk(ggthemes::theme_calc, 14, "sans")
.plot3 <- ggplot(data = subset(.nrisk, x == 0), aes(x = x, y = y, label = z, colour = z)) +
geom_text(hjust = 0, size = 14 * 0.282, family = "sans") +
scale_x_continuous(limits = c(-5, 5)) + scale_y_continuous(limits = c(0, 1)) +
scale_colour_brewer(palette = "Set1") +
RcmdrPlugin.KMggplot2::theme_natrisk21(ggthemes::theme_calc, 14, "sans")
.plotb <- ggplot(.df, aes(x = x, y = y)) + geom_blank() +
RcmdrPlugin.KMggplot2::theme_natriskbg(ggthemes::theme_calc, 14, "sans")
grid::grid.newpage(); grid::pushViewport(grid::viewport(layout =
grid::grid.layout(2, 2, heights = unit(c(1, 3), c("null", "lines")), widths =
unit(c(4, 1), c("lines", "null")))));
print(.plotb, vp =
grid::viewport(layout.pos.row = 1:2, layout.pos.col = 1:2));
print(.plot , vp =
grid::viewport(layout.pos.row = 1 , layout.pos.col = 1:2));
print(.plot2, vp =
grid::viewport(layout.pos.row = 2 , layout.pos.col = 1:2));
print(.plot3, vp =
grid::viewport(layout.pos.row = 2 , layout.pos.col = 1 ));
.plot <- recordPlot()
print(.plot)
Here's a start (code below)
I guess you can create the table need and replace it by the random.table
# install.packages("ggplot2", dependencies = TRUE)
# install.packages("RGraphics", dependencies = TRUE)
# install.packages("gridExtra", dependencies = TRUE)
# install.packages("survival", dependencies = TRUE)
require(ggplot2)
library(RGraphics)
library(gridExtra)
library(survival)
# Plot
data(lung)
sf.sex <- survfit(Surv(time, status) ~ sex, data = lung)
pl.sex <- ggsurv(sf.sex) +
geom_ribbon(aes(ymin=low,ymax=up,fill=group),alpha=0.3) +
guides(fill=guide_legend("sex"))
# Table
random.table <- data.frame("CL 95"=rnorm(5),n=runif(5,1,3))
pl.table <- tableGrob(random.table)
# Arrange the plots on the same page
grid.arrange(pl.sex, pl.table, ncol=1)