Downloading libraries for project:
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.5.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── 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
library(lubridate)
library(patchwork)
## Warning: package 'patchwork' was built under R version 4.5.2
library(ggplot2)
library(readr)
library(cowplot)
## Warning: package 'cowplot' was built under R version 4.5.2
##
## Attaching package: 'cowplot'
##
## The following object is masked from 'package:patchwork':
##
## align_plots
##
## The following object is masked from 'package:lubridate':
##
## stamp
library(rlang)
##
## Attaching package: 'rlang'
##
## The following objects are masked from 'package:purrr':
##
## %@%, flatten, flatten_chr, flatten_dbl, flatten_int, flatten_lgl,
## flatten_raw, invoke, splice
library(knitr)
library(kableExtra)
## Warning: package 'kableExtra' was built under R version 4.5.2
##
## Attaching package: 'kableExtra'
##
## The following object is masked from 'package:dplyr':
##
## group_rows
Introduction - Need to do more Literature Review for the Narrative: Revisit when other sections are done: Methods - Re- do diagrams, explain flux theory, and theory needed for stats, locations, data cleaning, and more revisit when Results is done.
Results Section
Functions for creating figures:
# importing data sets
Flux_Data_With_Covars <- read_csv("C:/Users/KAUFMADA/Documents/R_Files/windrow-fluxes-co2-model-improvements/windrow-fluxes-co2-model-improvements/data_clean/Flux_Data_With_Covars.csv")
## Rows: 21090 Columns: 82
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): Pile, Chamber_Corrected, Turning_Status, Date, DATE_TIME
## dbl (77): Chamber_Elevation, DOY, air_temperature, RH, VPD, Tdew, wind_speed...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Functions to clean data
Plotting Moisture and Temperature for the experimental cycle.
plot_points_err <- function(df,
x, y_mean, y_se,
group,
cols = NULL,
shapes = NULL,
point_size = 2.0,
point_alpha = 0.85,
err_alpha = 0.6,
err_lwd = 0.4,
err_width = 0,
base_size = 12,
legend_position = "top",
drop_na = TRUE,
x_lab = NULL,
y_lab = NULL,
legend_title = NULL,
vline = NULL,
vlines_red = NULL,
vlines_black = NULL,
vline_lwd = 0.4,
vline_alpha = 0.8,
vline_linetype = "dashed",
vline_red_linetype = "solid",
vline_black_linetype = "dashed",
vline_red_colour = "#9b1c31",
vline_black_colour = "#000000"){
# capture column names
x <- enquo(x)
y_mean <- enquo(y_mean)
y_se <- enquo(y_se)
group <- enquo(group)
# optionally drop NA rows for required columns
if (drop_na) {
df <- df[complete.cases(
df[, c(as_name(x), as_name(y_mean), as_name(y_se), as_name(group))]
), ]
}
p <- ggplot(df, aes(x = !!x, y = !!y_mean)) +
# error bars first (so points draw on top)
geom_errorbar(
aes(ymin = (!!y_mean) - (!!y_se),
ymax = (!!y_mean) + (!!y_se),
colour = !!group),
width = err_width,
alpha = err_alpha,
linewidth = err_lwd
)
if (!is.null(vlines_red)) {
p <- p + geom_vline(
xintercept = vlines_red,
colour = vline_red_colour,
linetype = vline_red_linetype,
linewidth = vline_lwd,
alpha = vline_alpha
)
}
if (!is.null(vlines_black)) {
p <- p + geom_vline(
xintercept = vlines_black,
colour = vline_black_colour,
linetype = vline_black_linetype,
linewidth = vline_lwd,
alpha = vline_alpha
)
}
p <- p +
# points (no lines)
geom_point(
aes(colour = !!group, shape = !!group),
size = point_size,
alpha = point_alpha
) +
theme_bw(base_size = base_size) +
theme(
legend.position = legend_position,
panel.grid.minor = element_blank()
)
# manual scales if provided (keeps consistent styling across plots)
if (!is.null(cols)) {
p <- p + scale_colour_manual(values = cols)
}
if (!is.null(shapes)) {
p <- p + scale_shape_manual(values = shapes)
}
# ── LABELS SECTION ─────────────────────────────
if (!is.null(x_lab) || !is.null(y_lab) || !is.null(legend_title)) {
p <- p + labs(
x = x_lab,
y = y_lab,
colour = legend_title,
shape = legend_title
)
}
return(p)
}
Pile Temperature Plot using Daily Average Values Pile Moisture Using Daily Average Values
#turning data to add to plots if needed
turns_both_red <- c(159, 186, 208, 234, 262, 290)
turns_control_black <- c(173, 191, 222, 249, 276)
turns_both_red_week <- c(159, 186, 208, 234, 262, 290)/7
turns_control_black_week <- c(173, 191, 222, 249, 276)/7
pile_cols <- c(C = "#000000", E = "#9b1c31")
pile_shapes <- c(C = 16, E = 17)
fig_moist_doy <- plot_points_err(
daily_pile_doy,
x = DOY,
y_mean = pile_moist_mean,
y_se = pile_moist_se,
group = Pile,
cols = pile_cols,
shapes = pile_shapes,
point_size = 1.8,
x_lab = "Day of year",
y_lab = expression("Volumetric water content (m"^3*" m"^-3*")"),
legend_title = "Pile",
vlines_red = turns_both_red,
vlines_black = turns_control_black,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_moist_doy
fig_moist_weekly <- plot_points_err(
weekly_moist,
x = week,
y_mean = mean,
y_se = se,
group = Pile,
cols = pile_cols,
shapes = pile_shapes,
point_size = 1.8,
x_lab = "Week of year",
y_lab = expression("Volumetric water content (m"^3*" m"^-3*")"),
legend_title = "Pile",
vlines_red = turns_both_red_week,
vlines_black = turns_control_black_week,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_moist_weekly
fig_temp_doy <- plot_points_err(
daily_pile_doy,
x = DOY,
y_mean =pile_temp_mean,
y_se = pile_temp_se,
group = Pile,
cols = pile_cols,
shapes = pile_shapes,
point_size = 1.8,
x_lab = "Day of year",
y_lab = expression("Pile Temperature Degrees Celsius"),
legend_title = "Pile",
vlines_red = turns_both_red,
vlines_black = turns_control_black,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_temp_doy
fig_temp_weekly <- plot_points_err(
weekly_temp,
x = week,
y_mean =mean,
y_se = se,
group = Pile,
cols = pile_cols,
shapes = pile_shapes,
point_size = 1.8,
x_lab = "Week of year",
y_lab = expression("Pile Temperature Degrees Celsius"),
legend_title = "Pile",
vlines_red = turns_both_red_week,
vlines_black = turns_control_black_week,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_temp_weekly
Creating Tables with Pile Variables:
pile_vars_temp <- Cleaned_Data %>%
filter(!is.na(pile_temp)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_temp = mean(pile_temp),
sd_temp = sd(pile_temp),
se_temp = sd_temp/sqrt(n_obs)
)
pile_vars_water <- Cleaned_Data %>%
filter(!is.na(pile_moist)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_moist = mean(pile_moist),
sd_moist = sd(pile_moist),
se_moist = sd_moist/sqrt(n_obs)
)
Displaying Tables of Summary Stats for Moisture and Temperature
| Pile | n_obs | mean_moist | sd_moist | se_moist |
|---|---|---|---|---|
| C | 9177 | 0.490 | 0.327 | 0.003 |
| E | 9403 | 0.787 | 0.244 | 0.003 |
| Pile | n_obs | mean_temp | sd_temp | se_temp |
|---|---|---|---|---|
| C | 9192 | 54.069 | 8.992 | 0.094 |
| E | 9420 | 51.778 | 12.812 | 0.132 |
Examining Measured Fluxes by Pile
library(readxl)
co2_raw <- read.csv("C:/Users/KAUFMADA/Documents/R_Files/windrow-fluxes-co2-model-improvements/windrow-fluxes-co2-model-improvements/data_clean/CO2_R_2_filtered.csv")
ch4_raw <- read.csv("C:/Users/KAUFMADA/Documents/R_Files/windrow-fluxes-co2-model-improvements/windrow-fluxes-co2-model-improvements/data_clean/CH4_R_2_filtered.csv")
n2o_raw <- read.csv("C:/Users/KAUFMADA/Documents/R_Files/windrow-fluxes-co2-model-improvements/windrow-fluxes-co2-model-improvements/data_clean/N2O_R_2_filtered.csv")
Making Chart with Average values by Pile and SD,SE
pile_vars_co2 <- co2_raw %>%
filter(!is.na(FCO2_DRY.LIN)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_co2 = mean(FCO2_DRY.LIN),
sd_co2 = sd(FCO2_DRY.LIN),
se_co2 = sd_co2/sqrt(n_obs)
)
pile_vars_ch4 <- ch4_raw %>%
filter(!is.na(FCH4_DRY.LIN)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_ch4 = mean(FCH4_DRY.LIN),
sd_ch4 = sd(FCH4_DRY.LIN),
se_ch4 = sd_ch4/sqrt(n_obs)
)
pile_vars_n2o <- n2o_raw %>%
filter(!is.na(FN2O_DRY.LIN)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_n2o = mean(FN2O_DRY.LIN),
sd_n2o = sd(FN2O_DRY.LIN),
se_n2o = sd_n2o/sqrt(n_obs)
)
Displaying Average Values for Each Trace Gas:
kable(
pile_vars_co2,
digits = 3,
caption = "Summary statistics for co2 flux by pile."
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("bordered", "striped")
)
| Pile | n_obs | mean_co2 | sd_co2 | se_co2 |
|---|---|---|---|---|
| C | 5064 | 190.076 | 202.288 | 2.843 |
| E | 4215 | 191.757 | 193.987 | 2.988 |
kable(
pile_vars_ch4,
digits = 3,
caption = "Summary statistics for ch4 flux by pile."
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("bordered", "striped")
)
| Pile | n_obs | mean_ch4 | sd_ch4 | se_ch4 |
|---|---|---|---|---|
| C | 5355 | 7055.016 | 11741.80 | 160.456 |
| E | 4937 | 6594.771 | 10324.23 | 146.935 |
kable(
pile_vars_n2o,
digits = 3,
caption = "Summary statistics for n2o flux by pile."
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("bordered", "striped")
)
| Pile | n_obs | mean_n2o | sd_n2o | se_n2o |
|---|---|---|---|---|
| C | 6906 | 157.089 | 295.036 | 3.550 |
| E | 6911 | 98.481 | 245.689 | 2.955 |
Creating Daily and Weekly Plots for all Fluxes
# N2O
daily_n2o <- n2o_raw %>%
mutate(DOY = floor(DOY)) %>% # collapse fractional DOY
group_by(Pile, DOY) %>%
summarise(
n_obs = sum(!is.na(FN2O_DRY.LIN)),
n2o_mean = mean(FN2O_DRY.LIN, na.rm = TRUE),
n2o_se = se(FN2O_DRY.LIN),
.groups = "drop"
) %>%
filter(n_obs >= 3) # tweak threshold if needed
# CO2
daily_co2 <- co2_raw %>%
mutate(DOY = floor(DOY)) %>%
group_by(Pile, DOY) %>%
summarise(
n_obs = sum(!is.na(FCO2_DRY.LIN)),
co2_mean = mean(FCO2_DRY.LIN, na.rm = TRUE),
co2_se = se(FCO2_DRY.LIN),
.groups = "drop"
) %>%
filter(n_obs >= 3)
# CH4
daily_ch4 <- ch4_raw %>%
mutate(DOY = floor(DOY)) %>%
group_by(Pile, DOY) %>%
summarise(
n_obs = sum(!is.na(FCH4_DRY.LIN)),
ch4_mean = mean(FCH4_DRY.LIN, na.rm = TRUE),
ch4_se = se(FCH4_DRY.LIN),
.groups = "drop"
) %>%
filter(n_obs >= 3)
weekly_n2o <- n2o_raw %>%
mutate(
week = floor((DOY - 1) / 7) + 1
) %>%
group_by(Pile, week) %>%
summarise(
n_obs = sum(!is.na(FN2O_DRY.LIN)),
n2o_mean = mean(FN2O_DRY.LIN, na.rm = TRUE),
n2o_se = sd(FN2O_DRY.LIN, na.rm = TRUE) / sqrt(n_obs),
DOY = mean(DOY, na.rm = TRUE), # x-position for plotting (optional but useful)
.groups = "drop"
) %>%
filter(n_obs >= 3)
# CO2
weekly_co2 <- co2_raw %>%
mutate(
week = floor((DOY - 1) / 7) + 1
) %>%
group_by(Pile, week) %>%
summarise(
n_obs = sum(!is.na(FCO2_DRY.LIN)),
co2_mean = mean(FCO2_DRY.LIN, na.rm = TRUE),
co2_se = sd(FCO2_DRY.LIN, na.rm = TRUE) / sqrt(n_obs),
DOY = mean(DOY, na.rm = TRUE),
.groups = "drop"
) %>%
filter(n_obs >= 3)
# CH4
weekly_ch4 <- ch4_raw %>%
mutate(
week = floor((DOY - 1) / 7) + 1
) %>%
group_by(Pile, week) %>%
summarise(
n_obs = sum(!is.na(FCH4_DRY.LIN)),
ch4_mean = mean(FCH4_DRY.LIN, na.rm = TRUE),
ch4_se = sd(FCH4_DRY.LIN, na.rm = TRUE) / sqrt(n_obs),
DOY = mean(DOY, na.rm = TRUE),
.groups = "drop"
) %>%
filter(n_obs >= 3)
Plotting Values
fig_co2_daily <- plot_points_err(
daily_co2,
x = DOY, y_mean = co2_mean, y_se = co2_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red,
vlines_black = turns_control_black,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_co2_daily
fig_co2_weekly <- plot_points_err(
weekly_co2,
x = week, y_mean = co2_mean, y_se = co2_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red_week,
vlines_black = turns_control_black_week,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_co2_weekly
fig_ch4_daily <- plot_points_err(
daily_ch4,
x = DOY, y_mean = ch4_mean, y_se = ch4_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red,
vlines_black = turns_control_black,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_ch4_daily
fig_ch4_weekly <- plot_points_err(
weekly_ch4,
x = week, y_mean = ch4_mean, y_se = ch4_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red_week,
vlines_black = turns_control_black_week,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_ch4_weekly
fig_n2o_daily <- plot_points_err(
daily_n2o,
x = DOY, y_mean = n2o_mean, y_se = n2o_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red,
vlines_black = turns_control_black,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_n2o_daily
fig_n2o_weekly <- plot_points_err(
weekly_n2o,
x = week, y_mean = n2o_mean, y_se = n2o_se,
group = Pile,
cols = pile_cols, shapes = pile_shapes,
point_size = 1.4,
vlines_red = turns_both_red_week,
vlines_black = turns_control_black_week,
vline_red_linetype = "solid",
vline_black_linetype = "dashed"
)
fig_n2o_weekly
Looking at A Combination of all three gases using established 100 year conversion, these can easily be changed:
Co2 1 Ch4 28 N2o 265
To combine Trace Gases as cleaning was done on a per measurement basis:
Method 1: Looking at trace gases where all there trace gases where taken at once Method 2: Averaging Per Day and Comparing Daily Average GHG Potential Method 3: Weekly Averaging and Comparing Weekly GHG Potential
Method to keep only rows with all three trace gases
Flux_All_Gases_QC <- Flux_Data_With_Covars %>%
filter(
# CO2
FCO2_DRY.LIN > 0,
FCO2_DRY.LIN_R2 > 0.9,
# CH4
FCH4_DRY.LIN > 0,
FCH4_DRY.LIN_R2 > 0.9,
# N2O
FN2O_DRY.LIN > 0,
FN2O_DRY.LIN_R2 > 0.9
)
Flux_Data_With_Covars %>%
summarise(
total_obs = n(),
pass_all = sum(
FCO2_DRY.LIN > 0 & FCO2_DRY.LIN_R2 > 0.9 &
FCH4_DRY.LIN > 0 & FCH4_DRY.LIN_R2 > 0.9 &
FN2O_DRY.LIN > 0 & FN2O_DRY.LIN_R2 > 0.9,
na.rm = TRUE
),
percent_retained = 100 * pass_all / total_obs
)
## # A tibble: 1 × 3
## total_obs pass_all percent_retained
## <int> <int> <dbl>
## 1 21090 5558 26.4
Flux_All_Gases_QC <- Flux_All_Gases_QC %>%
mutate(
# keep units explicit
CO2_umol = FCO2_DRY.LIN, # µmol m-2 s-1
N2O_umol = FN2O_DRY.LIN, # µmol m-2 s-1
CH4_umol = FCH4_DRY.LIN * 0.001, # nmol -> µmol
# GWP100 CO2-equivalent (µmol CO2-eq m-2 s-1)
GHG_CO2e_umol = CO2_umol + 28 * CH4_umol + 265 * N2O_umol
)
Summary Stats of Co2e by pile when looking at measurements where all three gases passed qa/qc
pile_vars_co2e <- Flux_All_Gases_QC %>%
filter(!is.na(GHG_CO2e_umol)) %>%
group_by(Pile) %>%
summarise(
n_obs = n(),
mean_CO2e = mean(GHG_CO2e_umol),
sd_CO2e = sd(GHG_CO2e_umol),
se_CO2e = sd_CO2e/sqrt(n_obs)
)
kable(
pile_vars_co2e,
digits = 3,
caption = "Summary statistics for co2e flux by pile."
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("bordered", "striped")
)
| Pile | n_obs | mean_CO2e | sd_CO2e | se_CO2e |
|---|---|---|---|---|
| C | 3269 | 59570.66 | 101672.24 | 1778.259 |
| E | 2289 | 40046.13 | 96185.23 | 2010.414 |
We are going to write the code to plot this but we will plot all three together - as this is only the first method of plotting the values.