Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pharmaverse/ggsurvfit
https://github.com/pharmaverse/ggsurvfit
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/pharmaverse/ggsurvfit
- Owner: pharmaverse
- License: other
- Created: 2022-08-03T16:59:09.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-05-17T17:35:21.000Z (6 months ago)
- Last Synced: 2024-07-18T02:34:59.576Z (4 months ago)
- Language: R
- Homepage: http://www.danieldsjoberg.com/ggsurvfit/
- Size: 33 MB
- Stars: 68
- Watchers: 6
- Forks: 19
- Open Issues: 16
-
Metadata Files:
- Readme: README.Rmd
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
- Codemeta: codemeta.json
Awesome Lists containing this project
README
---
output: github_document
---```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%",
warning = FALSE
)
```[![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)
[](https://pharmaverse.org)## 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"))
```