forked from pharmaverse/ggsurvfit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.Rmd
172 lines (137 loc) · 7.9 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%",
warning = FALSE
)
```
# ggsurvfit <a href="https://www.danieldsjoberg.com/ggsurvfit/"><img src="man/figures/logo.png" align="right" height="138" /></a>
<!-- badges: start -->
[![R-CMD-check](https://github.com/pharmaverse/ggsurvfit/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/pharmaverse/ggsurvfit/actions/workflows/R-CMD-check.yaml)
[![Codecov test coverage](https://codecov.io/gh/pharmaverse/ggsurvfit/branch/main/graph/badge.svg)](https://app.codecov.io/gh/pharmaverse/ggsurvfit?branch=main)
[![CRAN status](https://www.r-pkg.org/badges/version/ggsurvfit)](https://CRAN.R-project.org/package=ggsurvfit)
[![](https://cranlogs.r-pkg.org/badges/ggsurvfit)](https://cran.r-project.org/package=ggsurvfit)
[<img src="http://pharmaverse.org/shields/ggsurvfit.svg">](https://pharmaverse.org)
<!-- badges: end -->
## Introduction
The **ggsurvfit** package eases the creation of time-to-event (aka survival) summary figures with ggplot2.
The concise and modular code creates images that are ready for publication or sharing.
Competing risks cumulative incidence is also supported via `ggcuminc()`.
## Why ggsurvfit?
- **Use ggplot2 functions:** Each **ggsurvfit** add-on function (e.g. `add_confidence_interval()`, `add_risktable()`, etc.) is written as a proper ggplot2 ['geom'](https://ggplot2.tidyverse.org/reference/index.html), meaning the package functions can be woven with ggplot2 functions seamlessly. You don't need to learn how to style the plot within the ggsurvfit functions: rather, rely on the suite of ggplot2 functions you already know.
- **Publishable Legends:** Raw variable names do not appear in the figure legend, e.g. `"sex=Female"`.
- **Limitless Customization:** You can modify the x-axis scales or any other plot feature and the risk table will still align with the plot.
- **Simple Saving:** Save individual images easily with `ggplot2::ggsave()`.
## Installation
Install **ggsurvfit** from CRAN with:
```r
install.packages("ggsurvfit")
```
You can install the development version from [GitHub](https://github.com/pharmaverse/ggsurvfit) with:
``` r
# install.packages("devtools")
devtools::install_github("pharmaverse/ggsurvfit")
```
## Examples
Review the [**figure gallery**](https://www.danieldsjoberg.com/ggsurvfit/articles/gallery.html) for many more examples.
The code below constructs a basic {ggsurvfit} figure without customization.
```{r example, fig.height=5.5}
library(ggsurvfit)
p <- survfit2(Surv(time, status) ~ surg, data = df_colon) |>
ggsurvfit(linewidth = 1) +
add_confidence_interval() +
add_risktable() +
add_quantile(y_value = 0.6, color = "gray50", linewidth = 0.75) +
scale_ggsurvfit()
```
Any figure created with {ggsurvfit} can be customized using {ggplot2} functions.
```{r}
p +
# limit plot to show 8 years and less
coord_cartesian(xlim = c(0, 8)) +
# update figure labels/titles
labs(
y = "Percentage Survival",
title = "Recurrence by Time From Surgery to Randomization",
)
```
## `survfit2()` vs `survfit()`
Both functions have identical inputs, so why do we need `survfit2()`?
The `survfit2()` tracks the environment from which the function was called, resulting in the following benefits.
- We can reliably remove the raw variable names from the figure legend, e.g. `SEX=Female`.
- P-values can be calculated with `survfit_p()` and added to figures.
- The items above are often *possible* using `survfit()`. However, by utilizing the calling [environment](https://adv-r.hadley.nz/environments.html) we are assured the correct elements are found, rather than crossing our fingers that the search path contains the needed elements.
## CDISC ADaM ADTTE
The package also includes gems for those using the [CDISC ADaM ADTTE v1.0](https://www.cdisc.org/standards/foundational/adam/adam-basic-data-structure-bds-time-event-tte-analyses-v1-0) data model.
If columns `"PARAM"` or `"PARAMCD"` are present in the data frame passed to `survfit2()`, their values will be used to construct default labels in the `ggsurvfit()` figure.
The event indicator in ADTTE data sets is named `"CNSR"` and is coded in the opposite way the survival package expects outcomes---`1 = 'censored'` and `0 = 'event'`.
This difference creates an opportunity for errors to be introduced in an analysis.
The **ggsurvfit** package exports a function called `Surv_CNSR()` to resolve this concern.
The function creates a survival object (e.g. `survival::Surv()`) that uses CDISC ADaM ADTTE coding conventions as the default values.
The function can be used in **ggsurvfit** as well as any other package that uses `survival::Surv()`.
```{r}
survfit(Surv_CNSR() ~ 1, adtte)
```
## Related Packages
```{r, related-pkgs, echo = FALSE}
gt_related_pkgs <-
dplyr::tribble(
~pkg, ~cran, ~survfit, ~survfit_risktable, ~cmprsk, ~cmprsk_risktable, ~ggplot2, ~gh_owner, ~gh_repo, ~gh_branch,
"ggsurvfit", "X", "X", "X", "X", "X", "X", "pharmaverse", "ggsurvfit", "main",
"survminer", "X", "X", "X", "X", "", "", "kassambara", "survminer", "master",
"KMunicate", "X", "X", "X", "", "", "", "ellessenne", "KMunicate-package", "master",
"GGally", "X", "X", "", "", "", "", "ggobi", "ggally", "master",
"ggfortify", "X", "X", "", "", "", "", "sinhrks", "ggfortify", "master",
"iwillsurvive", "", "X", "X", "", "", "", "ndphillips", "iwillsurvive", "master"
) |>
dplyr::mutate(
covr_badge =
sprintf(
"![](%s)",
glue::glue("https://codecov.io/gh/{gh_owner}/{gh_repo}/branch/{gh_branch}/graph/badge.svg")
)
) |>
dplyr::select(-dplyr::starts_with("gh_")) |>
gt::gt() |>
gt::cols_label(
pkg = gt::md("**Package**"),
cran = gt::md("**CRAN**"),
survfit = gt::md("**Estimates**"),
survfit_risktable = gt::md("**Risktable**"),
cmprsk = gt::md("**Estimates**"),
cmprsk_risktable = gt::md("**Risktable**"),
ggplot2 = gt::md("**{ggplot2} \nIntegration**"),
covr_badge = gt::md("**Code Coverage**")
) |>
gt::tab_spanner(c(survfit, survfit_risktable), label = gt::md("**Kaplan-Meier**")) |>
gt::tab_spanner(c(cmprsk, cmprsk_risktable), label = gt::md("**Competing Risks**")) |>
gt::fmt_markdown(c(pkg, covr_badge)) |>
gt::tab_footnote(
footnote = "Use any {ggplot2} function to modify plot area (including scales) and the risktable will align with the plot.",
locations = gt::cells_column_labels(ggplot2)
) |>
gt::text_transform(
locations =
gt::cells_body(columns = c(cran, survfit, survfit_risktable, cmprsk, cmprsk_risktable, ggplot2)),
fn = function(x) {
ifelse(x == "X", emoji::emoji("check_mark"), x)
}
) |>
gt::cols_align(align = "center", columns = c(cran, survfit, survfit_risktable, cmprsk, cmprsk_risktable, ggplot2)) |>
gt::tab_options(table.font.size = 13, data_row.padding = gt::px(1),
summary_row.padding = gt::px(1), grand_summary_row.padding = gt::px(1),
footnotes.padding = gt::px(1), source_notes.padding = gt::px(1),
row_group.padding = gt::px(1))
```
```{r related-pkgs-save, include = FALSE}
gt::gtsave(gt_related_pkgs, filename = here::here("man", "figures" , "README-gt-related-pkgs.png"))
```
```{r echo=FALSE}
knitr::include_graphics(path = here::here("man", "figures" , "README-gt-related-pkgs.png"))
```