go-hep.org/x/hep@v0.38.1/hplot/internal/talbot/ticks.go (about) 1 // Copyright ©2020 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 package talbot 6 7 import ( 8 "math" 9 "strconv" 10 11 "gonum.org/v1/gonum/floats/scalar" 12 "gonum.org/v1/plot" 13 ) 14 15 // Ticks returns Ticks in the specified range. 16 func Ticks(min, max float64, n int) []plot.Tick { 17 if max <= min { 18 panic("illegal range") 19 } 20 21 suggestedTicks := n 22 23 labels, step, q, mag := talbotLinHanrahan(min, max, suggestedTicks, withinData, nil, nil, nil) 24 majorDelta := step * math.Pow10(mag) 25 if q == 0 { 26 // Simple fall back was chosen, so 27 // majorDelta is the label distance. 28 majorDelta = labels[1] - labels[0] 29 } 30 31 // Choose a reasonable, but ad 32 // hoc formatting for labels. 33 fc := byte('f') 34 var off int 35 if mag < -1 || 6 < mag { 36 off = 1 37 fc = 'g' 38 } 39 if math.Trunc(q) != q { 40 off += 2 41 } 42 prec := minInt(6, maxInt(off, -mag)) 43 var ticks []plot.Tick 44 for _, v := range labels { 45 ticks = append(ticks, plot.Tick{Value: v, Label: strconv.FormatFloat(v, fc, prec, 64)}) 46 } 47 lastMajor := ticks[len(ticks)-1] 48 49 var minorDelta float64 50 // See talbotLinHanrahan for the values used here. 51 switch step { 52 case 1, 2.5: 53 minorDelta = majorDelta / 5 54 case 2, 3, 4, 5: 55 minorDelta = majorDelta / step 56 default: 57 if majorDelta/2 < dlamchP { 58 return ticks 59 } 60 minorDelta = majorDelta / 2 61 } 62 63 // Find the first minor tick not greater 64 // than the lowest data value. 65 var i float64 66 for labels[0]+(i-1)*minorDelta > min { 67 i-- 68 } 69 // Add ticks at minorDelta intervals when 70 // they are not within minorDelta/2 of a 71 // labelled tick. 72 for { 73 val := labels[0] + i*minorDelta 74 if val > max { 75 break 76 } 77 found := false 78 for _, t := range ticks { 79 if math.Abs(t.Value-val) < minorDelta/2 { 80 found = true 81 } 82 } 83 if !found { 84 ticks = append(ticks, plot.Tick{Value: val}) 85 } 86 i++ 87 } 88 89 if last := &ticks[len(ticks)-1]; last.IsMinor() { 90 // check if we could elect it to "major" 91 delta := last.Value - lastMajor.Value 92 elect := scalar.EqualWithinAbs(delta, majorDelta, 1e-15) 93 if elect { 94 last.Label = strconv.FormatFloat(last.Value, fc, prec, 64) 95 } 96 } 97 98 return ticks 99 } 100 101 func minInt(a, b int) int { 102 if a < b { 103 return a 104 } 105 return b 106 } 107 108 func maxInt(a, b int) int { 109 if a > b { 110 return a 111 } 112 return b 113 }