269 lines
6.0 KiB
Go
269 lines
6.0 KiB
Go
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
// Package plotter defines a variety of standard Plotters for the
|
||
// plot package.
|
||
//
|
||
// Plotters use the primitives provided by the plot package to draw to
|
||
// the data area of a plot. This package provides some standard data
|
||
// styles such as lines, scatter plots, box plots, labels, and more.
|
||
//
|
||
// New* functions return an error if the data contains Inf, NaN, or is
|
||
// empty. Some of the New* functions return other plotter-specific errors
|
||
// too.
|
||
package plotter // import "gonum.org/v1/plot/plotter"
|
||
|
||
import (
|
||
"errors"
|
||
"image/color"
|
||
"math"
|
||
|
||
"gonum.org/v1/plot/vg"
|
||
"gonum.org/v1/plot/vg/draw"
|
||
)
|
||
|
||
var (
|
||
// DefaultLineStyle is the default style for drawing
|
||
// lines.
|
||
DefaultLineStyle = draw.LineStyle{
|
||
Color: color.Black,
|
||
Width: vg.Points(1),
|
||
Dashes: []vg.Length{},
|
||
DashOffs: 0,
|
||
}
|
||
|
||
// DefaultGlyphStyle is the default style used
|
||
// for gyph marks.
|
||
DefaultGlyphStyle = draw.GlyphStyle{
|
||
Color: color.Black,
|
||
Radius: vg.Points(2.5),
|
||
Shape: draw.RingGlyph{},
|
||
}
|
||
)
|
||
|
||
// Valuer wraps the Len and Value methods.
|
||
type Valuer interface {
|
||
// Len returns the number of values.
|
||
Len() int
|
||
|
||
// Value returns a value.
|
||
Value(int) float64
|
||
}
|
||
|
||
// Range returns the minimum and maximum values.
|
||
func Range(vs Valuer) (min, max float64) {
|
||
min = math.Inf(1)
|
||
max = math.Inf(-1)
|
||
for i := 0; i < vs.Len(); i++ {
|
||
v := vs.Value(i)
|
||
min = math.Min(min, v)
|
||
max = math.Max(max, v)
|
||
}
|
||
return
|
||
}
|
||
|
||
// Values implements the Valuer interface.
|
||
type Values []float64
|
||
|
||
var (
|
||
ErrInfinity = errors.New("plotter: infinite data point")
|
||
ErrNaN = errors.New("plotter: NaN data point")
|
||
ErrNoData = errors.New("plotter: no data points")
|
||
)
|
||
|
||
// CheckFloats returns an error if any of the arguments are NaN or Infinity.
|
||
func CheckFloats(fs ...float64) error {
|
||
for _, f := range fs {
|
||
switch {
|
||
case math.IsNaN(f):
|
||
return ErrNaN
|
||
case math.IsInf(f, 0):
|
||
return ErrInfinity
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CopyValues returns a Values that is a copy of the values
|
||
// from a Valuer, or an error if there are no values, or if one of
|
||
// the copied values is a NaN or Infinity.
|
||
func CopyValues(vs Valuer) (Values, error) {
|
||
if vs.Len() == 0 {
|
||
return nil, ErrNoData
|
||
}
|
||
cpy := make(Values, vs.Len())
|
||
for i := 0; i < vs.Len(); i++ {
|
||
cpy[i] = vs.Value(i)
|
||
if err := CheckFloats(cpy[i]); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return cpy, nil
|
||
}
|
||
|
||
func (vs Values) Len() int {
|
||
return len(vs)
|
||
}
|
||
|
||
func (vs Values) Value(i int) float64 {
|
||
return vs[i]
|
||
}
|
||
|
||
// XYer wraps the Len and XY methods.
|
||
type XYer interface {
|
||
// Len returns the number of x, y pairs.
|
||
Len() int
|
||
|
||
// XY returns an x, y pair.
|
||
XY(int) (x, y float64)
|
||
}
|
||
|
||
// XYRange returns the minimum and maximum
|
||
// x and y values.
|
||
func XYRange(xys XYer) (xmin, xmax, ymin, ymax float64) {
|
||
xmin, xmax = Range(XValues{xys})
|
||
ymin, ymax = Range(YValues{xys})
|
||
return
|
||
}
|
||
|
||
// XYs implements the XYer interface.
|
||
type XYs []XY
|
||
|
||
// XY is an x and y value.
|
||
type XY struct{ X, Y float64 }
|
||
|
||
// CopyXYs returns an XYs that is a copy of the x and y values from
|
||
// an XYer, or an error if one of the data points contains a NaN or
|
||
// Infinity.
|
||
func CopyXYs(data XYer) (XYs, error) {
|
||
cpy := make(XYs, data.Len())
|
||
for i := range cpy {
|
||
cpy[i].X, cpy[i].Y = data.XY(i)
|
||
if err := CheckFloats(cpy[i].X, cpy[i].Y); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return cpy, nil
|
||
}
|
||
|
||
func (xys XYs) Len() int {
|
||
return len(xys)
|
||
}
|
||
|
||
func (xys XYs) XY(i int) (float64, float64) {
|
||
return xys[i].X, xys[i].Y
|
||
}
|
||
|
||
// XValues implements the Valuer interface,
|
||
// returning the x value from an XYer.
|
||
type XValues struct {
|
||
XYer
|
||
}
|
||
|
||
func (xs XValues) Value(i int) float64 {
|
||
x, _ := xs.XY(i)
|
||
return x
|
||
}
|
||
|
||
// YValues implements the Valuer interface,
|
||
// returning the y value from an XYer.
|
||
type YValues struct {
|
||
XYer
|
||
}
|
||
|
||
func (ys YValues) Value(i int) float64 {
|
||
_, y := ys.XY(i)
|
||
return y
|
||
}
|
||
|
||
// XYZer wraps the Len and XYZ methods.
|
||
type XYZer interface {
|
||
// Len returns the number of x, y, z triples.
|
||
Len() int
|
||
|
||
// XYZ returns an x, y, z triple.
|
||
XYZ(int) (float64, float64, float64)
|
||
|
||
// XY returns an x, y pair.
|
||
XY(int) (float64, float64)
|
||
}
|
||
|
||
// XYZs implements the XYZer interface using a slice.
|
||
type XYZs []XYZ
|
||
|
||
// XYZ is an x, y and z value.
|
||
type XYZ struct{ X, Y, Z float64 }
|
||
|
||
// Len implements the Len method of the XYZer interface.
|
||
func (xyz XYZs) Len() int {
|
||
return len(xyz)
|
||
}
|
||
|
||
// XYZ implements the XYZ method of the XYZer interface.
|
||
func (xyz XYZs) XYZ(i int) (float64, float64, float64) {
|
||
return xyz[i].X, xyz[i].Y, xyz[i].Z
|
||
}
|
||
|
||
// XY implements the XY method of the XYer interface.
|
||
func (xyz XYZs) XY(i int) (float64, float64) {
|
||
return xyz[i].X, xyz[i].Y
|
||
}
|
||
|
||
// CopyXYZs copies an XYZer.
|
||
func CopyXYZs(data XYZer) (XYZs, error) {
|
||
cpy := make(XYZs, data.Len())
|
||
for i := range cpy {
|
||
cpy[i].X, cpy[i].Y, cpy[i].Z = data.XYZ(i)
|
||
if err := CheckFloats(cpy[i].X, cpy[i].Y, cpy[i].Z); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return cpy, nil
|
||
}
|
||
|
||
// XYValues implements the XYer interface, returning
|
||
// the x and y values from an XYZer.
|
||
type XYValues struct{ XYZer }
|
||
|
||
// XY implements the XY method of the XYer interface.
|
||
func (xy XYValues) XY(i int) (float64, float64) {
|
||
x, y, _ := xy.XYZ(i)
|
||
return x, y
|
||
}
|
||
|
||
// Labeller wraps the Label methods.
|
||
type Labeller interface {
|
||
// Label returns a label.
|
||
Label(int) string
|
||
}
|
||
|
||
// XErrorer wraps the XError method.
|
||
type XErrorer interface {
|
||
// XError returns two error values for X data.
|
||
XError(int) (float64, float64)
|
||
}
|
||
|
||
// Errors is a slice of low and high error values.
|
||
type Errors []struct{ Low, High float64 }
|
||
|
||
// XErrors implements the XErrorer interface.
|
||
type XErrors Errors
|
||
|
||
func (xe XErrors) XError(i int) (float64, float64) {
|
||
return xe[i].Low, xe[i].High
|
||
}
|
||
|
||
// YErrorer wraps the YError method.
|
||
type YErrorer interface {
|
||
// YError returns two error values for Y data.
|
||
YError(int) (float64, float64)
|
||
}
|
||
|
||
// YErrors implements the YErrorer interface.
|
||
type YErrors Errors
|
||
|
||
func (ye YErrors) YError(i int) (float64, float64) {
|
||
return ye[i].Low, ye[i].High
|
||
}
|