How to add line of text under the whole ggsurvplot? - r

I would like to add line of text under the whole plot. However, it seems ggsurvplot handles plot and risk-table as two entities. I would like to have it like this: enter image description here
However, this is added in MS Word and the journal asks to have it embedded in the picture itself and I am unable to do that.
Thank you :-)
ggsurvplot(fit = fit, data = dat, pval = TRUE,
color = "black",
risk.table = T,
break.time.by = 12,
surv.scale = "percent",
linetype = c("solid","dotted", "dashed"),
legend.labs = c("Control group", "TMA R-ve", "TMA R+ve"),
censor.shape = 124,
legend.title = "",
title = "5-years death-censored graft survival",
xlab = "Months from transplantation",
ylab = "Survival (%)")

I suppose there may be multiple approaches to laying out the plot, table, and text caption. Here is one way I thought might be easier to work with.
The ggsurvplot object, if you include the risk table, will have two ggplot objects contained in it, one for the curve plot, and one for the table (the table itself is a plot).
You can just add to the table plot a caption, and this will appear below the table in the end. If you include hjust = 0 with plot.caption it will be left justified.
Here is an example:
library(survival)
library(survminer)
fit <- survfit(Surv(time, status) ~ sex, data = lung)
ggsurv <- ggsurvplot(fit, risk.table = TRUE)
ggsurv$table <- ggsurv$table +
theme(plot.caption = element_text(hjust = 0)) +
labs(caption = "Figure 1: 5-years death-censored graft survival")
ggsurv

Related

How to edit ticks and tick labels in ggusrvplot, like in ggplot2?

I want to only have labels every second number, but have the small ticks for every number in my graph. As you can see in the figure I added, the labels are every 2nd tick on the X-axis.
But I want to achieve the result that's on the Y-axis:
With ggplot, this is possible with ggh4x and if_elfse. But I can't find a way how to do this in ggsurvplot. This is my code, for the first picture. The code for the second picture is found here: Code 2
ggsurvplot(fit, data = d,
conf.int = F,
censor = F,
palette = c("green", "purple", "red"),
legend.labs = c("Reference water (pH 7.3)\n(N = 66)",
"Acidic al-poor (pH 5.8)\n(N = 66)",
"Acidic al-rich (pH 5.8)\n(N = 66)"),
legend.title = "Water quality",
xlab = "Days",
xlim = c(1,23),
break.time.by = 2
)
Thank you in advance for yor help.
As ggsurvplot returns a list containing the plot as a ggplot2 object you could achieve your desired result using ggh2x by overriding the x scale as in the example code by #tjebo from Adding minor tick marks to the x axis in ggplot2 (with no labels).
Making use of the default example from ?ggsruvplot:
library(survminer)
library(survival)
library(ggh4x)
fit<- survfit(Surv(time, status) ~ sex, data = lung)
p <- ggsurvplot(fit, data = lung, main = "Survival curve",
xlab = "Days",
xlim = c(1,23))
p$plot +
scale_x_continuous(minor_breaks = seq(0, 24, 1), breaks = seq(0, 24, 2), guide = "axis_minor") +
theme(ggh4x.axis.ticks.length.minor = rel(1))
#> Scale for 'x' is already present. Adding another scale for 'x', which will
#> replace the existing scale.

Customizing a competing risks plot in R with package "cmprsk"

I am trying to customize a plot for competing risks using R and the package cmprsk. Specifically, I want to overwrite the default that for competing events colors are used and for different groups linetypes are used.
Here is my reproducible example:
library(ggplot2)
library(cmprsk)
library(survminer)
# some simulated data to get started
comp.risk.data <- data.frame("tfs.days" = rweibull(n = 100, shape = 1, scale = 1)*100,
"status.tfs" = c(sample(c(0,1,1,1,1,2), size=50, replace=T)),
"Typing" = sample(c("A","B","C","D"), size=50, replace=T))
# fitting a competing risks model
CR <- cuminc(ftime = comp.risk.data$tfs.days,
fstatus = comp.risk.data$status.tfs,
cencode = 0,
group = comp.risk.data$Typing)
# the default plot makes it impossible to identify the groups
ggcompetingrisks(fit = CR, multiple_panels = F, xlab = "Days", ylab = "Cumulative incidence of event",title = "Competing Risks Analysis")+
scale_color_manual(name="", values=c("blue","red"), labels=c("Tumor", "Death without tumor"))
Using ggplot_build() I managed to change the default regarding linetype and color, but I cannot find a way to add a legend.
p2 <- ggcompetingrisks(fit = CR, multiple_panels = FALSE, xlab = "Days", ylab = "Cumulative incidence of event",title = "Death by TCR", ylim = c(0, 1)) +
scale_color_manual(name="", values=c("blue","red"), labels=c("Tumor", "Death without tumor"))
q <- ggplot_build(p2)
q$data[[1]]$colour2 <- ifelse(q$data[[1]]$linetype=="solid","blue", ifelse(q$data[[1]]$linetype==22,"red", ifelse(q$data[[1]]$linetype==42,"green", ifelse(q$data[[1]]$linetype==44,"black", NA))))
q$data[[1]]$linetype <- ifelse(q$data[[1]]$colour=="blue","solid", ifelse(q$data[[1]]$colour=="red","dashed", NA))
q$data[[1]]$colour <- q$data[[1]]$colour2
q$plot <- q$plot + ggtitle("Competing Risks Analysis") + guides(col = guide_legend()) + theme(legend.position = "right")
p2 <- ggplot_gtable(q)
plot(p2)
Does anyone know how to add the legend to a plot manipulated by ggplot_build()? Or an alternative way to plot the competing risks such that color indicated group and linetype indicates event?
You don't need to go down the ggplot_build route. The function ggcompetingrisks returns a ggplot object, which itself contains the aesthetic mappings. You can overwrite these with aes:
p <- ggcompetingrisks(fit = CR,
multiple_panels = F,
xlab = "Days",
ylab = "Cumulative incidence of event",
title = "Competing Risks Analysis")
p$mapping <- aes(x = time, y = est, colour = group, linetype = event)
Now we have reversed the linetype and color aesthetic mappings, we just need to swap the legend labels and we're good to go:
p + labs(linetype = "event", colour = "group")
Note that you can also add color scales, themes, coordinate transforms to p like any other ggplot object.

Remove variable name from legend in ggsurvplot

Is there a concise way to remove the variable name in the legend of plots created by ggsurvplot?
Example:
library(survival)
library(survminer)
set.seed(123)
df=data.frame(gender=c(rep("male", 10), rep("female", 10)), value=c(rnorm(10,mean = 2), rnorm(10,mean = 3)))
fit = surv_fit(Surv(value) ~ gender, data = df)
p = ggsurvplot(fit, data = df, surv.median.line = "none")
What I want is to remove the word 'gender' from the legend as in the following plot. I can achieve this by manually setting the legend labels:
p = ggsurvplot(fit, data = df, surv.median.line = "none", legend.labs = c("male", "female"))
But is there a better way?
EDIT: I accidentally swapped male and female when I manually assigned the gender (2. plot), which shows how dangerous this method is.
Hack the strata with gsub.
names(fit$strata) <- gsub("gender=", "", names(fit$strata))
ggsurvplot(fit, data=df, surv.median.line="none")
To avoid the mistake of swapping the legend labels, use this option in the ggsurvplot function instead: legend.labs = levels(df$gender)
you can simply change the attribute of strata
attr(fit$strata,'names') <- c('female', 'male')
and then make the plot
p = ggsurvplot(fit, surv.median.line = "none")

Using ggrepel and shadowtext on the same geom_text

I have a plot (made in R with ggplot2) that's the result of some singular value decomposition of a bunch of text data, so I basically have a data set of ~100 words used in some reviews and ~10 categories of reviews, with 2D coordinates for each of them. I'm having trouble getting the plot to look legible because of the amount of text and how close together a lot of the important points are.
The way my data is structured now, I'm plotting 2 different geom_texts with different formatting and whatnot, passing each one a separate data frame of coordinates. This has been easier since it's fine if the ~10 categories overlap the ~100 terms (which are of secondary importance) and I wanted pretty different formatting for the two, but there's not necessarily a reason they couldn't be put together in the same data frame and geom I guess if someone can figure out a solution.
What I'd like to do is use the ggrepel functionality so the ~10 categories are repelled from each other and use the shadowtext functionality to make them stand out from the background of colorful words, but since they're different geoms I'm not sure how to make that happen.
Minimal example with some fake data:
library(ggplo2)
library(ggrepel)
library(shadowtext)
dictionary <- c("spicy", "Thanksgiving", "carborator", "mixed", "cocktail", "stubborn",
"apple", "rancid", "table", "antiseptic", "sewing", "coffee", "tragic",
"nonsense", "stufing", "words", "bottle", "distillery", "green")
tibble(Dim1 = rnorm(100),
Dim2 = rnorm(100),
Term = sample(dictionary, 100, replace = TRUE),
Color = as.factor(sample.int(10, 100, replace = TRUE))) -> words
tibble(Dim1 = c(-1,-1,0,-0.5,0.25,0.25,0.3),
Dim2 = c(-1,-0.9, 0, 0, 0.25, 0.4, 0.1),
Term = c("Scotland", "Ireland", "America", "Taiwan", "Japan", "China", "New Zealand")) -> locations
#Base graph
ggplot() +
xlab("Factor 1") +
ylab("Factor 2") +
theme(legend.position = "none") +
geom_text_repel(aes(x = Dim1, y = Dim2, label = Term, color = Color),
words,
fontface = "italic", size = 8) -> p
#Cluttered and impossible to read:
p + geom_text(aes(x = Dim1, y = Dim2, label = Term),
locations,
fontface = "bold", size = 16, color = "#747474")
#I can make it repel:
p + geom_text_repel(aes(x = Dim1, y = Dim2, label = Term),
locations,
fontface = "bold", size = 16, color = "#747474")
#Or I can make the shadowtext:
p + geom_shadowtext(aes(x = Dim1, y = Dim2, label = Term),
locations,
fontface = "bold", size = 16, color = "#747474", bg.color = "white")
The results of the second plot, nicely repelling:
The results of the last plot, with these clean-looking white buffers around the category labels:
Is there a way to do both? I tried using geom_label_repel without the borders but I didn't think it looked as clean as the shadowtext solution.
This answer comes a little late, but I recently found myself in a similar pickle and figured a solution. I am writing cause it may be useful for someone else.
#I can make it repel:
p + geom_text_repel(aes(x = Dim1, y = Dim2, label = Term),
locations,
fontface = "bold", size = 16,
color = "white",
bg.color = "black",
bg.r = .15)
The bg.color and bg.r options from geom_text_repel allow you to select a shading color and size for your text, dramatically improving the contrast in your images (see below!). This solution is borrowed from this stack link!

How To Rotate Labels when using Mosaic Plots within VCD

I am trying to rotate labels (not variable names) for a plot I have created, and I am struggling to find and adopt any workable solution. As you can see the labels are not readable I the current form.
Plot is looking into reasons for planning permission objections, and variables are Income, politics, Sex, and Attitude to new homes in their region.
Here is the code. Last iteration, includes labeling function, but does not have any effect on the plot.
library(vcd)
mosaic(~Sex+HomsBultBPV+HHIncQV++PartyID, data=BSA, shade=TRUE,
labeling_args = list(set_varnames = c(Sex="Gender", HomsBultBPV="Attitude To Homes Built in Area",
PartyID="Political Affiliation", HHIncQV="Income Quartile",
labeling= labeling_border(rot_labels = c(25,25,25,0),
just_labels = c("left",
"center",
"center",
"center")))))
The solution is this parameter: "vcd::labeling_border(rot_labels = c(__, __))"
Try out this code:
library(vcd)
mosaic(~ Sex + Age + Survived, data = Titanic,
main = "Survival on the Titanic", shade = TRUE, legend = TRUE,
labeling = vcd::labeling_border(rot_labels = c(45, 45)))

Resources