Beispiel #1
0
// Plot implements the plot.Plotter interface.
func (b *BarChart) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)

	for i, ht := range b.Values {
		x := b.XMin + float64(i)
		xmin := trX(float64(x))
		if !c.ContainsX(xmin) {
			continue
		}
		xmin = xmin - b.Width/2 + b.Offset
		xmax := xmin + b.Width
		bottom := b.stackedOn.BarHeight(i)
		ymin := trY(bottom)
		ymax := trY(bottom + ht)

		pts := []draw.Point{
			{xmin, ymin},
			{xmin, ymax},
			{xmax, ymax},
			{xmax, ymin},
		}
		poly := c.ClipPolygonY(pts)
		c.FillPolygon(b.Color, poly)

		pts = append(pts, draw.Point{xmin, ymin})
		outline := c.ClipLinesY(pts)
		c.StrokeLines(b.LineStyle, outline...)
	}
}
Beispiel #2
0
// Plot implements the Plotter interface, drawing a line
// that connects each point in the Line.
func (f *Function) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)

	d := (p.X.Max - p.X.Min) / float64(f.Samples-1)
	line := make([]draw.Point, f.Samples)
	for i := range line {
		x := p.X.Min + float64(i)*d
		line[i].X = trX(x)
		line[i].Y = trY(f.F(x))
	}

	// For every continuous block of non-NaN Y values, stroke lines
	for i := 0; i < len(line); i++ {
		if !math.IsNaN(float64(line[i].Y)) {
			j := i + 1
			for ; j < len(line); j++ {
				if math.IsNaN(float64(line[j].Y)) {
					break
				}
			}
			c.StrokeLines(f.LineStyle, c.ClipLinesXY(line[i:j])...)
			i = j
		}
	}
}
Beispiel #3
0
// Plot draws the Line, implementing the plot.Plotter interface.
func (rp *ResponsePlotter) Plot(canvas vgdraw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&canvas)

	start := float64(rp.Response.GetStartTime())
	step := float64(rp.Response.GetStepTime())
	absent := rp.Response.IsAbsent

	lines := make([][]vgdraw.Point, 1)
	lines[0] = make([]vgdraw.Point, 0, len(rp.Response.Values))

	/* ikruglov
	 * swithing between lineMode and looping inside
	 * is more branch-prediction friendly i.e. potentially faster */
	switch rp.lineMode {
	case "slope":
		currentLine := 0
		lastAbsent := false
		for i, v := range rp.Response.Values {
			if absent[i] {
				lastAbsent = true
			} else if lastAbsent {
				currentLine++
				lines = append(lines, make([]vgdraw.Point, 1))
				lines[currentLine][0] = vgdraw.Point{X: trX(start + float64(i)*step), Y: trY(v)}
				lastAbsent = false
			} else {
				lines[currentLine] = append(lines[currentLine], vgdraw.Point{X: trX(start + float64(i)*step), Y: trY(v)})
			}
		}

	case "connected":
		for i, v := range rp.Response.Values {
			if absent[i] {
				continue
			}

			lines[0] = append(lines[0], vgdraw.Point{X: trX(start + float64(i)*step), Y: trY(v)})
		}

	case "drawAsInfinite":
		for i, v := range rp.Response.Values {
			if !absent[i] && v > 0 {
				infiniteLine := []vgdraw.Point{
					vgdraw.Point{X: trX(start + float64(i)*step), Y: canvas.Y(1)},
					vgdraw.Point{X: trX(start + float64(i)*step), Y: canvas.Y(0)},
				}
				lines = append(lines, infiniteLine)
			}
		}

	//case "staircase": // TODO
	default:
		panic("Unimplemented " + rp.lineMode)
	}

	canvas.StrokeLines(rp.LineStyle, lines...)
}
Beispiel #4
0
// DataCanvas returns a new draw.Canvas that
// is the subset of the given draw area into which
// the plot data will be drawn.
func (p *Plot) DataCanvas(da draw.Canvas) draw.Canvas {
	if p.Title.Text != "" {
		da.Max.Y -= p.Title.Height(p.Title.Text) - p.Title.Font.Extents().Descent
		da.Max.Y -= p.Title.Padding
	}
	p.X.sanitizeRange()
	x := horizontalAxis{p.X}
	p.Y.sanitizeRange()
	y := verticalAxis{p.Y}
	return padY(p, padX(p, da.Crop(y.size(), x.size(), 0, 0)))
}
Beispiel #5
0
// Plot implements the Plotter interface, drawing a line
// that connects each point in the Line.
func (f *Function) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)

	d := (p.X.Max - p.X.Min) / float64(f.Samples-1)
	line := make([]draw.Point, f.Samples)
	for i := range line {
		x := p.X.Min + float64(i)*d
		line[i].X = trX(x)
		line[i].Y = trY(f.F(x))
	}
	c.StrokeLines(f.LineStyle, c.ClipLinesXY(line)...)
}
Beispiel #6
0
// Plot implements the Plotter interface, drawing labels.
func (l *Labels) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)
	for i, label := range l.Labels {
		x := trX(l.XYs[i].X)
		y := trY(l.XYs[i].Y)
		if !c.Contains(draw.Point{x, y}) {
			continue
		}
		x += l.XOffset
		y += l.YOffset
		c.FillText(l.TextStyle, x, y, l.XAlign, l.YAlign, label)
	}
}
Beispiel #7
0
// Plot implements the Plotter interface, drawing labels.
func (e *YErrorBars) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)
	for i, err := range e.YErrors {
		x := trX(e.XYs[i].X)
		ylow := trY(e.XYs[i].Y - math.Abs(err.Low))
		yhigh := trY(e.XYs[i].Y + math.Abs(err.High))

		bar := c.ClipLinesY([]draw.Point{{x, ylow}, {x, yhigh}})
		c.StrokeLines(e.LineStyle, bar...)
		e.drawCap(&c, x, ylow)
		e.drawCap(&c, x, yhigh)
	}
}
Beispiel #8
0
// Plot implements the Plotter interface, drawing labels.
func (e *XErrorBars) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)
	for i, err := range e.XErrors {
		y := trY(e.XYs[i].Y)
		xlow := trX(e.XYs[i].X - math.Abs(err.Low))
		xhigh := trX(e.XYs[i].X + math.Abs(err.High))

		bar := c.ClipLinesX([]draw.Point{{xlow, y}, {xhigh, y}})
		c.StrokeLines(e.LineStyle, bar...)
		e.drawCap(&c, xlow, y)
		e.drawCap(&c, xhigh, y)
	}
}
Beispiel #9
0
// bottomMost returns the bottom-most GlyphBox.
func bottomMost(c *draw.Canvas, boxes []GlyphBox) GlyphBox {
	miny := c.Min.Y
	l := GlyphBox{}
	for _, b := range boxes {
		if b.Size().Y <= 0 {
			continue
		}
		if y := c.Y(b.Y) + b.Min.Y; y < miny && b.Y >= 0 {
			miny = y
			l = b
		}
	}
	return l
}
Beispiel #10
0
// topMost returns the top-most GlyphBox.
func topMost(c *draw.Canvas, boxes []GlyphBox) GlyphBox {
	maxy := c.Max.Y
	t := GlyphBox{Y: 1}
	for _, b := range boxes {
		if b.Size().Y <= 0 {
			continue
		}
		if y := c.Y(b.Y) + b.Min.Y + b.Size().Y; y > maxy && b.Y <= 1 {
			maxy = y
			t = b
		}
	}
	return t
}
Beispiel #11
0
// leftMost returns the left-most GlyphBox.
func leftMost(c *draw.Canvas, boxes []GlyphBox) GlyphBox {
	minx := c.Min.X
	l := GlyphBox{}
	for _, b := range boxes {
		if b.Size().X <= 0 {
			continue
		}
		if x := c.X(b.X) + b.Min.X; x < minx && b.X >= 0 {
			minx = x
			l = b
		}
	}
	return l
}
Beispiel #12
0
// rightMost returns the right-most GlyphBox.
func rightMost(c *draw.Canvas, boxes []GlyphBox) GlyphBox {
	maxx := c.Max.X
	r := GlyphBox{X: 1}
	for _, b := range boxes {
		if b.Size().X <= 0 {
			continue
		}
		if x := c.X(b.X) + b.Min.X + b.Size().X; x > maxx && b.X <= 1 {
			maxx = x
			r = b
		}
	}
	return r
}
Beispiel #13
0
// Draw draws a plot to a draw.Canvas.
//
// Plotters are drawn in the order in which they were
// added to the plot.  Plotters that  implement the
// GlyphBoxer interface will have their GlyphBoxes
// taken into account when padding the plot so that
// none of their glyphs are clipped.
func (p *Plot) Draw(c draw.Canvas) {
	if p.BackgroundColor != nil {
		c.SetColor(p.BackgroundColor)
		c.Fill(c.Rectangle.Path())
	}
	if p.Title.Text != "" {
		c.FillText(p.Title.TextStyle, c.Center().X, c.Max.Y, -0.5, -1, p.Title.Text)
		c.Max.Y -= p.Title.Height(p.Title.Text) - p.Title.Font.Extents().Descent
		c.Max.Y -= p.Title.Padding
	}

	p.X.sanitizeRange()
	x := horizontalAxis{p.X}
	p.Y.sanitizeRange()
	y := verticalAxis{p.Y}

	ywidth := y.size()
	x.draw(padX(p, draw.Crop(c, ywidth, 0, 0, 0)))
	xheight := x.size()
	y.draw(padY(p, draw.Crop(c, 0, 0, xheight, 0)))

	dataC := padY(p, padX(p, draw.Crop(c, ywidth, 0, xheight, 0)))
	for _, data := range p.plotters {
		data.Plot(dataC, p)
	}

	p.Legend.draw(draw.Crop(draw.Crop(c, ywidth, 0, 0, 0), 0, 0, xheight, 0))
}
Beispiel #14
0
// Plot implements the plot.Plotter interface.
func (g *Grid) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)

	if g.Vertical.Color == nil {
		goto horiz
	}
	for _, tk := range plt.X.Tick.Marker.Ticks(plt.X.Min, plt.X.Max) {
		if tk.IsMinor() {
			continue
		}
		x := trX(tk.Value)
		c.StrokeLine2(g.Vertical, x, c.Min.Y, x, c.Min.Y+c.Size().Y)
	}

horiz:
	if g.Horizontal.Color == nil {
		return
	}
	for _, tk := range plt.Y.Tick.Marker.Ticks(plt.Y.Min, plt.Y.Max) {
		if tk.IsMinor() {
			continue
		}
		y := trY(tk.Value)
		c.StrokeLine2(g.Horizontal, c.Min.X, y, c.Min.X+c.Size().X, y)
	}
}
Beispiel #15
0
// DrawGlyphBoxes draws red outlines around the plot's
// GlyphBoxes.  This is intended for debugging.
func (p *Plot) DrawGlyphBoxes(c *draw.Canvas) {
	c.SetColor(color.RGBA{R: 255, A: 255})
	for _, b := range p.GlyphBoxes(p) {
		b.Rectangle.Min.X += c.X(b.X)
		b.Rectangle.Min.Y += c.Y(b.Y)
		c.Stroke(b.Rectangle.Path())
	}
}
Beispiel #16
0
func (b *BarChart) Thumbnail(c *draw.Canvas) {
	pts := []draw.Point{
		{c.Min.X, c.Min.Y},
		{c.Min.X, c.Max.Y},
		{c.Max.X, c.Max.Y},
		{c.Max.X, c.Min.Y},
	}
	poly := c.ClipPolygonY(pts)
	c.FillPolygon(b.Color, poly)

	pts = append(pts, draw.Point{c.Min.X, c.Min.Y})
	outline := c.ClipLinesY(pts)
	c.StrokeLines(b.LineStyle, outline...)
}
Beispiel #17
0
// Plot implements the Plot method of the plot.Plotter interface.
func (h *Contour) Plot(c draw.Canvas, plt *plot.Plot) {
	if naive {
		h.naivePlot(c, plt)
		return
	}

	var pal []color.Color
	if h.Palette != nil {
		pal = h.Palette.Colors()
	}

	trX, trY := plt.Transforms(&c)

	// Collate contour paths and draw them.
	//
	// The alternative naive approach is to draw each line segment as
	// conrec returns it. The integrated path approach allows graphical
	// optimisations and is necessary for contour fill shading.
	cp := contourPaths(h.GridXYZ, h.Levels, trX, trY)

	// ps is a palette scaling factor to scale the palette uniformly
	// across the given levels. This enables a discordance between the
	// number of colours and the number of levels. Sorting is not
	// necessary since contourPaths sorts the levels as a side effect.
	ps := float64(len(pal)-1) / (h.Levels[len(h.Levels)-1] - h.Levels[0])
	if len(h.Levels) == 1 {
		ps = 0
	}

	for i, z := range h.Levels {
		if math.IsNaN(z) {
			continue
		}
		for _, pa := range cp[z] {
			if isLoop(pa) {
				pa.Close()
			}

			style := h.LineStyles[i%len(h.LineStyles)]
			var col color.Color
			switch {
			case z < h.Min:
				col = h.Underflow
			case z > h.Max:
				col = h.Overflow
			case len(pal) == 0:
				col = style.Color
			default:
				col = pal[int((z-h.Levels[0])*ps+0.5)] // Apply palette scaling.
			}
			if col != nil && style.Width != 0 {
				c.SetLineStyle(style)
				c.SetColor(col)
				c.Stroke(pa)
			}
		}
	}
}
Beispiel #18
0
// draw draws the legend to the given draw.Canvas.
func (l *Legend) draw(c draw.Canvas) {
	iconx := c.Min.X
	textx := iconx + l.ThumbnailWidth + l.TextStyle.Width(" ")
	xalign := 0.0
	if !l.Left {
		iconx = c.Max.X - l.ThumbnailWidth
		textx = iconx - l.TextStyle.Width(" ")
		xalign = -1
	}
	textx += l.XOffs
	iconx += l.XOffs

	enth := l.entryHeight()
	y := c.Max.Y - enth
	if !l.Top {
		y = c.Min.Y + (enth+l.Padding)*(vg.Length(len(l.entries))-1)
	}
	y += l.YOffs

	icon := &draw.Canvas{
		Canvas: c.Canvas,
		Rectangle: draw.Rectangle{
			Min: draw.Point{iconx, y},
			Max: draw.Point{iconx + l.ThumbnailWidth, y + enth},
		},
	}
	for _, e := range l.entries {
		for _, t := range e.thumbs {
			t.Thumbnail(icon)
		}
		yoffs := (enth - l.TextStyle.Height(e.text)) / 2
		c.FillText(l.TextStyle, textx, icon.Min.Y+yoffs, xalign, 0, e.text)
		icon.Min.Y -= enth + l.Padding
		icon.Max.Y -= enth + l.Padding
	}
}
Beispiel #19
0
// Plot implements the Plotter interface, drawing a line
// that connects each point in the Line.
func (h *Histogram) Plot(c draw.Canvas, p *plot.Plot) {
	trX, trY := p.Transforms(&c)

	for _, bin := range h.Bins {
		pts := []draw.Point{
			{trX(bin.Min), trY(0)},
			{trX(bin.Max), trY(0)},
			{trX(bin.Max), trY(bin.Weight)},
			{trX(bin.Min), trY(bin.Weight)},
		}
		if h.FillColor != nil {
			c.FillPolygon(h.FillColor, c.ClipPolygonXY(pts))
		}
		pts = append(pts, draw.Point{trX(bin.Min), trY(0)})
		c.StrokeLines(h.LineStyle, c.ClipLinesXY(pts)...)
	}
}
Beispiel #20
0
// Thumbnail the thumbnail for the Line,
// implementing the plot.Thumbnailer interface.
func (pts *Line) Thumbnail(c *draw.Canvas) {
	if pts.ShadeColor != nil {
		points := []draw.Point{
			{c.Min.X, c.Min.Y},
			{c.Min.X, c.Max.Y},
			{c.Max.X, c.Max.Y},
			{c.Max.X, c.Min.Y},
		}
		poly := c.ClipPolygonY(points)
		c.FillPolygon(*pts.ShadeColor, poly)

		points = append(points, draw.Point{c.Min.X, c.Min.Y})
	} else {
		y := c.Center().Y
		c.StrokeLine2(pts.LineStyle, c.Min.X, y, c.Max.X, y)
	}
}
Beispiel #21
0
// Thumbnail draws a rectangle in the given style of the histogram.
func (h *Histogram) Thumbnail(c *draw.Canvas) {
	ymin := c.Min.Y
	ymax := c.Max.Y
	xmin := c.Min.X
	xmax := c.Max.X

	pts := []draw.Point{
		{xmin, ymin},
		{xmax, ymin},
		{xmax, ymax},
		{xmin, ymax},
	}
	if h.FillColor != nil {
		c.FillPolygon(h.FillColor, c.ClipPolygonXY(pts))
	}
	pts = append(pts, draw.Point{xmin, ymin})
	c.StrokeLines(h.LineStyle, c.ClipLinesXY(pts)...)
}
Beispiel #22
0
func (g GlyphBoxes) Plot(c draw.Canvas, plt *plot.Plot) {
	for _, b := range plt.GlyphBoxes(plt) {
		x := c.X(b.X) + b.Rectangle.Min.X
		y := c.Y(b.Y) + b.Rectangle.Min.Y
		c.StrokeLines(g.LineStyle, []draw.Point{
			{x, y},
			{x + b.Rectangle.Size().X, y},
			{x + b.Rectangle.Size().X, y + b.Rectangle.Size().Y},
			{x, y + b.Rectangle.Size().Y},
			{x, y},
		})
	}
}
Beispiel #23
0
// Plot draws the Line, implementing the plot.Plotter
// interface.
func (pts *Line) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	ps := make([]draw.Point, len(pts.XYs))

	for i, p := range pts.XYs {
		ps[i].X = trX(p.X)
		ps[i].Y = trY(p.Y)
	}

	if pts.ShadeColor != nil && len(ps) > 0 {
		c.SetColor(*pts.ShadeColor)
		minY := trY(plt.Y.Min)
		var pa vg.Path
		pa.Move(ps[0].X, minY)
		for i := range pts.XYs {
			pa.Line(ps[i].X, ps[i].Y)
		}
		pa.Line(ps[len(pts.XYs)-1].X, minY)
		pa.Close()
		c.Fill(pa)
	}

	c.StrokeLines(pts.LineStyle, c.ClipLinesXY(ps)...)
}
Beispiel #24
0
func (b *QuartPlot) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	x := trX(b.Location)
	if !c.ContainsX(x) {
		return
	}
	x += b.Offset

	med := draw.Point{x, trY(b.Median)}
	q1 := trY(b.Quartile1)
	q3 := trY(b.Quartile3)
	aLow := trY(b.AdjLow)
	aHigh := trY(b.AdjHigh)

	c.StrokeLine2(b.WhiskerStyle, x, aHigh, x, q3)
	if c.ContainsY(med.Y) {
		c.DrawGlyphNoClip(b.MedianStyle, med)
	}
	c.StrokeLine2(b.WhiskerStyle, x, aLow, x, q1)

	ostyle := b.MedianStyle
	ostyle.Radius = b.MedianStyle.Radius / 2
	for _, out := range b.Outside {
		y := trY(b.Value(out))
		if c.ContainsY(y) {
			c.DrawGlyphNoClip(ostyle, draw.Point{x, y})
		}
	}
}
Beispiel #25
0
// Plot implements the plot.Plotter interface.
func (b *BarChart) Plot(c draw.Canvas, plt *plot.Plot) {
	trCat, trVal := plt.Transforms(&c)
	if b.Horizontal {
		trCat, trVal = trVal, trCat
	}

	for i, ht := range b.Values {
		catVal := b.XMin + float64(i)
		catMin := trCat(float64(catVal))
		if !b.Horizontal {
			if !c.ContainsX(catMin) {
				continue
			}
		} else {
			if !c.ContainsY(catMin) {
				continue
			}
		}
		catMin = catMin - b.Width/2 + b.Offset
		catMax := catMin + b.Width
		bottom := b.stackedOn.BarHeight(i)
		valMin := trVal(bottom)
		valMax := trVal(bottom + ht)

		var pts []draw.Point
		var poly []draw.Point
		if !b.Horizontal {
			pts = []draw.Point{
				{catMin, valMin},
				{catMin, valMax},
				{catMax, valMax},
				{catMax, valMin},
			}
			poly = c.ClipPolygonY(pts)
		} else {
			pts = []draw.Point{
				{valMin, catMin},
				{valMin, catMax},
				{valMax, catMax},
				{valMax, catMin},
			}
			poly = c.ClipPolygonX(pts)
		}
		c.FillPolygon(b.Color, poly)

		var outline [][]draw.Point
		if !b.Horizontal {
			pts = append(pts, draw.Point{X: catMin, Y: valMin})
			outline = c.ClipLinesY(pts)
		} else {
			pts = append(pts, draw.Point{X: valMin, Y: catMin})
			outline = c.ClipLinesX(pts)
		}
		c.StrokeLines(b.LineStyle, outline...)
	}
}
Beispiel #26
0
// naivePlot implements the a naive rendering approach for contours.
// It is here as a debugging mode since it simply draws line segments
// generated by conrec without further computation.
func (h *Contour) naivePlot(c draw.Canvas, plt *plot.Plot) {
	var pal []color.Color
	if h.Palette != nil {
		pal = h.Palette.Colors()
	}

	trX, trY := plt.Transforms(&c)

	// Sort levels prior to palette scaling since we can't depend on
	// sorting as a side effect from calling contourPaths.
	sort.Float64s(h.Levels)
	// ps is a palette scaling factor to scale the palette uniformly
	// across the given levels. This enables a discordance between the
	// number of colours and the number of levels.
	ps := float64(len(pal)-1) / (h.Levels[len(h.Levels)-1] - h.Levels[0])
	if len(h.Levels) == 1 {
		ps = 0
	}

	levelMap := make(map[float64]int)
	for i, z := range h.Levels {
		levelMap[z] = i
	}

	// Draw each line segment as conrec generates it.
	var pa vg.Path
	conrec(h.GridXYZ, h.Levels, func(_, _ int, l line, z float64) {
		if math.IsNaN(z) {
			return
		}

		pa = pa[:0]

		x1, y1 := trX(l.p1.X), trY(l.p1.Y)
		x2, y2 := trX(l.p2.X), trY(l.p2.Y)

		if !c.Contains(draw.Point{x1, y1}) || !c.Contains(draw.Point{x2, y2}) {
			return
		}

		pa.Move(x1, y1)
		pa.Line(x2, y2)
		pa.Close()

		style := h.LineStyles[levelMap[z]%len(h.LineStyles)]
		var col color.Color
		switch {
		case z < h.Min:
			col = h.Underflow
		case z > h.Max:
			col = h.Overflow
		case len(pal) == 0:
			col = style.Color
		default:
			col = pal[int((z-h.Levels[0])*ps+0.5)] // Apply palette scaling.
		}
		if col != nil && style.Width != 0 {
			c.SetLineStyle(style)
			c.SetColor(col)
			c.Stroke(pa)
		}
	})
}
Beispiel #27
0
// draw draws the axis along the left side of a draw.Canvas.
func (a *verticalAxis) draw(c draw.Canvas) {
	x := c.Min.X
	if a.Label.Text != "" {
		x += a.Label.Height(a.Label.Text)
		c.Push()
		c.Rotate(math.Pi / 2)
		c.FillText(a.Label.TextStyle, c.Center().Y, -x, -0.5, 0, a.Label.Text)
		c.Pop()
		x += -a.Label.Font.Extents().Descent
	}
	marks := a.Tick.Marker.Ticks(a.Min, a.Max)
	if w := tickLabelWidth(a.Tick.Label, marks); len(marks) > 0 && w > 0 {
		x += w
	}
	major := false
	for _, t := range marks {
		y := c.Y(a.Norm(t.Value))
		if !c.ContainsY(y) || t.IsMinor() {
			continue
		}
		c.FillText(a.Tick.Label, x, y, -1, -0.5, t.Label)
		major = true
	}
	if major {
		x += a.Tick.Label.Width(" ")
	}
	if a.drawTicks() && len(marks) > 0 {
		len := a.Tick.Length
		for _, t := range marks {
			y := c.Y(a.Norm(t.Value))
			if !c.ContainsY(y) {
				continue
			}
			start := t.lengthOffset(len)
			c.StrokeLine2(a.Tick.LineStyle, x+start, y, x+len, y)
		}
		x += len
	}
	c.StrokeLine2(a.LineStyle, x, c.Min.Y, x, c.Max.Y)
}
Beispiel #28
0
// Plot draws the Scatter, implementing the plot.Plotter
// interface.
func (pts *Scatter) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	for _, p := range pts.XYs {
		c.DrawGlyph(pts.GlyphStyle, draw.Point{trX(p.X), trY(p.Y)})
	}
}
Beispiel #29
0
// Thumbnail the thumbnail for the Scatter,
// implementing the plot.Thumbnailer interface.
func (pts *Scatter) Thumbnail(c *draw.Canvas) {
	c.DrawGlyph(pts.GlyphStyle, c.Center())
}
Beispiel #30
0
// draw draws the axis along the lower edge of a draw.Canvas.
func (a *horizontalAxis) draw(c draw.Canvas) {
	y := c.Min.Y
	if a.Label.Text != "" {
		y -= a.Label.Font.Extents().Descent
		c.FillText(a.Label.TextStyle, c.Center().X, y, -0.5, 0, a.Label.Text)
		y += a.Label.Height(a.Label.Text)
	}

	marks := a.Tick.Marker.Ticks(a.Min, a.Max)
	for _, t := range marks {
		x := c.X(a.Norm(t.Value))
		if !c.ContainsX(x) || t.IsMinor() {
			continue
		}
		c.FillText(a.Tick.Label, x, y, -0.5, 0, t.Label)
	}

	if len(marks) > 0 {
		y += tickLabelHeight(a.Tick.Label, marks)
	} else {
		y += a.Width / 2
	}

	if len(marks) > 0 && a.drawTicks() {
		len := a.Tick.Length
		for _, t := range marks {
			x := c.X(a.Norm(t.Value))
			if !c.ContainsX(x) {
				continue
			}
			start := t.lengthOffset(len)
			c.StrokeLine2(a.Tick.LineStyle, x, y+start, x, y+len)
		}
		y += len
	}

	c.StrokeLine2(a.LineStyle, c.Min.X, y, c.Max.X, y)
}