Exemplo n.º 1
0
// 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 = draw.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
}
Exemplo n.º 2
0
// 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:      draw.TextStyle{Font: font},
	}, nil
}
Exemplo n.º 3
0
// Draw the plot logo.
func Example() {
	p, err := plot.New()
	if err != nil {
		log.Panic(err)
	}

	DefaultLineStyle.Width = vg.Points(1)
	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 := XYs{{0, 0}, {0, 1}, {0.5, 1}, {0.5, 0.6}, {0, 0.6}}
	line, err := NewLine(pts)
	if err != nil {
		log.Panic(err)
	}
	scatter, err := NewScatter(pts)
	if err != nil {
		log.Panic(err)
	}
	p.Add(line, scatter)

	pts = XYs{{1, 0}, {0.75, 0}, {0.75, 0.75}}
	line, err = NewLine(pts)
	if err != nil {
		log.Panic(err)
	}
	scatter, err = NewScatter(pts)
	if err != nil {
		log.Panic(err)
	}
	p.Add(line, scatter)

	pts = XYs{{0.5, 0.5}, {1, 0.5}}
	line, err = NewLine(pts)
	if err != nil {
		log.Panic(err)
	}
	scatter, err = NewScatter(pts)
	if err != nil {
		log.Panic(err)
	}
	p.Add(line, scatter)

	err = p.Save(100, 100, "testdata/plotLogo.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 4
0
func main() {
	var levels []float64
	for l := 100.5; l < volcano.Matrix.(*mat64.Dense).Max(); l += 5 {
		levels = append(levels, l)
	}
	c := plotter.NewContour(volcano, levels, palette.Rainbow(len(levels), (palette.Yellow+palette.Red)/2, palette.Blue, 1, 1, 1))
	quarterStyle := draw.LineStyle{
		Color:  color.Black,
		Width:  vg.Points(0.5),
		Dashes: []vg.Length{0.2, 0.4},
	}
	halfStyle := draw.LineStyle{
		Color:  color.Black,
		Width:  vg.Points(0.5),
		Dashes: []vg.Length{5, 2, 1, 2},
	}
	c.LineStyles = append(c.LineStyles, quarterStyle, halfStyle, quarterStyle)

	h := plotter.NewHeatMap(volcano, palette.Heat(len(levels)*2, 1))

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Maunga Whau Volcano"

	p.Add(h)
	p.Add(c)

	p.X.Padding = 0
	p.Y.Padding = 0
	_, p.X.Max, _, p.Y.Max = h.DataRange()

	name := "example_volcano"

	for _, ext := range []string{
		".eps",
		".pdf",
		".svg",
		".png",
		".tiff",
		".jpg",
	} {
		if err := p.Save(4, 4, name+ext); err != nil {
			panic(err)
		}
	}
}
Exemplo n.º 5
0
// DrawGlyph implements the Glyph interface.
func (RingGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.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()
	c.Stroke(p)
}
Exemplo n.º 6
0
// DrawGlyph implements the Glyph interface.
func (TriangleGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.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()
	c.Stroke(p)
}
Exemplo n.º 7
0
// DrawGlyph implements the Glyph interface.
func (SquareGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.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()
	c.Stroke(p)
}
Exemplo n.º 8
0
// DrawGlyph implements the Glyph interface.
func (CrossGlyph) DrawGlyph(c *Canvas, sty GlyphStyle, pt Point) {
	c.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)
	c.Stroke(p)
	p = vg.Path{}
	p.Move(pt.X-r, pt.Y+r)
	p.Line(pt.X+r, pt.Y-r)
	c.Stroke(p)
}
Exemplo n.º 9
0
func ExampleBubbles() {
	// randomTriples returns some random x, y, z triples
	// with some interesting kind of trend.
	randomTriples := func(n int) XYZs {
		data := make(XYZs, n)
		for i := range data {
			if i == 0 {
				data[i].X = rand.Float64()
			} else {
				data[i].X = data[i-1].X + 2*rand.Float64()
			}
			data[i].Y = data[i].X + 10*rand.Float64()
			data[i].Z = data[i].X
		}
		return data
	}

	n := 10
	bubbleData := randomTriples(n)

	p, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p.Title.Text = "Bubbles"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	bs, err := NewBubbles(bubbleData, vg.Points(1), vg.Points(20))
	if err != nil {
		log.Panic(err)
	}
	bs.Color = color.RGBA{R: 196, B: 128, A: 255}
	p.Add(bs)

	err = p.Save(200, 200, "testdata/bubbles.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 10
0
Arquivo: add.go Projeto: skiesel/plot
// 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
}
Exemplo n.º 11
0
// An example of making a histogram.
func ExampleHistogram() {
	// stdNorm returns the probability of drawing a
	// value from a standard normal distribution.
	stdNorm := func(x float64) float64 {
		const sigma = 1.0
		const mu = 0.0
		const root2π = 2.50662827459517818309
		return 1.0 / (sigma * root2π) * math.Exp(-((x-mu)*(x-mu))/(2*sigma*sigma))
	}

	n := 10000
	vals := make(Values, n)
	for i := 0; i < n; i++ {
		vals[i] = rand.NormFloat64()
	}

	p, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p.Title.Text = "Histogram"
	h, err := NewHist(vals, 16)
	if err != nil {
		log.Panic(err)
	}
	h.Normalize(1)
	p.Add(h)

	// The normal distribution function
	norm := NewFunction(stdNorm)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	err = p.Save(200, 200, "testdata/histogram.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 12
0
// ExampleFunction draws some functions.
func ExampleFunction() {
	quad := NewFunction(func(x float64) float64 { return x * x })
	quad.Color = color.RGBA{B: 255, A: 255}

	exp := 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 := 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, err := plot.New()
	if err != nil {
		log.Panic(err)
	}

	p.Title.Text = "Functions"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	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 = 0.5 * vg.Inch

	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 100

	err = p.Save(200, 200, "testdata/functions.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 13
0
Arquivo: axis.go Projeto: skiesel/plot
// makeAxis returns a default Axis.
//
// The default range is (∞, ­∞), and thus any finite
// value is less than Min and greater than Max.
func makeAxis() (Axis, error) {
	labelFont, err := vg.MakeFont(DefaultFont, vg.Points(12))
	if err != nil {
		return Axis{}, err
	}

	tickFont, err := vg.MakeFont(DefaultFont, vg.Points(10))
	if err != nil {
		return Axis{}, err
	}

	a := Axis{
		Min: math.Inf(1),
		Max: math.Inf(-1),
		LineStyle: draw.LineStyle{
			Color: color.Black,
			Width: vg.Points(0.5),
		},
		Padding: vg.Points(5),
		Scale:   LinearScale{},
	}
	a.Label.TextStyle = draw.TextStyle{
		Color: color.Black,
		Font:  labelFont,
	}
	a.Tick.Label = draw.TextStyle{
		Color: color.Black,
		Font:  tickFont,
	}
	a.Tick.LineStyle = draw.LineStyle{
		Color: color.Black,
		Width: vg.Points(0.5),
	}
	a.Tick.Length = vg.Points(8)
	a.Tick.Marker = DefaultTicks{}

	return a, nil
}
Exemplo n.º 14
0
// than the max number of GlyphDrawers
// in the DefaultGlyphShapes slice.
func Shape(i int) draw.GlyphDrawer {
	n := len(DefaultGlyphShapes)
	if i < 0 {
		return DefaultGlyphShapes[i%n+n]
	}
	return DefaultGlyphShapes[i%n]
}

// DefaultDashes is a set of dash patterns used by
// the Dashes function.
var DefaultDashes = [][]vg.Length{
	{},

	{vg.Points(6), vg.Points(2)},

	{vg.Points(2), vg.Points(2)},

	{vg.Points(1), vg.Points(1)},

	{vg.Points(5), vg.Points(2), vg.Points(1), vg.Points(2)},

	{vg.Points(10), vg.Points(2), vg.Points(2), vg.Points(2),
		vg.Points(2), vg.Points(2), vg.Points(2), vg.Points(2)},

	{vg.Points(10), vg.Points(2), vg.Points(2), vg.Points(2)},

	{vg.Points(5), vg.Points(2), vg.Points(5), vg.Points(2),
		vg.Points(2), vg.Points(2), vg.Points(2), vg.Points(2)},
Exemplo n.º 15
0
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")
	// }

}
Exemplo n.º 16
0
import (
	"errors"
	"image/color"
	"math"

	"github.com/skiesel/plot/vg"
	"github.com/skiesel/plot/vg/draw"
)

var (
	// DefaultLineStyle is the default style for drawing
	// lines.
	DefaultLineStyle = draw.LineStyle{
		Color:    color.Black,
		Width:    vg.Points(1),
		Dashes:   []vg.Length{},
		DashOffs: 0,
	}

	// DefaultGlyphStyle is the default style used
	// for gyph marks.
	DefaultGlyphStyle = draw.GlyphStyle{
		Color:  color.Black,
		Radius: vg.Points(2.5),
		Shape:  draw.RingGlyph{},
	}
)

// Valuer wraps the Len and Value methods.
type Valuer interface {
Exemplo n.º 17
0
Arquivo: grid.go Projeto: skiesel/plot
package plotter

import (
	"image/color"

	"github.com/skiesel/plot"
	"github.com/skiesel/plot/vg"
	"github.com/skiesel/plot/vg/draw"
)

var (
	// DefaultGridLineStyle is the default style for grid lines.
	DefaultGridLineStyle = draw.LineStyle{
		Color: color.Gray{128},
		Width: vg.Points(0.25),
	}
)

// Grid implements the plot.Plotter interface, drawing
// a set of grid lines at the major tick marks.
type Grid struct {
	// Vertical is the style of the vertical lines.
	Vertical draw.LineStyle

	// Horizontal is the style of the horizontal lines.
	Horizontal draw.LineStyle
}

// NewGrid returns a new grid with both vertical and
// horizontal lines using the default grid line style.
Exemplo n.º 18
0
// Copyright ©2015 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package plotter

import (
	"math"

	"github.com/skiesel/plot"
	"github.com/skiesel/plot/vg"
	"github.com/skiesel/plot/vg/draw"
)

// DefaultCapWidth is the default width of error bar caps.
var DefaultCapWidth = vg.Points(5)

// YErrorBars implements the plot.Plotter, plot.DataRanger,
// and plot.GlyphBoxer interfaces, drawing vertical error
// bars, denoting error in Y values.
type YErrorBars struct {
	XYs

	// YErrors is a copy of the Y errors for each point.
	YErrors

	// LineStyle is the style used to draw the error bars.
	draw.LineStyle

	// CapWidth is the width of the caps drawn at the top
	// of each error bar.
Exemplo n.º 19
0
func NewGlyphBoxes() *GlyphBoxes {
	g := new(GlyphBoxes)
	g.Color = color.RGBA{R: 255, A: 255}
	g.Width = vg.Points(0.25)
	return g
}
Exemplo n.º 20
0
func ExampleBoxPlot() {
	// Create the sample data.
	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)
	}

	// Make boxes for our data and add them to the plot.
	uniBox, err := NewBoxPlot(vg.Points(20), 0, uniform)
	if err != nil {
		log.Panic(err)
	}
	normBox, err := NewBoxPlot(vg.Points(20), 1, normal)
	if err != nil {
		log.Panic(err)
	}
	expBox, err := NewBoxPlot(vg.Points(20), 2, expon)
	if err != nil {
		log.Panic(err)
	}

	// Make a vertical box plot.
	uniLabels, err := uniBox.OutsideLabels(uniform)
	if err != nil {
		log.Panic(err)
	}
	normLabels, err := normBox.OutsideLabels(normal)
	if err != nil {
		log.Panic(err)
	}
	expLabels, err := expBox.OutsideLabels(expon)
	if err != nil {
		log.Panic(err)
	}

	p1, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p1.Title.Text = "Vertical Box Plot"
	p1.Y.Label.Text = "plotter.Values"
	p1.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.
	p1.NominalX("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")

	err = p1.Save(200, 200, "testdata/verticalBoxPlot.png")
	if err != nil {
		log.Panic(err)
	}

	// Now, make the same plot but horizontal.
	normBox.Horizontal = true
	expBox.Horizontal = true
	uniBox.Horizontal = true
	// We can use the same plotters but the labels need to be recreated.
	uniLabels, err = uniBox.OutsideLabels(uniform)
	if err != nil {
		log.Panic(err)
	}
	normLabels, err = normBox.OutsideLabels(normal)
	if err != nil {
		log.Panic(err)
	}
	expLabels, err = expBox.OutsideLabels(expon)
	if err != nil {
		log.Panic(err)
	}

	p2, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p2.Title.Text = "Horizontal Box Plot"
	p2.X.Label.Text = "plotter.Values"

	p2.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels)

	// Set the Y axis of the plot to nominal with
	// the given names for y=0, y=1 and y=2.
	p2.NominalY("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")

	err = p2.Save(200, 200, "testdata/horizontalBoxPlot.png")
	if err != nil {
		log.Panic(err)
	}

	// Now, make a grouped box plot.
	p3, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p3.Title.Text = "Box Plot"
	p3.Y.Label.Text = "plotter.Values"

	w := vg.Points(20)
	for x := 0.0; x < 3.0; x++ {
		b0, err := NewBoxPlot(w, x, uniform)
		if err != nil {
			log.Panic(err)
		}
		b0.Offset = -w - vg.Points(3)
		b1, err := NewBoxPlot(w, x, normal)
		if err != nil {
			log.Panic(err)
		}
		b2, err := NewBoxPlot(w, x, expon)
		if err != nil {
			log.Panic(err)
		}
		b2.Offset = w + vg.Points(3)
		p3.Add(b0, b1, b2)
	}
	// Add a GlyphBox plotter for debugging.
	p3.Add(NewGlyphBoxes())

	// Set the X axis of the plot to nominal with
	// the given names for x=0, x=1 and x=2.
	p3.NominalX("Group 0", "Group 1", "Group 2")
	err = p3.Save(300, 300, "testdata/groupedBoxPlot.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 21
0
func TestLegendAlignment(t *testing.T) {
	font, err := vg.MakeFont(plot.DefaultFont, 10.822510822510822) // This font size gives an entry height of 10.
	if err != nil {
		t.Fatalf("failed to create font: %v", err)
	}
	l := plot.Legend{
		ThumbnailWidth: vg.Points(20),
		TextStyle:      draw.TextStyle{Font: font},
	}
	for _, n := range []string{"A", "B", "C", "D"} {
		b, err := plotter.NewBarChart(plotter.Values{0}, 1)
		if err != nil {
			t.Fatalf("failed to create bar chart %q: %v", n, err)
		}
		l.Add(n, b)
	}

	var r recorder.Canvas
	c := draw.NewCanvas(&r, 100, 100)
	l.Draw(draw.Canvas{
		Canvas: c.Canvas,
		Rectangle: draw.Rectangle{
			Min: draw.Point{0, 0},
			Max: draw.Point{100, 100},
		},
	})

	got := r.Actions

	// want is a snapshot of the actions for the code above when the
	// graphical output has been visually confirmed to be correct for
	// the bar charts example show in gonum/plot#25.
	want := []recorder.Action{
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.Fill{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 30},
				{Type: vg.LineComp, X: 80, Y: 40},
				{Type: vg.LineComp, X: 100, Y: 40},
				{Type: vg.LineComp, X: 100, Y: 30},
				{Type: vg.CloseComp},
			},
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.SetLineWidth{
			Width: 1,
		},
		&recorder.SetLineDash{},
		&recorder.Stroke{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 30},
				{Type: vg.LineComp, X: 80, Y: 40},
				{Type: vg.LineComp, X: 100, Y: 40},
				{Type: vg.LineComp, X: 100, Y: 30},
				{Type: vg.LineComp, X: 80, Y: 30},
			},
		},
		&recorder.SetColor{},
		&recorder.FillString{
			Font:   string("Times-Roman"),
			Size:   10.822510822510822,
			X:      69.48051948051948,
			Y:      30.82251082251082,
			String: "A",
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.Fill{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 20},
				{Type: vg.LineComp, X: 80, Y: 30},
				{Type: vg.LineComp, X: 100, Y: 30},
				{Type: vg.LineComp, X: 100, Y: 20},
				{Type: vg.CloseComp},
			},
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.SetLineWidth{
			Width: 1,
		},
		&recorder.SetLineDash{},
		&recorder.Stroke{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 20},
				{Type: vg.LineComp, X: 80, Y: 30},
				{Type: vg.LineComp, X: 100, Y: 30},
				{Type: vg.LineComp, X: 100, Y: 20},
				{Type: vg.LineComp, X: 80, Y: 20},
			},
		},
		&recorder.SetColor{},
		&recorder.FillString{
			Font:   string("Times-Roman"),
			Size:   10.822510822510822,
			X:      70.07575757575758,
			Y:      20.82251082251082,
			String: "B",
		},
		&recorder.SetColor{
			Color: color.Gray16{
				Y: uint16(0),
			},
		},
		&recorder.Fill{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 10},
				{Type: vg.LineComp, X: 80, Y: 20},
				{Type: vg.LineComp, X: 100, Y: 20},
				{Type: vg.LineComp, X: 100, Y: 10},
				{Type: vg.CloseComp},
			},
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.SetLineWidth{
			Width: 1,
		},
		&recorder.SetLineDash{},
		&recorder.Stroke{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 10},
				{Type: vg.LineComp, X: 80, Y: 20},
				{Type: vg.LineComp, X: 100, Y: 20},
				{Type: vg.LineComp, X: 100, Y: 10},
				{Type: vg.LineComp, X: 80, Y: 10},
			},
		},
		&recorder.SetColor{},
		&recorder.FillString{
			Font:   string("Times-Roman"),
			Size:   10.822510822510822,
			X:      70.07575757575758,
			Y:      10.822510822510822,
			String: "C",
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.Fill{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 0},
				{Type: vg.LineComp, X: 80, Y: 10},
				{Type: vg.LineComp, X: 100, Y: 10},
				{Type: vg.LineComp, X: 100, Y: 0},
				{Type: vg.CloseComp},
			},
		},
		&recorder.SetColor{
			Color: color.Gray16{},
		},
		&recorder.SetLineWidth{
			Width: 1,
		},
		&recorder.SetLineDash{},
		&recorder.Stroke{
			Path: vg.Path{
				{Type: vg.MoveComp, X: 80, Y: 0},
				{Type: vg.LineComp, X: 80, Y: 10},
				{Type: vg.LineComp, X: 100, Y: 10},
				{Type: vg.LineComp, X: 100, Y: 0},
				{Type: vg.LineComp, X: 80, Y: 0},
			},
		},
		&recorder.SetColor{},
		&recorder.FillString{
			Font:   string("Times-Roman"),
			Size:   10.822510822510822,
			X:      69.48051948051948,
			Y:      0.8225108225108215,
			String: "D",
		},
	}

	if !reflect.DeepEqual(got, want) {
		t.Errorf("unexpected legend actions:\ngot:\n%s\nwant:\n%s", formatActions(got), formatActions(want))
	}
}
Exemplo n.º 22
0
package plotter

import (
	"errors"

	"github.com/skiesel/plot"
	"github.com/skiesel/plot/vg"
	"github.com/skiesel/plot/vg/draw"
)

var (
	// DefaultFont is the default font for label text.
	DefaultFont = plot.DefaultFont

	// DefaultFontSize is the default font.
	DefaultFontSize = vg.Points(10)
)

// Labels implements the Plotter interface,
// drawing a set of labels at specified points.
type Labels struct {
	XYs

	// Labels is the set of labels corresponding
	// to each point.
	Labels []string

	// TextStyle is the style of the label text.
	draw.TextStyle

	// XAlign and YAlign are multiplied by the width
Exemplo n.º 23
0
// ExampleScatter draws some scatter points, a line,
// and a line with points.
func ExampleScatter() {
	// randomPoints returns some random x, y points
	// with some interesting kind of trend.
	randomPoints := func(n int) XYs {
		pts := make(XYs, n)
		for i := range pts {
			if i == 0 {
				pts[i].X = rand.Float64()
			} else {
				pts[i].X = pts[i-1].X + rand.Float64()
			}
			pts[i].Y = pts[i].X + 10*rand.Float64()
		}
		return pts
	}

	n := 15
	scatterData := randomPoints(n)
	lineData := randomPoints(n)
	linePointsData := randomPoints(n)

	p, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p.Title.Text = "Points Example"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"
	p.Add(NewGrid())

	s, err := NewScatter(scatterData)
	if err != nil {
		log.Panic(err)
	}
	s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255}
	s.GlyphStyle.Radius = vg.Points(3)

	l, err := NewLine(lineData)
	if err != nil {
		log.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}

	lpLine, lpPoints, err := NewLinePoints(linePointsData)
	if err != nil {
		log.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)

	err = p.Save(200, 200, "testdata/scatter.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 24
0
func ExampleQuartPlot() {
	// Create the example data.
	n := 100
	uniform := make(Values, n)
	normal := make(Values, n)
	expon := make(Values, n)
	for i := 0; i < n; i++ {
		uniform[i] = rand.Float64()
		normal[i] = rand.NormFloat64()
		expon[i] = rand.ExpFloat64()
	}

	// Create the QuartPlots
	qp1, err := NewQuartPlot(0, uniform)
	if err != nil {
		log.Panic(err)
	}
	qp2, err := NewQuartPlot(1, normal)
	if err != nil {
		log.Panic(err)
	}
	qp3, err := NewQuartPlot(2, expon)
	if err != nil {
		log.Panic(err)
	}

	// Create a vertical plot
	p1, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p1.Title.Text = "Quartile Plot"
	p1.Y.Label.Text = "plotter.Values"
	p1.Add(qp1, qp2, qp3)

	// Set the X axis of the plot to nominal with
	// the given names for x=0, x=1 and x=2.
	p1.NominalX("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")

	err = p1.Save(200, 200, "testdata/verticalQuartPlot.png")
	if err != nil {
		log.Panic(err)
	}

	// Create a horizontal plot
	qp1.Horizontal = true
	qp2.Horizontal = true
	qp3.Horizontal = true

	p2, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p2.Title.Text = "Quartile Plot"
	p2.X.Label.Text = "plotter.Values"
	p2.Add(qp1, qp2, qp3)

	// Set the Y axis of the plot to nominal with
	// the given names for y=0, y=1 and y=2.
	p2.NominalY("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")

	err = p2.Save(200, 200, "testdata/horizontalQuartPlot.png")
	if err != nil {
		log.Panic(err)
	}

	// Now, create a grouped quartile plot.

	p3, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p3.Title.Text = "Box Plot"
	p3.Y.Label.Text = "plotter.Values"

	w := vg.Points(10)
	for x := 0.0; x < 3.0; x++ {
		b0, err := NewQuartPlot(x, uniform)
		if err != nil {
			log.Panic(err)
		}
		b0.Offset = -w
		b1, err := NewQuartPlot(x, normal)
		if err != nil {
			log.Panic(err)
		}
		b2, err := NewQuartPlot(x, expon)
		if err != nil {
			log.Panic(err)
		}
		b2.Offset = w
		p3.Add(b0, b1, b2)
	}
	p3.Add(NewGlyphBoxes())

	p3.NominalX("Group 0", "Group 1", "Group 2")

	err = p3.Save(200, 200, "testdata/groupedQuartPlot.png")
	if err != nil {
		log.Panic(err)
	}
}
Exemplo n.º 25
0
package plotter

import (
	"image/color"

	"github.com/skiesel/plot"
	"github.com/skiesel/plot/vg"
	"github.com/skiesel/plot/vg/draw"
)

var (
	// DefaultQuartMedianStyle is a fat dot.
	DefaultQuartMedianStyle = draw.GlyphStyle{
		Color:  color.Black,
		Radius: vg.Points(1.5),
		Shape:  draw.CircleGlyph{},
	}

	// DefaultQuartWhiskerStyle is a hairline.
	DefaultQuartWhiskerStyle = draw.LineStyle{
		Color:    color.Black,
		Width:    vg.Points(0.5),
		Dashes:   []vg.Length{},
		DashOffs: 0,
	}
)

// QuartPlot implements the Plotter interface, drawing
// a plot to represent the distribution of values.
//
Exemplo n.º 26
0
func ExampleBarChart() {
	// Create the plot values and labels.
	values := Values{0.5, 10, 20, 30}
	verticalLabels := []string{"A", "B", "C", "D"}
	horizontalLabels := []string{"Label A", "Label B", "Label C", "Label D"}

	// Create a vertical BarChart
	p1, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	verticalBarChart, err := NewBarChart(values, 0.5*vg.Centimeter)
	if err != nil {
		log.Panic(err)
	}
	p1.Add(verticalBarChart)
	p1.NominalX(verticalLabels...)
	err = p1.Save(100, 100, "testdata/verticalBarChart.png")
	if err != nil {
		log.Panic(err)
	}

	// Create a horizontal BarChart
	p2, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	horizontalBarChart, err := NewBarChart(values, 0.5*vg.Centimeter)
	horizontalBarChart.Horizontal = true // Specify a horizontal BarChart.
	if err != nil {
		log.Panic(err)
	}
	p2.Add(horizontalBarChart)
	p2.NominalY(horizontalLabels...)
	err = p2.Save(100, 100, "testdata/horizontalBarChart.png")
	if err != nil {
		log.Panic(err)
	}

	// Now, make a different type of BarChart.
	groupA := Values{20, 35, 30, 35, 27}
	groupB := Values{25, 32, 34, 20, 25}
	groupC := Values{12, 28, 15, 21, 8}
	groupD := Values{30, 42, 6, 9, 12}

	p, err := plot.New()
	if err != nil {
		log.Panic(err)
	}
	p.Title.Text = "Bar chart"
	p.Y.Label.Text = "Heights"

	w := vg.Points(8)

	barsA, err := NewBarChart(groupA, w)
	if err != nil {
		log.Panic(err)
	}
	barsA.Color = color.RGBA{R: 255, A: 255}
	barsA.Offset = -w / 2

	barsB, err := NewBarChart(groupB, w)
	if err != nil {
		log.Panic(err)
	}
	barsB.Color = color.RGBA{R: 196, G: 196, A: 255}
	barsB.Offset = w / 2

	barsC, err := NewBarChart(groupC, w)
	if err != nil {
		log.Panic(err)
	}
	barsC.XMin = 6
	barsC.Color = color.RGBA{B: 255, A: 255}
	barsC.Offset = -w / 2

	barsD, err := NewBarChart(groupD, w)
	if err != nil {
		log.Panic(err)
	}
	barsD.Color = color.RGBA{B: 255, R: 255, A: 255}
	barsD.XMin = 6
	barsD.Offset = w / 2

	p.Add(barsA, barsB, barsC, barsD)
	p.Legend.Add("A", barsA)
	p.Legend.Add("B", barsB)
	p.Legend.Add("C", barsC)
	p.Legend.Add("D", barsD)
	p.Legend.Top = true
	p.NominalX("Zero", "One", "Two", "Three", "Four", "",
		"Six", "Seven", "Eight", "Nine", "Ten")

	p.Add(NewGlyphBoxes())
	err = p.Save(300, 250, "testdata/barChart2.png")
	if err != nil {
		log.Panic(err)
	}

	// Now, make a stacked BarChart.
	p, err = plot.New()
	if err != nil {
		log.Panic(err)
	}
	p.Title.Text = "Bar chart"
	p.Y.Label.Text = "Heights"

	w = vg.Points(15)

	barsA, err = NewBarChart(groupA, w)
	if err != nil {
		log.Panic(err)
	}
	barsA.Color = color.RGBA{R: 255, A: 255}
	barsA.Offset = -w / 2

	barsB, err = NewBarChart(groupB, w)
	if err != nil {
		log.Panic(err)
	}
	barsB.Color = color.RGBA{R: 196, G: 196, A: 255}
	barsB.StackOn(barsA)

	barsC, err = NewBarChart(groupC, w)
	if err != nil {
		log.Panic(err)
	}
	barsC.Offset = w / 2
	barsC.Color = color.RGBA{B: 255, A: 255}

	barsD, err = NewBarChart(groupD, w)
	if err != nil {
		log.Panic(err)
	}
	barsD.StackOn(barsC)
	barsD.Color = color.RGBA{B: 255, R: 255, A: 255}

	p.Add(barsA, barsB, barsC, barsD)
	p.Legend.Add("A", barsA)
	p.Legend.Add("B", barsB)
	p.Legend.Add("C", barsC)
	p.Legend.Add("D", barsD)
	p.Legend.Top = true
	p.NominalX("Zero", "One", "Two", "Three", "Four", "",
		"Six", "Seven", "Eight", "Nine", "Ten")

	p.Add(NewGlyphBoxes())
	err = p.Save(250, 250, "testdata/stackedBarChart.png")
	if err != nil {
		log.Panic(err)
	}
}