Example #1
0
File: plot.go Project: zzn01/plot
// 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())
	}
}
Example #2
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)
			}
		}
	}
}
Example #3
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)
		}
	})
}