def draw_chromosomes( root, bedfile, sizes, iopts, mergedist, winsize, imagemap, mappingfile=None, gauge=False, legend=True, empty=False, title=None, ): bed = Bed(bedfile) prefix = bedfile.rsplit(".", 1)[0] if imagemap: imgmapfile = prefix + ".map" mapfh = open(imgmapfile, "w") print('<map id="' + prefix + '">', file=mapfh) if mappingfile: mappings = DictFile(mappingfile, delimiter="\t") classes = sorted(set(mappings.values())) preset_colors = (DictFile( mappingfile, keypos=1, valuepos=2, delimiter="\t") if DictFile.num_columns(mappingfile) >= 3 else {}) else: classes = sorted(set(x.accn for x in bed)) mappings = dict((x, x) for x in classes) preset_colors = {} logging.debug("A total of {} classes found: {}".format( len(classes), ",".join(classes))) # Assign colors to classes ncolors = max(3, min(len(classes), 12)) palette = set1_n if ncolors <= 8 else set3_n colorset = palette(number=ncolors) colorset = sample_N(colorset, len(classes)) class_colors = dict(zip(classes, colorset)) class_colors.update(preset_colors) logging.debug("Assigned colors: {}".format(class_colors)) chr_lens = {} centromeres = {} if sizes: chr_lens = Sizes(sizes).sizes_mapping else: for b, blines in groupby(bed, key=(lambda x: x.seqid)): blines = list(blines) maxlen = max(x.end for x in blines) chr_lens[b] = maxlen for b in bed: accn = b.accn if accn == "centromere": centromeres[b.seqid] = b.start if accn in mappings: b.accn = mappings[accn] else: b.accn = "-" chr_number = len(chr_lens) if centromeres: assert chr_number == len( centromeres), "chr_number = {}, centromeres = {}".format( chr_number, centromeres) r = 0.7 # width and height of the whole chromosome set xstart, ystart = 0.15, 0.85 xinterval = r / chr_number xwidth = xinterval * 0.5 # chromosome width max_chr_len = max(chr_lens.values()) ratio = r / max_chr_len # canvas / base # first the chromosomes for a, (chr, clen) in enumerate(sorted(chr_lens.items())): xx = xstart + a * xinterval + 0.5 * xwidth root.text(xx, ystart + 0.01, str(get_number(chr)), ha="center") if centromeres: yy = ystart - centromeres[chr] * ratio ChromosomeWithCentromere(root, xx, ystart, yy, ystart - clen * ratio, width=xwidth) else: Chromosome(root, xx, ystart, ystart - clen * ratio, width=xwidth) chr_idxs = dict((a, i) for i, a in enumerate(sorted(chr_lens.keys()))) alpha = 1 # color the regions for chr in sorted(chr_lens.keys()): segment_size, excess = 0, 0 bac_list = [] prev_end, prev_klass = 0, None for b in bed.sub_bed(chr): clen = chr_lens[chr] idx = chr_idxs[chr] klass = b.accn if klass == "centromere": continue start = b.start end = b.end if start < prev_end + mergedist and klass == prev_klass: start = prev_end xx = xstart + idx * xinterval yystart = ystart - end * ratio yyend = ystart - start * ratio root.add_patch( Rectangle( (xx, yystart), xwidth, yyend - yystart, fc=class_colors.get(klass, "lightslategray"), lw=0, alpha=alpha, )) prev_end, prev_klass = b.end, klass if imagemap: """ `segment` : size of current BAC being investigated + `excess` `excess` : left-over bases from the previous BAC, as a result of iterating over `winsize` regions of `segment` """ if excess == 0: segment_start = start segment = (end - start + 1) + excess while True: if segment < winsize: bac_list.append(b.accn) excess = segment break segment_end = segment_start + winsize - 1 tlx, tly, brx, bry = ( xx, (1 - ystart) + segment_start * ratio, xx + xwidth, (1 - ystart) + segment_end * ratio, ) print( "\t" + write_ImageMapLine( tlx, tly, brx, bry, iopts.w, iopts.h, iopts.dpi, chr + ":" + ",".join(bac_list), segment_start, segment_end, ), file=mapfh, ) segment_start += winsize segment -= winsize bac_list = [] if imagemap and excess > 0: bac_list.append(b.accn) segment_end = end tlx, tly, brx, bry = ( xx, (1 - ystart) + segment_start * ratio, xx + xwidth, (1 - ystart) + segment_end * ratio, ) print( "\t" + write_ImageMapLine( tlx, tly, brx, bry, iopts.w, iopts.h, iopts.dpi, chr + ":" + ",".join(bac_list), segment_start, segment_end, ), file=mapfh, ) if imagemap: print("</map>", file=mapfh) mapfh.close() logging.debug("Image map written to `{0}`".format(mapfh.name)) if gauge: xstart, ystart = 0.9, 0.85 Gauge(root, xstart, ystart - r, ystart, max_chr_len) if "centromere" in class_colors: del class_colors["centromere"] # class legends, four in a row if legend: xstart = 0.1 xinterval = 0.8 / len(class_colors) xwidth = 0.04 yy = 0.08 for klass, cc in sorted(class_colors.items()): if klass == "-": continue root.add_patch( Rectangle((xstart, yy), xwidth, xwidth, fc=cc, lw=0, alpha=alpha)) root.text(xstart + xwidth + 0.01, yy, latex(klass), fontsize=10) xstart += xinterval if empty: root.add_patch( Rectangle((xstart, yy), xwidth, xwidth, fill=False, lw=1)) root.text(xstart + xwidth + 0.01, yy, empty, fontsize=10) if title: root.text(0.5, 0.95, markup(title), ha="center", va="center")
def ancestral(args): """ %prog ancestral ancestral.txt assembly.fasta Karyotype evolution of pineapple. The figure is inspired by Amphioxus paper Figure 3 and Tetradon paper Figure 9. """ p = OptionParser(ancestral.__doc__) opts, args, iopts = p.set_image_options(args, figsize="8x7") if len(args) != 2: sys.exit(not p.print_help()) regionsfile, sizesfile = args regions = RegionsFile(regionsfile) sizes = Sizes(sizesfile).mapping sizes = dict((k, v) for (k, v) in sizes.iteritems() if k[:2] == "LG") maxsize = max(sizes.values()) ratio = .5 / maxsize fig = plt.figure(1, (iopts.w, iopts.h)) root = fig.add_axes((0, 0, 1, 1)) from jcvi.graphics.base import set2 a, b, c, d, e, f, g = set2[:7] set2 = (c, g, b, e, d, a, f) # Upper panel is the evolution of segments # All segments belong to one of seven karyotypes 1 to 7 karyotypes = regions.karyotypes xgap = 1. / (1 + len(karyotypes)) ygap = .05 mgap = xgap / 4.5 gwidth = mgap * .75 tip = .02 coords = {} for i, k in enumerate(regions.karyotypes): x = (i + 1) * xgap y = .9 root.text(x, y + tip, "Anc" + k, ha="center") root.plot((x, x), (y, y - ygap), "k-", lw=2) y -= 2 * ygap coords['a'] = (x - 1.5 * mgap , y) coords['b'] = (x - .5 * mgap , y) coords['c'] = (x + .5 * mgap , y) coords['d'] = (x + 1.5 * mgap , y) coords['ab'] = join_nodes_vertical(root, coords, 'a', 'b', y + ygap / 2) coords['cd'] = join_nodes_vertical(root, coords, 'c', 'd', y + ygap / 2) coords['abcd'] = join_nodes_vertical(root, coords, 'ab', 'cd', y + ygap) for n in 'abcd': nx, ny = coords[n] root.text(nx, ny - tip, n, ha="center") coords[n] = (nx, ny - ygap / 2) kdata = regions.get_karyotype(k) for kd in kdata: g = kd.group gx, gy = coords[g] gsize = ratio * kd.span gy -= gsize p = Rectangle((gx - gwidth / 2, gy), gwidth, gsize, lw=0, color=set2[i]) root.add_patch(p) root.text(gx, gy + gsize / 2, kd.chromosome, ha="center", va="center", color='w') coords[g] = (gx, gy - tip) # Bottom panel shows the location of segments on chromosomes # TODO: redundant code, similar to graphics.chromosome ystart = .54 chr_number = len(sizes) xstart, xend = xgap - 2 * mgap, 1 - xgap + 2 * mgap xinterval = (xend - xstart - gwidth) / (chr_number - 1) chrpos = {} for a, (chr, clen) in enumerate(sorted(sizes.items())): chr = get_number(chr) xx = xstart + a * xinterval + gwidth / 2 chrpos[chr] = xx root.text(xx, ystart + .01, chr, ha="center") Chromosome(root, xx, ystart, ystart - clen * ratio, width=gwidth) # Start painting for r in regions: xx = chrpos[r.chromosome] yystart = ystart - r.start * ratio yyend = ystart - r.end * ratio p = Rectangle((xx - gwidth / 2, yystart), gwidth, yyend - yystart, color=set2[int(r.karyotype) - 1], lw=0) root.add_patch(p) root.set_xlim(0, 1) root.set_ylim(0, 1) root.set_axis_off() pf = "pineapple-karyotype" image_name = pf + "." + iopts.format savefig(image_name, dpi=iopts.dpi, iopts=iopts)