def test_single_bp_dup(self): transcript = fusion.FusionTranscript() transcript.position = Interval(1, 500) transcript.exons = [ genomic.Exon(1, 7, transcript=transcript, intact_end_splice=False), genomic.Exon(8, 8, transcript=transcript, intact_start_splice=False, intact_end_splice=False), genomic.Exon(9, 100, transcript=transcript, intact_start_splice=False), genomic.Exon(200, 500, transcript=transcript), ] cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_single_bp_dup.svg')
def test_single_bp_ins_exon(self): transcript = fusion.FusionTranscript() transcript.position = Interval(401258, 408265) transcript.exons = [ genomic.Exon(401258, 401461, transcript=transcript), genomic.Exon(404799, 405254, intact_end_splice=False, transcript=transcript), genomic.Exon( 405255, 405255, intact_start_splice=False, intact_end_splice=False, transcript=transcript, ), genomic.Exon(405256, 408265, intact_start_splice=False, transcript=transcript), ] cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_single_bp_ins_exon.svg')
def test_two_exon_transcript(self): transcript = fusion.FusionTranscript() transcript.position = Interval(1, 555) transcript.exons = [ genomic.Exon(55820038, 55820969, transcript=transcript), genomic.Exon(55820971, 55820976, transcript=transcript), ] transcript.exon_mapping[Interval(55820971, 55820976)] = MockObject( transcript=MockObject(exon_number=lambda *x: 2)) cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_two_exon_transcript.svg')
class Figure(object): def __init__(self): self.elements = [] self.extra = [] self.ticks = [] self.svg = Drawing() def add(self, element, xy): self.elements.append(element) self.extra.append(xy) return element def add_genome(self, xy, name, length): genome = self.add(Genome(name, end=length), xy) return genome def add_genome_from_file(self, xy, file): file_format = file.split(".")[-1] if file_format in "gb|genbank": for record in SeqIO.parse(file, "genbank"): genome = self.add( Genome( name=record.id, end=len(record.seq), ), xy) for feature in record.features: if feature.type == "CDS": name = feature.qualifiers["locus_tag"][0] genome.add_feature( name=name, start=feature.location.start, end=feature.location.end, strand=feature.location.strand, ) break return genome def add_ticks(self, xy, ticks, labels): tick = Axis(ticks, labels) self.elements.append(tick) self.extra.append(xy) return tick def homology(self, name, color): h**o = Homology(name, color) self.elements.append(h**o) self.extra.append([0, 0]) return h**o def save(self, filename="out.svg"): scale = 1200.0 / max([ i.length - i.break_length for i in self.elements if isinstance(i, Genome) ]) genomes = [] for i, e in enumerate(self.elements): if isinstance(e, Genome): genomes.append( e.plot(scale=scale, x=self.extra[i][0], y=self.extra[i][1], stroke="black", stroke_width=2)) continue self.svg.add( e.plot(scale=scale, x=self.extra[i][0], y=self.extra[i][1], stroke="black", stroke_width=2)) for g in genomes: self.svg.add(g) self.svg.saveas(filename, pretty=True)
class TestDraw(unittest.TestCase): def setUp(self): self.canvas = Drawing(height=100, width=1000) def test_generate_interval_mapping_outside_range_error(self): temp = [ Interval(48556470, 48556646), Interval(48573290, 48573665), Interval(48575056, 48575078), ] mapping = generate_interval_mapping( input_intervals=temp, target_width=431.39453125, ratio=20, min_width=14, buffer_length=None, end=None, start=None, min_inter_width=10, ) st = min([x.start for x in temp]) end = min([x.end for x in temp]) Interval.convert_pos(mapping, st) Interval.convert_pos(mapping, end) def test_generate_gene_mapping_err(self): # _generate_interval_mapping [genomic.IntergenicRegion(11:77361962_77361962+)] 1181.39453125 5 30 None 77356962 77366962) ir = genomic.IntergenicRegion('11', 5000, 5000, STRAND.POS) tgt_width = 1000 d = DiagramSettings() d.gene_min_buffer = 10 # (self, canvas, gene, width, height, fill, label='', reference_genome=None) draw_genes(d, self.canvas, [ir], tgt_width, []) # _generate_interval_mapping ['Interval(29684391, 29684391)', 'Interval(29663998, 29696515)'] 1181.39453125 5 60 None 29662998 29697515 # def generate_interval_mapping(cls, input_intervals, target_width, ratio, min_width, buffer_length=None, start=None, end=None, min_inter_width=None) itvls = [Interval(29684391, 29684391), Interval(29663998, 29696515)] generate_interval_mapping(itvls, 1181.39, 5, 60, None, 29662998, 29697515) def test_split_intervals_into_tracks(self): # ----======--------- # ------======-------- # -----=============== t = split_intervals_into_tracks([(1, 3), (3, 7), (2, 2), (4, 5), (3, 10)]) self.assertEqual(3, len(t)) self.assertEqual([(1, 3), (4, 5)], t[0]) self.assertEqual([(2, 2), (3, 7)], t[1]) self.assertEqual([(3, 10)], t[2]) def test_draw_genes(self): x = genomic.Gene('1', 1000, 2000, strand=STRAND.POS) y = genomic.Gene('1', 5000, 7000, strand=STRAND.NEG) z = genomic.Gene('1', 1500, 2500, strand=STRAND.POS) d = DiagramSettings() breakpoints = [Breakpoint('1', 1100, 1200, orient=ORIENT.RIGHT)] g = draw_genes( d, self.canvas, [x, y, z], 500, breakpoints, { x: d.gene1_color, y: d.gene2_color_selected, z: d.gene2_color }, ) # test the class structure self.assertEqual(6, len(g.elements)) self.assertEqual('scaffold', g.elements[0].attribs.get('class', '')) for i in range(1, 4): self.assertEqual('gene', g.elements[i].attribs.get('class', '')) self.assertEqual('mask', g.elements[4].attribs.get('class', '')) self.assertEqual('breakpoint', g.elements[5].attribs.get('class', '')) self.assertEqual( d.track_height * 2 + d.padding + d.breakpoint_bottom_margin + d.breakpoint_top_margin, g.height, ) self.canvas.add(g) self.assertEqual(len(g.labels), 4) self.assertEqual(x, g.labels['G1']) self.assertEqual(z, g.labels['G2']) self.assertEqual(y, g.labels['G3']) self.assertEqual(breakpoints[0], g.labels['B1']) def test_draw_ustranscript(self): d = DiagramSettings() # domains = [protein.Domain()] d1 = protein.Domain('first', [(55, 61), (71, 73)]) d2 = protein.Domain('second', [(10, 20), (30, 34)]) t = build_transcript( gene=None, cds_start=50, cds_end=249, exons=[(1, 99), (200, 299), (400, 499)], strand=STRAND.NEG, domains=[d2, d1], ) b = Breakpoint('1', 350, 410, orient=ORIENT.LEFT) g = draw_ustranscript(d, self.canvas, t, 500, colors={t.exons[1]: '#FFFF00'}, breakpoints=[b]) self.canvas.add(g) # self.canvas.saveas('test_draw_ustranscript.svg') self.assertEqual(2, len(self.canvas.elements)) self.assertEqual(3, len(g.elements)) for el, cls in zip(g.elements[0].elements, ['splicing', 'exon_track', 'protein']): self.assertEqual(cls, el.attribs.get('class', '')) for el, cls in zip(g.elements[0].elements[1].elements, ['scaffold', 'exon', 'exon', 'exon']): self.assertEqual(cls, el.attribs.get('class', '')) for el, cls in zip(g.elements[0].elements[2].elements, ['translation', 'domain', 'domain']): self.assertEqual(cls, el.attribs.get('class', '')) self.assertEqual( sum([ d.track_height, d.splice_height, 2 * d.padding, d.domain_track_height * 2, d.translation_track_height, d.padding, d.breakpoint_top_margin, d.breakpoint_bottom_margin, ]), g.height, ) self.assertEqual(d1.name, g.labels['D1']) self.assertEqual(d2.name, g.labels['D2']) def test_draw_consec_exons(self): d = DiagramSettings() # domains = [protein.Domain()] t = build_transcript( gene=None, cds_start=50, cds_end=249, exons=[(1, 99), (200, 299), (300, 350), (400, 499)], strand=STRAND.POS, domains=[], ) b = Breakpoint('1', 350, 410, orient=ORIENT.LEFT) g = draw_ustranscript(d, self.canvas, t, 500, colors={t.exons[1]: '#FFFF00'}, breakpoints=[b]) self.canvas.add(g) if OUTPUT_SVG: self.canvas.saveas('test_draw_consec_exons.svg') # self.canvas.saveas('test_draw_ustranscript.svg') self.assertEqual(2, len(self.canvas.elements)) self.assertEqual(3, len(g.elements)) # check that only 2 splicing marks were created self.assertEqual(2, len(g.elements[0].elements[0].elements)) # get the second exon ex2 = g.elements[0].elements[1].elements[2].elements[0] print(ex2) self.assertAlmostEqual(120.7783426339, ex2.attribs.get('width')) # get the third exon ex3 = g.elements[0].elements[1].elements[3].elements[0] print(ex3) self.assertAlmostEqual(96.52494419642852, ex3.attribs.get('width')) def test_dynamic_label_color(self): self.assertEqual(HEX_WHITE, dynamic_label_color(HEX_BLACK)) self.assertEqual(HEX_BLACK, dynamic_label_color(HEX_WHITE)) def test_draw_legend(self): d = DiagramSettings() swatches = [ ('#000000', 'black'), ('#FF0000', 'red'), ('#0000FF', 'blue'), ('#00FF00', 'green'), ('#FFFF00', 'yellow'), ] g = draw_legend(d, self.canvas, swatches) self.canvas.add(g) self.assertEqual('legend', g.attribs.get('class', '')) self.assertEqual( d.legend_swatch_size * len(swatches) + d.padding * (len(swatches) - 1 + 2), g.height) self.assertEqual(6, len(g.elements)) self.assertEqual( 6 * d.legend_font_size * d.font_width_height_ratio + d.padding * 3 + d.legend_swatch_size, g.width, ) def test_draw_layout_single_transcript(self): d = DiagramSettings() d1 = protein.Domain('first', [(55, 61), (71, 73)]) d2 = protein.Domain('second', [(10, 20), (30, 34)]) g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS) t = build_transcript(g1, [(200, 299), (400, 499), (700, 899)], 50, 249, [d2, d1]) b1 = Breakpoint('1', 350, orient=ORIENT.RIGHT) b2 = Breakpoint('1', 600, orient=ORIENT.LEFT) bpp = BreakpointPair(b1, b2, opposing_strands=False, untemplated_seq='') ann = variant.Annotation(bpp, transcript1=t, transcript2=t, event_type=SVTYPE.DUP, protocol=PROTOCOL.GENOME) ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS)) reference_genome = {'1': MockObject(seq=MockString('A'))} ft = variant.FusionTranscript.build(ann, reference_genome) ann.fusion = ft canvas, legend = draw_sv_summary_diagram(d, ann) self.assertEqual(4, len(canvas.elements)) # defs counts as element expected_height = (d.top_margin + d.bottom_margin + d.track_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.inner_margin + d.track_height + d.splice_height + d.padding + d.translation_track_height + d.padding * 2 + d.domain_track_height * 2 + d.inner_margin + d.track_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.splice_height) if OUTPUT_SVG: canvas.saveas('test_draw_layout_single_transcript.svg') self.assertEqual(expected_height, canvas.attribs['height']) def test_draw_layout_single_genomic(self): d = DiagramSettings() d1 = protein.Domain('first', [(55, 61), (71, 73)]) d2 = protein.Domain('second', [(10, 20), (30, 34)]) g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS) g2 = genomic.Gene('1', 5000, 7500, strand=STRAND.POS) t1 = build_transcript( gene=g1, cds_start=50, cds_end=249, exons=[(200, 299), (400, 499), (700, 899)], domains=[d2, d1], ) t2 = build_transcript( gene=g2, cds_start=20, cds_end=500, exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)], domains=[], ) b1 = Breakpoint('1', 350, orient=ORIENT.LEFT) b2 = Breakpoint('1', 6500, orient=ORIENT.RIGHT) bpp = BreakpointPair(b1, b2, opposing_strands=False, untemplated_seq='') ann = variant.Annotation(bpp, transcript1=t1, transcript2=t2, event_type=SVTYPE.DEL, protocol=PROTOCOL.GENOME) ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS)) ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS)) ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG)) reference_genome = {'1': MockObject(seq=MockString('A'))} ft = variant.FusionTranscript.build(ann, reference_genome) ann.fusion = ft self.assertEqual(t1.exons[0], ft.exon_mapping[ft.exons[0].position]) self.assertEqual(t2.exons[2], ft.exon_mapping[ft.exons[1].position]) self.assertEqual(t2.exons[3], ft.exon_mapping[ft.exons[2].position]) canvas, legend = draw_sv_summary_diagram(d, ann) self.assertEqual(5, len(canvas.elements)) # defs counts as element expected_height = (d.top_margin + d.bottom_margin + d.track_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.inner_margin + d.track_height + d.splice_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.padding + d.translation_track_height + d.padding * 2 + d.domain_track_height * 2 + d.inner_margin + d.track_height + d.splice_height) self.assertEqual(expected_height, canvas.attribs['height']) if OUTPUT_SVG: canvas.saveas('test_draw_layout_single_genomic.svg') def test_draw_layout_translocation(self): d = DiagramSettings() d1 = protein.Domain('first', [(55, 61), (71, 73)]) d2 = protein.Domain('second', [(10, 20), (30, 34)]) g1 = genomic.Gene('1', 150, 1000, strand=STRAND.POS) g2 = genomic.Gene('2', 5000, 7500, strand=STRAND.NEG) t1 = build_transcript( gene=g1, cds_start=50, cds_end=249, exons=[(200, 299), (400, 499), (700, 899)], domains=[d2, d1], ) t2 = build_transcript( gene=g2, cds_start=120, cds_end=700, exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)], domains=[], ) b1 = Breakpoint('1', 350, orient=ORIENT.LEFT) b2 = Breakpoint('2', 6520, orient=ORIENT.LEFT) bpp = BreakpointPair(b1, b2, opposing_strands=True, untemplated_seq='') ann = variant.Annotation(bpp, transcript1=t1, transcript2=t2, event_type=SVTYPE.ITRANS, protocol=PROTOCOL.GENOME) # genes 1 ann.add_gene(genomic.Gene('1', 1500, 1950, strand=STRAND.POS)) ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS)) ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG)) # genes 2 ann.add_gene(genomic.Gene('2', 1500, 1950, strand=STRAND.NEG)) ann.add_gene(genomic.Gene('2', 5500, 9000, strand=STRAND.POS)) ann.add_gene(genomic.Gene('2', 3700, 4400, strand=STRAND.NEG)) reference_genome = { '1': MockObject(seq=MockString('A')), '2': MockObject(seq=MockString('A')), } ft = variant.FusionTranscript.build(ann, reference_genome) ann.fusion = ft canvas, legend = draw_sv_summary_diagram(d, ann) self.assertEqual(6, len(canvas.elements)) # defs counts as element expected_height = ( d.top_margin + d.bottom_margin + d.track_height * 2 + d.padding + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.inner_margin + d.track_height + d.splice_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.padding + d.translation_track_height + d.padding * 2 + d.domain_track_height * 2 + d.inner_margin + d.track_height + d.splice_height) self.assertEqual(expected_height, canvas.attribs['height']) def test_draw_template(self): # def draw_template(self, canvas, template, target_width, height, labels=None, colors=None): d = DiagramSettings() canvas = Drawing(size=(1000, 50)) t = genomic.Template( '1', 1, 100000, bands=[ BioInterval(None, 1, 8000, 'p1'), BioInterval(None, 10000, 15000, 'p2') ], ) g = draw_template(d, canvas, t, 1000) canvas.add(g) canvas.attribs['height'] = g.height canvas = Drawing(size=(1000, 50)) g = draw_template(d, canvas, TEMPLATE_METADATA['1'], 1000) self.assertEqual( d.breakpoint_top_margin + d.breakpoint_bottom_margin + d.template_track_height, g.height) canvas.add(g) canvas.attribs['height'] = g.height self.assertEqual(2, len(canvas.elements)) def test_draw_translocation_with_template(self): d = DiagramSettings() d1 = protein.Domain('PF0001', [(55, 61), (71, 73)]) d2 = protein.Domain('PF0002', [(10, 20), (30, 34)]) g1 = genomic.Gene(TEMPLATE_METADATA['1'], 150, 1000, strand=STRAND.POS, aliases=['HUGO2']) g2 = genomic.Gene(TEMPLATE_METADATA['X'], 5000, 7500, strand=STRAND.NEG, aliases=['HUGO3']) t1 = build_transcript( gene=g1, name='transcript1', cds_start=50, cds_end=249, exons=[(200, 299), (400, 499), (700, 899)], domains=[d2, d1], ) t2 = build_transcript( gene=g2, name='transcript2', cds_start=120, cds_end=700, exons=[(5100, 5299), (5800, 6199), (6500, 6549), (6700, 6799)], domains=[], ) b1 = Breakpoint('1', 350, orient=ORIENT.LEFT) b2 = Breakpoint('2', 6520, orient=ORIENT.LEFT) bpp = BreakpointPair(b1, b2, opposing_strands=True, untemplated_seq='') ann = variant.Annotation(bpp, transcript1=t1, transcript2=t2, event_type=SVTYPE.ITRANS, protocol=PROTOCOL.GENOME) # genes 1 ann.add_gene( genomic.Gene('1', 1500, 1950, strand=STRAND.POS, aliases=['HUGO5'])) ann.add_gene(genomic.Gene('1', 3000, 3980, strand=STRAND.POS)) ann.add_gene(genomic.Gene('1', 3700, 4400, strand=STRAND.NEG)) # genes 2 ann.add_gene(genomic.Gene('2', 1500, 1950, strand=STRAND.NEG)) ann.add_gene(genomic.Gene('2', 5500, 9000, strand=STRAND.POS)) ann.add_gene(genomic.Gene('2', 3700, 4400, strand=STRAND.NEG)) reference_genome = { '1': MockObject(seq=MockString('A')), '2': MockObject(seq=MockString('A')), } ft = variant.FusionTranscript.build(ann, reference_genome) ann.fusion = ft canvas, legend = draw_sv_summary_diagram(d, ann, draw_reference_templates=True, templates=TEMPLATE_METADATA) if OUTPUT_SVG: canvas.saveas('test_draw_translocation_with_template.svg') self.assertEqual(8, len(canvas.elements)) # defs counts as element expected_height = ( d.top_margin + d.bottom_margin + d.track_height * 2 + d.padding + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.inner_margin + d.track_height + d.splice_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.padding + d.translation_track_height + d.padding * 2 + d.domain_track_height * 2 + d.inner_margin * 2 + d.track_height + d.breakpoint_bottom_margin + d.breakpoint_top_margin + d.splice_height + d.template_track_height) self.assertAlmostEqual(expected_height, canvas.attribs['height']) def test_draw_overlay(self): gene = genomic.Gene('12', 25357723, 25403870, strand=STRAND.NEG, name='KRAS') marker = BioInterval('12', 25403865, name='splice site mutation') t = build_transcript( cds_start=193, cds_end=759, exons=[ (25403685, 25403865), (25398208, 25398329), (25380168, 25380346), (25378548, 25378707), (25357723, 25362845), ], gene=gene, domains=[], ) build_transcript( cds_start=198, cds_end=425, exons=[(25403685, 25403870), (25398208, 25398329), (25362102, 25362845)], gene=gene, domains=[], ) build_transcript( cds_start=65, cds_end=634, exons=[ (25403685, 25403737), (25398208, 25398329), (25380168, 25380346), (25378548, 25378707), (25368371, 25368494), (25362365, 25362845), ], gene=gene, domains=[ protein.Domain('domain1', [(1, 10)]), protein.Domain('domain1', [(4, 10)]) ], is_best_transcript=True, ) build_transcript( cds_start=65, cds_end=634, exons=[(25403698, 25403863), (25398208, 25398329), (25386753, 25388160)], gene=gene, domains=[], ) d = DiagramSettings() for i, t in enumerate(gene.transcripts): t.name = 'transcript {}'.format(i + 1) scatterx = [x + 100 for x in range(gene.start, gene.end + 1, 400)] scattery = [random.uniform(-0.2, 0.2) for x in scatterx] s = ScatterPlot(list(zip(scatterx, scattery)), 'cna', ymin=-1, ymax=1, yticks=[-1, 0, 1]) d.gene_min_buffer = 0 canvas = draw_multi_transcript_overlay(d, gene, vmarkers=[marker], plots=[s, s]) self.assertEqual(2, len(canvas.elements)) # defs counts as element if OUTPUT_SVG: canvas.saveas('test_draw_overlay.svg') def test_single_bp_ins_exon(self): transcript = fusion.FusionTranscript() transcript.position = Interval(401258, 408265) transcript.exons = [ genomic.Exon(401258, 401461, transcript=transcript), genomic.Exon(404799, 405254, intact_end_splice=False, transcript=transcript), genomic.Exon( 405255, 405255, intact_start_splice=False, intact_end_splice=False, transcript=transcript, ), genomic.Exon(405256, 408265, intact_start_splice=False, transcript=transcript), ] cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_single_bp_ins_exon.svg') def test_single_bp_dup(self): transcript = fusion.FusionTranscript() transcript.position = Interval(1, 500) transcript.exons = [ genomic.Exon(1, 7, transcript=transcript, intact_end_splice=False), genomic.Exon(8, 8, transcript=transcript, intact_start_splice=False, intact_end_splice=False), genomic.Exon(9, 100, transcript=transcript, intact_start_splice=False), genomic.Exon(200, 500, transcript=transcript), ] cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_single_bp_dup.svg') def test_two_exon_transcript(self): transcript = fusion.FusionTranscript() transcript.position = Interval(1, 555) transcript.exons = [ genomic.Exon(55820038, 55820969, transcript=transcript), genomic.Exon(55820971, 55820976, transcript=transcript), ] transcript.exon_mapping[Interval(55820971, 55820976)] = MockObject( transcript=MockObject(exon_number=lambda *x: 2)) cfg = DiagramSettings(width=1500) canvas = Drawing(size=(cfg.width, 1000)) drawing_width = cfg.width - cfg.label_left_margin - cfg.left_margin - cfg.right_margin canvas.add( draw_ustranscript(cfg, canvas, transcript, target_width=drawing_width)) if OUTPUT_SVG: canvas.saveas('test_two_exon_transcript.svg')
def process(self): items = {} max_weight = 1 colour_property = self.options.get( "colour_property", self.options["colour_property"]["default"]) size_property = self.options.get( "size_property", self.options["size_property"]["default"]) # first create a map with the ranks for each period with self.source_file.open() as input: reader = csv.DictReader(input) weight_attribute = "value" if "value" in reader.fieldnames else "frequency" item_attribute = "item" if "item" in reader.fieldnames else "text" date_attribute = "date" if "date" in reader.fieldnames else "time" weighted = (weight_attribute in reader.fieldnames) for row in reader: if row[date_attribute] not in items: items[row[date_attribute]] = {} weight = convert_to_int(row[weight_attribute], 1) if weighted else 1 items[row[date_attribute]][row[item_attribute]] = weight max_weight = max(max_weight, weight) # determine per-period changes # this is used for determining what colour to give to nodes, and # visualise outlying items in the data changes = {} max_change = 1 for period in items: changes[period] = {} for item in items[period]: now = items[period][item] then = -1 for previous_period in items: if previous_period == period: break for previous_item in items[previous_period]: if previous_item == item: then = items[previous_period][item] if then >= 0: change = abs(now - then) max_change = max(max_change, change) changes[period][item] = change else: changes[period][item] = 1 # some sizing parameters for the chart - experiment with those box_width = 12 box_height = 10 # boxes will never be smaller than this box_max_height = 100 box_gap_x = 90 box_gap_y = 5 # don't change this - initial X value for top left box box_start_x = 0 # we use this to know if and where to draw the flow curve between a box # and its previous counterpart previous_boxes = {} previous = [] # we need to store the svg elements before drawing them to the canvas # because we need to know what elements to draw before we can set the # canvas up for drawing to boxes = [] labels = [] flows = [] definitions = [] # this is the default colour for items (it's blue-ish) # we're using HSV, so we can increase the hue for more prominent items base_colour = [.55, .95, .95] max_y = 0 # go through all periods and draw boxes and flows for period in items: # reset Y coordinate, i.e. start at top box_start_y = 0 for item in items[period]: # determine weight (and thereby height) of this particular item weight = items[period][item] weight_factor = weight / max_weight height = int(max(box_height, box_max_height * weight_factor) ) if size_property and weighted else box_height # colour ranges from blue to red change = changes[period][item] change_factor = 0 if not weighted or change <= 0 else ( changes[period][item] / max_change) colour = base_colour.copy() colour[0] += (1 - base_colour[0]) * ( weight_factor if colour_property == "weight" else change_factor) # first draw the box box_fill = "rgb(%i, %i, %i)" % tuple( [int(v * 255) for v in colorsys.hsv_to_rgb(*colour)]) box = Rect(insert=(box_start_x, box_start_y), size=(box_width, height), fill=box_fill) boxes.append(box) # then the text label label_y = (box_start_y + (height / 2)) + 3 label = Text( text=(item + (" (%s)" % weight if weight != 1 else "")), insert=(box_start_x + box_width + box_gap_y, label_y)) labels.append(label) # store the max y coordinate, which marks the SVG overall height max_y = max(max_y, (box["y"] + box["height"])) # then draw the flow curve, if the box was ranked in an earlier # period as well if item in previous: previous_box = previous_boxes[item] # create a gradient from the colour of the previous box for # this item to this box's colour colour_from = previous_box["fill"] colour_to = box["fill"] gradient = LinearGradient(start=(0, 0), end=(1, 0)) gradient.add_stop_color(offset="0%", color=colour_from) gradient.add_stop_color(offset="100%", color=colour_to) definitions.append(gradient) # the addition of ' none' in the auto-generated fill colour # messes up some viewers/browsers, so get rid of it gradient_key = gradient.get_paint_server().replace( " none", "") # calculate control points for the connecting bezier bar # the top_offset determines the 'steepness' of the curve, # experiment with the "/ 2" part to make it less or more # steep top_offset = (box["x"] - previous_box["x"] + previous_box["width"]) / 2 control_top_left = (previous_box["x"] + previous_box["width"] + top_offset, previous_box["y"]) control_top_right = (box["x"] - top_offset, box["y"]) bottom_offset = top_offset # mirroring looks best control_bottom_left = (previous_box["x"] + previous_box["width"] + bottom_offset, previous_box["y"] + previous_box["height"]) control_bottom_right = (box["x"] - bottom_offset, box["y"] + box["height"]) # now add the bezier curves - svgwrite has no convenience # function for beziers unfortunately. we're using cubic # beziers though quadratic could work as well since our # control points are, in principle, mirrored flow_start = (previous_box["x"] + previous_box["width"], previous_box["y"]) flow = Path(fill=gradient_key, opacity="0.35") flow.push("M %f %f" % flow_start) # go to start flow.push("C %f %f %f %f %f %f" % (*control_top_left, *control_top_right, box["x"], box["y"])) # top bezier flow.push( "L %f %f" % (box["x"], box["y"] + box["height"])) # right boundary flow.push("C %f %f %f %f %f %f" % (*control_bottom_right, *control_bottom_left, previous_box["x"] + previous_box["width"], previous_box["y"] + previous_box["height"])) # bottom bezier flow.push("L %f %f" % flow_start) # back to start flow.push("Z") # close path flows.append(flow) # mark this item as having appeared previously previous.append(item) previous_boxes[item] = box box_start_y += height + box_gap_y box_start_x += (box_gap_x + box_width) # generate SVG canvas to add elements to canvas = Drawing(self.dataset.get_results_path(), size=(len(items) * (box_width + box_gap_x), max_y), style="font-family:monospace;font-size:8px;") # now add the various shapes and paths. We only do this here rather than # as we go because only at this point can the canvas be instantiated, as # before we don't know the dimensions of the SVG drawing. # add our gradients so they can be referenced for definition in definitions: canvas.defs.add(definition) # add flows (which should go beyond the boxes) for flow in flows: canvas.add(flow) # add boxes and labels: for item in (*boxes, *labels): canvas.add(item) # finally, save the svg file canvas.saveas(pretty=True, filename=str(self.dataset.get_results_path())) self.dataset.finish(len(items) * len(list(items.items()).pop()))