func tracks(scores []rings.Scorer, diameter vg.Length) ([]plot.Plotter, error) { var p []plot.Plotter radius := diameter / 2 // Relative sizes. const ( gap = 0.005 label = 117. / 110. countsInner = 97. / 110. countsOuter = 70. / 110. karyotypeInner = 100. / 110. karyotypeOuter = 1. large = 6. / 110. small = 2. / 110. ) sty := plotter.DefaultLineStyle sty.Width /= 2 chr := make([]feat.Feature, len(hg19.Chromosomes)) for i, c := range hg19.Chromosomes { chr[i] = c } hs, err := rings.NewGappedBlocks( chr, rings.Arc{rings.Complete / 4 * rings.CounterClockwise, rings.Complete * rings.Clockwise}, radius*karyotypeInner, radius*karyotypeOuter, gap, ) if err != nil { return nil, err } hs.LineStyle = sty p = append(p, hs) bands := make([]feat.Feature, len(hg19.Bands)) cens := make([]feat.Feature, 0, len(hg19.Chromosomes)) for i, b := range hg19.Bands { bands[i] = colorBand{b} s := b.Start() // This condition depends on p -> q sort order in the $karyotype.Bands variable. // All standard genome packages follow this, though here the test is more general than // actually required since hs is telocentric. if b.Band[0] == 'q' && (s == 0 || hg19.Bands[i-1].Band[0] == 'p') { cens = append(cens, colorBand{&genome.Band{Band: "cen", Desc: "Band", StartPos: s, EndPos: s, Giemsa: "acen", Chr: b.Location()}}) } } b, err := rings.NewBlocks(bands, hs, radius*karyotypeInner, radius*karyotypeOuter) if err != nil { return nil, fmt.Errorf("bands: %v", err) } p = append(p, b) c, err := rings.NewBlocks(cens, hs, radius*karyotypeInner, radius*karyotypeOuter) if err != nil { return nil, fmt.Errorf("centromeres: %v", err) } p = append(p, c) font, err := vg.MakeFont("Helvetica", radius*large) if err != nil { return nil, err } lb, err := rings.NewLabels(hs, radius*label, rings.NameLabels(hs.Set)...) if err != nil { return nil, err } lb.TextStyle = draw.TextStyle{Color: color.Gray16{0}, Font: font} p = append(p, lb) smallFont, err := vg.MakeFont("Helvetica", radius*small) if err != nil { return nil, err } counts := make([]rings.Scorer, len(scores)) for i, s := range scores { counts[i] = s.(*feature) } ct, err := rings.NewScores(counts, hs, radius*countsInner, radius*countsOuter, &rings.Trace{ LineStyles: func() []draw.LineStyle { ls := []draw.LineStyle{sty} ls[0].Color = color.Gray16{0} return ls }(), Join: true, Axis: &rings.Axis{ Angle: rings.Complete / 4, Grid: plotter.DefaultGridLineStyle, LineStyle: sty, Tick: rings.TickConfig{ Marker: plot.DefaultTicks{}, LineStyle: sty, Length: 2, Label: draw.TextStyle{Color: color.Gray16{0}, Font: smallFont}, }, }, }, ) if err != nil { return nil, err } p = append(p, ct) return p, nil }
func mouseTracks(scores []rings.Scorer, highlight []string, palname string, diameter vg.Length, lenRange int) (pp []plot.Plotter, lo, hi float64, err error) { var p []plot.Plotter radius := diameter / 2 // Relative sizes. const ( gap = 0.005 label = 117. / 110. countsInner = 25. / 110. countsOuter = 40. / 110. heatInner = 45. / 110. heatOuter = 75. / 110. traceInner = 80. / 110. traceOuter = 95. / 110. karyotypeInner = 100. / 110. karyotypeOuter = 1. large = 7. / 110. small = 2. / 110. ) sty := plotter.DefaultLineStyle sty.Width /= 2 chr := make([]feat.Feature, len(mm10.Chromosomes)) for i, c := range mm10.Chromosomes { chr[i] = c } mm, err := rings.NewGappedBlocks( chr, rings.Arc{rings.Complete / 4 * rings.CounterClockwise, rings.Complete * rings.Clockwise}, radius*karyotypeInner, radius*karyotypeOuter, gap, ) if err != nil { return nil, 0, 0, err } mm.LineStyle = sty pal, err := brewer.GetPalette(brewer.TypeQualitative, palname, len(highlight)) if err == nil { for i, hn := range highlight { for _, c := range mm.Set { if hn == strings.ToLower(c.Name()) { arc, err := mm.Base.ArcOf(c, nil) arc.Theta += rings.Complete * gap / 2 arc.Phi -= rings.Complete * gap if err != nil { fmt.Printf("could not find: %s\n", hn) break } col := pal.Colors()[i] nc := color.NRGBAModel.Convert(col).(color.NRGBA) nc.A = 0x40 h := rings.NewHighlight( nc, arc, radius*(traceInner-2.5/110.), radius*(label+5./110.), ) h.LineStyle = sty h.LineStyle.Width /= 4 p = append(p, h) break } } } } else if len(highlight) > 0 { fmt.Println("no palette") } p = append(p, mm) bands := make([]feat.Feature, len(mm10.Bands)) cens := make([]feat.Feature, 0, len(mm10.Chromosomes)) for i, b := range mm10.Bands { bands[i] = colorBand{b} s := b.Start() // This condition depends on p -> q sort order in the $karyotype.Bands variable. // All standard genome packages follow this, though here the test is more general than // actually required since mm is telocentric. if b.Band[0] == 'q' && (s == 0 || mm10.Bands[i-1].Band[0] == 'p') { cens = append(cens, colorBand{&genome.Band{Band: "cen", Desc: "Band", StartPos: s, EndPos: s, Giemsa: "acen", Chr: b.Location()}}) } } b, err := rings.NewBlocks(bands, mm, radius*karyotypeInner, radius*karyotypeOuter) if err != nil { return nil, 0, 0, fmt.Errorf("bands: %v", err) } p = append(p, b) c, err := rings.NewBlocks(cens, mm, radius*karyotypeInner, radius*karyotypeOuter) if err != nil { return nil, 0, 0, fmt.Errorf("centromeres: %v", err) } p = append(p, c) font, err := vg.MakeFont("Helvetica", radius*large) if err != nil { return nil, 0, 0, err } lb, err := rings.NewLabels(mm, radius*label, rings.NameLabels(mm.Set)...) if err != nil { return nil, 0, 0, err } lb.TextStyle = draw.TextStyle{Color: color.Gray16{0}, Font: font} p = append(p, lb) s, err := rings.NewScores(scores, mm, radius*heatInner, radius*heatOuter, &rings.Heat{Palette: palette.Heat(10, 1).Colors()}, ) if err != nil { return nil, 0, 0, err } p = append(p, s) smallFont, err := vg.MakeFont("Helvetica", radius*small) if err != nil { return nil, 0, 0, err } traces := make([]rings.Scorer, len(scores)) for i, s := range scores { traces[i] = &tfs{s.(*feature)} } t, err := rings.NewScores(traces, mm, radius*traceInner, radius*traceOuter, &rings.Trace{ LineStyles: func() []draw.LineStyle { ls := []draw.LineStyle{sty, sty} for i, c := range brewer.Set1[3].Colors()[:len(ls)] { nc := color.NRGBAModel.Convert(c).(color.NRGBA) nc.A = 0x80 ls[i].Color = nc } return ls }(), Join: true, Axis: &rings.Axis{ Angle: rings.Complete / 4, Grid: plotter.DefaultGridLineStyle, LineStyle: sty, Tick: rings.TickConfig{ Marker: plot.DefaultTicks{}, LineStyle: sty, Length: 2, Label: draw.TextStyle{Color: color.Gray16{0}, Font: smallFont}, }, }, }, ) if err != nil { return nil, 0, 0, err } if maxTrace != 0 { t.Max = maxTrace if t.Min > t.Max { return nil, 0, 0, fmt.Errorf("maximum trace out of range: min=%f", t.Min) } } if !math.IsInf(t.Max-t.Min, 0) { p = append(p, t) } counts := make([]rings.Scorer, len(scores)) for i, s := range scores { counts[i] = ctfs{s.(*feature)} } ct, err := rings.NewScores(counts, mm, radius*countsInner, radius*countsOuter, &rings.Trace{ LineStyles: func() []draw.LineStyle { ls := []draw.LineStyle{sty} ls[0].Color = color.Gray16{0} return ls }(), Join: true, Axis: &rings.Axis{ Angle: rings.Complete / 4, Grid: plotter.DefaultGridLineStyle, LineStyle: sty, Tick: rings.TickConfig{ Marker: plot.DefaultTicks{}, LineStyle: sty, Length: 2, Label: draw.TextStyle{Color: color.Gray16{0}, Font: smallFont}, }, }, }, ) if err != nil { return nil, 0, 0, err } if maxCounts != 0 { ct.Max = maxCounts if ct.Min > ct.Max { return nil, 0, 0, fmt.Errorf("maximum counts out of range: min=%f", ct.Min) } } p = append(p, ct) return p, s.Min, s.Max, nil }