library(readxl); library(dplyr); library(tidyr); library(ggplot2); library(knitr); library(kableExtra); library(scales)
theme_report <- function() { theme_minimal(base_size=12) + theme(plot.title=element_text(face="bold",size=14,hjust=0,color="#1a365d"), plot.subtitle=element_text(size=11,hjust=0,color="#4a5568"), legend.position="bottom", panel.grid.minor=element_blank(), axis.title=element_text(face="bold",size=11), strip.text=element_text(face="bold",size=11)) }
theme_set(theme_report())
setwd("C:/Users/SAlemu/OneDrive - CGIAR/Documents/Poultryaudit/Dataset/")
file_path <- "Additional_Poultry dataset_audit.xlsx"
lil_data <- read_excel(file_path, sheet = "LIL")
bil_data <- read_excel(file_path, sheet = "BIL")
nhil_data <- read_excel(file_path, sheet = "NHIL")
clean_names <- function(df) { colnames(df) <- gsub(" ", "_", colnames(df)); return(df) }
lil_data <- clean_names(lil_data); bil_data <- clean_names(bil_data); nhil_data <- clean_names(nhil_data)
convert_types <- function(df) { df$Generation <- as.character(df$Generation); df$Batch <- as.character(df$Batch); df$ID <- as.character(df$ID); df$Sire_ID <- as.character(df$Sire_ID); df$Dam_ID <- as.character(df$Dam_ID); return(df) }
lil_data <- convert_types(lil_data); bil_data <- convert_types(bil_data); nhil_data <- convert_types(nhil_data)
total_birds <- nrow(lil_data) + nrow(bil_data) + nrow(nhil_data)
lil_total <- nrow(lil_data); bil_total <- nrow(bil_data); nhil_total <- nrow(nhil_data)
lil_bw16_mean <- round(mean(lil_data$BW_16wk, na.rm=T), 0)
bil_bw16_mean <- round(mean(bil_data$BW_16wk, na.rm=T), 0)
nhil_bw16_mean <- round(mean(nhil_data$BW_16wk, na.rm=T), 0)
lil_survival <- round((1-sum(!is.na(lil_data$Cull_Reason))/lil_total)*100, 1)
bil_survival <- round((1-sum(!is.na(bil_data$Cull_Reason))/bil_total)*100, 1)
nhil_survival <- round((1-sum(!is.na(nhil_data$Cull_Reason))/nhil_total)*100, 1)
afe_col <- which(grepl("AFE", colnames(lil_data)))[1]
lil_egg_n <- sum(!is.na(lil_data[[afe_col]]))
bil_egg_n <- sum(!is.na(bil_data[[afe_col]]))
nhil_egg_n <- sum(!is.na(nhil_data[[afe_col]]))

1 Overview

This report presents descriptive statistics for three ILRI poultry lines: LIL-20, BIL-20, and NHIL-20.

3,128
Total Birds
All 3 Lines
1215
LIL-20
797
BIL-20
1116
NHIL-20

ℹ️ Pedigree Structure

G0 founders have unknown parents by design — this is standard for base/foundation populations. Pedigree completeness for G1 and G2 determines suitability for genetic evaluation.


2 LIL-20 Line Analysis

2.1 Population Structure

1215
Total Birds
981g
Mean BW 16wk
74.7%
Survival
46
Egg Records
lil_gen <- lil_data %>% group_by(Generation) %>% summarise(N=n(), Males=sum(Sex=="M",na.rm=T), Females=sum(Sex=="F",na.rm=T), Unknown_Sex=sum(is.na(Sex)|Sex==""), Deaths=sum(!is.na(Cull_Reason)&Cull_Reason!=""), .groups="drop") %>% mutate(Survival_Pct=round((N-Deaths)/N*100,1), Generation=paste0("G",Generation))
lil_gen %>% kable(col.names=c("Gen","Total","Males","Females","Unknown","Deaths","Survival %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=T) %>% row_spec(0,bold=T,background="#3182ce",color="white")
Gen Total Males Females Unknown Deaths Survival %
G0 612 122 175 315 292 52.3
G1 157 58 76 23 15 90.4
G2 446 219 222 5 0 100.0
lil_data %>% group_by(Generation,Batch) %>% summarise(N=n(),.groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","Batch","N")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#3182ce",color="white")
Gen Batch N
G0 1 219
G0 2 149
G0 3 244
G1 1 54
G1 2 70
G1 3 33
G2 1 265
G2 2 181

2.2 Pedigree & Mating Structure

lil_ped <- lil_data %>% group_by(Generation) %>% summarise(N=n(), Sire_Known=sum(!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"), Dam_Known=sum(!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"), Unique_Sires=n_distinct(Sire_ID[!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"]), Unique_Dams=n_distinct(Dam_ID[!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"]), .groups="drop") %>% mutate(Sire_Pct=round(Sire_Known/N*100,1), Dam_Pct=round(Dam_Known/N*100,1), Offspring_per_Sire=ifelse(Unique_Sires>0,round(Sire_Known/Unique_Sires,1),NA), Offspring_per_Dam=ifelse(Unique_Dams>0,round(Dam_Known/Unique_Dams,1),NA), Generation=paste0("G",Generation))
lil_ped %>% select(Generation,N,Sire_Known,Dam_Known,Sire_Pct,Dam_Pct) %>% kable(col.names=c("Gen","N","Sire Known","Dam Known","Sire %","Dam %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#3182ce",color="white")
Gen N Sire Known Dam Known Sire % Dam %
G0 612 0 0 0 0
G1 157 157 157 100 100
G2 446 446 446 100 100

👨‍👩‍👧 Mating Structure - LIL-20

lil_m <- lil_ped %>% filter(Unique_Sires>0) %>% select(Generation,Unique_Sires,Unique_Dams,Offspring_per_Sire,Offspring_per_Dam)
if(nrow(lil_m)>0) { lil_m %>% kable(col.names=c("Gen","Unique Sires","Unique Dams","Offspring/Sire","Offspring/Dam")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white") } else { cat("No mating data available.\n") }
Gen Unique Sires Unique Dams Offspring/Sire Offspring/Dam
G1 11 22 14.3 7.1
G2 12 43 37.2 10.4

2.3 Body Weight

lil_data %>% group_by(Generation) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#3182ce",color="white")
Gen N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
G0 612 31.2 356.8 713.6 933.0
G1 157 35.2 328.7 684.3 949.5
G2 446 33.6 413.6 666.2 1031.4
lil_data %>% filter(Sex %in% c("M","F")) %>% group_by(Sex) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Sex=ifelse(Sex=="M","Male","Female")) %>% kable(col.names=c("Sex","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white")
Sex N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
Female 473 32.9 356.9 653.2 866.1
Male 399 33.2 420.4 745.4 1125.4
lil_data %>% group_by(Generation) %>% summarise(BW_0wk=mean(BW_0wk,na.rm=T), BW_8wk=mean(BW_8wk,na.rm=T), BW_12wk=mean(BW_12wk,na.rm=T), BW_16wk=mean(BW_16wk,na.rm=T), .groups="drop") %>% pivot_longer(-Generation,names_to="Trait",values_to="Mean") %>% mutate(Generation=paste0("G",Generation), Trait=factor(Trait,levels=c("BW_0wk","BW_8wk","BW_12wk","BW_16wk"),labels=c("Hatch","8wk","12wk","16wk"))) %>% ggplot(aes(x=Generation,y=Mean,fill=Generation)) + geom_bar(stat="identity",width=0.6) + geom_text(aes(label=round(Mean,0)),vjust=-0.5,size=3.5) + facet_wrap(~Trait,scales="free_y") + scale_fill_manual(values=c("#3182ce","#38a169","#805ad5")) + labs(title="LIL-20: Mean Body Weight by Generation",x="Generation",y="Mean BW (g)") + theme(legend.position="none") + scale_y_continuous(expand=expansion(mult=c(0,0.15)))

2.4 Egg Production

afe_col <- colnames(lil_data)[grepl("AFE",colnames(lil_data))][1]
lil_egg <- lil_data %>% filter(!is.na(.data[[afe_col]])|!is.na(Egg_no_45wk)|!is.na(Egg_weight))
cat("Birds with egg data:",nrow(lil_egg),"\n")
## Birds with egg data: 48
if(nrow(lil_egg)>0) { data.frame(Trait=c("AFE(wk)","Egg_no_45wk","Egg_wt(g)"), N=c(sum(!is.na(lil_egg[[afe_col]])),sum(!is.na(lil_egg$Egg_no_45wk)),sum(!is.na(lil_egg$Egg_weight))), Mean=round(c(mean(lil_egg[[afe_col]],na.rm=T),mean(lil_egg$Egg_no_45wk,na.rm=T),mean(lil_egg$Egg_weight,na.rm=T)),2), SD=round(c(sd(lil_egg[[afe_col]],na.rm=T),sd(lil_egg$Egg_no_45wk,na.rm=T),sd(lil_egg$Egg_weight,na.rm=T)),2)) %>% kable(col.names=c("Trait","N","Mean","SD")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#3182ce",color="white") }
Trait N Mean SD
AFE(wk) 46 25.41 2.24
Egg_no_45wk 48 92.12 21.00
Egg_wt(g) 48 45.38 9.88

3 BIL-20 Line Analysis

3.1 Population Structure

797
Total Birds
1354g
Mean BW 16wk
92.8%
Survival
43
Egg Records
bil_gen <- bil_data %>% group_by(Generation) %>% summarise(N=n(), Males=sum(Sex=="M",na.rm=T), Females=sum(Sex=="F",na.rm=T), Unknown_Sex=sum(is.na(Sex)|Sex==""), Deaths=sum(!is.na(Cull_Reason)&Cull_Reason!=""), .groups="drop") %>% mutate(Survival_Pct=round((N-Deaths)/N*100,1), Generation=paste0("G",Generation))
bil_gen %>% kable(col.names=c("Gen","Total","Males","Females","Unknown","Deaths","Survival %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=T) %>% row_spec(0,bold=T,background="#38a169",color="white")
Gen Total Males Females Unknown Deaths Survival %
G0 300 155 136 9 30 90.0
G1 155 71 53 31 18 88.4
G2 342 179 160 3 9 97.4
bil_data %>% group_by(Generation,Batch) %>% summarise(N=n(),.groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","Batch","N")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white")
Gen Batch N
G0 1 300
G1 1 22
G1 2 57
G1 3 76
G2 1 156
G2 2 116
G2 3 70

3.2 Pedigree & Mating Structure

bil_ped <- bil_data %>% group_by(Generation) %>% summarise(N=n(), Sire_Known=sum(!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"), Dam_Known=sum(!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"), Unique_Sires=n_distinct(Sire_ID[!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"]), Unique_Dams=n_distinct(Dam_ID[!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"]), .groups="drop") %>% mutate(Sire_Pct=round(Sire_Known/N*100,1), Dam_Pct=round(Dam_Known/N*100,1), Offspring_per_Sire=ifelse(Unique_Sires>0,round(Sire_Known/Unique_Sires,1),NA), Offspring_per_Dam=ifelse(Unique_Dams>0,round(Dam_Known/Unique_Dams,1),NA), Generation=paste0("G",Generation))
bil_ped %>% select(Generation,N,Sire_Known,Dam_Known,Sire_Pct,Dam_Pct) %>% kable(col.names=c("Gen","N","Sire Known","Dam Known","Sire %","Dam %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white")
Gen N Sire Known Dam Known Sire % Dam %
G0 300 0 0 0 0
G1 155 155 155 100 100
G2 342 342 342 100 100

👨‍👩‍👧 Mating Structure - BIL-20

bil_m <- bil_ped %>% filter(Unique_Sires>0) %>% select(Generation,Unique_Sires,Unique_Dams,Offspring_per_Sire,Offspring_per_Dam)
if(nrow(bil_m)>0) { bil_m %>% kable(col.names=c("Gen","Unique Sires","Unique Dams","Offspring/Sire","Offspring/Dam")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white") } else { cat("No mating data available.\n") }
Gen Unique Sires Unique Dams Offspring/Sire Offspring/Dam
G1 6 27 25.8 5.7
G2 8 39 42.8 8.8

3.3 Body Weight

bil_data %>% group_by(Generation) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white")
Gen N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
G0 300 NaN 558.9 1022.8 1422.3
G1 155 38.4 462.7 902.3 1345.9
G2 342 36.2 522.7 853.9 1294.3
bil_data %>% filter(Sex %in% c("M","F")) %>% group_by(Sex) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Sex=ifelse(Sex=="M","Male","Female")) %>% kable(col.names=c("Sex","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white")
Sex N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
Female 349 36.4 494.1 869.2 1200.1
Male 405 37.1 562.3 996.8 1494.2
bil_data %>% group_by(Generation) %>% summarise(BW_0wk=mean(BW_0wk,na.rm=T), BW_8wk=mean(BW_8wk,na.rm=T), BW_12wk=mean(BW_12wk,na.rm=T), BW_16wk=mean(BW_16wk,na.rm=T), .groups="drop") %>% pivot_longer(-Generation,names_to="Trait",values_to="Mean") %>% mutate(Generation=paste0("G",Generation), Trait=factor(Trait,levels=c("BW_0wk","BW_8wk","BW_12wk","BW_16wk"),labels=c("Hatch","8wk","12wk","16wk"))) %>% ggplot(aes(x=Generation,y=Mean,fill=Generation)) + geom_bar(stat="identity",width=0.6) + geom_text(aes(label=round(Mean,0)),vjust=-0.5,size=3.5) + facet_wrap(~Trait,scales="free_y") + scale_fill_manual(values=c("#38a169","#3182ce","#805ad5")) + labs(title="BIL-20: Mean Body Weight by Generation",x="Generation",y="Mean BW (g)") + theme(legend.position="none") + scale_y_continuous(expand=expansion(mult=c(0,0.15)))

3.4 Egg Production

afe_col_bil <- colnames(bil_data)[grepl("AFE",colnames(bil_data))][1]
bil_egg <- bil_data %>% filter(!is.na(.data[[afe_col_bil]])|!is.na(Egg_no_45wk)|!is.na(Egg_weight))
cat("Birds with egg data:",nrow(bil_egg),"\n")
## Birds with egg data: 43
if(nrow(bil_egg)>0) { data.frame(Trait=c("AFE(wk)","Egg_no_45wk","Egg_wt(g)"), N=c(sum(!is.na(bil_egg[[afe_col_bil]])),sum(!is.na(bil_egg$Egg_no_45wk)),sum(!is.na(bil_egg$Egg_weight))), Mean=round(c(mean(bil_egg[[afe_col_bil]],na.rm=T),mean(bil_egg$Egg_no_45wk,na.rm=T),mean(bil_egg$Egg_weight,na.rm=T)),2), SD=round(c(sd(bil_egg[[afe_col_bil]],na.rm=T),sd(bil_egg$Egg_no_45wk,na.rm=T),sd(bil_egg$Egg_weight,na.rm=T)),2)) %>% kable(col.names=c("Trait","N","Mean","SD")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#38a169",color="white") }
Trait N Mean SD
AFE(wk) 43 24.72 4.04
Egg_no_45wk 43 85.42 25.02
Egg_wt(g) 43 46.82 3.64

4 NHIL-20 Line Analysis

4.1 Population Structure

1116
Total Birds
1196g
Mean BW 16wk
62.5%
Survival
31
Egg Records
nhil_gen <- nhil_data %>% group_by(Generation) %>% summarise(N=n(), Males=sum(Sex=="M",na.rm=T), Females=sum(Sex=="F",na.rm=T), Unknown_Sex=sum(is.na(Sex)|Sex==""), Deaths=sum(!is.na(Cull_Reason)&Cull_Reason!=""), .groups="drop") %>% mutate(Survival_Pct=round((N-Deaths)/N*100,1), Generation=paste0("G",Generation))
nhil_gen %>% kable(col.names=c("Gen","Total","Males","Females","Unknown","Deaths","Survival %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=T) %>% row_spec(0,bold=T,background="#805ad5",color="white")
Gen Total Males Females Unknown Deaths Survival %
G0 721 135 198 388 390 45.9
G1 151 63 49 39 14 90.7
G2 244 131 112 1 15 93.9
nhil_data %>% group_by(Generation,Batch) %>% summarise(N=n(),.groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","Batch","N")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#805ad5",color="white")
Gen Batch N
G0 2 267
G0 3 107
G0 4 226
G0 5 121
G1 1 71
G1 2 80
G2 1 119
G2 2 82
G2 3 43

4.2 Pedigree & Mating Structure

nhil_ped <- nhil_data %>% group_by(Generation) %>% summarise(N=n(), Sire_Known=sum(!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"), Dam_Known=sum(!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"), Unique_Sires=n_distinct(Sire_ID[!is.na(Sire_ID)&Sire_ID!=""&Sire_ID!="NA"]), Unique_Dams=n_distinct(Dam_ID[!is.na(Dam_ID)&Dam_ID!=""&Dam_ID!="NA"]), .groups="drop") %>% mutate(Sire_Pct=round(Sire_Known/N*100,1), Dam_Pct=round(Dam_Known/N*100,1), Offspring_per_Sire=ifelse(Unique_Sires>0,round(Sire_Known/Unique_Sires,1),NA), Offspring_per_Dam=ifelse(Unique_Dams>0,round(Dam_Known/Unique_Dams,1),NA), Generation=paste0("G",Generation))
nhil_ped %>% select(Generation,N,Sire_Known,Dam_Known,Sire_Pct,Dam_Pct) %>% kable(col.names=c("Gen","N","Sire Known","Dam Known","Sire %","Dam %")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#805ad5",color="white")
Gen N Sire Known Dam Known Sire % Dam %
G0 721 0 0 0 0
G1 151 151 151 100 100
G2 244 244 244 100 100

👨‍👩‍👧 Mating Structure - NHIL-20

nhil_m <- nhil_ped %>% filter(Unique_Sires>0) %>% select(Generation,Unique_Sires,Unique_Dams,Offspring_per_Sire,Offspring_per_Dam)
if(nrow(nhil_m)>0) { nhil_m %>% kable(col.names=c("Gen","Unique Sires","Unique Dams","Offspring/Sire","Offspring/Dam")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#805ad5",color="white") } else { cat("No mating data available.\n") }
Gen Unique Sires Unique Dams Offspring/Sire Offspring/Dam
G1 5 24 30.2 6.3
G2 6 27 40.7 9.0

4.3 Body Weight

nhil_data %>% group_by(Generation) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Generation=paste0("G",Generation)) %>% kable(col.names=c("Gen","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#805ad5",color="white")
Gen N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
G0 721 40.8 414.5 707.3 1062.1
G1 151 39.7 467.7 804.2 1170.6
G2 244 40.2 578.9 966.5 1414.8
nhil_data %>% filter(Sex %in% c("M","F")) %>% group_by(Sex) %>% summarise(N=n(), BW_0wk=round(mean(BW_0wk,na.rm=T),1), BW_8wk=round(mean(BW_8wk,na.rm=T),1), BW_12wk=round(mean(BW_12wk,na.rm=T),1), BW_16wk=round(mean(BW_16wk,na.rm=T),1), .groups="drop") %>% mutate(Sex=ifelse(Sex=="M","Male","Female")) %>% kable(col.names=c("Sex","N","Hatch(g)","8wk(g)","12wk(g)","16wk(g)")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white")
Sex N Hatch(g) 8wk(g) 12wk(g) 16wk(g)
Female 359 40.3 436.9 733.5 995.0
Male 329 40.6 551.4 972.9 1427.1
nhil_data %>% group_by(Generation) %>% summarise(BW_0wk=mean(BW_0wk,na.rm=T), BW_8wk=mean(BW_8wk,na.rm=T), BW_12wk=mean(BW_12wk,na.rm=T), BW_16wk=mean(BW_16wk,na.rm=T), .groups="drop") %>% pivot_longer(-Generation,names_to="Trait",values_to="Mean") %>% mutate(Generation=paste0("G",Generation), Trait=factor(Trait,levels=c("BW_0wk","BW_8wk","BW_12wk","BW_16wk"),labels=c("Hatch","8wk","12wk","16wk"))) %>% ggplot(aes(x=Generation,y=Mean,fill=Generation)) + geom_bar(stat="identity",width=0.6) + geom_text(aes(label=round(Mean,0)),vjust=-0.5,size=3.5) + facet_wrap(~Trait,scales="free_y") + scale_fill_manual(values=c("#805ad5","#3182ce","#38a169")) + labs(title="NHIL-20: Mean Body Weight by Generation",x="Generation",y="Mean BW (g)") + theme(legend.position="none") + scale_y_continuous(expand=expansion(mult=c(0,0.15)))

4.4 Egg Production

afe_col_nhil <- colnames(nhil_data)[grepl("AFE",colnames(nhil_data))][1]
nhil_egg <- nhil_data %>% filter(!is.na(.data[[afe_col_nhil]])|!is.na(Egg_no_45wk)|!is.na(Egg_weight))
cat("Birds with egg data:",nrow(nhil_egg),"\n")
## Birds with egg data: 31
if(nrow(nhil_egg)>0) { data.frame(Trait=c("AFE(wk)","Egg_no_45wk","Egg_wt(g)"), N=c(sum(!is.na(nhil_egg[[afe_col_nhil]])),sum(!is.na(nhil_egg$Egg_no_45wk)),sum(!is.na(nhil_egg$Egg_weight))), Mean=round(c(mean(nhil_egg[[afe_col_nhil]],na.rm=T),mean(nhil_egg$Egg_no_45wk,na.rm=T),mean(nhil_egg$Egg_weight,na.rm=T)),2), SD=round(c(sd(nhil_egg[[afe_col_nhil]],na.rm=T),sd(nhil_egg$Egg_no_45wk,na.rm=T),sd(nhil_egg$Egg_weight,na.rm=T)),2)) %>% kable(col.names=c("Trait","N","Mean","SD")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#805ad5",color="white") }
Trait N Mean SD
AFE(wk) 31 24.90 2.39
Egg_no_45wk 31 71.26 15.29
Egg_wt(g) 0 NaN NA

5 Comparison Across All Lines

5.1 Population Summary

data.frame(Line=c("LIL-20","BIL-20","NHIL-20","TOTAL"), Total=c(lil_total,bil_total,nhil_total,total_birds), G0=c(sum(lil_data$Generation=="0"),sum(bil_data$Generation=="0"),sum(nhil_data$Generation=="0"),sum(lil_data$Generation=="0")+sum(bil_data$Generation=="0")+sum(nhil_data$Generation=="0")), G1=c(sum(lil_data$Generation=="1"),sum(bil_data$Generation=="1"),sum(nhil_data$Generation=="1"),sum(lil_data$Generation=="1")+sum(bil_data$Generation=="1")+sum(nhil_data$Generation=="1")), G2=c(sum(lil_data$Generation=="2"),sum(bil_data$Generation=="2"),sum(nhil_data$Generation=="2"),sum(lil_data$Generation=="2")+sum(bil_data$Generation=="2")+sum(nhil_data$Generation=="2"))) %>% kable(col.names=c("Line","Total","G0","G1","G2")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white") %>% row_spec(4,bold=T,background="#f7fafc")
Line Total G0 G1 G2
LIL-20 1215 612 157 446
BIL-20 797 300 155 342
NHIL-20 1116 721 151 244
TOTAL 3128 1633 463 1032

5.2 Body Weight at 16 Weeks

data.frame(Line=c("LIL-20","BIL-20","NHIL-20"), N=c(sum(!is.na(lil_data$BW_16wk)),sum(!is.na(bil_data$BW_16wk)),sum(!is.na(nhil_data$BW_16wk))), Mean=round(c(mean(lil_data$BW_16wk,na.rm=T),mean(bil_data$BW_16wk,na.rm=T),mean(nhil_data$BW_16wk,na.rm=T)),1), SD=round(c(sd(lil_data$BW_16wk,na.rm=T),sd(bil_data$BW_16wk,na.rm=T),sd(nhil_data$BW_16wk,na.rm=T)),1)) %>% kable(col.names=c("Line","N","Mean(g)","SD")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white")
Line N Mean(g) SD
LIL-20 793 980.8 224.0
BIL-20 686 1353.8 280.6
NHIL-20 641 1196.4 409.5
all_data <- bind_rows(lil_data %>% mutate(Line="LIL-20"), bil_data %>% mutate(Line="BIL-20"), nhil_data %>% mutate(Line="NHIL-20"))
ggplot(all_data %>% filter(!is.na(BW_16wk)), aes(x=Line,y=BW_16wk,fill=Line)) + geom_boxplot(alpha=0.8,outlier.shape=21) + scale_fill_manual(values=c("LIL-20"="#3182ce","BIL-20"="#38a169","NHIL-20"="#805ad5")) + labs(title="Body Weight at 16 Weeks - Comparison Across Lines",x="Line",y="Body Weight (g)") + theme(legend.position="none")

5.3 Mating Structure Summary

mating_all <- bind_rows(lil_ped %>% filter(Unique_Sires>0) %>% mutate(Line="LIL-20"), bil_ped %>% filter(Unique_Sires>0) %>% mutate(Line="BIL-20"), nhil_ped %>% filter(Unique_Sires>0) %>% mutate(Line="NHIL-20")) %>% select(Line,Generation,N,Unique_Sires,Unique_Dams,Offspring_per_Sire,Offspring_per_Dam)
if(nrow(mating_all)>0) { mating_all %>% kable(col.names=c("Line","Gen","N","Sires","Dams","Offspring/Sire","Offspring/Dam")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#2d3748",color="white") } else { cat("No mating data available.\n") }
Line Gen N Sires Dams Offspring/Sire Offspring/Dam
LIL-20 G1 157 11 22 14.3 7.1
LIL-20 G2 446 12 43 37.2 10.4
BIL-20 G1 155 6 27 25.8 5.7
BIL-20 G2 342 8 39 42.8 8.8
NHIL-20 G1 151 5 24 30.2 6.3
NHIL-20 G2 244 6 27 40.7 9.0

5.4 Pedigree Integrity Check

# Check if parent IDs in G1/G2 actually exist in previous generations
check_pedigree <- function(data, line_name) {
  g0_ids <- data %>% filter(Generation == "0") %>% pull(ID)
  g1_ids <- data %>% filter(Generation == "1") %>% pull(ID)
  
  # G1 parents should be in G0
  g1_sires <- data %>% filter(Generation == "1", !is.na(Sire_ID), Sire_ID != "", Sire_ID != "NA") %>% pull(Sire_ID)
  g1_dams <- data %>% filter(Generation == "1", !is.na(Dam_ID), Dam_ID != "", Dam_ID != "NA") %>% pull(Dam_ID)
  
  # G2 parents should be in G1
  g2_sires <- data %>% filter(Generation == "2", !is.na(Sire_ID), Sire_ID != "", Sire_ID != "NA") %>% pull(Sire_ID)
  g2_dams <- data %>% filter(Generation == "2", !is.na(Dam_ID), Dam_ID != "", Dam_ID != "NA") %>% pull(Dam_ID)
  
  data.frame(
    Line = line_name,
    G1_Sires_in_G0 = ifelse(length(g1_sires) > 0, paste0(sum(g1_sires %in% g0_ids), "/", length(g1_sires)), "0/0"),
    G1_Dams_in_G0 = ifelse(length(g1_dams) > 0, paste0(sum(g1_dams %in% g0_ids), "/", length(g1_dams)), "0/0"),
    G2_Sires_in_G1 = ifelse(length(g2_sires) > 0, paste0(sum(g2_sires %in% g1_ids), "/", length(g2_sires)), "0/0"),
    G2_Dams_in_G1 = ifelse(length(g2_dams) > 0, paste0(sum(g2_dams %in% g1_ids), "/", length(g2_dams)), "0/0")
  )
}

ped_check <- bind_rows(
  check_pedigree(lil_data, "LIL-20"),
  check_pedigree(bil_data, "BIL-20"),
  check_pedigree(nhil_data, "NHIL-20")
)

ped_check %>% 
  kable(col.names = c("Line", "G1 Sires in G0", "G1 Dams in G0", "G2 Sires in G1", "G2 Dams in G1")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#2d3748", color = "white")
Line G1 Sires in G0 G1 Dams in G0 G2 Sires in G1 G2 Dams in G1
LIL-20 157/157 157/157 347/446 361/446
BIL-20 155/155 155/155 342/342 342/342
NHIL-20 151/151 151/151 244/244 244/244

ℹ️ Interpreting Pedigree Integrity

The table shows how many recorded parent IDs can be found in the previous generation. For example, “45/45” means all 45 sire IDs were found; “40/45” means 5 sire IDs are missing from the previous generation’s records.


6 Summary

data.frame(Measure=c("Total birds","Mean BW 16wk","Egg records","G1/G2 Pedigree"), LIL=c(lil_total,paste0(lil_bw16_mean,"g"),lil_egg_n,"See integrity check"), BIL=c(bil_total,paste0(bil_bw16_mean,"g"),bil_egg_n,"See integrity check"), NHIL=c(nhil_total,paste0(nhil_bw16_mean,"g"),nhil_egg_n,"See integrity check")) %>% kable(col.names=c("Measure","LIL-20","BIL-20","NHIL-20")) %>% kable_styling(bootstrap_options=c("striped","hover"),full_width=F) %>% row_spec(0,bold=T,background="#3182ce",color="white")
Measure LIL-20 BIL-20 NHIL-20
Total birds 1215 797 1116
Mean BW 16wk 981g 1354g 1196g
Egg records 46 43 31
G1/G2 Pedigree See integrity check See integrity check See integrity check

📝 Recommended Next Steps

  1. Review pedigree integrity results — Address any missing parent IDs if found
  2. Complete data collection — Finish G2 egg production records, verify outliers
  3. Proceed with genetic analysis — Variance components, heritability, EBV estimation