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.
Related
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
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.
I'm trying to figure out how to modify a scatter-plot that contains two groups of data along a continuum separated by a large gap. The graph needs a break on the x-axis as well as on the regression line.
This R code using the ggplot2 library accurately presents the data, but is unsightly due to the vast amount of empty space on the graph. Pearson's correlation is -0.1380438.
library(ggplot2)
p <- ggplot(, aes(x = dis, y = result[, 1])) + geom_point(shape = 1) +
xlab("X-axis") +
ylab("Y-axis") + geom_smooth(color = "red", method = "lm", se = F) + theme_classic()
p + theme(plot.title = element_text(hjust = 0.5, size = 14))
This R code uses gap.plot to produce the breaks needed, but the regression line doesn't contain a break and doesn't reflect the slope properly. As you can see, the slope of the regression line isn't as sharp as the graph above and there needs to be a visible distinction in the slope of the line between those disparate groups.
library(plotrix)
gap.plot(
x = dis,
y = result[, 1],
gap = c(700, 4700),
gap.axis = "x",
xlab = "X-Axis",
ylab = "Y-Axis",
xtics = seq(0, 5575, by = 200)
)
abline(v = seq(700, 733) , col = "white")
abline(lm(result[, 1] ~ dis), col = "red", lwd = 2)
axis.break(1, 716, style = "slash")
Using MS Paint, I created an approximation of what the graph should look like. Notice the break marks on the top as well as the discontinuity between on the regression line between the two groups.
One solution is to plot the regression line in two pieces, using ablineclip to limit what's plotted each time. (Similar to #tung's suggestion, although it's clear that you want the appearance of a single graph rather than the appearance of facets.) Here's how that would work:
library(plotrix)
# Simulate some data that looks roughly like the original graph.
dis = c(rnorm(100, 300, 50), rnorm(100, 5000, 100))
result = c(rnorm(100, 0.6, 0.1), rnorm(100, 0.5, 0.1))
# Store the location of the gap so we can refer to it later.
x.axis.gap = c(700, 4700)
# gap.plot() works internally by shifting the location of the points to be
# plotted based on the gap size/location, and then adjusting the axis labels
# accordingly. We'll re-compute the second half of the regression line in the
# same way; these are the new values for the x-axis.
dis.alt = dis - x.axis.gap[1]
# Plot (same as before).
gap.plot(
x = dis,
y = result,
gap = x.axis.gap,
gap.axis = "x",
xlab = "X-Axis",
ylab = "Y-Axis",
xtics = seq(0, 5575, by = 200)
)
abline(v = seq(700, 733), col = "white")
axis.break(1, 716, style = "slash")
# Add regression line in two pieces: from 0 to the start of the gap, and from
# the end of the gap to infinity.
ablineclip(lm(result ~ dis), col = "red", lwd = 2, x2 = x.axis.gap[1])
ablineclip(lm(result ~ dis.alt), col = "red", lwd = 2, x1 = x.axis.gap[1] + 33)
I need to map my Erosion values for different levels of tillage (colomns) with three levels of soil depth (rows (A1, A2, A3)). I want all of this to be shown as a barchart in a single plot.
Here is a reproducible example:
a<- matrix(c(1:36), byrow = T, ncol = 4)
rownames(a)<-(c("A1","B1","C1","A2","B2","C2","A3","B3","C3"))
colnames(a)<-(c("Int_till", "Redu_till", "mulch_till", "no_till"))
barplot(a[1,], xlab = "A1", ylab = "Erosion")
barplot(a[4,], xlab = "A2", ylab = "Erosion")
barplot(a[7,], xlab = "A3", ylab = "Erosion")
##I want these three barchart side by side in a single plot
## for comparison
### and need similar plots for all the "Bs" and "Cs"
### Lastly, i want these three plots in the same page.
I have seen people do similar things using "fill" in ggplot (for lines) and specifying the factor which nicely separates the chart for different categories but I tried doing it but always run into error maybe because my data is continuous.
If any body could help me with these two things.. It will be a great help. I will appreciate it.
Thank you!
We can use ggplot
library(reshape2)
library(ggplot2)
library(dplyr)
melt(a) %>%
ggplot(., aes(x = Var2, y = value, fill = Var1)) +
geom_bar(stat = 'identity',
position = position_dodge2(preserve = "single")) +
facet_wrap(~ Var1)
Set mfcol to specify a 3x3 grid and then for each row generate its bar plot. Also, you could consider adding the barplot argument ylim = c(0, max(a)) so that all graphs use the same Y axis. title and mtext can be used to set the overall title and various margin text as we do below. See ?par, ?title and ?mtext for more information.
opar <- par(mfcol = c(3, 3), oma = c(0, 3, 0, 0))
for(r in rownames(a)) barplot(a[r, ], xlab = r, ylab = "Erosion")
par(opar)
title("My Plots", outer = TRUE, line = -1)
mtext(LETTERS[1:3], side = 2, outer = TRUE, line = -1,
at = c(0.85, 0.5, 0.17), las = 2)
Just a minor question. I am trying to make a legend for the following plot.
# fitting the linear model
iris_lm = lm(Petal.Length ~ Sepal.Length, data = iris)
summary(iris_lm)
# calculating the confidence interval for the fitted line
preds = predict(iris_lm, newdata = data.frame(Sepal.Length = seq(4,8,0.1)),
interval = "confidence")
# making the initial plot
par(family = "serif")
plot(Petal.Length ~ Sepal.Length, data = iris, col = "darkgrey",
family = "serif", las = 1, xlab = "Sepal Length", ylab = "Pedal Length")
# shading in the confidence interval
polygon(
c(seq(8,4,-0.1), seq(4,8,0.1)), # all of the necessary x values
c(rev(preds[,3]), preds[,2]), # all of the necessary y values
col = rgb(0.2745098, 0.5098039, 0.7058824, 0.4), # the color of the interval
border = NA # turning off the border
)
# adding the regression line
abline(iris_lm, col = "SteelBlue")
# adding a legend
legend("bottomright", legend = c("Fitted Values", "Confidence Interval"),
lty = c(1,0))
Here's the output so far:
My goal is to put a box in the legend next to the "Confidence Interval" tab, and color it in the same shade that it is in the picture. Naturally, I thought to use the pch parameter. However, when I re-run my code with the additional legend option pch = c(NA, 25), I get the following:
It is not super noticeable, but if you look closely at the padding on the left margin of the legend, it actually has decreased, and the edge of the border is now closer to the line than I would like. Is there any way to work around this?
That's a curious behavior in legend(). I'm sure someone will suggest a ggplot2 alternative. However, legend() does offer a solution. This solution calls the function without plotting anything to capture the dimensions of the desired rectangle. The legend is then plotted with the elements you really want but no enclosing box (bty = "n"). The desired rectangle is added explicitly. I assume you mean pch = 22 to get the filled box symbol. I added pt.cex = 2 to make it a bit larger.
# Capture the confidence interval color, reusable variables
myCol <- rgb(0.2745098, 0.5098039, 0.7058824, 0.4)
legText <- c("Fitted Values", "Confidence Interval")
# Picking it up from 'adding a legend'
ans <- legend("bottomright", lty = c(1,0), legend = legText, plot = F)
r <- ans$rect
legend("bottomright", lty = c(1,0), legend = legText, pch = c(NA,22),
pt.bg = myCol, col = c(1, 0), pt.cex = 2, bty = "n")
# Draw the desired box
rect(r$left, r$top - r$h, r$left + r$w, r$top)
By the way, I don't think this will work without further tweaking if you place the legend on the left side.