go-hep.org/x/hep@v0.38.1/hplot/ticks.go (about)

     1  // Copyright ©2016 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 hplot
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strconv"
    11  
    12  	"go-hep.org/x/hep/hplot/internal/talbot"
    13  	"gonum.org/v1/gonum/floats/scalar"
    14  	"gonum.org/v1/plot"
    15  )
    16  
    17  const (
    18  	// displayPrecision is a sane level of float precision for a plot.
    19  	displayPrecision = 4
    20  )
    21  
    22  // FreqTicks implements a simple plot.Ticker scheme.
    23  // FreqTicks will generate N ticks where 1 every Freq tick will be labeled.
    24  type FreqTicks struct {
    25  	N    int // number of ticks
    26  	Freq int // frequency of labeled ticks
    27  }
    28  
    29  // Ticks returns Ticks in a specified range
    30  func (ft FreqTicks) Ticks(min, max float64) []plot.Tick {
    31  	prec := maxInt(precisionOf(min), precisionOf(max))
    32  	ticks := make([]plot.Tick, ft.N)
    33  	for i := range ticks {
    34  		v := min + float64(i)*(max-min)/float64(len(ticks)-1)
    35  		label := ""
    36  		if i%ft.Freq == 0 {
    37  			label = formatFloatTick(v, prec)
    38  		}
    39  		ticks[i] = plot.Tick{Value: v, Label: label}
    40  	}
    41  	return ticks
    42  }
    43  
    44  // formatFloatTick returns a g-formated string representation of v
    45  // to the specified precision.
    46  func formatFloatTick(v float64, prec int) string {
    47  	return strconv.FormatFloat(scalar.Round(v, prec), 'g', displayPrecision, 64)
    48  }
    49  
    50  // precisionOf returns the precision needed to display x without e notation.
    51  func precisionOf(x float64) int {
    52  	return int(math.Max(math.Ceil(-math.Log10(math.Abs(x))), displayPrecision))
    53  }
    54  
    55  func maxInt(a, b int) int {
    56  	if a > b {
    57  		return a
    58  	}
    59  	return b
    60  }
    61  
    62  // NoTicks implements plot.Ticker but does not display any tick.
    63  type NoTicks struct{}
    64  
    65  // Ticks returns Ticks in a specified range
    66  func (NoTicks) Ticks(min, max float64) []plot.Tick {
    67  	return nil
    68  }
    69  
    70  // Ticks implements plot.Ticker.
    71  // Ticks allows to specify the maximum number of major ticks to display.
    72  // The zero value of Ticks display a maximum number of 3 major ticks.
    73  type Ticks struct {
    74  	N int // N is the suggested number of major ticks to display.
    75  
    76  	// Format is an optional major-tick formatter.
    77  	// If empty, a format will be automatically chosen.
    78  	Format string
    79  }
    80  
    81  func (tck Ticks) Ticks(min, max float64) []plot.Tick {
    82  	if tck.N == 0 {
    83  		tck.N = 3 // same default than plot.DefaultTicks
    84  	}
    85  
    86  	ticks := talbot.Ticks(min, max, tck.N)
    87  	if xfmt := tck.Format; xfmt != "" {
    88  		for i, tck := range ticks {
    89  			if tck.IsMinor() {
    90  				continue
    91  			}
    92  			ticks[i].Label = fmt.Sprintf(xfmt, tck.Value)
    93  		}
    94  	}
    95  	return ticks
    96  }