{"id":32206598,"url":"https://github.com/biostats-dev/ggsurveillance","last_synced_at":"2026-02-20T16:02:06.609Z","repository":{"id":274195588,"uuid":"913966218","full_name":"biostats-dev/ggsurveillance","owner":"biostats-dev","description":"Tools And ggplot Extensions For Infectious Disease Surveillance And Outbreak Investigation","archived":false,"fork":false,"pushed_at":"2025-11-27T15:53:40.000Z","size":8442,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-09T01:46:28.293Z","etag":null,"topics":["epidemiology","infectious-disease-surveillance","infectious-diseases","outbreaks","r","r-package","rstats"],"latest_commit_sha":null,"homepage":"https://ggsurveillance.biostats.dev/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/biostats-dev.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"biostats-dev"}},"created_at":"2025-01-08T17:33:06.000Z","updated_at":"2025-11-27T15:49:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"53bee093-d8c6-494d-be2d-84f6291e31c6","html_url":"https://github.com/biostats-dev/ggsurveillance","commit_stats":null,"previous_names":["biostats-dev/ggsurveillance"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/biostats-dev/ggsurveillance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/biostats-dev%2Fggsurveillance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/biostats-dev%2Fggsurveillance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/biostats-dev%2Fggsurveillance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/biostats-dev%2Fggsurveillance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/biostats-dev","download_url":"https://codeload.github.com/biostats-dev/ggsurveillance/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/biostats-dev%2Fggsurveillance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29530132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T00:57:22.232Z","status":"online","status_checked_at":"2026-02-17T02:00:08.105Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["epidemiology","infectious-disease-surveillance","infectious-diseases","outbreaks","r","r-package","rstats"],"created_at":"2025-10-22T05:32:19.767Z","updated_at":"2026-02-20T16:02:06.603Z","avatar_url":"https://github.com/biostats-dev.png","language":"R","funding_links":["https://github.com/sponsors/biostats-dev"],"categories":[],"sub_categories":[],"readme":"# ggsurveillance \u003cimg src=\"man/figures/logo.svg\" alt=\"logo\" align=\"right\" width=\"120\" height=\"139\" style=\"border: none; float: right;\"/\u003e\n\n\u003c!-- badges: start --\u003e\n\n[![CRAN status](https://www.r-pkg.org/badges/version/ggsurveillance)](https://CRAN.R-project.org/package=ggsurveillance) [![Download](https://cranlogs.r-pkg.org/badges/grand-total/ggsurveillance)](https://cran.r-project.org/package=ggsurveillance) [![Lifecycle](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![R-CMD-check](https://github.com/biostats-dev/ggsurveillance/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/biostats-dev/ggsurveillance/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/biostats-dev/ggsurveillance/graph/badge.svg)](https://app.codecov.io/gh/biostats-dev/ggsurveillance)\n\n\u003c!-- badges: end --\u003e\n\n**ggsurveillance** is an R package with helpful tools and ggplot extensions for epidemiology, especially infectious disease surveillance and outbreak investigation. All functions provide tidy functional interfaces for easy integration with the tidyverse. For documentation and vignettes see: \u003ca href=\"https://ggsurveillance.biostats.dev\" target=\"_blank\"\u003eggsurveillance.biostats.dev\u003c/a\u003e\n\n## Key Features\n\n### 📊 Epidemic Curves\n-   `geom_epicurve()`: A ggplot geom for plotting epicurves.\n    -   `stat_bin_date()`: Date interval (week, month etc.) based binning of case numbers with perfect alignment with e.g. reporting week.\n    -   `geom_epicurve_text()` and `geom_epicurve_point()`: New geoms to easily add text annotations or points to cases in epidemic curves.\n    -   `geom_vline_year()`: Automatically detects the turn of the year(s) from the date or datetime axis and draws a vertical line.\n    -   `scale_y_cases_5er()`: For better (case) count axis breaks and positioning.\n\n### 📅 Date \u0026 Time Transformations\n-   `bin_by_date()`: A `tidyverse`-compatible function for flexible date-based aggregation (binning).\n\n-   `align_dates_seasonal()`: Align surveillance data for seasonal plots (e.g. flu season).\n\n### 📈 Specialized Epi Visualizations\n-   `geom_bar_diverging()`: A geom for diverging bar charts, which can be used to plot population pyramids, likert scales (sentiment analyses) and other data with opposing categories, like vaccination status or imported vs autochthonous (local) infections.\n    -   `stat_diverging()` for easy labeling of these charts with category counts/percentages or total counts/percentages\n    -   `scale_x_continuous_diverging()` for symmetric diverging scales\n    -   `geom_area_diverging()` for continuous variables (e.g. changes over time)\n\n-   `geom_epigantt()`: A geom for epigantt plots. Helpful to visualize overlapping time intervals for contact tracing (e.g. hospital outbreaks).\n    -   including `scale_y_discrete_reverse()` which reverses the order of the categorical scale.\n\n### 🎨 ggplot2 Extensions \u0026 Theme Modifications\n-   More `ggplot2` add-ons: \n    -   `guide_axis_nested_date()`: An axis guide for creating nested date labels for hierarchical time periods (e.g., year \u003e month \u003e day).\n    -   `geom_label_last_value()`: A geom for labeling the last value of a time series (e.g. `geom_line()`). \n    -   `label_power10()`: A `ggplot2`-compatible labeling function to format numbers in scientific notation with powers of 10 (e.g., $2 \\times 10^5$).\n\n-   `theme_mod_` functions for ggplot2 theme modifications:\n\n    -   `theme_mod_legend_position()` etc. to adjust the legend positions.\n    -   `theme_mod_rotate_x_axis_labels()` etc. for rotating x axis labels.\n    -   `theme_mod_remove_minor_grid()` etc. to remove the minor grid lines (x, y or both) or all grid lines.\n\n### 🔧 Other Utilities\n-   `create_agegroups()`: Create reproducible age groups with highly customizable labels.\n\n-   Additional utilities: `geometric_mean()`, `expand_counts()`, and more\n\n## Examples\n\n### Creating Epicurves\n\n``` r\nlibrary(ggplot2)\nlibrary(tidyr)\nlibrary(outbreaks)\nlibrary(ggsurveillance)\n\nsars_canada_2003 |\u003e #SARS dataset from outbreaks\n  pivot_longer(starts_with(\"cases\"), \n               names_prefix = \"cases_\", \n               names_to = \"origin\") |\u003e\n  ggplot(aes(x = date, weight = value, fill = origin)) +\n  geom_epicurve(date_resolution = \"week\") +\n  geom_epicurve_text(aes(label = ifelse(origin == \"travel\", \"🛪\", \"\")), \n                     date_resolution = \"week\", size = 1.5, color = \"white\") + \n  scale_x_date(date_labels = \"W%V'%g\", date_breaks = \"2 weeks\") +\n  scale_y_cases_5er() +\n  scale_fill_brewer(type = \"qual\", palette = 6) +\n  theme_classic()\n```\n\n![Epicurve of the 2003 SARS outbreak in Canada](man/figures/epicurve_readme.png)\n\n### Align surveillance data for seasonal comparison\n\n``` r\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(ggsurveillance)\n\ninfluenza_germany |\u003e\n  filter(AgeGroup == \"00+\") |\u003e\n  align_dates_seasonal(dates_from = ReportingWeek,\n                       date_resolution = \"isoweek\",\n                       start = 28) -\u003e df_flu_aligned\n\nggplot(df_flu_aligned, aes(x = date_aligned, y = Incidence)) +\n  stat_summary(\n    aes(linetype = \"Historical Median (Min-Max)\"), data = . %\u003e% filter(!current_season), \n    fun.data = median_hilow, geom = \"ribbon\", alpha = 0.3) +\n  stat_summary(\n    aes(linetype = \"Historical Median (Min-Max)\"), data = . %\u003e% filter(!current_season), \n    fun = median, geom = \"line\") +\n  geom_line(\n    aes(linetype = \"2024/25\"), data = . %\u003e% filter(current_season), \n        colour = \"dodgerblue4\", linewidth = 2) +\n  labs(linetype = NULL) +\n  scale_x_date(date_breaks = \"month\", date_labels = \"%b'%Y\", \n               guide = guide_axis_nested_date()) +\n  theme_bw() +\n  theme_mod_legend_position(position.inside = c(0.2, 0.8))\n```\n\n![Seasonal influenza data from Germany by age group](man/figures/seasonal_plot_readme.png)\n\n### Create Epigantt plots to visualize exposure intervals in outbreaks\n\n``` r\nlibrary(dplyr)\nlibrary(tidyr)\nlibrary(ggplot2)\nlibrary(ggsurveillance)\n\n# Transform to long format\nlinelist_hospital_outbreak |\u003e\n  pivot_longer(\n    cols = starts_with(\"ward\"),\n    names_to = c(\".value\", \"num\"),\n    names_pattern = \"ward_(name|start_of_stay|end_of_stay)_([0-9]+)\",\n    values_drop_na = TRUE\n  ) -\u003e df_stays_long\n\nlinelist_hospital_outbreak |\u003e\n  pivot_longer(cols = starts_with(\"pathogen\"), values_to = \"date\") -\u003e df_detections_long\n\n# Plot\nggplot(df_stays_long) +\n  geom_epigantt(aes(y = Patient, xmin = start_of_stay, xmax = end_of_stay, color = name)) +\n  geom_point(aes(y = Patient, x = date, shape = \"Date of pathogen detection\"), \n    data = df_detections_long) +\n  scale_y_discrete_reverse() +\n  theme_bw() +\n  theme_mod_legend_bottom()\n```\n\n![Epigantt chart of a fictional hospital outbreak](man/figures/epigantt_plot_readme.png)\n\n### Create Diverging Bar Charts\n\nUseful for population pyramids, vaccination status, likert scales (sentiment) etc.\n\n``` r\nlibrary(dplyr)\nlibrary(ggplot2)\nlibrary(ggsurveillance)\n\npopulation_german_states |\u003e\n  filter(state %in% c(\"Berlin\", \"Mecklenburg-Vorpommern\"), age \u003c 90) |\u003e\n  ggplot(aes(y = age, fill = sex, weight = n)) +\n  geom_bar_diverging(width = 1) +\n  geom_vline(xintercept = 0) +\n  scale_x_continuous_diverging(n.breaks = 7) +\n  facet_wrap(~state, scales = \"free_x\") +\n  theme_bw() +\n  theme_mod_legend_top()\n```\n\n![Population pyramids of Berlin and Mecklenburg-Vorpommern](man/figures/diverging_bar_chart_age_pyramid_readme.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbiostats-dev%2Fggsurveillance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbiostats-dev%2Fggsurveillance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbiostats-dev%2Fggsurveillance/lists"}