// Draw the plotinum logo. func Example_logo() *plot.Plot { p, err := plot.New() if err != nil { panic(err) } plotter.DefaultLineStyle.Width = vg.Points(1) plotter.DefaultGlyphStyle.Radius = vg.Points(3) p.Y.Tick.Marker = plot.ConstantTicks([]plot.Tick{ {0, "0"}, {0.25, ""}, {0.5, "0.5"}, {0.75, ""}, {1, "1"}, }) p.X.Tick.Marker = plot.ConstantTicks([]plot.Tick{ {0, "0"}, {0.25, ""}, {0.5, "0.5"}, {0.75, ""}, {1, "1"}, }) pts := plotter.XYs{{0, 0}, {0, 1}, {0.5, 1}, {0.5, 0.6}, {0, 0.6}} line := must(plotter.NewLine(pts)).(*plotter.Line) scatter := must(plotter.NewScatter(pts)).(*plotter.Scatter) p.Add(line, scatter) pts = plotter.XYs{{1, 0}, {0.75, 0}, {0.75, 0.75}} line = must(plotter.NewLine(pts)).(*plotter.Line) scatter = must(plotter.NewScatter(pts)).(*plotter.Scatter) p.Add(line, scatter) pts = plotter.XYs{{0.5, 0.5}, {1, 0.5}} line = must(plotter.NewLine(pts)).(*plotter.Line) scatter = must(plotter.NewScatter(pts)).(*plotter.Scatter) p.Add(line, scatter) return p }
// AddLines adds Line plotters to a plot. // The variadic arguments must be either strings // or plotter.XYers. Each plotter.XYer is added to // the plot using the next color and dashes // shape via the Color and Dashes functions. // If a plotter.XYer is immediately preceeded by // a string then a legend entry is added to the plot // using the string as the name. // // If an error occurs then none of the plotters are added // to the plot, and the error is returned. func AddLines(plt *plot.Plot, vs ...interface{}) error { var ps []plot.Plotter names := make(map[*plotter.Line]string) name := "" var i int for _, v := range vs { switch t := v.(type) { case string: name = t case plotter.XYer: l, err := plotter.NewLine(t) if err != nil { return err } l.Color = Color(i) l.Dashes = Dashes(i) i++ ps = append(ps, l) if name != "" { names[l] = name name = "" } default: panic(fmt.Sprintf("AddLines handles strings and plotter.XYers, got %T", t)) } } plt.Add(ps...) for p, n := range names { plt.Legend.Add(n, p) } return nil }
func (s *Plots) DrawTps() { p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Response Time" p.X.Label.Text = "Time (seconds)" p.Y.Label.Text = "Response time (ms)" p.Add(plotter.NewGrid()) // Make a line plotter and set its style. l, err := plotter.NewLine(s.intervalsTps) if err != nil { panic(err) } l.LineStyle.Color = color.RGBA{B: 255, A: 255} p.Add(l) p.Legend.Add("line", l) // Save the plot to a PNG file. if err := p.Save(128*vg.Inch, 32*vg.Inch, "tps.svg"); err != nil { panic(err) } }
func DataTableToPng(b *bytes.Buffer, dt *db.DataTable, title string, width, height float64, xLabel string) error { p, err := plot.New() if err != nil { return err } p.Title.Text = title p.X.Label.Text = xLabel p.Y.Label.Text = "msec" // TODO: Fix this. // TODO: need new ticker function to handle equalX (while keeping xLabel as selected) if xLabel == common.TimeName { p.X.Tick.Marker = TimeTicks } p.Legend.Top = true numColumns := len(dt.ColumnNames) lines := make([]plotter.XYs, numColumns-1) // Skip X column. for _, dRow := range dt.Data { xp := (*dRow)[0] if xp != nil { for col := 1; col < numColumns; col++ { // Skip X column. yp := (*dRow)[col] if yp != nil { lines[col-1] = append(lines[col-1], struct{ X, Y float64 }{X: *xp, Y: *yp}) } } } } colorList := getColors(numColumns - 1) // Skip X column. for i, line := range lines { columnName := dt.ColumnNames[i+1] l, err := plotter.NewLine(line) if err != nil { return err } if strings.Index(columnName, common.RegressNamePrefix) == 0 { // If regression value. l.LineStyle.Color = color.RGBA{255, 0, 0, 255} l.LineStyle.Width = vg.Points(2.0) } else { l.LineStyle.Color = colorList[i] l.LineStyle.Width = vg.Points(1.5) } p.Add(l) p.Legend.Add(columnName, l) } tPng := time.Now() drawPng(b, p, width, height) glog.V(3).Infof("PERF: makePng time: %v", time.Now().Sub(tPng)) return nil }
func (p *Plot) Write(f string) error { for i, ln := range p.lines { l, _ := plotter.NewLine(ln.pts) l.LineStyle.Width = vg.Points(2) l.LineStyle.Color = colors[i%len(colors)] p.p.Legend.Add(ln.name, l) p.p.Add(l) } return p.p.Save(10*vg.Inch, 10*vg.Inch, f) }
func lines(w vg.Length) (*plot.Plot, error) { p, err := plot.New() if err != nil { return nil, err } pts := plotter.XYs{{0, 0}, {0, 1}, {1, 0}, {1, 1}} line, err := plotter.NewLine(pts) line.Width = w if err != nil { return nil, err } p.Add(line) return p, nil }
// AddStackedAreaPlots adds stacked area plot plotters to a plot. // The variadic arguments must be either strings // or plotter.Valuers. Each valuer adds a stacked area // plot to the plot below the stacked area plots added // before it. If a plotter.Valuer is immediately // preceeded by a string then the string value is used to // label the legend. // Plots should be added in order of tallest to shortest, // because they will be drawn in the order they are added // (i.e. later plots will be painted over earlier plots). // // If an error occurs then none of the plotters are added // to the plot, and the error is returned. func AddStackedAreaPlots(plt *plot.Plot, xs plotter.Valuer, vs ...interface{}) error { var ps []plot.Plotter names := make(map[*plotter.Line]string) name := "" var i int for _, v := range vs { switch t := v.(type) { case string: name = t case plotter.Valuer: if xs.Len() != t.Len() { return errors.New("X/Y length mismatch") } // Make a line plotter and set its style. l, err := plotter.NewLine(combineXYs{xs: xs, ys: t}) if err != nil { return err } l.LineStyle.Width = vg.Points(0) color := Color(i) i++ l.ShadeColor = &color ps = append(ps, l) if name != "" { names[l] = name name = "" } default: panic(fmt.Sprintf("AddStackedAreaPlots handles strings and plotter.Valuers, got %T", t)) } } plt.Add(ps...) for p, n := range names { plt.Legend.Add(n, p) } return nil }
func (plt *plttr) addDiscrete(name string, sig Discrete) { // TODO there appears to be a bug in gonum plot where certain // dashed lines for a particular result will not render correctly. // Raw calls of plotutil are just tossed in here for now and avoids // dashed lines. l, err := plotter.NewLine(xyer([]float64(sig))) if err != nil { panic(err) } l.Color = plotutil.Color(plt.nlines) // l.Dashes = plotutil.Dashes(plt.nlines) plt.Add(l) plt.Legend.Add(name, l) plt.nlines++ }
// Example_points draws some scatter points, a line, // and a line with points. func Example_points() *plot.Plot { rand.Seed(int64(0)) n := 15 scatterData := randomPoints(n) lineData := randomPoints(n) linePointsData := randomPoints(n) p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Points Example" p.X.Label.Text = "X" p.Y.Label.Text = "Y" p.Add(plotter.NewGrid()) s := must(plotter.NewScatter(scatterData)).(*plotter.Scatter) s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255} s.GlyphStyle.Radius = vg.Points(3) l := must(plotter.NewLine(lineData)).(*plotter.Line) l.LineStyle.Width = vg.Points(1) l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)} l.LineStyle.Color = color.RGBA{B: 255, A: 255} lpLine, lpPoints, err := plotter.NewLinePoints(linePointsData) if err != nil { panic(err) } lpLine.Color = color.RGBA{G: 255, A: 255} lpPoints.Shape = draw.CircleGlyph{} lpPoints.Color = color.RGBA{R: 255, A: 255} p.Add(s, l, lpLine, lpPoints) p.Legend.Add("scatter", s) p.Legend.Add("line", l) p.Legend.Add("line points", lpLine, lpPoints) return p }
func (s *Plots) DrawLats() { p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Response Time" p.X.Label.Text = "Time (seconds)" p.Y.Label.Text = "Response time (ms)" p.Add(plotter.NewGrid()) // Make a scatter plotter and set its style. scatter, err := plotter.NewScatter(s.points) if err != nil { panic(err) } scatter.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255} // Make a line plotter and set its style. l, err := plotter.NewLine(s.intervalLats) if err != nil { panic(err) } l.LineStyle.Width = vg.Points(1) l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)} l.LineStyle.Color = color.RGBA{B: 255, A: 255} p.Add(scatter, l) p.Legend.Add("scatter", scatter) p.Legend.Add("line", l) // Save the plot to a PNG file. if err := p.Save(64*vg.Inch, 24*vg.Inch, "points.png"); err != nil { panic(err) } }
func createBoard(somePlot *plot.Plot) { pts := make(plotter.XYs, 35) pts[0].X = float64(8.5) pts[0].Y = float64(.5) pts[1].X = float64(.5) pts[1].Y = float64(.5) pts[2].X = float64(.5) pts[2].Y = float64(1.5) pts[3].X = float64(8.5) pts[3].Y = float64(1.5) pts[4].X = float64(8.5) pts[4].Y = float64(2.5) pts[5].X = float64(.5) pts[5].Y = float64(2.5) pts[6].X = float64(.5) pts[6].Y = float64(3.5) pts[7].X = float64(8.5) pts[7].Y = float64(3.5) pts[8].X = float64(8.5) pts[8].Y = float64(4.5) pts[9].X = float64(.5) pts[9].Y = float64(4.5) pts[10].X = float64(.5) pts[10].Y = float64(5.5) pts[11].X = float64(8.5) pts[11].Y = float64(5.5) pts[12].X = float64(8.5) pts[12].Y = float64(6.5) pts[13].X = float64(.5) pts[13].Y = float64(6.5) pts[14].X = float64(.5) pts[14].Y = float64(7.5) pts[15].X = float64(8.5) pts[15].Y = float64(7.5) pts[16].X = float64(8.5) pts[16].Y = float64(8.5) pts[17].X = float64(.5) pts[17].Y = float64(8.5) pts[18].X = float64(.5) pts[18].Y = float64(.5) pts[19].X = float64(1.5) pts[19].Y = float64(.5) pts[20].X = float64(1.5) pts[20].Y = float64(8.5) pts[21].X = float64(2.5) pts[21].Y = float64(8.5) pts[22].X = float64(2.5) pts[22].Y = float64(.5) pts[23].X = float64(3.5) pts[23].Y = float64(.5) pts[24].X = float64(3.5) pts[24].Y = float64(8.5) pts[25].X = float64(4.5) pts[25].Y = float64(8.5) pts[26].X = float64(4.5) pts[26].Y = float64(.5) pts[27].X = float64(5.5) pts[27].Y = float64(.5) pts[28].X = float64(5.5) pts[28].Y = float64(8.5) pts[29].X = float64(6.5) pts[29].Y = float64(8.5) pts[30].X = float64(6.5) pts[30].Y = float64(.5) pts[31].X = float64(7.5) pts[31].Y = float64(.5) pts[32].X = float64(7.5) pts[32].Y = float64(8.5) pts[33].X = float64(8.5) pts[33].Y = float64(8.5) pts[34].X = float64(8.5) pts[34].Y = float64(.5) lines, _ := plotter.NewLine(pts) lines.LineStyle.Width = vg.Points(1) lines.LineStyle.Color = color.RGBA{R: 0, B: 0, A: 255} myPlot.Add(lines) }
func (c *client) run() { var err error dir, err := ioutil.TempDir("", "snfusion-web-") if err != nil { log.Printf("error creating temporary directory: %v\n", err) return } defer func() { c.srv.unregister <- c c.ws.Close() c.srv = nil os.RemoveAll(dir) }() type params struct { ID int `json:"id"` NumIters int `json:"num_iters"` NumCarbons float64 `json:"num_carbons"` Seed int64 `json:"seed"` } type genReply struct { ID int `json:"id"` Stage string `json:"stage"` Err error `json:"err"` Msg string `json:"msg"` Engine sim.Engine `json:"engine"` } type plotReply struct { ID int `json:"id"` Stage string `json:"stage"` Err error `json:"err"` SVG string `json:"svg"` } type zipReply struct { ID int `json:"id"` Stage string `json:"stage"` Err error `json:"err"` Href string `json:"href"` } for { param := params{ NumIters: 100000, NumCarbons: 60, Seed: 1234, } log.Printf("waiting for simulation parameters...\n") err = websocket.JSON.Receive(c.ws, ¶m) if err != nil { log.Printf("error rcv: %v\n", err) return } id := param.ID msgbuf := new(bytes.Buffer) msg := log.New(msgbuf, "snfusion-sim: ", 0) engine := sim.Engine{ NumIters: param.NumIters, NumCarbons: param.NumCarbons, Seed: param.Seed, } engine.SetLogger(msg) log.Printf("processing... %#v\n", engine) csvbuf := new(bytes.Buffer) errc := make(chan error) ticker := time.NewTicker(1 * time.Second) go func() { errc <- engine.Run(csvbuf) ticker.Stop() }() err = <-errc if err != nil { log.Printf("error: %v\n", err) _ = websocket.JSON.Send(c.ws, genReply{ ID: id, Err: err, Engine: engine, Stage: "gen-done", Msg: msgbuf.String(), }) return } err = websocket.JSON.Send(c.ws, genReply{ ID: id, Err: err, Engine: engine, Stage: "gen-done", Msg: msgbuf.String(), }) if err != nil { log.Printf("error sending data: %v\n", err) return } csvdata := make([]byte, len(csvbuf.Bytes())) copy(csvdata, csvbuf.Bytes()) log.Printf("running post-processing...\n") r := csv.NewReader(csvbuf) r.Comma = ';' r.Comment = '#' table := make([]plotter.XYs, len(engine.Population)) for i := range table { table[i] = make(plotter.XYs, engine.NumIters+1) } for ix := 0; ix < engine.NumIters+1; ix++ { var text []string text, err = r.Read() if err != nil { break } for i := range engine.Population { table[i][ix].X = float64(ix) table[i][ix].Y = float64(atoi(text[i])) } } if err == io.EOF { err = nil } if err != nil { log.Printf("error reading data: %v\n", err) return } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = fmt.Sprintf( "Time evolution of nuclei C%v-O%v (seed=%d)", engine.NumCarbons, 100-engine.NumCarbons, engine.Seed, ) p.X.Label.Text = "Iteration number" p.Y.Label.Text = "Atomic mass of nuclei" for i, n := range engine.Population { line, err := plotter.NewLine(table[i]) if err != nil { log.Fatalf( "error adding data points for nucleus %v: %v\n", n, err, ) } line.LineStyle.Color = col(n) line.LineStyle.Width = vg.Points(1) p.Add(line) p.Legend.Add(label(n), line) } p.Add(plotter.NewGrid()) p.Legend.Top = true p.Legend.XOffs = -1 * vg.Centimeter figX := 25 * vg.Centimeter figY := figX / vg.Length(math.Phi) // Create a Canvas for writing SVG images. canvas := vgsvg.New(figX, figY) // Draw to the Canvas. p.Draw(draw.New(canvas)) outsvg := new(bytes.Buffer) _, err = canvas.WriteTo(outsvg) if err != nil { log.Printf("error svg: %v\n", err) return } err = websocket.JSON.Send(c.ws, plotReply{ ID: id, Err: err, SVG: outsvg.String(), Stage: "plot-done", }) if err != nil { log.Printf("error sending data: %v\n", err) return } pngcanvas := vgimg.PngCanvas{Canvas: vgimg.New(figX, figY)} p.Draw(draw.New(pngcanvas)) outpng := new(bytes.Buffer) _, err = pngcanvas.WriteTo(outpng) if err != nil { log.Printf("error png: %v\n", err) return } href := filepath.Join(dir, fmt.Sprintf("output-%d.zip", id)) zipf, err := os.Create(href) if err != nil { log.Printf("error creating zip file: %v\n", err) } defer zipf.Close() zipw := zip.NewWriter(zipf) defer zipw.Close() for _, file := range []struct { Name string Body []byte }{ {"output.csv", csvdata}, {"output.png", outpng.Bytes()}, } { ff, err := zipw.Create(file.Name) if err != nil { log.Printf("error creating zip content %v: %v\n", file.Name, err) return } _, err = ff.Write(file.Body) if err != nil { log.Printf("error writing zip content %v: %v\n", file.Name, err) return } } err = zipw.Close() if err != nil { log.Printf("error closing zip-writer: %v\n", err) return } err = zipf.Close() if err != nil { log.Printf("error closing zip-file: %v\n", err) return } err = websocket.JSON.Send(c.ws, zipReply{ ID: id, Err: err, Href: href, Stage: "zip-done", }) if err != nil { log.Printf("error sending zip: %v\n", err) return } log.Printf("saved report under %v\n", href) } }
func TestPersistency(t *testing.T) { // Get some random points rand.Seed(0) // The default random seed is 1. n := 15 scatterData := randomPoints(n) lineData := randomPoints(n) linePointsData := randomPoints(n) p, err := plot.New() if err != nil { t.Fatalf("error creating plot: %v\n", err) } p.Title.Text = "Plot Example" p.X.Label.Text = "X" p.Y.Label.Text = "Y" // Use a custom tick marker function that computes the default // tick marks and re-labels the major ticks with commas. p.Y.Tick.Marker = commaTicks{} // Draw a grid behind the data p.Add(plotter.NewGrid()) // Make a scatter plotter and set its style. s, err := plotter.NewScatter(scatterData) if err != nil { panic(err) } s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255} // Make a line plotter and set its style. l, err := plotter.NewLine(lineData) if err != nil { panic(err) } l.LineStyle.Width = vg.Points(1) l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)} l.LineStyle.Color = color.RGBA{B: 255, A: 255} // Make a line plotter with points and set its style. lpLine, lpPoints, err := plotter.NewLinePoints(linePointsData) if err != nil { panic(err) } lpLine.Color = color.RGBA{G: 255, A: 255} lpPoints.Shape = draw.PyramidGlyph{} lpPoints.Color = color.RGBA{R: 255, A: 255} // Add the plotters to the plot, with a legend // entry for each p.Add(s, l, lpLine, lpPoints) p.Legend.Add("scatter", s) p.Legend.Add("line", l) p.Legend.Add("line points", lpLine, lpPoints) // Save the plot to a PNG file. err = p.Save(4, 4, "test-persistency.png") if err != nil { t.Fatalf("error saving to PNG: %v\n", err) } defer os.Remove("test-persistency.png") buf := new(bytes.Buffer) enc := gob.NewEncoder(buf) err = enc.Encode(p) if err != nil { t.Fatalf("error gob-encoding plot: %v\n", err) } // TODO(sbinet): impl. BinaryMarshal for plot.Plot and vg.Font // { // dec := gob.NewDecoder(buf) // var p plot.Plot // err = dec.Decode(&p) // if err != nil { // t.Fatalf("error gob-decoding plot: %v\n", err) // } // // Save the plot to a PNG file. // err = p.Save(4, 4, "test-persistency-readback.png") // if err != nil { // t.Fatalf("error saving to PNG: %v\n", err) // } // defer os.Remove("test-persistency-readback.png") // } }
func main() { ifname := flag.String("f", "output.csv", "input CSV file to analyze") ofname := flag.String("o", "output.png", "output PNG file") flag.Parse() log.SetPrefix("snfusion-plot: ") log.SetFlags(0) f, err := os.Open(*ifname) if err != nil { log.Fatalf("error opening %s: %v\n", *ifname, err) } defer f.Close() var engine sim.Engine var hdr []byte { scanner := bufio.NewScanner(f) for scanner.Scan() { data := scanner.Bytes() if !bytes.HasPrefix(data, []byte("#")) { break } if !bytes.HasPrefix(data, sim.HeaderCSV) { continue } hdr = make([]byte, len(data)-len(sim.HeaderCSV)) copy(hdr, data[len(sim.HeaderCSV):]) break } err = scanner.Err() if err == io.EOF { err = nil } if err != nil { log.Fatalf("error peeking at meta-data: %v\n", err) } if len(hdr) == 0 { log.Fatalf("could not find meta-data in file %s\n", *ifname, ) } _, err = f.Seek(0, 0) if err != nil { log.Fatalf("error rewinding input file %s: %v\n", *ifname, err, ) } } err = json.Unmarshal(hdr, &engine) if err != nil { log.Fatalf("error reading meta-data: %v\n", err) } log.Printf("plotting...\n") log.Printf("NumIters: %d\n", engine.NumIters) log.Printf("NumCarbons: %v\n", engine.NumCarbons) log.Printf("Seed: %d\n", engine.Seed) log.Printf("Nuclei: %v\n", engine.Population) r := csv.NewReader(f) r.Comma = ';' r.Comment = '#' table := make([]plotter.XYs, len(engine.Population)) for i := range table { table[i] = make(plotter.XYs, engine.NumIters+1) } for ix := 0; ix < engine.NumIters+1; ix++ { var text []string text, err = r.Read() if err != nil { break } for i := range engine.Population { table[i][ix].X = float64(ix) table[i][ix].Y = float64(atoi(text[i])) } } if err == io.EOF { err = nil } if err != nil { log.Fatalf("error reading data: %v\n", err) } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = fmt.Sprintf( "Time evolution of nuclei C%v-O%v (seed=%d)", engine.NumCarbons, 100-engine.NumCarbons, engine.Seed, ) p.X.Label.Text = "Iteration number" p.Y.Label.Text = "Atomic mass of nuclei" for i, n := range engine.Population { line, err := plotter.NewLine(table[i]) if err != nil { log.Fatalf( "error adding data points for nucleus %v: %v\n", n, err, ) } line.LineStyle.Color = col(n) line.LineStyle.Width = vg.Points(1) p.Add(line) p.Legend.Add(label(n), line) } p.Add(plotter.NewGrid()) p.Legend.Top = true p.Legend.XOffs = -1 * vg.Centimeter figX := 25 * vg.Centimeter figY := figX / vg.Length(phi) // Save the plot to a PNG file. if err := p.Save(figX, figY, *ofname); err != nil { panic(err) } }