// NewBoxPlot returns a new BoxPlot that represents // the distribution of the given values. The style of // the box plot is that used for Tukey's schematic // plots is ``Exploratory Data Analysis.'' // // An error is returned if the boxplot is created with // no values. // // The fence values are 1.5x the interquartile before // the first quartile and after the third quartile. Any // value that is outside of the fences are drawn as // Outside points. The adjacent values (to which the // whiskers stretch) are the minimum and maximum // values that are not outside the fences. func NewBoxPlot(w vg.Length, loc float64, values Valuer) (*BoxPlot, error) { if w < 0 { return nil, errors.New("Negative boxplot width") } b := new(BoxPlot) var err error if b.fiveStatPlot, err = newFiveStat(w, loc, values); err != nil { return nil, err } b.Width = w b.CapWidth = 3 * w / 4 b.GlyphStyle = DefaultGlyphStyle b.BoxStyle = DefaultLineStyle b.MedianStyle = DefaultLineStyle b.WhiskerStyle = plot.LineStyle{ Width: vg.Points(0.5), Dashes: []vg.Length{vg.Points(4), vg.Points(2)}, } if len(b.Values) == 0 { b.Width = 0 b.GlyphStyle.Radius = 0 b.BoxStyle.Width = 0 b.MedianStyle.Width = 0 b.WhiskerStyle.Width = 0 } return b, nil }
// Example_groupedBoxPlots draws vertical boxplots. func Example_groupedBoxPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(plotter.Values, n) normal := make(plotter.Values, n) expon := make(plotter.Values, n) for i := 0; i < n; i++ { uniform[i] = rand.Float64() normal[i] = rand.NormFloat64() expon[i] = rand.ExpFloat64() } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Box Plot" p.Y.Label.Text = "plotter.Values" w := vg.Points(20) for x := 0.0; x < 3.0; x++ { b0 := must(plotter.NewBoxPlot(w, x, uniform)).(*plotter.BoxPlot) b0.Offset = -w - vg.Points(3) b1 := must(plotter.NewBoxPlot(w, x, normal)).(*plotter.BoxPlot) b2 := must(plotter.NewBoxPlot(w, x, expon)).(*plotter.BoxPlot) b2.Offset = w + vg.Points(3) p.Add(b0, b1, b2) } // Set the X axis of the plot to nominal with // the given names for x=0, x=1 and x=2. p.NominalX("Group 0", "Group 1", "Group 2") return p }
// Example_groupedHorizontalBoxPlots draws vertical boxplots. func Example_groupedHorizontalBoxPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(plotter.Values, n) normal := make(plotter.Values, n) expon := make(plotter.Values, n) for i := 0; i < n; i++ { uniform[i] = rand.Float64() normal[i] = rand.NormFloat64() expon[i] = rand.ExpFloat64() } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Box Plot" p.Y.Label.Text = "plotter.Values" w := vg.Points(20) for y := 0.0; y < 3.0; y++ { b0 := must(plotter.MakeHorizBoxPlot(w, y, uniform)).(plotter.HorizBoxPlot) b0.Offset = -w - vg.Points(3) b1 := must(plotter.MakeHorizBoxPlot(w, y, normal)).(plotter.HorizBoxPlot) b2 := must(plotter.MakeHorizBoxPlot(w, y, expon)).(plotter.HorizBoxPlot) b2.Offset = w + vg.Points(3) p.Add(b0, b1, b2) } p.NominalY("Group 0", "Group 1", "Group 2") return p }
func test_point() { rand.Seed(int64(0)) points_data := randomPoint(200) points_data2 := randomPoint(50) p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Points" p.X.Label.Text = "X" p.Y.Label.Text = "Y" bs, _ := plotter.NewBubbles(points_data, vg.Points(5), vg.Points(5)) bs2, _ := plotter.NewBubbles(points_data2, vg.Points(5), vg.Points(5)) bs.Color = color.RGBA{R: 255, G: 0, B: 0, A: 255} bs2.Color = color.RGBA{R: 0, G: 255, B: 0, A: 255} p.Add(bs) p.Add(bs2) if err := p.Save(10, 10, "points.png"); err != nil { panic(err) } }
// Example_boxPlots draws vertical boxplots. func Example_boxPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(plotter.Values, n) normal := make(plotter.Values, n) expon := make(plotter.Values, n) for i := 0; i < n; i++ { uniform[i] = rand.Float64() normal[i] = rand.NormFloat64() expon[i] = rand.ExpFloat64() } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Box Plot" p.Y.Label.Text = "plotter.Values" // Make boxes for our data and add them to the plot. p.Add(must(plotter.NewBoxPlot(vg.Points(20), 0, uniform)).(*plotter.BoxPlot), must(plotter.NewBoxPlot(vg.Points(20), 1, normal)).(*plotter.BoxPlot), must(plotter.NewBoxPlot(vg.Points(20), 2, expon)).(*plotter.BoxPlot)) // Set the X axis of the plot to nominal with // the given names for x=0, x=1 and x=2. p.NominalX("Uniform\nDistribution", "Normal\nDistribution", "Exponential\nDistribution") return p }
// 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 }
// makeLegend returns a legend with the default // parameter settings. func makeLegend() (Legend, error) { font, err := vg.MakeFont(defaultFont, vg.Points(12)) if err != nil { return Legend{}, err } return Legend{ ThumbnailWidth: vg.Points(20), TextStyle: TextStyle{Font: font}, }, nil }
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 }
// NewBoxPlot returns a new BoxPlot that represents // the distribution of the given values. The style of // the box plot is that used for Tukey's schematic // plots is ``Exploratory Data Analysis.'' // // An error is returned if the boxplot is created with // no values. // // The fence values are 1.5x the interquartile before // the first quartile and after the third quartile. Any // value that is outside of the fences are drawn as // Outside points. The adjacent values (to which the // whiskers stretch) are the minimum and maximum // values that are not outside the fences. func NewBoxPlot(w vg.Length, loc float64, values Valuer) *BoxPlot { b := new(BoxPlot) b.Location = loc b.Width = w b.CapWidth = 3 * w / 4 b.GlyphStyle = DefaultGlyphStyle b.BoxStyle = DefaultLineStyle b.MedianStyle = DefaultLineStyle b.WhiskerStyle = plot.LineStyle{ Width: vg.Points(0.5), Dashes: []vg.Length{vg.Points(4), vg.Points(2)}, } b.Values = CopyValues(values) sorted := CopyValues(values) sort.Float64s(sorted) if len(sorted) == 0 { b.Width = 0 b.GlyphStyle.Radius = 0 b.BoxStyle.Width = 0 b.MedianStyle.Width = 0 b.WhiskerStyle.Width = 0 return b } else if len(sorted) == 1 { b.Median = sorted[0] b.Quartile1 = sorted[0] b.Quartile3 = sorted[0] } else { b.Median = median(sorted) b.Quartile1 = median(sorted[:len(sorted)/2]) b.Quartile3 = median(sorted[len(sorted)/2:]) } b.Min = sorted[0] b.Max = sorted[len(sorted)-1] low := b.Quartile1 - 1.5*(b.Quartile3-b.Quartile1) high := b.Quartile3 + 1.5*(b.Quartile3-b.Quartile1) b.AdjLow = math.Inf(1) b.AdjHigh = math.Inf(-1) for i, v := range b.Values { if v > high || v < low { b.Outside = append(b.Outside, i) continue } if v < b.AdjLow { b.AdjLow = v } if v > b.AdjHigh { b.AdjHigh = v } } return b }
func linesPlot() *plot.Plot { // Get some random points rand.Seed(int64(0)) n := 10 scatterData := randomPoints(n) lineData := randomPoints(n) linePointsData := randomPoints(n) // Create a new plot, set its title and // axis labels. p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Points Example" p.X.Label.Text = "X" p.Y.Label.Text = "Y" // 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 = plot.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) return p }
// Example_horizontalBoxPlots draws horizontal boxplots // with some labels on their points. func Example_horizontalBoxPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(valueLabels, n) normal := make(valueLabels, n) expon := make(valueLabels, n) for i := 0; i < n; i++ { uniform[i].Value = rand.Float64() uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value) normal[i].Value = rand.NormFloat64() normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value) expon[i].Value = rand.ExpFloat64() expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value) } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Horizontal Box Plot" p.X.Label.Text = "plotter.Values" // Make boxes for our data and add them to the plot. uniBox := must(plotter.MakeHorizBoxPlot(vg.Points(20), 0, uniform)).(plotter.HorizBoxPlot) uniLabels, err := uniBox.OutsideLabels(uniform) if err != nil { panic(err) } normBox := must(plotter.MakeHorizBoxPlot(vg.Points(20), 1, normal)).(plotter.HorizBoxPlot) normLabels, err := normBox.OutsideLabels(normal) if err != nil { panic(err) } expBox := must(plotter.MakeHorizBoxPlot(vg.Points(20), 2, expon)).(plotter.HorizBoxPlot) expLabels, err := expBox.OutsideLabels(expon) if err != nil { panic(err) } p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels) // Add a GlyphBox plotter for debugging. p.Add(plotter.NewGlyphBoxes()) // Set the Y axis of the plot to nominal with // the given names for y=0, y=1 and y=2. p.NominalY("Uniform\nDistribution", "Normal\nDistribution", "Exponential\nDistribution") return p }
// Example_verticalBoxPlots draws vertical boxplots // with some labels on their points. func Example_verticalBoxPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(valueLabels, n) normal := make(valueLabels, n) expon := make(valueLabels, n) for i := 0; i < n; i++ { uniform[i].Value = rand.Float64() uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value) normal[i].Value = rand.NormFloat64() normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value) expon[i].Value = rand.ExpFloat64() expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value) } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Box Plot" p.Y.Label.Text = "plotter.Values" // Make boxes for our data and add them to the plot. uniBox := plotter.NewBoxPlot(vg.Points(20), 0, uniform) uniLabels, err := uniBox.OutsideLabels(uniform) if err != nil { panic(err) } normBox := plotter.NewBoxPlot(vg.Points(20), 1, normal) normLabels, err := normBox.OutsideLabels(normal) if err != nil { panic(err) } expBox := plotter.NewBoxPlot(vg.Points(20), 2, expon) expLabels, err := expBox.OutsideLabels(expon) if err != nil { panic(err) } p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels) // Set the X axis of the plot to nominal with // the given names for x=0, x=1 and x=2. p.NominalX("Uniform\nDistribution", "Normal\nDistribution", "Exponential\nDistribution") return p }
func histPlot() *plot.Plot { // Draw some random values from the standard // normal distribution. rand.Seed(int64(0)) v := make(plotter.Values, 1000) for i := range v { v[i] = rand.NormFloat64() } // Make a plot and set its title. p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Histogram" // Create a histogram of our values drawn // from the standard normal. h, err := plotter.NewHist(v, 16) if err != nil { panic(err) } // Normalize the area under the histogram to // sum to one. h.Normalize(1) p.Add(h) // The normal distribution function norm := plotter.NewFunction(stdNorm) norm.Color = color.RGBA{R: 255, A: 255} norm.Width = vg.Points(2) p.Add(norm) return p }
func plotData(name string, xs, ys []float64) { p, err := plot.New() if err != nil { fmt.Printf("Cannot create new plot: %s\n", err) return } p.Title.Text = "Chernoff lower bound" p.X.Label.Text = "Sigma" p.X.Min = 0.2 p.X.Max = 0.5 p.Y.Label.Text = "Probability of correct detection" p.Y.Min = 0.9 p.Y.Max = 1.0 p.Add(plotter.NewGrid()) l := plotter.NewLine(dataset(xs, ys)) 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(l) if err := p.Save(4, 4, name); err != nil { fmt.Printf("Save to '%s' failed: %s\n", name, err) } }
func plotData(name string, us, ys, ts, fs []float64) { p, err := plot.New() if err != nil { fmt.Printf("Cannot create new plot: %s\n", err) return } p.Title.Text = "Least-square fit of convex function" p.X.Min = -0.1 p.X.Max = 2.3 p.Y.Min = -1.1 p.Y.Max = 7.2 p.Add(plotter.NewGrid()) pts := plotter.NewScatter(dataset(us, ys)) pts.GlyphStyle.Color = color.RGBA{R: 255, A: 255} fit := plotter.NewLine(dataset(ts, fs)) fit.LineStyle.Width = vg.Points(1) fit.LineStyle.Color = color.RGBA{B: 255, A: 255} p.Add(pts) p.Add(fit) if err := p.Save(4, 4, name); err != nil { fmt.Printf("Save to '%s' failed: %s\n", name, err) } }
// crosshair draws a plus at the given point. func crosshair(img draw.Image, x, y int, str string) { c := vgimg.NewImage(img) // drawPlots here because NewImage // clears the canvas. Instead, the canvas // should just be stored instead of being // recreated at each redraw. drawPlots(img) c.SetColor(color.RGBA{R: 255, A: 255}) xc := vg.Inches(float64(x) / c.DPI()) yc := vg.Inches(float64(y) / c.DPI()) radius := vg.Points(5) var p vg.Path p.Move(xc-radius, yc) p.Line(xc+radius, yc) c.Stroke(p) p = vg.Path{} p.Move(xc, yc+radius) p.Line(xc, yc-radius) c.Stroke(p) c.SetColor(color.Black) c.FillString(font, vg.Length(0), vg.Length(0), str) }
func Example_groupedQuartPlots() *plot.Plot { rand.Seed(int64(0)) n := 100 uniform := make(plotter.Values, n) normal := make(plotter.Values, n) expon := make(plotter.Values, n) for i := 0; i < n; i++ { uniform[i] = rand.Float64() normal[i] = rand.NormFloat64() expon[i] = rand.ExpFloat64() } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Box Plot" p.Y.Label.Text = "plotter.Values" w := vg.Points(10) for x := 0.0; x < 3.0; x++ { b0 := must(plotter.NewQuartPlot(x, uniform)).(*plotter.QuartPlot) b0.Offset = -w b1 := must(plotter.NewQuartPlot(x, normal)).(*plotter.QuartPlot) b2 := must(plotter.NewQuartPlot(x, expon)).(*plotter.QuartPlot) b2.Offset = w p.Add(b0, b1, b2) } p.Add(plotter.NewGlyphBoxes()) p.NominalX("Group 0", "Group 1", "Group 2") return p }
// An example of making a histogram. func Example_histogram() *plot.Plot { rand.Seed(int64(0)) n := 10000 vals := make(plotter.Values, n) for i := 0; i < n; i++ { vals[i] = rand.NormFloat64() } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Histogram" h, err := plotter.NewHist(vals, 16) if err != nil { panic(err) } h.Normalize(1) p.Add(h) // The normal distribution function norm := plotter.NewFunction(stdNorm) norm.Color = color.RGBA{R: 255, A: 255} norm.Width = vg.Points(2) p.Add(norm) return p }
// DrawGlyph implements the Glyph interface. func (RingGlyph) DrawGlyph(da *DrawArea, sty GlyphStyle, pt Point) { da.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)}) var p vg.Path p.Move(pt.X+sty.Radius, pt.Y) p.Arc(pt.X, pt.Y, sty.Radius, 0, 2*math.Pi) p.Close() da.Stroke(p) }
func main() { fmt.Println("Running...") start := time.Now() count := 0 pt = make([]plotter.XYs, 0) for n := nMin; n <= nMax; n *= 2 { y1 = make([]float64, n) y2 = make([]float64, n) pt = append(pt, make(plotter.XYs, n)) y1[0] = 1.0 y2[0] = 3.0 h = (tMax - tMin) / float64(n-1) for i := 1; i < n; i++ { y1[i] = y1[i-1] + 2*y1[i-1]*(1-y2[i-1])*h y2[i] = y2[i-1] - y2[i-1]*(1-y1[i-1])*h } for i := 0; i < n; i++ { pt[count][i].X = y1[i] pt[count][i].Y = y2[i] } count++ } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = fmt.Sprintf("Enright and Pryce #B1:Euler") p.Y.Label.Text = "y2(t)" p.X.Label.Text = "y1(t)" n := nMin for i := 0; i < count; i++ { l := plotter.NewLine(pt[i]) l.LineStyle.Width = vg.Points(1) l.LineStyle.Color = color.RGBA{R: 255 / uint8(i+1), G: 255 / uint8(i+1), B: 255 / uint8(i+1), A: 255} p.Add(l) n *= 2 } p.X.Min = 0 p.X.Max = 6.5 p.Y.Min = 0 p.Y.Max = 6.5 // Save the plot to a PNG file. if err := p.Save(6, 6, "euler_test.png"); err != nil { panic(err) } fmt.Println(time.Since(start)) fmt.Println("...program terminated successfully!") }
func Example_bubbles() *plot.Plot { rand.Seed(int64(0)) n := 10 bubbleData := randomTriples(n) p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Bubbles" p.X.Label.Text = "X" p.Y.Label.Text = "Y" bs := plotter.NewBubbles(bubbleData, vg.Points(1), vg.Points(20)) bs.Color = color.RGBA{R: 196, B: 128, A: 255} p.Add(bs) return p }
func LineStyle(color color.RGBA, width float64, dashes ...[]vg.Length) plot.LineStyle { ls := plot.LineStyle{ Color: color, Width: vg.Points(width), } if len(dashes) != 0 { ls.Dashes = dashes[0] } return ls }
// DrawGlyph implements the Glyph interface. func (TriangleGlyph) DrawGlyph(da *DrawArea, sty GlyphStyle, pt Point) { da.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)}) r := sty.Radius + (sty.Radius-sty.Radius*sinπover6)/2 var p vg.Path p.Move(pt.X, pt.Y+r) p.Line(pt.X-r*cosπover6, pt.Y-r*sinπover6) p.Line(pt.X+r*cosπover6, pt.Y-r*sinπover6) p.Close() da.Stroke(p) }
// DrawGlyph implements the Glyph interface. func (SquareGlyph) DrawGlyph(da *DrawArea, sty GlyphStyle, pt Point) { da.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)}) x := (sty.Radius-sty.Radius*cosπover4)/2 + sty.Radius*cosπover4 var p vg.Path p.Move(pt.X-x, pt.Y-x) p.Line(pt.X+x, pt.Y-x) p.Line(pt.X+x, pt.Y+x) p.Line(pt.X-x, pt.Y+x) p.Close() da.Stroke(p) }
// 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 = plot.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 }
// DrawGlyph implements the Glyph interface. func (CrossGlyph) DrawGlyph(da *DrawArea, sty GlyphStyle, pt Point) { da.SetLineStyle(LineStyle{Color: sty.Color, Width: vg.Points(0.5)}) r := sty.Radius * cosπover4 var p vg.Path p.Move(pt.X-r, pt.Y-r) p.Line(pt.X+r, pt.Y+r) da.Stroke(p) p = vg.Path{} p.Move(pt.X-r, pt.Y+r) p.Line(pt.X+r, pt.Y-r) da.Stroke(p) }
// Example_functions draws some functions. func Example_functions() *plot.Plot { p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Functions" p.X.Label.Text = "X" p.Y.Label.Text = "Y" quad := plotter.NewFunction(func(x float64) float64 { return x * x }) quad.Color = color.RGBA{B: 255, A: 255} exp := plotter.NewFunction(func(x float64) float64 { return math.Pow(2, x) }) exp.Dashes = []vg.Length{vg.Points(2), vg.Points(2)} exp.Width = vg.Points(2) exp.Color = color.RGBA{G: 255, A: 255} sin := plotter.NewFunction(func(x float64) float64 { return 10*math.Sin(x) + 50 }) sin.Dashes = []vg.Length{vg.Points(4), vg.Points(5)} sin.Width = vg.Points(4) sin.Color = color.RGBA{R: 255, A: 255} p.Add(quad, exp, sin) p.Legend.Add("x^2", quad) p.Legend.Add("2^x", exp) p.Legend.Add("10*sin(x)+50", sin) p.Legend.ThumbnailWidth = vg.Inches(0.5) p.X.Min = 0 p.X.Max = 10 p.Y.Min = 0 p.Y.Max = 100 return p }
// DrawFonts draws some text in all of the various // fonts along with a box to make sure that their // sizes are computed correctly. func DrawFonts(c vg.Canvas) { y := vg.Points(0) var fonts []string for fname := range vg.FontMap { fonts = append(fonts, fname) } sort.Strings(fonts) for _, fname := range fonts { font, err := vg.MakeFont(fname, 20) if err != nil { panic(err) } w := font.Width(fname + "Xqg") h := font.Extents().Ascent c.FillString(font, 0, y-font.Extents().Descent, fname+"Xqg") fmt.Println(fname) var path vg.Path path.Move(0, y+h) path.Line(w, y+h) path.Line(w, y) path.Line(0, y) path.Close() c.Stroke(path) path = vg.Path{} c.SetColor(color.RGBA{B: 255, A: 255}) c.SetLineDash([]vg.Length{vg.Points(5), vg.Points(3)}, 0) path.Move(0, y-font.Extents().Descent) path.Line(w, y-font.Extents().Descent) c.Stroke(path) c.SetColor(color.Black) c.SetLineDash([]vg.Length{}, 0) y += h } }
func test2() { rand.Seed(int64(0)) n := 100 bubbleData := randomTriples(n) p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "Bubbles" p.X.Label.Text = "X" p.Y.Label.Text = "Y" bs, err := plotter.NewBubbles(bubbleData, vg.Points(5), vg.Points(5)) if err != nil { panic(err) } bs.Color = color.RGBA{R: 196, B: 128, A: 255} p.Add(bs) if err := p.Save(10, 5, "bubble.png"); err != nil { panic(err) } }
func main() { ps[0].plot = linesPlot() ps[1].plot = histPlot() var err error font, err = vg.MakeFont("Times-Roman", vg.Points(12)) if err != nil { panic(err) } win, err := x11.NewWindow() if err != nil { panic(err) } drawPlots(win.Screen()) win.FlushImage() if cpuProfile != "" { f, err := os.Create(cpuProfile) if err != nil { panic(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if memProfile != "" { f, err := os.Create(memProfile) if err != nil { panic(err) } pprof.WriteHeapProfile(f) f.Close() } events := win.EventChan() for ev := range events { if m, ok := ev.(ui.MouseEvent); ok && m.Buttons == 1 { winHeight := 600 // hard-coded for ui/x11… p, x, y := dataCoord(m.Loc.X, winHeight-m.Loc.Y) if p >= 0 { str := fmt.Sprintf("plot: %d, coord: %g, %g\n", p, x, y) crosshair(win.Screen(), m.Loc.X, winHeight-m.Loc.Y, str) win.FlushImage() } } } }