Randomized clinical trial evaluating the practical and biological limits of colostral IgG dosing in dairy calves
Author
Dini Hapukotuwa and Sam Rowe
Published
October 28, 2025
Authors and affiliations
Dini Hapukotuwa1, John House1, Katie Denholm2, and Sam Rowe1
1Sydney School of Veterinary Science, University of Sydney, Camden 2750, NSW, Australia
2School of Biodiversity, One Health and Veterinary Medicine, University of Glasgow, Glasgow, Scotland
Acknowledgements
We would like to thank the participating farm, Anna Waldron, and Jennie Mohler
Study objectives
Determine the effect of oral IgG dose (200, 250, 300, 350g IgG) on serum IgG
A secondary objective was to determine if the effect of oral IgG on serum IgG is modified by other variables.
Determine the effect of oral IgG dose (200, 250, 300, 350g IgG) on apparent efficiency of absorption
To identify the practically feasible dose of colostral IgG when considering IgG supply (i.e., IgG harvested and stored), demand (number of calves to be fed), and practical constraints on dose (colostral IgG concentration and volume limits per calf)
Identify if volume impacts IgG independently of total dose administered
Causal diagram (DAG)
Based on this causal diagram, colostrum IgG concentration and volume should be included as covariates as they could provide a backdoor path (confounding bias). Other variables do not need to be included.
The number of excluded animals is low and similar between each group. This indicates that there is less bias between groups.
There is a higher proportion of Angus in the 200g group compared to the other groups. This may create bias if Angus was different in their response to oral IgG. When results were adjusted for breed below, it was found that there was no significant difference between both, and therefore there is no bias in the numbers above.
Comparison of treatment groups after exclusions, losses to follow-up and calves changing treatment group (n = 6)
Show the code
data <- data %>%mutate(originally_assiged_to_other_dose =case_when( tx_group == tx_assigned ~0, T ~1 ) %>% as_factor)data <- data %>%filter(excluded==0, lost_to_follow_up ==0,!is.na(tx_group))
Objective 1 - Effect of oral IgG on serum IgG in Holstein calves
Plots
Box and whisker plot showing serum IgG for calves randomized to 4 doses of colostrum.
Show the code
figure <-ggplot(data %>%filter(breed =="Holstein"), aes(x = tx_group, y = igg)) +# Removed fill from aes()# Add shaded regionsgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10), fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18), fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25), fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf), fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Add boxplot with fixed fill colorgeom_boxplot(fill ="white", # Set all boxplots to light blueoutlier.shape =16, outlier.size =2, alpha =1) +# Labelslabs(title ="",x ="Oral IgG dose",y ="Serum IgG (g/L)",fill ="Treatment" ) +# Custom themetheme_minimal() +coord_cartesian(ylim =c(0, 60)) +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure
Show the code
ggsave(filename ="figure 1.tiff", # File nameplot = figure, # ggplot object to savedevice ="tiff", # Output formatwidth =4, # Width in inchesheight =4, # Height in inchesdpi =200# Resolution in dots per inch)
This box and whisker plot is comparing the IgG levels across treatment groups (250, 300 and 350g), relative to baseline (200g) for Holstein animals.
There appears to be a dose dependent effect of oral IgG on serum IgG in Holstein calves.
Show the code
prop_data <- data %>%filter(breed =="Holstein") %>%filter(!is.na(tx_group), !is.na(igg_category)) %>%group_by(tx_group, igg_category) %>%summarize(count =n(), .groups ="drop") %>%group_by(tx_group) %>%mutate(proportion = count /sum(count))figure <-ggplot(prop_data, aes(x = tx_group, y = proportion, fill = igg_category)) +geom_bar(stat ="identity", position ="stack") +# Add text labels for proportionsgeom_text(aes(label = scales::percent(proportion, accuracy =1)), # Format proportion as percentageposition =position_stack(vjust =0.5), # Place text in the middle of the stacked barssize =3, # Adjust text sizefamily ="Times New Roman"# Ensure consistent font ) +labs(title ="",x ="Oral IgG dose",y ="Proportion",fill ="IgG Levels" ) +scale_y_continuous(labels = scales::percent) +# Show percentagestheme_minimal() +scale_fill_manual(values =c('#A2D9CE', '#C3D69B', '#FFF2CC', "pink")) +theme(panel.border =element_rect(color ="black", fill =NA, linewidth =1),text =element_text(family ="Times New Roman") )figure
Show the code
ggsave(filename ="figure 2.tiff", # File nameplot = figure, # ggplot object to savedevice ="tiff", # Output formatwidth =6, # Width in inchesheight =5, # Height in inchesdpi =200# Resolution in dots per inch)
This graph shows the proportion of Holstein calves from each dose group that fall into the new proposed categories by Godden and colleagues (2019) for passive immunity in calves.
Lombard and collaborators (2020) proposed that >40% calves should be able to achieve an excellent level of passive immunity when given 300g if feeding once.
It is evident from this graph that this is also possible at a dose of 250g as 75% Holstein calves in the study were able to achieve a serum IgG >=25g/L IgG.
Statistical models
Main effects linear regression
Model includes concentration and volume as covariates (multi-colinearity. model rejected)
OK: No outliers detected.
- Based on the following method and threshold: cook (0.8).
- For variable: (Whole model)
Show the code
check_collinearity(lm)
Term
VIF
VIF_CI_low
VIF_CI_high
SE_factor
Tolerance
Tolerance_CI_low
Tolerance_CI_high
tx_group
82.54447
68.10437
100.09191
2.086642
0.0121147
0.0099908
0.0146833
concentration
37.91441
31.33392
45.92243
6.157468
0.0263752
0.0217759
0.0319143
vol
92.55015
76.34800
112.23627
9.620299
0.0108050
0.0089098
0.0130979
Decision - model is unstable due to multi-colinearity (volume and concentration). Will include volume only as more data support the link between volume and AEA.
Model includes volume as covariate
Show the code
lm <-lm(igg ~ tx_group + vol, data = data)summary(lm)
Call:
lm(formula = igg ~ tx_group + vol, data = data)
Residuals:
Min 1Q Median 3Q Max
-23.1171 -4.6460 -0.0524 4.7329 19.6052
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 28.068 2.549 11.009 < 2e-16 ***
tx_group250g 5.553 1.359 4.086 5.34e-05 ***
tx_group300g 8.388 1.674 5.011 8.24e-07 ***
tx_group350g 13.178 1.884 6.993 1.19e-11 ***
vol -1.422 1.047 -1.358 0.175
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.058 on 387 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.1982, Adjusted R-squared: 0.1899
F-statistic: 23.92 on 4 and 387 DF, p-value: < 2.2e-16
There is a significant difference between the means of the 250g vs 350g and 300g and 350g groups. This shows that there is a linear effect of oral IgG dose and serum IgG. This is consistent with Godden’s principle of a dose-dependant effect of oral IgG and serum IgG.
Show the code
figure <-ggplot(data, aes(x = tx_group, y = igg)) +# Removed fill from aes()# Add shaded regionsgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10), fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18), fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25), fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf), fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Add boxplot with fixed fill colorgeom_boxplot(fill ="white", # Set all boxplots to light blueoutlier.shape =16, outlier.size =2, alpha =1) +# Labelslabs(title ="",x ="Oral IgG dose",y ="Serum IgG (g/L)",fill ="Treatment" ) +# Custom themetheme_minimal() +coord_cartesian(ylim =c(0, 60)) +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure
Show the code
ggsave(filename ="figure 1a.tiff", # File nameplot = figure, # ggplot object to savedevice ="tiff", # Output formatwidth =5, # Width in inchesheight =4, # Height in inchesdpi =200# Resolution in dots per inch)
Table Objective 1
Final model includes volume as a covariate
Show the code
lm_all_breed <-lm(igg ~ tx_group + vol, data = data %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))) )lm_all_breed_tab <- lm_all_breed %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,1)," (",round(conf.low,1)," to ",round(conf.high,1),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_all_breed_tab <-emmeans(lm_all_breed, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,1)," (",round(lower.CL,1)," to ",round(upper.CL,1),")" )) %>%select(term,emmean)lm_holstein <-lm(igg ~tx_group + vol, data = data %>%filter(breed =="Holstein") %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))) )lm_holstein_tab <- lm_holstein %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,1)," (",round(conf.low,1)," to ",round(conf.high,1),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_holstein_tab <-emmeans(lm_holstein, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,1)," (",round(lower.CL,1)," to ",round(upper.CL,1),")" )) %>%select(term,emmean)lm_angus <-lm(igg ~ tx_group + vol,data = data %>%filter(breed =="Angus x Holstein") %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))))lm_angus_tab <- lm_angus %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,1)," (",round(conf.low,1)," to ",round(conf.high,1),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_angus_tab <-emmeans(lm_angus, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,1)," (",round(lower.CL,1)," to ",round(upper.CL,1),")" )) %>%select(term,emmean)emmean_all_breed_tab %>%left_join(lm_all_breed_tab, by ="term") %>%left_join(emmean_holstein_tab, by ="term",suffix =c("_overall","_holstein")) %>%left_join(lm_holstein_tab, by ="term", suffix =c("_overall","_holstein")) %>%left_join(emmean_angus_tab %>%rename(emmean_angus = emmean), by ="term") %>%left_join(lm_angus_tab %>%rename(difference_angus = difference), by ="term") %>%rename(tx = term) %>%arrange(tx)
These findings indicate that the linear relationship between dose and serum IgG is robust to potential clustering of calves within batches of colostrum.
Objective 1b - Investigating factors that may impact IgG absorption and therefore modify the effect of IgG dose on serum IgG.
Breed (Holstein vs Holstein x Angus)
Breed as an effect modifier
Box and whisker plot showing serum IgG for calves randomized to 4 doses of colostrum, stratified by breed
Show the code
figure <-ggplot(data %>%filter(!is.na(tx_group)), aes(x = tx_group, y = igg)) +# Removed fill from aes()# Add shaded regionsgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10), fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18), fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25), fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf), fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Add boxplot with fixed fill colorgeom_boxplot(fill ="white", # Set all boxplots to light blueoutlier.shape =16, outlier.size =2, alpha =1) +# Labelslabs(title ="",x ="Oral IgG dose",y ="Serum IgG (g/L)",fill ="Treatment" ) +# Custom themetheme_minimal() +facet_wrap(~ breed) +coord_cartesian(ylim =c(0, 60)) +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure
Show the code
ggsave(filename ="figure holstein and angus.tiff", # File nameplot = figure, # ggplot object to savedevice ="tiff", # Output formatwidth =5, # Width in inchesheight =3, # Height in inchesdpi =200# Resolution in dots per inch)
Show the code
prop_data <- data %>%filter(!is.na(tx_group), !is.na(igg_category)) %>%group_by(tx_group, igg_category, breed) %>%summarize(count =n(), .groups ="drop") %>%group_by(tx_group,breed) %>%mutate(proportion = count /sum(count))figure <-ggplot(prop_data, aes(x = tx_group, y = proportion, fill = igg_category)) +geom_bar(stat ="identity", position ="stack") +# Add text labels for proportionsgeom_text(aes(label = scales::percent(proportion, accuracy =1)), # Format proportion as percentageposition =position_stack(vjust =0.5), # Place text in the middle of the stacked barssize =3, # Adjust text sizefamily ="Times New Roman"# Ensure consistent font ) +labs(title ="",x ="Oral IgG dose",y ="Proportion",fill ="IgG Levels" ) +scale_y_continuous(labels = scales::percent) +# Show percentagestheme_minimal() +facet_wrap(~ breed) +scale_fill_manual(values =c('#A2D9CE', '#C3D69B', '#FFF2CC', "pink")) +theme(panel.border =element_rect(color ="black", fill =NA, linewidth =1),text =element_text(family ="Times New Roman") )figure
Show the code
ggsave(filename ="figure angus holstein groups.tiff", # File nameplot = figure, # ggplot object to savedevice ="tiff", # Output formatwidth =8, # Width in inchesheight =5, # Height in inchesdpi =200# Resolution in dots per inch)
Show the code
lm <-lm(igg ~ tx_group*breed + vol, data = data)summary(lm)
Call:
lm(formula = igg ~ tx_group * breed + vol, data = data)
Residuals:
Min 1Q Median 3Q Max
-23.820 -4.827 0.034 4.775 19.631
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 27.90179 2.82934 9.862 < 2e-16 ***
tx_group250g 5.46452 2.01331 2.714 0.00694 **
tx_group300g 6.65560 2.24264 2.968 0.00319 **
tx_group350g 11.95730 2.52244 4.740 3.01e-06 ***
breedHolstein -0.23146 2.11271 -0.110 0.91282
vol -1.29083 1.05318 -1.226 0.22108
tx_group250g:breedHolstein 0.08221 2.54388 0.032 0.97424
tx_group300g:breedHolstein 2.41561 2.52290 0.957 0.33893
tx_group350g:breedHolstein 1.42700 2.67584 0.533 0.59414
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.067 on 383 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.2045, Adjusted R-squared: 0.1879
F-statistic: 12.31 on 8 and 383 DF, p-value: 1.026e-15
Type 2 P-values for assessing significance of an interaction term
Show the code
car::Anova(lm)
Sum Sq
Df
F value
Pr(>F)
tx_group
2536.59849
3
16.9311836
0.0000000
breed
65.55740
1
1.3127395
0.2526146
vol
75.02029
1
1.5022271
0.2210821
tx_group:breed
86.36277
3
0.5764507
0.6307912
Residuals
19126.78291
383
NA
NA
Estimated marginal means
Show the code
emm <-emmeans(lm, ~ tx_group | breed)summary(emm)
tx_group
breed
emmean
SE
df
lower.CL
upper.CL
200g
Angus x Holstein
23.92888
1.7702482
383
20.44825
27.40950
250g
Angus x Holstein
29.39340
1.2507369
383
26.93423
31.85257
300g
Angus x Holstein
30.58448
1.1710728
383
28.28194
32.88701
350g
Angus x Holstein
35.88617
1.5301584
383
32.87761
38.89474
200g
Holstein
23.69742
1.7204628
383
20.31468
27.08015
250g
Holstein
29.24415
0.8125525
383
27.64653
30.84177
300g
Holstein
32.76863
0.8139977
383
31.16817
34.36909
350g
Holstein
37.08172
0.9332789
383
35.24673
38.91671
Show the code
emm_df <-as.data.frame(emm)# Plot the resultsggplot(emm_df, aes(x = tx_group, y = emmean, ymin = lower.CL, ymax = upper.CL)) +geom_point() +# Points for the meansgeom_errorbar(width =0.2) +# Error bars for confidence intervalsfacet_wrap(~ breed) +labs(title ="Estimated Marginal Means of IgG by Treatment group and breed",x ="Treatment Group",y ="Estimated Mean igg (with 95% CI)" )
Breed as a main effect
Univariable model for effect of volume on IgG.
Show the code
lm_not_control_for_dose <-lm(igg ~ breed, data = data)summary(lm_not_control_for_dose)
Call:
lm(formula = igg ~ breed, data = data)
Residuals:
Min 1Q Median 3Q Max
-23.2917 -5.7233 0.6448 4.9886 21.8532
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 30.2033 0.7154 42.219 <2e-16 ***
breedHolstein 1.8790 0.8572 2.192 0.029 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.804 on 390 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.01217, Adjusted R-squared: 0.009637
F-statistic: 4.805 on 1 and 390 DF, p-value: 0.02897
Show the code
broom::tidy(lm_not_control_for_dose, conf.int=T)
term
estimate
std.error
statistic
p.value
conf.low
conf.high
(Intercept)
30.20329
0.7153875
42.219482
0.000000
28.7967931
31.609790
breedHolstein
1.87905
0.8572413
2.191973
0.028972
0.1936574
3.564442
Model for effect of volume on IgG after controlling for IgG dose
Show the code
lm_control_for_dose <-lm(igg ~ tx_group + breed, data = data)summary(lm_control_for_dose)
Call:
lm(formula = igg ~ tx_group + breed, data = data)
Residuals:
Min 1Q Median 3Q Max
-23.2853 -4.7318 0.1331 4.8803 19.1561
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 24.4182 1.1329 21.554 < 2e-16 ***
tx_group250g 4.5976 1.2386 3.712 0.000236 ***
tx_group300g 6.7252 1.2407 5.421 1.05e-07 ***
tx_group350g 11.0509 1.2721 8.687 < 2e-16 ***
breedHolstein 0.9325 0.7848 1.188 0.235480
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.062 on 387 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.1973, Adjusted R-squared: 0.189
F-statistic: 23.78 on 4 and 387 DF, p-value: < 2.2e-16
Show the code
broom::tidy(lm_control_for_dose, conf.int=T)
term
estimate
std.error
statistic
p.value
conf.low
conf.high
(Intercept)
24.4182497
1.1328875
21.553993
0.0000000
22.1908652
26.645634
tx_group250g
4.5975982
1.2385995
3.711933
0.0002359
2.1623719
7.032825
tx_group300g
6.7252044
1.2406529
5.420698
0.0000001
4.2859408
9.164468
tx_group350g
11.0508788
1.2720549
8.687423
0.0000000
8.5498753
13.551882
breedHolstein
0.9324941
0.7847895
1.188209
0.2354796
-0.6104905
2.475479
Time to feeding
Show the code
figure <-ggplot(data %>%filter(!is.na(tx_group)), aes(x = tx_group, y = igg)) +# Removed fill from aes()# Add shaded regionsgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10), fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18), fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25), fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf), fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Add boxplot with fixed fill colorgeom_boxplot(fill ="white", # Set all boxplots to light blueoutlier.shape =16, outlier.size =2, alpha =1) +# Labelslabs(title ="Stratifed by time to feeding quartile",x ="Oral IgG dose",y ="Serum IgG (g/L)",fill ="Treatment" ) +# Custom themetheme_minimal() +facet_wrap(~ time_to_feed_cat) +coord_cartesian(ylim =c(0, 60)) +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure
Time to feeding as an effect modifier
Linear model evaluating effect modification. Statistical interaction between tx and time to feeding
Show the code
lm <-lm(igg ~ tx_group*time_to_feed + vol, data = data)summary(lm)
Call:
lm(formula = igg ~ tx_group * time_to_feed + vol, data = data)
Residuals:
Min 1Q Median 3Q Max
-21.5379 -4.7311 0.1043 4.7294 19.1700
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 28.879079 3.332775 8.665 < 2e-16 ***
tx_group250g 5.857875 2.759071 2.123 0.0344 *
tx_group300g 8.733863 3.024292 2.888 0.0041 **
tx_group350g 15.103089 3.311455 4.561 6.87e-06 ***
time_to_feed -0.016053 0.037600 -0.427 0.6697
vol -1.376495 1.048032 -1.313 0.1898
tx_group250g:time_to_feed -0.003930 0.041877 -0.094 0.9253
tx_group300g:time_to_feed -0.006984 0.044137 -0.158 0.8744
tx_group350g:time_to_feed -0.031003 0.046819 -0.662 0.5082
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.047 on 383 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.2089, Adjusted R-squared: 0.1924
F-statistic: 12.65 on 8 and 383 DF, p-value: 3.757e-16
Show the code
car::Anova(lm)
Sum Sq
Df
F value
Pr(>F)
tx_group
2693.30237
3
18.077639
0.0000000
time_to_feed
220.42335
1
4.438492
0.0357871
vol
85.66860
1
1.725041
0.1898317
tx_group:time_to_feed
37.82364
3
0.253875
0.8585660
Residuals
19020.45609
383
NA
NA
Estimated marginal means
Show the code
data %>%group_by(time_to_feed_cat) %>%summarise(mean_time_to_feed =mean(time_to_feed,na.rm=T),median_time_to_feed =median(time_to_feed) )
emm_df <-as.data.frame(emm)# Plot the resultsggplot(emm_df, aes(x = tx_group, y = emmean, ymin = lower.CL, ymax = upper.CL)) +geom_point() +# Points for the meansgeom_errorbar(width =0.2) +# Error bars for confidence intervalsfacet_wrap(~ time_to_feed) +labs(title ="Estimated Marginal Means of IgG by Treatment group and time to feeding",x ="Treatment Group",y ="Estimated Mean igg (with 95% CI)" )
Time to feeding as a main effect
Show the code
figure_scatter <-ggplot(data %>%filter(!is.na(tx_group)),aes(x = time_to_feed, y = igg)) +# Background zonesgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10),fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18),fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25),fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf),fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Scatter pointsgeom_point(size =1, alpha =0.8, colour ="black") +# Optionally add a smoothed line (remove if not desired)geom_smooth(method ="lm", se = T, linewidth =0.5, linetype ="dashed",colour ="black") +# Labelslabs(title ="Relationship between time to feeding and Serum IgG",x ="Time to feeding (min)",y ="Serum IgG (g/L)" ) +# Facet by treatment group if relevantfacet_wrap(~ tx_group) +coord_cartesian(ylim =c(0, 60)) +theme_minimal() +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure_scatter
Show the code
ggsave(filename ="figure scatter time.tiff", # File nameplot = figure_scatter, # ggplot object to savedevice ="tiff", # Output formatwidth =6, # Width in inchesheight =5, # Height in inchesdpi =200# Resolution in dots per inch)
Univariable model for effect of volume on IgG.
Show the code
lm_not_control_for_dose <-lm(igg ~ time_to_feed, data = data)summary(lm_not_control_for_dose)
Call:
lm(formula = igg ~ time_to_feed, data = data)
Residuals:
Min 1Q Median 3Q Max
-23.3501 -5.6577 0.4578 5.1479 21.9856
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 32.84105 0.89147 36.839 <2e-16 ***
time_to_feed -0.02228 0.01339 -1.663 0.0971 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.824 on 390 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.007044, Adjusted R-squared: 0.004498
F-statistic: 2.767 on 1 and 390 DF, p-value: 0.09706
Show the code
broom::tidy(lm_not_control_for_dose, conf.int=T)
term
estimate
std.error
statistic
p.value
conf.low
conf.high
(Intercept)
32.8410482
0.8914709
36.839172
0.0000000
31.0883582
34.5937382
time_to_feed
-0.0222772
0.0133934
-1.663298
0.0970562
-0.0486096
0.0040551
Model for effect of volume on IgG after controlling for IgG dose
Show the code
lm_control_for_dose <-lm(igg ~ tx_group + time_to_feed, data = data)summary(lm_control_for_dose)
Call:
lm(formula = igg ~ tx_group + time_to_feed, data = data)
Residuals:
Min 1Q Median 3Q Max
-21.4920 -4.6019 0.0523 4.8640 18.8429
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 26.38345 1.25273 21.061 < 2e-16 ***
tx_group250g 4.90516 1.22702 3.998 7.66e-05 ***
tx_group300g 6.85231 1.23084 5.567 4.85e-08 ***
tx_group350g 11.39734 1.25450 9.085 < 2e-16 ***
time_to_feed -0.02587 0.01208 -2.141 0.0329 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.033 on 387 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.2038, Adjusted R-squared: 0.1956
F-statistic: 24.77 on 4 and 387 DF, p-value: < 2.2e-16
Show the code
broom::tidy(lm_control_for_dose, conf.int=T)
term
estimate
std.error
statistic
p.value
conf.low
conf.high
(Intercept)
26.3834503
1.2527301
21.060762
0.0000000
23.9204417
28.8464589
tx_group250g
4.9051560
1.2270208
3.997615
0.0000766
2.4926948
7.3176172
tx_group300g
6.8523114
1.2308374
5.567195
0.0000000
4.4323462
9.2722766
tx_group350g
11.3973387
1.2544971
9.085185
0.0000000
8.9308559
13.8638215
time_to_feed
-0.0258732
0.0120848
-2.140965
0.0329011
-0.0496333
-0.0021131
Volume
Volume as an effect modifier.
Show the code
figure <-ggplot(data %>%filter(!is.na(tx_group)), aes(x = tx_group, y = igg)) +# Removed fill from aes()# Add shaded regionsgeom_rect(aes(xmin =-Inf, xmax =Inf, ymin =-5, ymax =10), fill ="pink", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =10, ymax =18), fill ="#FFF2CC", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =18, ymax =25), fill ="#C3D69B", alpha =0.5, inherit.aes =FALSE) +geom_rect(aes(xmin =-Inf, xmax =Inf, ymin =25, ymax =Inf), fill ="#A2D9CE", alpha =0.5, inherit.aes =FALSE) +# Add boxplot with fixed fill colorgeom_boxplot(fill ="white", # Set all boxplots to light blueoutlier.shape =16, outlier.size =2, alpha =1) +# Labelslabs(title ="Stratifed by volume fed (L)",x ="Oral IgG dose",y ="Serum IgG (g/L)",fill ="Treatment" ) +# Custom themetheme_minimal() +facet_wrap(~ vol_cat) +coord_cartesian(ylim =c(0, 60)) +theme(legend.position ="none",panel.border =element_rect(color ="black", fill =NA, linewidth =1 ),text =element_text(family ="Times New Roman") )figure
Statistical interaction between tx and volume fed
Show the code
lm <-lm(igg ~ tx_group*vol_cat, data = data)summary(lm)
Call:
lm(formula = igg ~ tx_group * vol_cat, data = data)
Residuals:
Min 1Q Median 3Q Max
-22.0128 -4.5394 -0.0687 4.6713 19.4430
Coefficients: (4 not defined because of singularities)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 25.400 1.243 20.439 < 2e-16 ***
tx_group250g 4.428 2.036 2.175 0.03026 *
tx_group300g 5.193 3.269 1.588 0.11302
tx_group350g 9.561 3.209 2.980 0.00307 **
vol_cat2.5-2.999 -1.676 2.312 -0.725 0.46899
vol_cat3.0-3.499 2.475 3.332 0.743 0.45804
vol_cat3.5-4.0 1.008 2.845 0.354 0.72324
tx_group250g:vol_cat2.5-2.999 2.377 2.935 0.810 0.41843
tx_group300g:vol_cat2.5-2.999 5.260 4.079 1.290 0.19798
tx_group350g:vol_cat2.5-2.999 1.821 4.426 0.411 0.68097
tx_group250g:vol_cat3.0-3.499 -6.227 3.295 -1.890 0.05952 .
tx_group300g:vol_cat3.0-3.499 -2.265 2.252 -1.006 0.31529
tx_group350g:vol_cat3.0-3.499 NA NA NA NA
tx_group250g:vol_cat3.5-4.0 NA NA NA NA
tx_group300g:vol_cat3.5-4.0 NA NA NA NA
tx_group350g:vol_cat3.5-4.0 NA NA NA NA
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.03 on 380 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.219, Adjusted R-squared: 0.1964
F-statistic: 9.687 on 11 and 380 DF, p-value: 1.727e-15
emm_df <-as.data.frame(emm)# Plot the resultsggplot(emm_df, aes(x = tx_group, y = emmean, ymin = lower.CL, ymax = upper.CL)) +geom_point() +# Points for the meansgeom_errorbar(width =0.2) +# Error bars for confidence intervalsfacet_wrap(~ vol_cat) +# Separate panels for each value of vollabs(title ="Estimated Marginal Means of igg by tx_group and vol",x ="Treatment Group (tx_group)",y ="Estimated Mean igg (with 95% CI)" )
emm_df <-as.data.frame(emm)# Plot the resultsggplot(emm_df, aes(x = vol_cat, y = emmean, ymin = lower.CL, ymax = upper.CL)) +geom_point() +# Points for the meansgeom_errorbar(width =0.2) +# Error bars for confidence intervalsfacet_wrap(~ tx_group) +# Separate panels for each value of vollabs(title ="Estimated Marginal Means of igg by tx_group and vol",x ="Treatment Group (tx_group)",y ="Estimated Mean igg (with 95% CI)" )
$emmeans
tx_group emmean SE df lower.CL upper.CL t.ratio p.value
200g 0.345 0.01060 387 0.324 0.366 32.474 <.0001
250g 0.327 0.00665 387 0.314 0.340 49.248 <.0001
300g 0.292 0.00667 387 0.279 0.305 43.783 <.0001
350g 0.284 0.00728 387 0.270 0.299 39.077 <.0001
Results are averaged over the levels of: breed
Confidence level used: 0.95
$contrasts
contrast estimate SE df lower.CL upper.CL t.ratio p.value
200g - 250g 0.01767 0.01250 387 -0.0146 0.0499 1.414 0.4916
200g - 300g 0.05289 0.01250 387 0.0206 0.0852 4.225 0.0002
200g - 350g 0.06063 0.01280 387 0.0275 0.0937 4.723 <.0001
250g - 300g 0.03522 0.00917 387 0.0116 0.0589 3.841 0.0008
250g - 350g 0.04296 0.00948 387 0.0185 0.0674 4.533 <.0001
300g - 350g 0.00774 0.00957 387 -0.0170 0.0324 0.809 0.8504
Results are averaged over the levels of: breed
Confidence level used: 0.95
Conf-level adjustment: tukey method for comparing a family of 4 estimates
P value adjustment: tukey method for comparing a family of 4 estimates
Model diagnostics
Show the code
check_model(lm)
Show the code
check_outliers(lm)
OK: No outliers detected.
- Based on the following method and threshold: cook (0.5).
- For variable: (Whole model)
Table out
Show the code
lm_all_breed <-lm(aea ~ tx_group + breed, data = data %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))) )lm_all_breed_tab <- lm_all_breed %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,3)," (",round(conf.low,3)," to ",round(conf.high,3),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_all_breed_tab <-emmeans(lm_all_breed, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,3)," (",round(lower.CL,3)," to ",round(upper.CL,3),")" )) %>%select(term,emmean)lm_holstein <-lm(aea ~ tx_group, data = data %>%filter(breed =="Holstein") %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))) )lm_holstein_tab <- lm_holstein %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,3)," (",round(conf.low,3)," to ",round(conf.high,3),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_holstein_tab <-emmeans(lm_holstein, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,3)," (",round(lower.CL,3)," to ",round(upper.CL,3),")" )) %>%select(term,emmean)lm_angus <-lm(aea ~ tx_group,data = data %>%filter(breed =="Angus x Holstein") %>%mutate(tx_group =fct_relevel(tx_group,c("250g","200g","300g","350g"))))lm_angus_tab <- lm_angus %>% broom::tidy(conf.int=T) %>%mutate(difference =case_when( term =="(Intercept)"~"Ref", T ~paste0(round(estimate,3)," (",round(conf.low,3)," to ",round(conf.high,3),")" )),term =case_when( term =="(Intercept)"~"250g", term !="(Intercept)"~str_remove(term, "tx_group")) )%>%select(term,difference)emmean_angus_tab <-emmeans(lm_angus, ~tx_group) %>% as_tibble %>%mutate(term = tx_group,emmean =paste0(round(emmean,3)," (",round(lower.CL,3)," to ",round(upper.CL,3),")" )) %>%select(term,emmean)emmean_all_breed_tab %>%left_join(lm_all_breed_tab, by ="term") %>%left_join(emmean_holstein_tab, by ="term",suffix =c("_overall","_holstein")) %>%left_join(lm_holstein_tab, by ="term", suffix =c("_overall","_holstein")) %>%left_join(emmean_angus_tab %>%rename(emmean_angus = emmean), by ="term") %>%left_join(lm_angus_tab %>%rename(difference_angus = difference), by ="term") %>%rename(tx = term) %>%arrange(tx)
tx
emmean_overall
difference_overall
emmean_holstein
difference_holstein
emmean_angus
difference_angus
200g
0.345 (0.324 to 0.366)
0.018 (-0.007 to 0.042)
0.344 (0.316 to 0.373)
0.016 (-0.016 to 0.048)
0.346 (0.316 to 0.377)
0.015 (-0.023 to 0.054)
250g
0.327 (0.314 to 0.34)
Ref
0.328 (0.313 to 0.343)
Ref
0.331 (0.307 to 0.355)
Ref
300g
0.292 (0.279 to 0.305)
-0.035 (-0.053 to -0.017)
0.301 (0.285 to 0.316)
-0.028 (-0.05 to -0.006)
0.279 (0.257 to 0.302)
-0.052 (-0.085 to -0.019)
350g
0.284 (0.27 to 0.299)
-0.043 (-0.062 to -0.024)
0.289 (0.273 to 0.304)
-0.04 (-0.061 to -0.018)
0.279 (0.25 to 0.308)
-0.052 (-0.089 to -0.014)
Predicting AEA slope and point of diminishing returns
Need to identify if the relationship between IgG dose and AEA is linear or quadratic.
Scatter plot
Show the code
ggplot(data, aes(x = tx_administered, y = aea)) +geom_point(alpha =0.6) +geom_smooth(method ="lm", formula = y ~ x, color ="blue", se =FALSE, linetype ="dashed") +# Lineargeom_smooth(method ="lm", formula = y ~poly(x, 2, raw =TRUE), color ="red", se =FALSE) +# Quadraticlabs(title ="Linear vs Quadratic Fit",x ="Oral IgG Dose (tx_administered)",y ="Apparent Efficiency of Absorption (AEA)" ) +theme_minimal()
Linear model
Show the code
lm <-lm(aea ~ tx_administered + breed, data = data)summary(lm)
Call:
lm(formula = aea ~ tx_administered + breed, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.234220 -0.044388 -0.002447 0.045777 0.217056
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.282e-01 2.153e-02 19.889 < 2e-16 ***
tx_administered -4.388e-04 7.385e-05 -5.942 6.27e-09 ***
breedHolstein 8.953e-03 7.888e-03 1.135 0.257
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07134 on 389 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.08366, Adjusted R-squared: 0.07895
F-statistic: 17.76 on 2 and 389 DF, p-value: 4.167e-08
Quadratic model
Show the code
lm_quad <-lm(aea ~ tx_administered +I(tx_administered^2) + breed, data = data)summary(lm_quad)
Call:
lm(formula = aea ~ tx_administered + I(tx_administered^2) + breed,
data = data)
Residuals:
Min 1Q Median 3Q Max
-0.232312 -0.044640 -0.002283 0.045461 0.218769
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.283e-01 1.222e-01 4.324 1.95e-05 ***
tx_administered -1.171e-03 8.824e-04 -1.327 0.185
I(tx_administered^2) 1.295e-06 1.556e-06 0.832 0.406
breedHolstein 9.149e-03 7.895e-03 1.159 0.247
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07137 on 388 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.0853, Adjusted R-squared: 0.07822
F-statistic: 12.06 on 3 and 388 DF, p-value: 1.454e-07
Compare AIC
Show the code
AIC(lm,lm_quad)
df
AIC
lm
4
-952.5559
lm_quad
5
-951.2554
Compare using LRT
Show the code
anova(lm,lm_quad)
Res.Df
RSS
Df
Sum of Sq
F
Pr(>F)
389
1.979783
NA
NA
NA
NA
388
1.976253
1
0.0035299
0.693039
0.4056447
No evidence that quadratic model is superior. Decision is to use linear model.
Show the code
lm <-lm(aea ~ tx_administered + breed, data = data)summary(lm)
Call:
lm(formula = aea ~ tx_administered + breed, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.234220 -0.044388 -0.002447 0.045777 0.217056
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.282e-01 2.153e-02 19.889 < 2e-16 ***
tx_administered -4.388e-04 7.385e-05 -5.942 6.27e-09 ***
breedHolstein 8.953e-03 7.888e-03 1.135 0.257
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07134 on 389 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.08366, Adjusted R-squared: 0.07895
F-statistic: 17.76 on 2 and 389 DF, p-value: 4.167e-08
lm <-lm(aea ~ vol + tx_group, data = data)summary(lm)
Call:
lm(formula = aea ~ vol + tx_group, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.240578 -0.043929 -0.000324 0.046024 0.217035
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.374341 0.025723 14.553 <2e-16 ***
vol -0.013081 0.010565 -1.238 0.2164
tx_group250g -0.008972 0.013713 -0.654 0.5133
tx_group300g -0.037659 0.016889 -2.230 0.0263 *
tx_group350g -0.041184 0.019013 -2.166 0.0309 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07121 on 387 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.09163, Adjusted R-squared: 0.08224
F-statistic: 9.76 on 4 and 387 DF, p-value: 1.572e-07
Breed
Show the code
lm <-lm(aea ~ breed, data = data)summary(lm)
Call:
lm(formula = aea ~ breed, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.228669 -0.049367 -0.006369 0.047162 0.234575
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.306292 0.006821 44.902 <2e-16 ***
breedHolstein 0.003602 0.008174 0.441 0.66
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07441 on 390 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.0004977, Adjusted R-squared: -0.002065
F-statistic: 0.1942 on 1 and 390 DF, p-value: 0.6597
Time to feeding
Show the code
lm <-lm(aea ~ time_to_feed, data = data)summary(lm)
Call:
lm(formula = aea ~ time_to_feed, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.218394 -0.048627 -0.006357 0.045703 0.229665
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.3233242 0.0084406 38.31 <2e-16 ***
time_to_feed -0.0002434 0.0001268 -1.92 0.0556 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07408 on 390 degrees of freedom
(7 observations deleted due to missingness)
Multiple R-squared: 0.009359, Adjusted R-squared: 0.006819
F-statistic: 3.685 on 1 and 390 DF, p-value: 0.05565
Objective 3 - Practically feasible dose
Our objective is to determine the amount of IgG available to feed per calf from pooled and pasteurised batches of 40L, when there is a limiting effect of colostral IgG concentration and volume administered.
Show the code
day
date
born
igg_kg
concentration_limited_dose
igg_per_calf
2024-10-24
14
8.798840
317.9076
628.4886
2024-10-25
22
8.254016
347.6477
375.1826
2024-10-26
15
7.864941
372.9109
524.3294
2024-10-27
28
7.254011
372.6910
259.0718
2024-10-28
18
6.837712
323.6434
379.8729
2024-10-29
17
7.940289
321.0714
467.0758
2024-10-30
20
6.121256
370.2976
306.0628
2024-10-31
24
8.923116
348.0520
371.7965
2024-11-01
26
8.435949
328.6460
324.4596
2024-11-02
15
6.238196
283.2936
415.8797
2024-11-03
21
4.299691
338.4722
204.7472
2024-11-04
24
8.903345
359.0180
370.9727
2024-11-05
19
2.424971
373.0724
127.6300
2024-11-06
32
7.826972
304.1152
244.5929
2024-11-07
38
5.596646
365.3151
147.2802
2024-11-08
35
12.133704
294.0847
346.6773
Number born per day
Show the code
ggplot(data = day, aes(x = date, y = born)) +geom_col() +labs(title ="",x ="Date",y ="Number born" ) +scale_x_date(date_breaks ="1 day", date_labels ="%b %d") +# Custom date labelstheme_minimal() +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontaxis.text.x =element_text(angle =90, hjust =0),panel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank() # Remove minor vertical grid lines )
From this histogram, it is clear that the number of calves born per day have increased since November 6th and that the demand for colostrum is higher. Therefore colostrum recommendations must be made to account for times of peak demand.
IgG available per calf (due to limitation of total IgG harvested on that day - mass limited dose)
Show the code
ggplot(data = day, aes(x = date, y = igg_per_calf)) +geom_col() +labs(title ="Mass limited dose",x ="",y ="IgG (g) available per calf" ) +scale_x_date(date_breaks ="1 day", date_labels ="%b %d") +# Custom date labelstheme_minimal() +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontaxis.text.x =element_text(angle =90, hjust =0),panel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank() # Remove minor vertical grid lines )
Show the code
mass_day <-ggplot(data = day, aes(y = igg_per_calf, x =1)) +# Add a dummy x-axis (1) for a single boxgeom_boxplot(outlier.shape =NA, width =0.3) +# Box plot with adjusted width and no outliersgeom_jitter(width =0.01, alpha =0.6, size =1.5) +# Jitter with slight width, transparency, and sizelabs(y ="IgG (g) available per calf",x =NULL ) +scale_y_continuous(limits =c(100, 640), # Set y-axis rangebreaks =seq(100, 640, by =20) # Primary y-axis gridlines every 20 units ) +theme_minimal() +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontpanel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank(), # Remove minor vertical grid linespanel.grid.major.y =element_line(color ="grey80"), # Keep primary y-axis gridlinespanel.grid.minor.y =element_blank(), # Remove secondary gridlinesaxis.text.x =element_blank(), # Remove x-axis textaxis.title.x =element_blank() # Remove x-axis title )ggsave(filename ="figure mass day.tiff", # File nameplot = mass_day, # ggplot object to savedevice ="tiff", # Output formatwidth =3, # Width in inchesheight =5, # Height in inchesdpi =200# Resolution in dots per inch)mass_day
IgG available per calf each day (due to limitation of 4L per calf = concentration limited dose)
Show the code
ggplot(data = day, aes(x = date, y = concentration_limited_dose)) +geom_col() +labs(title ="Concentration limited dose",x ="",y ="IgG (g) available per calf" ) +scale_x_date(date_breaks ="1 day", date_labels ="%b %d") +# Custom date labelstheme_minimal() +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontaxis.text.x =element_text(angle =90, hjust =0),panel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank() # Remove minor vertical grid lines )
Concentration limited dose by batch
Show the code
ggplot(data = batch %>%arrange(dose_at_4l) %>%mutate(batch =1:nrow(batch)), aes(x = batch, y = dose_at_4l)) +geom_col() +labs(x ="Batches sorted by concentration", ) +theme_minimal() +scale_y_continuous(name ="IgG (g) in 4L feed",sec.axis =sec_axis(~ . /4, name ="IgG (g/L) in 1L") ) +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontpanel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank() # Remove minor vertical grid lines )
Show the code
concentration <-ggplot(data = batch, aes(y = dose_at_4l, x =1)) +# Add a dummy x-axis (1) for a single boxgeom_boxplot(outlier.shape =NA, width =0.3) +# Box plot with adjusted width and no outliersgeom_jitter(width =0.01, alpha =0.6, size =1.5) +# Jitter with slight width, transparency, and sizelabs(y ="IgG (g) in 4L (i.e., max dose)",x =NULL# Remove x-axis title ) +scale_y_continuous(limits =c(260, 500), # Set y-axis rangebreaks =seq(260, 500, by =20), # Primary y-axis gridlines every 20 unitssec.axis =sec_axis(~ . /4,name ="IgG (g) in 1L",breaks =seq(260, 500, by =20) /4# Align secondary axis breaks ) ) +theme_minimal() +theme(text =element_text(family ="Times New Roman"), # Set Times New Roman fontpanel.grid.major.x =element_blank(), # Remove major vertical grid linespanel.grid.minor.x =element_blank(), # Remove minor vertical grid linesaxis.text.x =element_blank(), # Remove x-axis textaxis.title.x =element_blank() # Remove x-axis title )ggsave(filename ="figure concentration.tiff", # File nameplot = concentration, # ggplot object to savedevice ="tiff", # Output formatwidth =3, # Width in inchesheight =5, # Height in inchesdpi =200# Resolution in dots per inch)concentration
tibble(date_range =paste0(min(day$date)," to ",max(day$date)),number_of_days =nrow(day),calves_born =sum(day$born),igg_harvested_kg =round(sum(day$igg_kg),1),igg_available_per_calf_g =round(igg_harvested_kg/calves_born *1000,0))
date_range
number_of_days
calves_born
igg_harvested_kg
igg_available_per_calf_g
2024-10-24 to 2024-11-08
16
368
117.9
320
Export data
Show the code
#data %>% write_rds('igg_trial.rds')
Secondary analyses
Sample size calculations
Sample size calculations were conducted prior to the start of the trial. The goal was to demonstrate differences in proportions of calves with serum IgG > 10, 15 and 25g/L cut-off points.
The B line is probably most appropriate for what we can expect the relationship between oral IgG dose and serum IgG. y = 0.0804 * oral dose. The standard deviation is not reported in the paper, but back calculation from the SE estimates in table 1 (SD = SE * sqrt(n)) give SD values of 4, 7, and 6 for groups B, C, and D, respectively. I will calculate sample sizes for SD values of 5 and 6.
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
140
70
70
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
68
34
34
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
60
30
30
0
0.8
Assuming SD = 6
250 vs 200
Show the code
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
152
76
76
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
94
47
47
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
86
43
43
0
0.8
Sample size calculation for 10g/L
Assuming SD = 5
250 vs 200
Show the code
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
180
90
90
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
752
376
376
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
5832
2916
2916
0
0.8
Assuming SD = 6
250 vs 200
Show the code
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
182
91
91
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
474
237
237
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_10_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_10_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
1910
955
955
0
0.8
Sample size calculation for 15g/L
Assuming SD = 5
250 vs 200
Show the code
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_15_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_15_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
68
34
34
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_ftpi_15_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_ftpi_15_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
140
70
70
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd5)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd5)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
60
30
30
0
0.8
Assuming SD = 6
250 vs 200
Show the code
treat <-250; control <-200treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
152
76
76
0
0.8
300 vs 250
Show the code
treat <-300; control <-250treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble
n.total
n.treat
n.control
delta
power
94
47
47
0
0.8
350 vs 300
Show the code
treat <-350; control <-300treat <- data %>%filter(igg_oral == treat) %>%pull(igg_excellent_sd6)control <- data %>%filter(igg_oral == control) %>%pull(igg_excellent_sd6)epi.sssupb(treat = treat, control = control,delta =0, power =0.8, alpha =0.05, n =NA) %>% as_tibble