def _ang(bp, L): devuelve math.pi/2 – 2*math.pi*(bp/L) def _pt(bp, r, L): a = _ang(bp, L); return r*math.cos(a), r*math.sin(a) def _arc(s, e, r, L, n=240): si e < s: e += L bps = np.linspace(s, e, max(2, int(n*(es)/L)+2)) return ([r*math.cos(_ang(b, L)) for b in bps],
[r*math.sin(_ang(b, L)) for b in bps]) def gc_percent(seq): s = str(seq).upper(); n = len(s) o 1 return 100.0 * (s.count("G") + s.count("C")) / n def circular_map(rec, title=None, show_gc=True): L = len(rec.seq); hazañas = norm_features(rec) fig, ax = plt.subplots(figsize=(8, 8)); R = 1,0 si show_gc: w = max(30, L // 120); paso = max(1, w // 2); media = gc_percent(rec.seq) s = str(rec.seq).upper() para i en el rango(0, L, paso): win = s[i:i+w] o s[i:] + s[:(i+w) % L]
dev = (gc_percent(win) - media) / 100,0 rr = 0,72 + dev * 0,9 x0, y0 = _pt(i, 0,72, L); x1, y1 = _pt(i, rr, L) ax.plot([x0, x1], [y0, y1]color="#2e86ab" if dev >= 0 else “#d1495b”, lw=1, alpha=0.5, zorder=1) xs, ys = _arc(0, L, R, L); ax.plot(xs, ys, color=”#333″, lw=2.5, zorder=2) paso = max(1, round(L/12/100)*100) o max(1, L//12) para t en el rango(0, L, paso): x0, y0 = _pt(t, R*1.015, L); x1, y1 = _pt(t, R*1.045, L) ax.plot([x0, x1], [y0, y1]color=”#999″, lw=1, zorder=2) lx, ly = _pt(t, R*1.10, L) ax.text(lx, ly, f”{t:,}”, ha=”center”, va=”center”, fontsize=7, color=”#777″) para f en hazañas: exterior = f[“strand”] >= 0 rr = R + 0.09 si exterior else R – 0.09 xs, ys = _arc(f[“start”]f[“end”]rr, L) ax.plot(xs, ys, color=f[“color”]lw=10, solid_capstyle=”trasero”, alfa=0.9, zorder=3) punta = f[“end”] si exterior más f[“start”]
a = _ang(punta, L); tx, ty = rr*math.cos(a), rr*math.sin(a) d = -1 si el exterior es 1 tanx, tany = -math.sin(a)*d, math.cos(a)*d px, py = math.cos(a), math.sin(a) ln, wd = 0.055, 0.052 ax.add_patch(Polygon([(tx+tanx*ln, ty+tany*ln),
(tx+px*wd, ty+py*wd),
(tx-px*wd, ty-py*wd)]color=f[“color”]orden z = 4)) intervalo = (f[“end”] – f[“start”]) % L medio = (f[“start”] + span/2) % L lx, ly = _pt(mid, (rr + 0.16) if outside else (rr – 0.16), L) ax.text(lx, ly, f[“label”]ha=”centro”, va=”centro”, tamaño de fuente=8.5, color=f[“color”]peso=”bold”, zorder=5) circ = “circular” if rec.annotations.get(“topology”) == “circular” else “linear” ax.text(0, 0.05, título o rec.name, ha=”center”, va=”center”, fontsize=15, peso=”bold”) ax.text(0, -0.07, f”{L:,} pb · {gc_percent(rec.seq):.1f}% GC · {circ}”, ha=”center”, va=”center”, fontsize=9.5, color=”#555″) ax.set_xlim(-1.45, 1.45); ax.set_ylim(-1.45, 1.45) ax.set_aspect(“igual”); eje.eje(“apagado”); plt.tight_layout(); plt.mostrar()
a = _ang(punta, L); tx, ty = rr*math.cos(a), rr*math.sin(a) d = -1 si el exterior es 1 tanx, tany = -math.sin(a)*d, math.cos(a)*d px, py = math.cos(a), math.sin(a) ln, wd = 0.055, 0.052 ax.add_patch(Polygon([(tx+tanx*ln, ty+tany*ln),
(tx+px*wd, ty+py*wd),
(tx-px*wd, ty-py*wd)]color=f[“color”]orden z = 4)) intervalo = (f[“end”] – f[“start”]) % L medio = (f[“start”] + span/2) % L lx, ly = _pt(mid, (rr + 0.16) if outside else (rr – 0.16), L) ax.text(lx, ly, f[“label”]ha=”centro”, va=”centro”, tamaño de fuente=8.5, color=f[“color”]peso=”bold”, zorder=5) circ = “circular” if rec.annotations.get(“topology”) == “circular” else “linear” ax.text(0, 0.05, título o rec.name, ha=”center”, va=”center”, fontsize=15, peso=”bold”) ax.text(0, -0.07, f”{L:,} pb · {gc_percent(rec.seq):.1f}% GC · {circ}”, ha=”center”, va=”center”, fontsize=9.5, color=”#555″) ax.set_xlim(-1.45, 1.45); ax.set_ylim(-1.45, 1.45) ax.set_aspect(“igual”); eje.eje(“apagado”); plt.tight_layout(); plt.mostrar()