Skip to content

Commit

Permalink
plotter: add colour magnitude vector field example
Browse files Browse the repository at this point in the history
Also fix API bug found from this and delete dead code.
  • Loading branch information
kortschak committed Apr 6, 2019
1 parent f2023ba commit 70be1cd
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 10 deletions.
12 changes: 9 additions & 3 deletions plotter/field.go
Expand Up @@ -127,9 +127,15 @@ func (f *Field) Plot(c draw.Canvas, plt *plot.Plot) {
v := f.FieldXY.Vector(i, j)
c.Rotate(math.Atan2(v.Y, v.X))
s := math.Hypot(v.X, v.Y) / (2 * f.max)
v.X *= s
v.Y *= s
c.Scale(s*float64(dx-x), s*float64(dy-y))
v.X /= f.max
v.Y /= f.max

// Do not scale when the vector is zero, otherwise the
// user cannot render special-case glyphs for that case.
if s != 0 {
c.Scale(s*float64(dx-x), s*float64(dy-y))
}

if f.DrawGlyph == nil {
drawVector(c, v)
} else {
Expand Down
87 changes: 80 additions & 7 deletions plotter/field_test.go
Expand Up @@ -5,13 +5,16 @@
package plotter_test

import (
"image/color"
"image/png"
"log"
"math"
"os"
"testing"

"gonum.org/v1/plot"
"gonum.org/v1/plot/cmpimg"
"gonum.org/v1/plot/palette/moreland"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
Expand Down Expand Up @@ -79,6 +82,78 @@ func TestField(t *testing.T) {
cmpimg.CheckPlot(ExampleField, t, "field.png")
}

func ExampleField_colors() {
f := plotter.NewField(field{
r: 5, c: 9,
fn: func(x, y float64) plotter.XY {
return plotter.XY{
X: -0.75*x + y,
Y: -0.75*y - x,
}
},
})

pal := moreland.ExtendedBlackBody()
pal.SetMin(0)
pal.SetMax(1.1) // Use 1.1 to make highest magnitude vectors visible on white.

// Provide a DrawGlyph function to render a custom
// vector instead of the default monochrome arrow.
f.DrawGlyph = func(c vg.Canvas, v plotter.XY) {
c.Push()
defer c.Pop()
mag := math.Hypot(v.X, v.Y)
var pa vg.Path
if mag == 0 {
// Draw a black dot for zero vectors.
c.SetColor(color.Black)
pa.Move(vg.Point{X: f.LineStyle.Width})
pa.Arc(vg.Point{}, f.LineStyle.Width, 0, 2*math.Pi)
pa.Close()
c.Fill(pa)
return
}
// Choose a color from the palette for the magnitude.
col, err := pal.At(mag)
if err != nil {
panic(err)
}
c.SetColor(col)
pa.Move(vg.Point{})
pa.Line(vg.Point{X: 1, Y: 0})
pa.Close()
c.Stroke(pa)
}

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

p.X.Tick.Marker = integerTicks{}
p.Y.Tick.Marker = integerTicks{}

p.Add(f)

img := vgimg.New(250, 175)
dc := draw.New(img)

p.Draw(dc)
w, err := os.Create("testdata/color_field.png")
if err != nil {
log.Panic(err)
}
png := vgimg.PngCanvas{Canvas: img}
if _, err = png.WriteTo(w); err != nil {
log.Panic(err)
}
}

func TestFieldColors(t *testing.T) {
cmpimg.CheckPlot(ExampleField_colors, t, "color_field.png")
}

func ExampleField_gophers() {
file, err := os.Open("testdata/gopher_running.png")
if err != nil {
Expand All @@ -103,6 +178,11 @@ func ExampleField_gophers() {
// Provide a DrawGlyph function to render a custom
// vector glyph instead of the default arrow.
f.DrawGlyph = func(c vg.Canvas, v plotter.XY) {
// The canvas is unscaled if the vector has a zero
// magnitude, so return in that case.
if math.Hypot(v.X, v.Y) == 0 {
return
}
// Vector glyphs are scaled to half unit length by the
// plotter, so scale the gopher to twice unit size so
// it fits the cell, and center on the cell.
Expand Down Expand Up @@ -135,13 +215,6 @@ func ExampleField_gophers() {
}
}

func max(a, b int) int {
if a > b {
return a
}
return b
}

func TestFieldGophers(t *testing.T) {
cmpimg.CheckPlot(ExampleField_gophers, t, "gopher_field.png")
}
Binary file added plotter/testdata/color_field_golden.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 70be1cd

Please sign in to comment.