diff --git a/.Rbuildignore b/.Rbuildignore index 696a616..73232c8 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -14,3 +14,4 @@ ^pkgdown$ ^Makefile$ ^CRAN-SUBMISSION$ +^CLAUDE\.md$ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7f22c9e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,121 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + + +## Standard Workflow + +1. **First think through the problem, read the codebase for relevant files, and write a plan to tasks/todo.md.** + +2. **The plan should have a list of todo items that you can check off as you complete them** + +3. **Before you begin working, check in with me and I will verify the plan.** + +4. **Then, begin working on the todo items, marking them as complete as you go.** + +5. **Please every step of the way just give me a high level explanation of what changes you made** + +6. **Make every task and code change you do as simple as possible. We want to avoid making any massive or complex changes. Every change should impact as little code as possible. Everything is about simplicity.** + +7. **Finally, add a review section to the todo.md file with a summary of the changes you made and any other relevant information.** + + +## Overview + +survminer is an R package for survival analysis and visualization built on ggplot2. It provides functions for drawing publication-ready survival curves with risk tables and diagnostic plots for Cox proportional hazards models. + +## Development Commands + + +### Load and test during the development + +```bash +Rscript -e "devtools::load_all()" +Rscript -e "devtools::document()" +Rscript -e "devtools::test()" +``` + + +### Package Checking + +```bash +Rscript -e "devtools::check()" +Rscript -e "urlchecker::url_check()" +``` + +### Install + +```bash +Rscript -e "devtools::install()" +``` + + +## Commit and pull request text strategy + +- neither add the following in commit message or pull request text: + +``` +Generated with [Claude Code](https://claude.ai/code) +Co-Authored-By: Claude " +``` +- don't use emojis like 📝, 📢, etc + + + +## Package Architecture + +### Core Components + +The package is organized into several functional areas: + +**Main Plotting Functions** (`R/ggsurvplot*.R`): +- `ggsurvplot_core.R`: Core survival curve plotting engine +- `ggsurvplot.R`: Main user-facing function with multiple dispatch +- `ggsurvplot_df.R`: Plot from data frame summaries +- `ggsurvplot_list.R`: Handle lists of survfit objects +- `ggsurvplot_facet.R`: Multi-panel faceted plots +- `ggsurvplot_group_by.R`: Group-wise plotting +- `ggsurvplot_combine.R`: Combine multiple survival curves + +**Cox Model Diagnostics** (`R/ggcox*.R`): +- `ggcoxdiagnostics.R`: Model fit diagnostics +- `ggcoxfunctional.R`: Functional form assessment +- `ggcoxzph.R`: Proportional hazards testing +- `ggforest.R`: Forest plots for hazard ratios + +**Utility Functions**: +- `utilities.R`: Core helper functions and imports +- `surv_summary.R`: Create tidy survival summaries +- `surv_pvalue.R`: Calculate log-rank test p-values +- `ggsurvtable.R`: Risk tables and event tables + +### Dependencies + +Built on tidyverse ecosystem with key dependencies: +- `ggplot2` (≥3.4.0): Core plotting +- `ggpubr` (≥0.1.6): Publication-ready themes +- `survival`: Survival analysis functions +- `dplyr`, `tidyr`, `purrr`: Data manipulation +- `ggtext`: Enhanced text formatting + +### Testing Structure + +Tests use `testthat` framework located in `tests/testthat/`: +- Test files follow `test-[function].R` naming convention +- `setup-load_data.R`: Common test data setup +- Main test entry point: `tests/testthat.R` + +### Documentation + +- Function documentation: `man/*.Rd` (auto-generated by roxygen2) +- Vignettes: `vignettes/*.Rmd` with detailed examples +- Package website: Built with pkgdown using `_pkgdown.yml` configuration +- Cheatsheet: `pkgdown/cheatsheet/survminer_cheatsheet.pdf` + +## Key Design Patterns + +1. **Function Hierarchy**: `ggsurvplot()` acts as dispatcher to specialized `ggsurvplot_*()` functions +2. **S3 Methods**: Uses S3 dispatch for print methods and plotting +3. **ggplot2 Integration**: Returns ggplot objects that can be further customized +4. **Modular Components**: Survival plots, risk tables, and censor plots are separate components that can be combined +5. **Data Pipeline**: `survfit` → `surv_summary()` → `ggsurvplot_df()` for custom workflows \ No newline at end of file diff --git a/NEWS.md b/NEWS.md index 44c436a..4de7d57 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,9 @@ ## Bug fixes +- Fix compatibility with ggplot2 development version (#681): Remove manual class assignment in `theme_survminer()` to ensure proper theme object construction +- Fix test suite compatibility with ggplot2 development version (#681): Update layer access syntax in tests to support both stable (`$layers`) and development (`@layers`) versions + # Survminer 0.5.0 diff --git a/R/ggsurvtheme.R b/R/ggsurvtheme.R index 06e276c..9193cc1 100644 --- a/R/ggsurvtheme.R +++ b/R/ggsurvtheme.R @@ -121,7 +121,6 @@ theme_survminer <- legend.text = legend.text, legend.title = legend.text ) - class(result) <- "theme" result } diff --git a/R/utilities.R b/R/utilities.R index dc69936..1fc2025 100644 --- a/R/utilities.R +++ b/R/utilities.R @@ -13,6 +13,14 @@ #' @importFrom rlang !! sym +# Check if an installed package version is superior to a specified version +# Version, pkg: character vector +is_pkg_version_sup<- function(pkg, version){ + vv <- as.character(utils::packageVersion(pkg)) + cc <- utils::compareVersion(vv, version) > 0 + cc +} + # Count the number of ggplots in a list .count_ggplots <- function(list.objects){ nplot <- 0 diff --git a/tests/testthat/test-ggsurvplot_facet.R b/tests/testthat/test-ggsurvplot_facet.R index dd88862..0473f0a 100644 --- a/tests/testthat/test-ggsurvplot_facet.R +++ b/tests/testthat/test-ggsurvplot_facet.R @@ -16,6 +16,12 @@ test_that("ggsurvplot_facet calculates pvalue for each facet", { fit <- survfit(Surv(time, status) ~ sex, data=kidney) p <- ggsurvplot_facet(fit, kidney, facet.by='disease', pval = TRUE) .build <- ggplot_build(p) - expect_equal(nrow(.build$plot$layer[[4]][['data']]), - length(unique(kidney[['disease']]))) + + # Handle ggplot2 dev version layer access syntax change + if (is_pkg_version_sup("ggplot2", "3.5.2")) { + observed <- nrow(.build$plot@layers[[4]][['data']]) + } else { + observed <- nrow(.build$plot$layers[[4]][['data']]) + } + expect_equal(observed, length(unique(kidney[['disease']]))) })