# Strawberry code [TOC] ## Strategic approach ## Tangle stats Count: bp and nodes in tangles, in frontiers and others (nodes in frontiers are ENDS, obviously). For the nodes in tangles, plot a distribution of count and bp by count of internal elements (i.e. to give an idea of how tangled the graph is and how complex these tangles are). probably a good idea to plot these numbers as a progress from 0% to 100% of a total count/size. ### Improving the initial graph. The initial graph needs improvement, so the tangle definition gets easier to work with (i.e. smaller tangles within . This being strawberry, the two more obvious ways to do this are to clip tips and to phase bubbles. **Gonza is working on phasing bubbly paths and solving other trivial structures by just expanding canonical repeats** **DONE** - Simple stats for repeats, bubbles and tips - Canonical repeat resolution with single-end short reads **TO DO** - Canonical repeat resolution with pairs (fallback after failing with single reads) - Bubble popping (error and heterozygous bubble mode, use KCI and paths) - Tip clipping (using paths) Ideally we would want to have a single heuristic step that can do: tip clippling, repeat expansion and bubble phasing in one go. For now, we have this pretty stupid simple code to just do repeat expansion: ```python from collections import Counter def is_canonical_repeat(nv): if len(nv.prev())==len(nv.next())>1: for pl in nv.prev(): if len(pl.node().next())>1: return False for nl in nv.next(): if len(nl.node().prev())>1: return False return True return False def is_bubble_side(nv): if len(nv.parallels())==len(nv.prev())==len(nv.next())==1 and len(nv.prev()[0].node().next())==len(nv.next()[0].node().prev())==2: return True return False def is_tip(nv): if len(nv.prev())==0 or len(nv.next())==0: return True return False def simple_structures_stats(dg): total=canrep=bubsides=tips=0 for nv in dg.get_all_nodeviews(): total+=1 if is_canonical_repeat(nv): canrep+=1 if is_bubble_side(nv): bubsides+=1 if is_tip(nv): tips+=1 print("%d tips, %d canonical repeats and %d bubble sides out of %d nodes"%(tips,canrep,bubsides,total)) def solve_canonical_repeat(ge,nv,peds,min_support=5,max_noise=10,snr=10,verbose=False): if verbose: print("\nSolving ",nv,nv.size(),"bp") out_nids=[x.node().node_id() for x in nv.next()] sols=[] for pnv in [x.node() for x in nv.prev()]: c=Counter() for p in peds.mapper.all_paths_fw(pnv.node_id(),False): if p[0]!=nv.node_id(): c[p[0]]+=1 elif len(p)>1: c[p[1]]+=1 if verbose: print(c.most_common()) t=sum(c.values()) if t<min_support: if verbose: print("FW too few paths!") return False (winner,votes)=c.most_common(1)[0] if votes<min_support: if verbose: print("FW winner poorly supported!") return False noise=t-votes if winner in out_nids and noise*snr<=votes and noise<max_noise: sols.append((-pnv.node_id(),winner)) else: if verbose: print("FW Not a clear winner!") return False if verbose: print(sols) if len(sols)<len(nv.prev()) or len(sols)>len(set([x[1] for x in sols])): return False in_nids=[-x.node().node_id() for x in nv.prev()] sols2=[] for nnv in [x.node() for x in nv.next()]: c=Counter() for p in peds.mapper.all_paths_fw(-nnv.node_id(),False): if p[0]!=-nv.node_id(): c[p[0]]+=1 elif len(p)>1: c[p[1]]+=1 t=sum(c.values()) if t<min_support: if verbose: print("BW too few paths!") return False (winner,votes)=c.most_common(1)[0] if votes<min_support: if verbose: print("BW winner poorly supported!") return False noise=t-votes if winner in in_nids and noise*snr<=votes and noise<max_noise: sols2.append((winner,nnv.node_id())) else: if verbose: print("BW Not a clear winner!") return False if verbose: print(sols2) sols2.sort() sols.sort() if sols!=sols2: if verbose: print("FW and BW solutions not the same") return False ge.queue_node_expansion(nv.node_id(),sols) #print(sols) return True def solve_all_canonical(peds,size=1000,apply=False): ge=SDG.GraphEditor(ws) total=solved=0 for nv in ws.sdg.get_all_nodeviews(): if nv.size()<=size and is_canonical_repeat(nv): total+=1 if solve_canonical_repeat(ge,nv,peds): solved+=1 print("\r%d / %d canonical repeats solved" % (solved,total), end='') print("%d / %d canonical repeats solved" % (solved,total)) if apply: ge.apply_all() ws.sdg.join_all_unitigs() #######RUN THIS BIT simple_structures_stats(ws.sdg) solve_all_canonical(peds,apply=True) simple_structures_stats(ws.sdg) kc.update_graph_counts() kc.compute_all_kcis() print(ws.sdg.stats_by_kci()) ``` ### Tangle drill down If we start by getting all tangles with frontiers of a large size, we can then decompose the unclassified tangles in their internal sub-tangles for a smaller size. By definition every internal node on a smaller-frontier defined tangle will be included in a single larger-frontier tangle. This allows for different types of tangles to be definied at independently-determined tangle sizes. # Code dumps!!! ```python import sys sys.path.append('/hpc-home/ggarcia/git_sources/bsg/gonza_master/SDGpython/') import SDGpython as SDG ws = SDG.WorkSpace('./00-raw_graph.sdgws') gc = SDG.GraphContigger(ws) gc.clip_tips(200) kc = ws.get_kmer_counter('kmers-pe-31') for i, c in enumerate(kc.count_spectra('pe')[:400]): print("%s,%s" %(i, c)) kc.update_graph_counts() kc.set_kci_peak(100) kc.compute_all_kcis() print(ws.sdg.stats_by_kci()) ws.dump('./01-tip_clipped.sdgws') kc.dump_cache('./01-tip_clipped.kci.cache') peds = ws.get_paired_reads_datastore('pe') ## Map reads peds.mapper.path_reads() peds.mapper.dump_readpaths('./01-tip_clipped.pe.paths') ``` ![](https://i.imgur.com/dBdC5MW.png) ```python import sys sys.path.append('/hpc-home/ggarcia/git_sources/bsg/gonza_master/SDGpython/') import SDGpython as SDG ws = SDG.WorkSpace('./01-tip_clipped.sdgws') kc = ws.get_kmer_counter('kmers-pe-31') kc.load_cache('./01-tip_clipped.kci.cache') ## Load mapped reads peds = ws.get_paired_reads_datastore('pe') peds.mapper.load_readpaths('./01-tip_clipped.pe.paths') simple_structures_stats(ws.sdg) solve_all_canonical(peds,True) simple_structures_stats(ws.sdg) kc.update_graph_counts() kc.compute_all_kcis() print(ws.sdg.stats_by_kci()) ``` ![](https://i.imgur.com/DWDtsBt.png) ![](https://i.imgur.com/5rmSkly.png) [Functions defined in](https://hackmd.io/7i2WQxdEQyOcOC3YLsY-VQ?view) ```python for ii in range(3): print('\n\nRound',ii,'starting...') if STATS: simple_structures_stats(ws.sdg) for i in range(3): peds.mapper.path_reads() clip_all_tips(peds,apply=True) if STATS: simple_structures_stats(ws.sdg) if STATS: kc.update_graph_counts() kc.compute_all_kcis() print(ws.sdg.stats_by_kci()) for i in [70,100,200]: peds.mapper.path_reads() solve_all_tangles(ws,i,apply=True) kc.update_graph_counts() kc.compute_all_kcis() if STATS: print(ws.sdg.stats_by_kci()) peds.mapper.path_reads() s=SDG.Strider(ws) s.add_datastore(peds) s.stride_from_anchors(min_kci=.5,max_kci=1.5) strider_run_from_cpp() if STATS: kc.update_graph_counts() kc.compute_all_kcis() print(ws.sdg.stats_by_kci()) ``` ```python lords = ws.add_long_reads_datastore('./nanoporeds.lords.loseq') lrr = SDG.LongReadsRecruiter() ``` ## testing mapper with k=63 and pathing ```python def mapping_report(peds,peds2,offset=1000000,total=1000000): same=old_longer=new_longer=old_empty=new_empty=same_difference=both_empty=0 for x in range(offset,offset+total): p1=list(peds.mapper.read_paths[x].path) p2=list(peds2.mapper.read_paths[x].path) if p1==p2: same+=1 if len(p1)==0: both_empty+=1 else: if len(p1)>len(p2): old_longer+=1 elif len(p2)>len(p1): new_longer+=1 else: same_difference+=1 if len(p1)==0: old_empty+=1 if len(p2)==0: new_empty+=1 print("same = %d (%.2f%%) --> both empty: %d (%.2f%%) " % (same,100*same/total,both_empty,100*both_empty/total)) print("old longer = %d (%.2f%%)" % (old_longer-new_empty,100*(old_longer-new_empty)/total)) print("new longer = %d (%.2f%%)" % (new_longer-old_empty,100*(new_longer-old_empty)/total)) print("old empty = %d (%.2f%%)" % (old_empty,100*old_empty/total)) print("new empty = %d (%.2f%%)" % (new_empty,100*new_empty/total)) print("same length different = %d (%.2f%%)" % (same_difference,100*same_difference/total)) peds1=ws.add_paired_reads_datastore('test.prseq','test1') peds2=ws.add_paired_reads_datastore('test.prseq','test2') peds1.mapper.path_reads(31,50) peds2.mapper.path_reads() mapping_report(peds1,peds2,1,peds1.size()) ```