go-hep.org/x/hep@v0.38.1/hplot/functions.go (about) 1 // Copyright ©2019 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Copyright ©2015 The Gonum Authors. All rights reserved. 6 // Use of this source code is governed by a BSD-style 7 // license that can be found in the LICENSE file. 8 9 package hplot 10 11 import ( 12 "math" 13 14 "gonum.org/v1/plot" 15 "gonum.org/v1/plot/plotter" 16 "gonum.org/v1/plot/vg" 17 "gonum.org/v1/plot/vg/draw" 18 ) 19 20 // Function implements the Plotter interface, 21 // drawing a line for the given function. 22 type Function struct { 23 F func(x float64) (y float64) 24 25 // XMin and XMax specify the range 26 // of x values to pass to F. 27 XMin, XMax float64 28 29 Samples int 30 31 draw.LineStyle 32 33 // LogY allows rendering with a log-scaled Y axis. 34 // When enabled, function values returning 0 will be discarded from 35 // the final plot. 36 LogY bool 37 } 38 39 // NewFunction returns a Function that plots F using 40 // the default line style with 50 samples. 41 func NewFunction(f func(float64) float64) *Function { 42 return &Function{ 43 F: f, 44 Samples: 50, 45 LineStyle: plotter.DefaultLineStyle, 46 } 47 } 48 49 // Plot implements the Plotter interface, drawing a line 50 // that connects each point in the Line. 51 func (f *Function) Plot(c draw.Canvas, p *plot.Plot) { 52 trX, trY := p.Transforms(&c) 53 54 min, max := f.XMin, f.XMax 55 if min == 0 && max == 0 { 56 min = p.X.Min 57 max = p.X.Max 58 } 59 d := (max - min) / float64(f.Samples-1) 60 switch { 61 case f.LogY: 62 var ( 63 line = 0 64 lines = [][]vg.Point{make([]vg.Point, 0, f.Samples)} 65 ) 66 for i := range f.Samples { 67 x := min + float64(i)*d 68 y := f.F(x) 69 switch { 70 case math.IsInf(y, -1) || y <= 0: 71 line++ 72 lines = append(lines, make([]vg.Point, 0, f.Samples-i)) 73 default: 74 lines[line] = append(lines[line], vg.Point{ 75 X: trX(x), 76 Y: trY(y), 77 }) 78 } 79 } 80 for _, line := range lines { 81 if len(line) <= 1 { 82 // FIXME(sbinet): we should find a couple of points around... 83 continue 84 } 85 c.StrokeLines(f.LineStyle, c.ClipLinesXY(line)...) 86 } 87 default: 88 line := make([]vg.Point, f.Samples) 89 for i := range line { 90 x := min + float64(i)*d 91 y := f.F(x) 92 line[i].X = trX(x) 93 line[i].Y = trY(y) 94 } 95 c.StrokeLines(f.LineStyle, c.ClipLinesXY(line)...) 96 } 97 } 98 99 // Thumbnail draws a line in the given style down the 100 // center of a DrawArea as a thumbnail representation 101 // of the LineStyle of the function. 102 func (f Function) Thumbnail(c *draw.Canvas) { 103 y := c.Center().Y 104 c.StrokeLine2(f.LineStyle, c.Min.X, y, c.Max.X, y) 105 }