install.packages("tidyverse")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.2     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
df = read.csv("donor_ffa_for_share.csv")
df <- df %>%
  mutate(
    Sample.Type = gsub("\n", " ", Sample.Type),  # remove line breaks
    Sample.Type = trimws(Sample.Type)
  )
unique(df$Sample.Type)
## [1] "Breath aerosol <5µm" "MTS"
library(dplyr)
df <- df %>%
  mutate(across(c(FFU, log10_ffu), ~replace(., . == 0, 1)))


df$Sample.Type <- factor(df$Sample.Type,
  levels = c("Breath aerosol <5µm",
             "Breath aerosol ≥5µm",
             "MTS",
             "Saliva"))
p2 = ggplot(df, aes(x = Sample.Type, y = log10_ffu, color = Sample.Type)) +
    geom_boxplot(
    width = 0.04,   
    fill = "white",
    color = "grey",
    outlier.shape = NA
  ) +
  geom_violin(
    fill = NA
  ) +
  geom_jitter(
    width = 0.2
  ) +
  scale_color_manual(values = c(
    "Breath aerosol <5µm" = "#E69F00",
    "MTS" = "#009E73"
  )) +
  labs(y = "FFU (log10)", x = NULL) +
  theme_bw()

p2

Fig 2

library(tidyverse)

pcr <- read.csv("donor_pcr_for_share.csv", stringsAsFactors = FALSE)
ffa <- read.csv("donor_ffa_for_share.csv", stringsAsFactors = FALSE)
names(pcr)
## [1] "UniqueID"             "Sample.Type"          "Collection.Date"     
## [4] "Quantity..copies.mL." "b_lod"                "Note"                
## [7] "days_in_study"
names(ffa)
## [1] "UniqueID"        "Sample.Type"     "Collection.Date" "FFU"            
## [5] "log10_ffu"       "days_in_study"
pcr <- pcr %>%
  mutate(
    Sample.Type = gsub("\n", " ", Sample.Type),
    Sample.Type = trimws(Sample.Type),
    log10_viral = log10(Quantity..copies.mL. + 1)
  )
unique(pcr$Sample.Type)
## [1] "G2 5-Micron Impactor"       "G2 Fine Aerosol Condensate"
## [3] "Midturbinate Swab"          "Saliva"
pcr <- pcr %>%
  mutate(
    Sample.Type = case_when(
      Sample.Type == "G2 Fine Aerosol Condensate" ~ "Breath aerosol <5µm",
      Sample.Type == "G2 5-Micron Impactor" ~ "Breath aerosol ≥5µm",
      Sample.Type == "Midturbinate Swab" ~ "MTS",
      Sample.Type == "Saliva" ~ "Saliva",
      TRUE ~ NA_character_
    ),
    
    log10_viral = log10(Quantity..copies.mL. + 1)
  )
pcr$Sample.Type <- factor(pcr$Sample.Type,
  levels = c("Breath aerosol <5µm",
             "Breath aerosol ≥5µm",
             "MTS",
             "Saliva"))
ggplot(pcr, aes(x = Sample.Type, y = log10_viral, color = Sample.Type)) +
  
  geom_violin(
    scale = "width",
    trim = FALSE,
    fill = NA,
    linewidth = 1.2
  ) +
  
  geom_boxplot(
    width = 0.12,
    fill = "white",
    outlier.shape = NA
  ) +
  
  geom_jitter(
    width = 0.08,
    size = 2
  ) +
  
  scale_color_manual(values = c(
    "Breath aerosol <5µm" = "#E69F00",
    "Breath aerosol ≥5µm" = "#56B4E9",
    "MTS" = "#009E73",
    "Saliva" = "#CC79A7"
  )) +
  
  labs(
    y = "Log10 viral RNA",
    x = NULL,
    color = "Sample type"
  ) +
  
  theme_gray()
## Warning: Removed 27 rows containing non-finite outside the scale range
## (`stat_ydensity()`).
## Warning: Groups with fewer than two datapoints have been dropped.
## ℹ Set `drop = FALSE` to consider such groups for position adjustment purposes.
## Warning: Removed 27 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 27 rows containing missing values or values outside the scale range
## (`geom_point()`).