@@ -54,6 +54,23 @@ def is_aunt_nephew(self: 'Sample', other: 'Sample') -> bool:
54
54
and (self .paternal_grandfather == other .father )
55
55
)
56
56
57
+ def is_in_direct_lineage (self : 'Sample' , other : 'Sample' ) -> bool :
58
+ return self .sample_id in {
59
+ other .mother ,
60
+ other .father ,
61
+ other .maternal_grandmother ,
62
+ other .maternal_grandfather ,
63
+ other .paternal_grandmother ,
64
+ other .paternal_grandfather ,
65
+ } or other .sample_id in {
66
+ self .mother ,
67
+ self .father ,
68
+ self .maternal_grandmother ,
69
+ self .maternal_grandfather ,
70
+ self .paternal_grandmother ,
71
+ self .paternal_grandfather ,
72
+ }
73
+
57
74
58
75
@dataclass
59
76
class Family :
@@ -107,56 +124,34 @@ def parse_collateral_lineage(
107
124
# A sample_i that is siblings with sample_j, will list sample_j as as sibling, but
108
125
# sample_j will not list sample_i as a sibling. Relationships only appear in the
109
126
# ibd table a single time, so we only need to check the pairing once.
110
- for sample_i , sample_j in itertools .combinations (samples .keys (), 2 ):
111
- # If other sample is already related, continue
112
- if sample_j in {
113
- samples [sample_i ].mother ,
114
- samples [sample_i ].father ,
115
- samples [sample_i ].maternal_grandmother ,
116
- samples [sample_i ].maternal_grandfather ,
117
- samples [sample_i ].paternal_grandmother ,
118
- samples [sample_i ].paternal_grandfather ,
119
- }:
127
+ for sample_i , sample_j in itertools .combinations (samples .values (), 2 ):
128
+ # If sample is already related from direct relationships, continue
129
+ if sample_i .is_in_direct_lineage (sample_j ):
120
130
continue
121
131
122
132
# If both parents are identified and the same, samples are siblings.
123
133
if (
124
- samples [ sample_i ] .mother
125
- and samples [ sample_i ] .father
126
- and (samples [ sample_i ] .mother == samples [ sample_j ] .mother )
127
- and (samples [ sample_i ] .father == samples [ sample_j ] .father )
134
+ sample_i .mother
135
+ and sample_i .father
136
+ and (sample_i .mother == sample_j .mother )
137
+ and (sample_i .father == sample_j .father )
128
138
):
129
- samples [sample_i ].siblings .append (
130
- sample_j ,
131
- )
139
+ sample_i .siblings .append (sample_j .sample_id )
132
140
continue
133
141
134
142
# If only a single parent is identified and the same, samples are half siblings
135
- if (
136
- samples [sample_i ].mother
137
- and samples [sample_i ].mother == samples [sample_j ].mother
138
- ) or (
139
- samples [sample_i ].father
140
- and samples [sample_i ].father == samples [sample_j ].father
143
+ if (sample_i .mother and sample_i .mother == sample_j .mother ) or (
144
+ sample_i .father and sample_i .father == sample_j .father
141
145
):
142
- samples [sample_i ].half_siblings .append (
143
- sample_j ,
144
- )
146
+ sample_i .half_siblings .append (sample_j .sample_id )
145
147
continue
146
148
147
149
# If either set of one's grandparents is identified and equal to the other's parents,
148
150
# they're aunt/uncle related
149
- # NB: because we will only check an i, j pair of samples a single time, (itertools.combinations)
151
+ # NB: because we will only check an i, j pair of samples a single time, (itertools.combinations)
150
152
# we need to check both grandparents_i == parents_j and parents_i == grandparents_j.
151
- # fmt: off
152
- if (
153
- samples [sample_i ].is_aunt_nephew (samples [sample_j ])
154
- or samples [sample_j ].is_aunt_nephew (samples [sample_i ])
155
- ):
156
- samples [sample_i ].aunt_nephews .append (
157
- sample_j ,
158
- )
159
- # fmt: on
153
+ if sample_i .is_aunt_nephew (sample_j ) or sample_j .is_aunt_nephew (sample_i ):
154
+ sample_i .aunt_nephews .append (sample_j .sample_id )
160
155
return samples
161
156
162
157
@classmethod
0 commit comments