func TestArcsEPS() { eps := vgeps.New(vg.Inches(4), vg.Inches(4), "arcs") DrawArcs(eps) if err := eps.Save("arcs.eps"); err != nil { panic(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 TestFontsPDF() { pdf := vgpdf.New(vg.Inches(4), vg.Inches(4)) DrawFonts(pdf) if err := pdf.Save("fonts.pdf"); err != nil { panic(err) } }
// DrawFontExtents draws some text and denotes the // various extents and width with lines. Expects // about a 4x4 inch canvas. func DrawFontExtents(c vg.Canvas) { x, y := vg.Inches(1), vg.Inches(2) str := "Eloquent" font, err := vg.MakeFont("Times-Roman", 18) if err != nil { panic(err) } width := font.Width(str) ext := font.Extents() des := ext.Descent asc := ext.Ascent c.FillString(font, x, y, str) // baseline path := vg.Path{} path.Move(x, y) path.Line(x+width, y) c.Stroke(path) // descent c.SetColor(color.RGBA{G: 255, A: 255}) path = vg.Path{} path.Move(x, y+des) path.Line(x+width, y+des) c.Stroke(path) // ascent c.SetColor(color.RGBA{B: 255, A: 255}) path = vg.Path{} path.Move(x, y+asc) path.Line(x+width, y+asc) c.Stroke(path) }
func TestFontExtentsEPS() { eps := vgeps.New(vg.Inches(4), vg.Inches(4), "extents") DrawFontExtents(eps) if err := eps.Save("extents.eps"); err != nil { panic(err) } }
func TestArcsPDF() { pdf := vgpdf.New(vg.Inches(4), vg.Inches(4)) DrawArcs(pdf) if err := pdf.Save("arcs.pdf"); err != nil { panic(err) } }
func TestArcsSVG() { img := vgsvg.New(vg.Inches(4), vg.Inches(4)) DrawArcs(img) err := img.Save("arcs.svg") if err != nil { panic(err) } }
func TestFontsSVG() { img := vgsvg.New(vg.Inches(4), vg.Inches(4)) DrawFonts(img) err := img.Save("fonts.svg") if err != nil { panic(err) } }
func TestArcsIMG() { img, err := vgimg.New(vg.Inches(4), vg.Inches(4)) if err != nil { panic(err) } DrawArcs(img) err = img.Save("arcs.png", png.Encode) if err != nil { panic(err) } }
func TestFontExtentsIMG() { img, err := vgimg.New(vg.Inches(4), vg.Inches(4)) if err != nil { panic(err) } DrawFontExtents(img) err = img.Save("extents.png", png.Encode) if err != nil { panic(err) } }
//Save saves the board (i.e. all subplots, appropriately laid out) to the specified filename. //It basically rips off the implementation of Save in plotinum to support various file formats. func (b *Board) Save(width, height float64, file string) (err error) { w, h := vg.Inches(width), vg.Inches(height) var c interface { vg.Canvas Size() (w, h vg.Length) io.WriterTo } switch ext := strings.ToLower(filepath.Ext(file)); ext { case ".eps": c = vgeps.NewTitle(w, h, file) case ".jpg", ".jpeg": c = vgimg.JpegCanvas{Canvas: vgimg.New(w, h)} case ".pdf": c = vgpdf.New(w, h) case ".png": c = vgimg.PngCanvas{Canvas: vgimg.New(w, h)} case ".svg": c = vgsvg.New(w, h) case ".tiff": c = vgimg.TiffCanvas{Canvas: vgimg.New(w, h)} default: return fmt.Errorf("Unsupported file extension: %s", ext) } for _, subplot := range b.SubPlots { w, h := c.Size() drawArea := plot.DrawArea{ Canvas: c, Rect: subplot.ScaledRect(float64(w), float64(h)), } subplot.Plot.Draw(drawArea) } f, err := os.Create(file) if err != nil { return err } if _, err = c.WriteTo(f); err != nil { return err } say.Println(0, say.Yellow("Saved %s", file)) return f.Close() }
// 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 }
// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image) *Canvas { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) draw.Draw(img, img.Bounds(), image.White, image.ZP, draw.Src) gc := draw2d.NewGraphicContext(img) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) c := &Canvas{ gc: gc, img: img, w: vg.Inches(w / dpi), h: vg.Inches(h / dpi), color: []color.Color{color.Black}, } vg.Initialize(c) return c }
// Save saves the plot to an image file. Width and height // are specified in inches, and the file format is determined // by the extension. Supported extensions are // .eps, .jpg, .jpeg, .pdf, .png, .svg, and .tiff. func (p *Plot) Save(width, height float64, file string) (err error) { w, h := vg.Inches(width), vg.Inches(height) var c interface { vg.Canvas Size() (w, h vg.Length) io.WriterTo } switch ext := strings.ToLower(filepath.Ext(file)); ext { case ".eps": c = vgeps.NewTitle(w, h, file) case ".jpg", ".jpeg": c = vgimg.JpegCanvas{Canvas: vgimg.New(w, h)} case ".pdf": c = vgpdf.New(w, h) case ".png": c = vgimg.PngCanvas{Canvas: vgimg.New(w, h)} case ".svg": c = vgsvg.New(w, h) case ".tiff": c = vgimg.TiffCanvas{Canvas: vgimg.New(w, h)} default: return fmt.Errorf("Unsupported file extension: %s", ext) } p.Draw(MakeDrawArea(c)) f, err := os.Create(file) if err != nil { return err } if _, err = c.WriteTo(f); err != nil { return err } return f.Close() }
// dataCoord returns the plot number and data // coordinate of a screen coordinate. A negative // plot numbers means that the screen coordinate // is not in the data area of any plot. func dataCoord(x, y int) (int, float64, float64) { dpi := ps[0].dataArea.DPI() pt := plot.Point{ X: vg.Inches(float64(x) / dpi), Y: vg.Inches(float64(y) / dpi), } for i, p := range ps { if p.dataArea.Contains(pt) { da := p.dataArea x := float64((pt.X - da.Min.X) / (da.Max().X - da.Min.X)) x *= (p.plot.X.Max - p.plot.X.Min) x += p.plot.X.Min y := float64((pt.Y - da.Min.Y) / (da.Max().Y - da.Min.Y)) y *= (p.plot.Y.Max - p.plot.Y.Min) y += p.plot.Y.Min return i, x, y } } return -1, 0, 0 }
// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image, name string) (*XImgCanvas, error) { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h))) err = ximg.CreatePixmap() if err != nil { return nil, err } painter := NewXimgPainter(ximg) gc := draw2d.NewGraphicContextWithPainter(ximg, painter) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) wid := ximg.XShowExtra(name, true) go func() { xevent.Main(X) }() c := &XImgCanvas{ gc: gc, w: vg.Inches(w / dpi), h: vg.Inches(h / dpi), color: []color.Color{color.Black}, x: X, ximg: ximg, wid: wid, } vg.Initialize(c) return c, nil }
func drawPng(b *bytes.Buffer, p *plot.Plot, width, height float64) { w, h := vg.Inches(width), vg.Inches(height) c := vgimg.PngCanvas{Canvas: vgimg.New(w, h)} p.Draw(plot.MakeDrawArea(c)) c.WriteTo(b) }
// DrawArcs draws some arcs to the canvas. // The canvas is assumed to be 4 inches square. func DrawArcs(c vg.Canvas) { green := color.RGBA{G: 255, A: 255} var p vg.Path p.Move(vg.Inches(3), vg.Inches(2)) p.Arc(vg.Inches(2), vg.Inches(2), vg.Inches(1), 0, 2*math.Pi) c.SetColor(color.RGBA{B: 255, A: 255}) c.Fill(p) p = vg.Path{} p.Move(vg.Inches(4), vg.Inches(2)) p.Line(vg.Inches(3), vg.Inches(2)) p.Arc(vg.Inches(2), vg.Inches(2), vg.Inches(1), 0, 5*math.Pi/2) p.Line(vg.Inches(2), vg.Inches(4)) c.SetColor(color.RGBA{R: 255, A: 255}) c.SetLineWidth(vg.Points(3)) c.Stroke(p) p = vg.Path{} p.Move(vg.Inches(0), vg.Inches(2)) p.Line(vg.Inches(1), vg.Inches(2)) p.Arc(vg.Inches(2), vg.Inches(2), vg.Inches(1), math.Pi, -7*math.Pi/2) p.Line(vg.Inches(2), vg.Inches(0)) c.SetColor(color.Black) c.SetLineWidth(vg.Points(1)) c.Stroke(p) p = vg.Path{} p.Move(vg.Inches(0), vg.Inches(1)) p.Arc(vg.Inches(1), vg.Inches(1), vg.Inches(1), math.Pi, math.Pi/2) c.SetLineWidth(vg.Points(3)) c.SetColor(green) c.Stroke(p) p = vg.Path{} p.Move(vg.Inches(1), vg.Inches(0)) p.Arc(vg.Inches(1), vg.Inches(1), vg.Inches(1), 3*math.Pi/2, -math.Pi/2) c.SetLineWidth(vg.Points(1)) c.SetColor(color.Black) c.Stroke(p) p = vg.Path{} p.Move(vg.Inches(3), vg.Inches(2)) p.Arc(vg.Inches(3), vg.Inches(3), vg.Inches(1), 3*math.Pi/2, 3*math.Pi/2) c.SetLineWidth(vg.Points(3)) c.SetColor(green) c.Stroke(p) p = vg.Path{} p.Move(vg.Inches(2), vg.Inches(3)) p.Arc(vg.Inches(3), vg.Inches(3), vg.Inches(1), math.Pi, -3*math.Pi/2) c.SetLineWidth(vg.Points(1)) c.SetColor(color.Black) c.Stroke(p) }