1515from tqdm import tqdm
1616
1717from ..util import datatypes , util
18- from . import filter_nonseparated , filter_rafs
18+ from . import filter_nonseparated
1919
2020log = logging .getLogger (__name__ )
2121
@@ -257,6 +257,53 @@ def parse_SVsignals_from_alignment(
257257 return sv_signals
258258
259259
260+ def sv_signals_densities (svSignals : list [datatypes .SVsignal ], radius : int ) -> list [int ]:
261+ """Returns"""
262+ if len (svSignals ) == 0 :
263+ return []
264+ # check if list is sorted
265+ if not all (
266+ svSignals [i ].ref_start <= svSignals [i + 1 ].ref_start
267+ for i in range (len (svSignals ) - 1 )
268+ ):
269+ raise ValueError ("List of SVsignals is not sorted by ref_start." )
270+
271+ # build a mask. The mask keeps the density of each signal. The mask has the length of svSignals
272+ mask = [0 ] * len (svSignals )
273+ left : int = 0
274+ right : int = 0
275+ for mid , midSvSignal in enumerate (svSignals ):
276+ # move right until right is out of radius (svSignals[right].ref_start - midSvSignal.ref_end > radius)
277+ while (
278+ right < len (svSignals )
279+ and svSignals [right ].ref_start - midSvSignal .ref_end <= radius
280+ ):
281+ right += 1
282+ # right is now the the first signal that is out of radius
283+ # move left until left is in radius (midSvSignal.ref_start - svSignals[left].ref_end <= radius)
284+ while left < mid and midSvSignal .ref_start - svSignals [left ].ref_end > radius :
285+ left += 1
286+ # left is now the first signal that is in the radius
287+ # sum all signals sizes of the same type as midSvSignal that are in the radius
288+ mask [mid ] = sum (
289+ s .size for s in svSignals [left :right ] if s .sv_type == midSvSignal .sv_type
290+ )
291+ # filter all signals that have a mask value below min_signal_bp
292+ return mask
293+
294+
295+ def filter_signals_for_minimum_density (
296+ svSignals : list [datatypes .SVsignal ], min_signal_bp : int , radius : int
297+ ) -> list [datatypes .SVsignal ]:
298+ """filters any signal that fails to accumulate another min_signal_bp within radius. The returned list is sorted by ref_start."""
299+ densities = sv_signals_densities (
300+ svSignals = sorted (svSignals , key = lambda x : x .ref_start ), radius = radius
301+ )
302+ return [
303+ svSignals [i ] for i in range (len (svSignals )) if densities [i ] >= min_signal_bp
304+ ]
305+
306+
260307def parse_ReadAlignmentFragment_from_alignment (
261308 alignment : pysam .AlignedSegment ,
262309 samplename : str ,
@@ -282,7 +329,7 @@ def parse_ReadAlignmentFragment_from_alignment(
282329 sv_signals_density_filtered = sv_signals
283330 if filter_density_radius > 0 and filter_density_min_bp > 0 :
284331 sv_signals_density_filtered = sorted (
285- filter_rafs . filter_signals_for_minimum_density (
332+ filter_signals_for_minimum_density (
286333 svSignals = sv_signals ,
287334 min_signal_bp = filter_density_min_bp ,
288335 radius = filter_density_radius ,
0 commit comments