Compare commits
2 commits
main
...
will/go1.1
Author | SHA1 | Date | |
---|---|---|---|
|
f23b63bae4 | ||
|
db4dcecf1f |
41 changed files with 612 additions and 587 deletions
|
@ -60,10 +60,10 @@ func (as AnnotationSeries) Measure(r Renderer, canvasBox Box, xrange, yrange Ran
|
||||||
lx := canvasBox.Left + xrange.Translate(a.XValue)
|
lx := canvasBox.Left + xrange.Translate(a.XValue)
|
||||||
ly := canvasBox.Bottom - yrange.Translate(a.YValue)
|
ly := canvasBox.Bottom - yrange.Translate(a.YValue)
|
||||||
ab := Draw.MeasureAnnotation(r, canvasBox, style, lx, ly, a.Label)
|
ab := Draw.MeasureAnnotation(r, canvasBox, style, lx, ly, a.Label)
|
||||||
box.Top = MinInt(box.Top, ab.Top)
|
box.Top = Min(box.Top, ab.Top)
|
||||||
box.Left = MinInt(box.Left, ab.Left)
|
box.Left = Min(box.Left, ab.Left)
|
||||||
box.Right = MaxInt(box.Right, ab.Right)
|
box.Right = Max(box.Right, ab.Right)
|
||||||
box.Bottom = MaxInt(box.Bottom, ab.Bottom)
|
box.Bottom = Max(box.Bottom, ab.Bottom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return box
|
return box
|
||||||
|
|
12
array.go
12
array.go
|
@ -1,24 +1,24 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Sequence = (*Array)(nil)
|
_ Sequence[int] = (*array[int])(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewArray returns a new array from a given set of values.
|
// NewArray returns a new array from a given set of values.
|
||||||
// Array implements Sequence, which allows it to be used with the sequence helpers.
|
// Array implements Sequence, which allows it to be used with the sequence helpers.
|
||||||
func NewArray(values ...float64) Array {
|
func Array[A any](values ...A) Sequence[A] {
|
||||||
return Array(values)
|
return array[A](values)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array is a wrapper for an array of floats that implements `ValuesProvider`.
|
// Array is a wrapper for an array of floats that implements `ValuesProvider`.
|
||||||
type Array []float64
|
type array[A any] []A
|
||||||
|
|
||||||
// Len returns the value provider length.
|
// Len returns the value provider length.
|
||||||
func (a Array) Len() int {
|
func (a array[A]) Len() int {
|
||||||
return len(a)
|
return len(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue returns the value at a given index.
|
// GetValue returns the value at a given index.
|
||||||
func (a Array) GetValue(index int) float64 {
|
func (a array[A]) GetValue(index int) A {
|
||||||
return a[index]
|
return a[index]
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,7 +409,7 @@ func (bc BarChart) getAdjustedCanvasBox(r Renderer, canvasBox Box, yrange Range,
|
||||||
lines := Text.WrapFit(r, bar.Label, barLabelBox.Width(), axisStyle)
|
lines := Text.WrapFit(r, bar.Label, barLabelBox.Width(), axisStyle)
|
||||||
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
||||||
|
|
||||||
xaxisHeight = MinInt(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
|
xaxisHeight = Min(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +476,7 @@ func (bc BarChart) styleDefaultsTitle() Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc BarChart) getTitleFontSize() float64 {
|
func (bc BarChart) getTitleFontSize() float64 {
|
||||||
effectiveDimension := MinInt(bc.GetWidth(), bc.GetHeight())
|
effectiveDimension := Min(bc.GetWidth(), bc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48
|
return 48
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
|
|
@ -20,7 +20,7 @@ type BollingerBandsSeries struct {
|
||||||
K float64
|
K float64
|
||||||
InnerSeries ValuesProvider
|
InnerSeries ValuesProvider
|
||||||
|
|
||||||
valueBuffer *ValueBuffer
|
valueBuffer *ValueBuffer[float64]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the time series.
|
// GetName returns the name of the time series.
|
||||||
|
@ -70,7 +70,7 @@ func (bbs *BollingerBandsSeries) GetBoundedValues(index int) (x, y1, y2 float64)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if bbs.valueBuffer == nil || index == 0 {
|
if bbs.valueBuffer == nil || index == 0 {
|
||||||
bbs.valueBuffer = NewValueBufferWithCapacity(bbs.GetPeriod())
|
bbs.valueBuffer = NewValueBufferWithCapacity[float64](bbs.GetPeriod())
|
||||||
}
|
}
|
||||||
if bbs.valueBuffer.Len() >= bbs.GetPeriod() {
|
if bbs.valueBuffer.Len() >= bbs.GetPeriod() {
|
||||||
bbs.valueBuffer.Dequeue()
|
bbs.valueBuffer.Dequeue()
|
||||||
|
@ -79,8 +79,8 @@ func (bbs *BollingerBandsSeries) GetBoundedValues(index int) (x, y1, y2 float64)
|
||||||
bbs.valueBuffer.Enqueue(py)
|
bbs.valueBuffer.Enqueue(py)
|
||||||
x = px
|
x = px
|
||||||
|
|
||||||
ay := Seq{bbs.valueBuffer}.Average()
|
ay := Seq[float64]{bbs.valueBuffer}.Average()
|
||||||
std := Seq{bbs.valueBuffer}.StdDev()
|
std := Seq[float64]{bbs.valueBuffer}.StdDev()
|
||||||
|
|
||||||
y1 = ay + (bbs.GetK() * std)
|
y1 = ay + (bbs.GetK() * std)
|
||||||
y2 = ay - (bbs.GetK() * std)
|
y2 = ay - (bbs.GetK() * std)
|
||||||
|
@ -99,15 +99,15 @@ func (bbs *BollingerBandsSeries) GetBoundedLastValues() (x, y1, y2 float64) {
|
||||||
startAt = 0
|
startAt = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
vb := NewValueBufferWithCapacity(period)
|
vb := NewValueBufferWithCapacity[float64](period)
|
||||||
for index := startAt; index < seriesLength; index++ {
|
for index := startAt; index < seriesLength; index++ {
|
||||||
xn, yn := bbs.InnerSeries.GetValues(index)
|
xn, yn := bbs.InnerSeries.GetValues(index)
|
||||||
vb.Enqueue(yn)
|
vb.Enqueue(yn)
|
||||||
x = xn
|
x = xn
|
||||||
}
|
}
|
||||||
|
|
||||||
ay := Seq{vb}.Average()
|
ay := Seq[float64]{vb}.Average()
|
||||||
std := Seq{vb}.StdDev()
|
std := Seq[float64]{vb}.StdDev()
|
||||||
|
|
||||||
y1 = ay + (bbs.GetK() * std)
|
y1 = ay + (bbs.GetK() * std)
|
||||||
y2 = ay - (bbs.GetK() * std)
|
y2 = ay - (bbs.GetK() * std)
|
||||||
|
|
44
box.go
44
box.go
|
@ -89,12 +89,12 @@ func (b Box) GetBottom(defaults ...int) int {
|
||||||
|
|
||||||
// Width returns the width
|
// Width returns the width
|
||||||
func (b Box) Width() int {
|
func (b Box) Width() int {
|
||||||
return AbsInt(b.Right - b.Left)
|
return Abs(b.Right - b.Left)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height returns the height
|
// Height returns the height
|
||||||
func (b Box) Height() int {
|
func (b Box) Height() int {
|
||||||
return AbsInt(b.Bottom - b.Top)
|
return Abs(b.Bottom - b.Top)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center returns the center of the box
|
// Center returns the center of the box
|
||||||
|
@ -146,10 +146,10 @@ func (b Box) Equals(other Box) bool {
|
||||||
// Grow grows a box based on another box.
|
// Grow grows a box based on another box.
|
||||||
func (b Box) Grow(other Box) Box {
|
func (b Box) Grow(other Box) Box {
|
||||||
return Box{
|
return Box{
|
||||||
Top: MinInt(b.Top, other.Top),
|
Top: Min(b.Top, other.Top),
|
||||||
Left: MinInt(b.Left, other.Left),
|
Left: Min(b.Left, other.Left),
|
||||||
Right: MaxInt(b.Right, other.Right),
|
Right: Max(b.Right, other.Right),
|
||||||
Bottom: MaxInt(b.Bottom, other.Bottom),
|
Bottom: Max(b.Bottom, other.Bottom),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,10 +220,10 @@ func (b Box) Fit(other Box) Box {
|
||||||
func (b Box) Constrain(other Box) Box {
|
func (b Box) Constrain(other Box) Box {
|
||||||
newBox := b.Clone()
|
newBox := b.Clone()
|
||||||
|
|
||||||
newBox.Top = MaxInt(newBox.Top, other.Top)
|
newBox.Top = Max(newBox.Top, other.Top)
|
||||||
newBox.Left = MaxInt(newBox.Left, other.Left)
|
newBox.Left = Max(newBox.Left, other.Left)
|
||||||
newBox.Right = MinInt(newBox.Right, other.Right)
|
newBox.Right = Min(newBox.Right, other.Right)
|
||||||
newBox.Bottom = MinInt(newBox.Bottom, other.Bottom)
|
newBox.Bottom = Min(newBox.Bottom, other.Bottom)
|
||||||
|
|
||||||
return newBox
|
return newBox
|
||||||
}
|
}
|
||||||
|
@ -262,36 +262,36 @@ type BoxCorners struct {
|
||||||
// Box return the BoxCorners as a regular box.
|
// Box return the BoxCorners as a regular box.
|
||||||
func (bc BoxCorners) Box() Box {
|
func (bc BoxCorners) Box() Box {
|
||||||
return Box{
|
return Box{
|
||||||
Top: MinInt(bc.TopLeft.Y, bc.TopRight.Y),
|
Top: Min(bc.TopLeft.Y, bc.TopRight.Y),
|
||||||
Left: MinInt(bc.TopLeft.X, bc.BottomLeft.X),
|
Left: Min(bc.TopLeft.X, bc.BottomLeft.X),
|
||||||
Right: MaxInt(bc.TopRight.X, bc.BottomRight.X),
|
Right: Max(bc.TopRight.X, bc.BottomRight.X),
|
||||||
Bottom: MaxInt(bc.BottomLeft.Y, bc.BottomRight.Y),
|
Bottom: Max(bc.BottomLeft.Y, bc.BottomRight.Y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Width returns the width
|
// Width returns the width
|
||||||
func (bc BoxCorners) Width() int {
|
func (bc BoxCorners) Width() int {
|
||||||
minLeft := MinInt(bc.TopLeft.X, bc.BottomLeft.X)
|
minLeft := Min(bc.TopLeft.X, bc.BottomLeft.X)
|
||||||
maxRight := MaxInt(bc.TopRight.X, bc.BottomRight.X)
|
maxRight := Max(bc.TopRight.X, bc.BottomRight.X)
|
||||||
return maxRight - minLeft
|
return maxRight - minLeft
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height returns the height
|
// Height returns the height
|
||||||
func (bc BoxCorners) Height() int {
|
func (bc BoxCorners) Height() int {
|
||||||
minTop := MinInt(bc.TopLeft.Y, bc.TopRight.Y)
|
minTop := Min(bc.TopLeft.Y, bc.TopRight.Y)
|
||||||
maxBottom := MaxInt(bc.BottomLeft.Y, bc.BottomRight.Y)
|
maxBottom := Max(bc.BottomLeft.Y, bc.BottomRight.Y)
|
||||||
return maxBottom - minTop
|
return maxBottom - minTop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center returns the center of the box
|
// Center returns the center of the box
|
||||||
func (bc BoxCorners) Center() (x, y int) {
|
func (bc BoxCorners) Center() (x, y int) {
|
||||||
|
|
||||||
left := MeanInt(bc.TopLeft.X, bc.BottomLeft.X)
|
left := Mean(bc.TopLeft.X, bc.BottomLeft.X)
|
||||||
right := MeanInt(bc.TopRight.X, bc.BottomRight.X)
|
right := Mean(bc.TopRight.X, bc.BottomRight.X)
|
||||||
x = ((right - left) >> 1) + left
|
x = ((right - left) >> 1) + left
|
||||||
|
|
||||||
top := MeanInt(bc.TopLeft.Y, bc.TopRight.Y)
|
top := Mean(bc.TopLeft.Y, bc.TopRight.Y)
|
||||||
bottom := MeanInt(bc.BottomLeft.Y, bc.BottomRight.Y)
|
bottom := Mean(bc.BottomLeft.Y, bc.BottomRight.Y)
|
||||||
y = ((bottom - top) >> 1) + top
|
y = ((bottom - top) >> 1) + top
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -123,7 +123,7 @@ func (pc DonutChart) drawTitle(r Renderer) {
|
||||||
|
|
||||||
func (pc DonutChart) drawSlices(r Renderer, canvasBox Box, values []Value) {
|
func (pc DonutChart) drawSlices(r Renderer, canvasBox Box, values []Value) {
|
||||||
cx, cy := canvasBox.Center()
|
cx, cy := canvasBox.Center()
|
||||||
diameter := MinInt(canvasBox.Width(), canvasBox.Height())
|
diameter := Min(canvasBox.Width(), canvasBox.Height())
|
||||||
radius := float64(diameter>>1) / 1.1
|
radius := float64(diameter>>1) / 1.1
|
||||||
labelRadius := (radius * 2.83) / 3.0
|
labelRadius := (radius * 2.83) / 3.0
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func (pc DonutChart) getDefaultCanvasBox() Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc DonutChart) getCircleAdjustedCanvasBox(canvasBox Box) Box {
|
func (pc DonutChart) getCircleAdjustedCanvasBox(canvasBox Box) Box {
|
||||||
circleDiameter := MinInt(canvasBox.Width(), canvasBox.Height())
|
circleDiameter := Min(canvasBox.Width(), canvasBox.Height())
|
||||||
|
|
||||||
square := Box{
|
square := Box{
|
||||||
Right: circleDiameter,
|
Right: circleDiameter,
|
||||||
|
@ -241,7 +241,7 @@ func (pc DonutChart) styleDonutChartValue(index int) Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc DonutChart) getScaledFontSize() float64 {
|
func (pc DonutChart) getScaledFontSize() float64 {
|
||||||
effectiveDimension := MinInt(pc.GetWidth(), pc.GetHeight())
|
effectiveDimension := Min(pc.GetWidth(), pc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48.0
|
return 48.0
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
@ -280,7 +280,7 @@ func (pc DonutChart) styleDefaultsTitle() Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc DonutChart) getTitleFontSize() float64 {
|
func (pc DonutChart) getTitleFontSize() float64 {
|
||||||
effectiveDimension := MinInt(pc.GetWidth(), pc.GetHeight())
|
effectiveDimension := Min(pc.GetWidth(), pc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48
|
return 48
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
|
4
draw.go
4
draw.go
|
@ -38,8 +38,8 @@ func (d draw) LineSeries(r Renderer, canvasBox Box, xrange, yrange Range, style
|
||||||
y = cb - yrange.Translate(vy)
|
y = cb - yrange.Translate(vy)
|
||||||
r.LineTo(x, y)
|
r.LineTo(x, y)
|
||||||
}
|
}
|
||||||
r.LineTo(x, MinInt(cb, cb-yv0))
|
r.LineTo(x, Min(cb, cb-yv0))
|
||||||
r.LineTo(x0, MinInt(cb, cb-yv0))
|
r.LineTo(x0, Min(cb, cb-yv0))
|
||||||
r.LineTo(x0, y0)
|
r.LineTo(x0, y0)
|
||||||
r.Fill()
|
r.Fill()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ func main() {
|
||||||
},
|
},
|
||||||
Series: []chart.Series{
|
Series: []chart.Series{
|
||||||
chart.ContinuousSeries{
|
chart.ContinuousSeries{
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(100).WithMax(512)}.Values(),
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(100).WithMax(512)}.Values(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ func main() {
|
||||||
|
|
||||||
mainSeries := chart.ContinuousSeries{
|
mainSeries := chart.ContinuousSeries{
|
||||||
Name: "A test series",
|
Name: "A test series",
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
||||||
}
|
}
|
||||||
|
|
||||||
// note we create a LinearRegressionSeries series by assignin the inner series.
|
// note we create a LinearRegressionSeries series by assignin the inner series.
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
mainSeries := chart.ContinuousSeries{
|
mainSeries := chart.ContinuousSeries{
|
||||||
Name: "A test series",
|
Name: "A test series",
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(50).WithMax(150)}.Values(),
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(50).WithMax(150)}.Values(),
|
||||||
}
|
}
|
||||||
|
|
||||||
minSeries := &chart.MinSeries{
|
minSeries := &chart.MinSeries{
|
||||||
|
|
|
@ -17,8 +17,8 @@ func main() {
|
||||||
|
|
||||||
mainSeries := chart.ContinuousSeries{
|
mainSeries := chart.ContinuousSeries{
|
||||||
Name: "A test series",
|
Name: "A test series",
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
||||||
}
|
}
|
||||||
|
|
||||||
polyRegSeries := &chart.PolynomialRegressionSeries{
|
polyRegSeries := &chart.PolynomialRegressionSeries{
|
||||||
|
|
|
@ -24,8 +24,8 @@ func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||||
DotWidth: 5,
|
DotWidth: 5,
|
||||||
DotColorProvider: viridisByY,
|
DotColorProvider: viridisByY,
|
||||||
},
|
},
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(127)}.Values(),
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(127)}.Values(),
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(128).WithMin(0).WithMax(1024)}.Values(),
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(128).WithMin(0).WithMax(1024)}.Values(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ func unit(res http.ResponseWriter, req *http.Request) {
|
||||||
},
|
},
|
||||||
Series: []chart.Series{
|
Series: []chart.Series{
|
||||||
chart.ContinuousSeries{
|
chart.ContinuousSeries{
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
||||||
YValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
YValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
mainSeries := chart.ContinuousSeries{
|
mainSeries := chart.ContinuousSeries{
|
||||||
Name: "A test series",
|
Name: "A test series",
|
||||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
XValues: chart.Seq[float64]{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(), //generates a []float64 from 1.0 to 100.0 in 1.0 step increments, or 100 elements.
|
||||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
YValues: chart.Seq[float64]{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
||||||
}
|
}
|
||||||
|
|
||||||
// note we create a SimpleMovingAverage series by assignin the inner series.
|
// note we create a SimpleMovingAverage series by assignin the inner series.
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -1,8 +1,8 @@
|
||||||
module github.com/wcharczuk/go-chart/v2
|
module github.com/wcharczuk/go-chart/v2
|
||||||
|
|
||||||
go 1.15
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||||
)
|
)
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -1,5 +1,6 @@
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|
|
@ -68,7 +68,7 @@ func Legend(c *Chart, userDefaults ...Style) Renderable {
|
||||||
}
|
}
|
||||||
legendContent.Bottom += tb.Height()
|
legendContent.Bottom += tb.Height()
|
||||||
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
|
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
|
||||||
legendContent.Right = MaxInt(legendContent.Right, right)
|
legendContent.Right = Max(legendContent.Right, right)
|
||||||
labelCount++
|
labelCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,8 +163,8 @@ func LegendThin(c *Chart, userDefaults ...Style) Renderable {
|
||||||
for x := 0; x < len(labels); x++ {
|
for x := 0; x < len(labels); x++ {
|
||||||
if len(labels[x]) > 0 {
|
if len(labels[x]) > 0 {
|
||||||
textBox = r.MeasureText(labels[x])
|
textBox = r.MeasureText(labels[x])
|
||||||
textHeight = MaxInt(textBox.Height(), textHeight)
|
textHeight = Max(textBox.Height(), textHeight)
|
||||||
textWidth = MaxInt(textBox.Width(), textWidth)
|
textWidth = Max(textBox.Width(), textWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ func LegendLeft(c *Chart, userDefaults ...Style) Renderable {
|
||||||
}
|
}
|
||||||
legendContent.Bottom += tb.Height()
|
legendContent.Bottom += tb.Height()
|
||||||
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
|
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
|
||||||
legendContent.Right = MaxInt(legendContent.Right, right)
|
legendContent.Right = Max(legendContent.Right, right)
|
||||||
labelCount++
|
labelCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (lrs LinearRegressionSeries) GetYAxis() YAxisType {
|
||||||
|
|
||||||
// Len returns the number of elements in the series.
|
// Len returns the number of elements in the series.
|
||||||
func (lrs LinearRegressionSeries) Len() int {
|
func (lrs LinearRegressionSeries) Len() int {
|
||||||
return MinInt(lrs.GetLimit(), lrs.InnerSeries.Len()-lrs.GetOffset())
|
return Min(lrs.GetLimit(), lrs.InnerSeries.Len()-lrs.GetOffset())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLimit returns the window size.
|
// GetLimit returns the window size.
|
||||||
|
@ -74,7 +74,7 @@ func (lrs LinearRegressionSeries) GetLimit() int {
|
||||||
func (lrs LinearRegressionSeries) GetEndIndex() int {
|
func (lrs LinearRegressionSeries) GetEndIndex() int {
|
||||||
windowEnd := lrs.GetOffset() + lrs.GetLimit()
|
windowEnd := lrs.GetOffset() + lrs.GetLimit()
|
||||||
innerSeriesLastIndex := lrs.InnerSeries.Len() - 1
|
innerSeriesLastIndex := lrs.InnerSeries.Len() - 1
|
||||||
return MinInt(windowEnd, innerSeriesLastIndex)
|
return Min(windowEnd, innerSeriesLastIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOffset returns the data offset.
|
// GetOffset returns the data offset.
|
||||||
|
@ -94,7 +94,7 @@ func (lrs *LinearRegressionSeries) GetValues(index int) (x, y float64) {
|
||||||
lrs.computeCoefficients()
|
lrs.computeCoefficients()
|
||||||
}
|
}
|
||||||
offset := lrs.GetOffset()
|
offset := lrs.GetOffset()
|
||||||
effectiveIndex := MinInt(index+offset, lrs.InnerSeries.Len())
|
effectiveIndex := Min(index+offset, lrs.InnerSeries.Len())
|
||||||
x, y = lrs.InnerSeries.GetValues(effectiveIndex)
|
x, y = lrs.InnerSeries.GetValues(effectiveIndex)
|
||||||
y = (lrs.m * lrs.normalize(x)) + lrs.b
|
y = (lrs.m * lrs.normalize(x)) + lrs.b
|
||||||
return
|
return
|
||||||
|
@ -161,14 +161,14 @@ func (lrs *LinearRegressionSeries) computeCoefficients() {
|
||||||
|
|
||||||
p := float64(endIndex - startIndex)
|
p := float64(endIndex - startIndex)
|
||||||
|
|
||||||
xvalues := NewValueBufferWithCapacity(lrs.Len())
|
xvalues := NewValueBufferWithCapacity[float64](lrs.Len())
|
||||||
for index := startIndex; index < endIndex; index++ {
|
for index := startIndex; index < endIndex; index++ {
|
||||||
x, _ := lrs.InnerSeries.GetValues(index)
|
x, _ := lrs.InnerSeries.GetValues(index)
|
||||||
xvalues.Enqueue(x)
|
xvalues.Enqueue(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
lrs.avgx = Seq{xvalues}.Average()
|
lrs.avgx = Seq[float64]{xvalues}.Average()
|
||||||
lrs.stddevx = Seq{xvalues}.StdDev()
|
lrs.stddevx = Seq[float64]{xvalues}.StdDev()
|
||||||
|
|
||||||
var sumx, sumy, sumxx, sumxy float64
|
var sumx, sumy, sumxx, sumxy float64
|
||||||
for index := startIndex; index < endIndex; index++ {
|
for index := startIndex; index < endIndex; index++ {
|
||||||
|
|
|
@ -2,12 +2,12 @@ package chart
|
||||||
|
|
||||||
// LinearRange returns an array of values representing the range from start to end, incremented by 1.0.
|
// LinearRange returns an array of values representing the range from start to end, incremented by 1.0.
|
||||||
func LinearRange(start, end float64) []float64 {
|
func LinearRange(start, end float64) []float64 {
|
||||||
return Seq{NewLinearSequence().WithStart(start).WithEnd(end).WithStep(1.0)}.Values()
|
return Seq[float64]{NewLinearSequence().WithStart(start).WithEnd(end).WithStep(1.0)}.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinearRangeWithStep returns the array values of a linear seq with a given start, end and optional step.
|
// LinearRangeWithStep returns the array values of a linear seq with a given start, end and optional step.
|
||||||
func LinearRangeWithStep(start, end, step float64) []float64 {
|
func LinearRangeWithStep(start, end, step float64) []float64 {
|
||||||
return Seq{NewLinearSequence().WithStart(start).WithEnd(end).WithStep(step)}.Values()
|
return Seq[float64]{NewLinearSequence().WithStart(start).WithEnd(end).WithStep(step)}.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLinearSequence returns a new linear generator.
|
// NewLinearSequence returns a new linear generator.
|
||||||
|
|
48
linear_sequence_test.go
Normal file
48
linear_sequence_test.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package chart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_LinearRange(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
|
values := LinearRange(1, 100)
|
||||||
|
testutil.AssertLen(t, values, 100)
|
||||||
|
testutil.AssertEqual(t, 1, values[0])
|
||||||
|
testutil.AssertEqual(t, 100, values[99])
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_LinearRange_WithStep(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
|
values := LinearRangeWithStep(0, 100, 5)
|
||||||
|
testutil.AssertEqual(t, 100, values[20])
|
||||||
|
testutil.AssertLen(t, values, 21)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_LinearRange_reversed(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
|
values := LinearRange(10.0, 1.0)
|
||||||
|
testutil.AssertEqual(t, 10, len(values))
|
||||||
|
testutil.AssertEqual(t, 10.0, values[0])
|
||||||
|
testutil.AssertEqual(t, 1.0, values[9])
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_LinearSequence_Regression(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
|
// note; this assumes a 1.0 step is implicitly set in the constructor.
|
||||||
|
linearProvider := NewLinearSequence().WithStart(1.0).WithEnd(100.0)
|
||||||
|
testutil.AssertEqual(t, 1, linearProvider.Start())
|
||||||
|
testutil.AssertEqual(t, 100, linearProvider.End())
|
||||||
|
testutil.AssertEqual(t, 100, linearProvider.Len())
|
||||||
|
|
||||||
|
values := Seq[float64]{linearProvider}.Values()
|
||||||
|
testutil.AssertLen(t, values, 100)
|
||||||
|
testutil.AssertEqual(t, 1.0, values[0])
|
||||||
|
testutil.AssertEqual(t, 100, values[99])
|
||||||
|
}
|
39
mathutil.go
39
mathutil.go
|
@ -1,6 +1,9 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import "math"
|
import (
|
||||||
|
"constraints"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_pi = math.Pi
|
_pi = math.Pi
|
||||||
|
@ -17,14 +20,14 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// MinMax returns the minimum and maximum of a given set of values.
|
// MinMax returns the minimum and maximum of a given set of values.
|
||||||
func MinMax(values ...float64) (min, max float64) {
|
func MinMax[A constraints.Ordered](values ...A) (min, max A) {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
max = values[0]
|
max = values[0]
|
||||||
min = values[0]
|
min = values[0]
|
||||||
var value float64
|
var value A
|
||||||
for index := 1; index < len(values); index++ {
|
for index := 1; index < len(values); index++ {
|
||||||
value = values[index]
|
value = values[index]
|
||||||
if value < min {
|
if value < min {
|
||||||
|
@ -38,13 +41,13 @@ func MinMax(values ...float64) (min, max float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinInt returns the minimum int.
|
// MinInt returns the minimum int.
|
||||||
func MinInt(values ...int) (min int) {
|
func Min[A constraints.Ordered](values ...A) (min A) {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
min = values[0]
|
min = values[0]
|
||||||
var value int
|
var value A
|
||||||
for index := 1; index < len(values); index++ {
|
for index := 1; index < len(values); index++ {
|
||||||
value = values[index]
|
value = values[index]
|
||||||
if value < min {
|
if value < min {
|
||||||
|
@ -55,13 +58,13 @@ func MinInt(values ...int) (min int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxInt returns the maximum int.
|
// MaxInt returns the maximum int.
|
||||||
func MaxInt(values ...int) (max int) {
|
func Max[A constraints.Ordered](values ...A) (max A) {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
max = values[0]
|
max = values[0]
|
||||||
var value int
|
var value A
|
||||||
for index := 1; index < len(values); index++ {
|
for index := 1; index < len(values); index++ {
|
||||||
value = values[index]
|
value = values[index]
|
||||||
if value > max {
|
if value > max {
|
||||||
|
@ -71,9 +74,15 @@ func MaxInt(values ...int) (max int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Number is a type that is a number.
|
||||||
|
type Number interface {
|
||||||
|
~int | ~uint | ~float64
|
||||||
|
}
|
||||||
|
|
||||||
// AbsInt returns the absolute value of an int.
|
// AbsInt returns the absolute value of an int.
|
||||||
func AbsInt(value int) int {
|
func Abs[A Number](value A) A {
|
||||||
if value < 0 {
|
var zero A
|
||||||
|
if value < zero {
|
||||||
return -value
|
return -value
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
|
@ -173,18 +182,12 @@ func Normalize(values ...float64) []float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mean returns the mean of a set of values
|
// Mean returns the mean of a set of values
|
||||||
func Mean(values ...float64) float64 {
|
func Mean[A Number](values ...A) A {
|
||||||
return Sum(values...) / float64(len(values))
|
return Sum(values...) / A(len(values))
|
||||||
}
|
|
||||||
|
|
||||||
// MeanInt returns the mean of a set of integer values.
|
|
||||||
func MeanInt(values ...int) int {
|
|
||||||
return SumInt(values...) / len(values)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum sums a set of values.
|
// Sum sums a set of values.
|
||||||
func Sum(values ...float64) float64 {
|
func Sum[A Number](values ...A) (total A) {
|
||||||
var total float64
|
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
total += v
|
total += v
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,7 +292,7 @@ func (m *Matrix) Copy() *Matrix {
|
||||||
// DiagonalVector returns a vector from the diagonal of a matrix.
|
// DiagonalVector returns a vector from the diagonal of a matrix.
|
||||||
func (m *Matrix) DiagonalVector() Vector {
|
func (m *Matrix) DiagonalVector() Vector {
|
||||||
rows, cols := m.Size()
|
rows, cols := m.Size()
|
||||||
rank := minInt(rows, cols)
|
rank := Min(rows, cols)
|
||||||
values := make([]float64, rank)
|
values := make([]float64, rank)
|
||||||
|
|
||||||
for index := 0; index < rank; index++ {
|
for index := 0; index < rank; index++ {
|
||||||
|
@ -304,7 +304,7 @@ func (m *Matrix) DiagonalVector() Vector {
|
||||||
// Diagonal returns a matrix from the diagonal of a matrix.
|
// Diagonal returns a matrix from the diagonal of a matrix.
|
||||||
func (m *Matrix) Diagonal() *Matrix {
|
func (m *Matrix) Diagonal() *Matrix {
|
||||||
rows, cols := m.Size()
|
rows, cols := m.Size()
|
||||||
rank := minInt(rows, cols)
|
rank := Min(rows, cols)
|
||||||
m2 := New(rank, rank)
|
m2 := New(rank, rank)
|
||||||
|
|
||||||
for index := 0; index < rank; index++ {
|
for index := 0; index < rank; index++ {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func minInt(values ...int) int {
|
func Min(values ...int) int {
|
||||||
min := math.MaxInt32
|
min := math.MaxInt32
|
||||||
|
|
||||||
for x := 0; x < len(values); x++ {
|
for x := 0; x < len(values); x++ {
|
||||||
|
@ -16,7 +16,7 @@ func minInt(values ...int) int {
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
func maxInt(values ...int) int {
|
func Max(values ...int) int {
|
||||||
max := math.MinInt32
|
max := math.MinInt32
|
||||||
|
|
||||||
for x := 0; x < len(values); x++ {
|
for x := 0; x < len(values); x++ {
|
||||||
|
|
|
@ -123,7 +123,7 @@ func (pc PieChart) drawTitle(r Renderer) {
|
||||||
|
|
||||||
func (pc PieChart) drawSlices(r Renderer, canvasBox Box, values []Value) {
|
func (pc PieChart) drawSlices(r Renderer, canvasBox Box, values []Value) {
|
||||||
cx, cy := canvasBox.Center()
|
cx, cy := canvasBox.Center()
|
||||||
diameter := MinInt(canvasBox.Width(), canvasBox.Height())
|
diameter := Min(canvasBox.Width(), canvasBox.Height())
|
||||||
radius := float64(diameter >> 1)
|
radius := float64(diameter >> 1)
|
||||||
labelRadius := (radius * 2.0) / 3.0
|
labelRadius := (radius * 2.0) / 3.0
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ func (pc PieChart) getDefaultCanvasBox() Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc PieChart) getCircleAdjustedCanvasBox(canvasBox Box) Box {
|
func (pc PieChart) getCircleAdjustedCanvasBox(canvasBox Box) Box {
|
||||||
circleDiameter := MinInt(canvasBox.Width(), canvasBox.Height())
|
circleDiameter := Min(canvasBox.Width(), canvasBox.Height())
|
||||||
|
|
||||||
square := Box{
|
square := Box{
|
||||||
Right: circleDiameter,
|
Right: circleDiameter,
|
||||||
|
@ -237,7 +237,7 @@ func (pc PieChart) stylePieChartValue(index int) Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc PieChart) getScaledFontSize() float64 {
|
func (pc PieChart) getScaledFontSize() float64 {
|
||||||
effectiveDimension := MinInt(pc.GetWidth(), pc.GetHeight())
|
effectiveDimension := Min(pc.GetWidth(), pc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48.0
|
return 48.0
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
@ -276,7 +276,7 @@ func (pc PieChart) styleDefaultsTitle() Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc PieChart) getTitleFontSize() float64 {
|
func (pc PieChart) getTitleFontSize() float64 {
|
||||||
effectiveDimension := MinInt(pc.GetWidth(), pc.GetHeight())
|
effectiveDimension := Min(pc.GetWidth(), pc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48
|
return 48
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (prs PolynomialRegressionSeries) GetYAxis() YAxisType {
|
||||||
|
|
||||||
// Len returns the number of elements in the series.
|
// Len returns the number of elements in the series.
|
||||||
func (prs PolynomialRegressionSeries) Len() int {
|
func (prs PolynomialRegressionSeries) Len() int {
|
||||||
return MinInt(prs.GetLimit(), prs.InnerSeries.Len()-prs.GetOffset())
|
return Min(prs.GetLimit(), prs.InnerSeries.Len()-prs.GetOffset())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLimit returns the window size.
|
// GetLimit returns the window size.
|
||||||
|
@ -61,7 +61,7 @@ func (prs PolynomialRegressionSeries) GetLimit() int {
|
||||||
func (prs PolynomialRegressionSeries) GetEndIndex() int {
|
func (prs PolynomialRegressionSeries) GetEndIndex() int {
|
||||||
windowEnd := prs.GetOffset() + prs.GetLimit()
|
windowEnd := prs.GetOffset() + prs.GetLimit()
|
||||||
innerSeriesLastIndex := prs.InnerSeries.Len() - 1
|
innerSeriesLastIndex := prs.InnerSeries.Len() - 1
|
||||||
return MinInt(windowEnd, innerSeriesLastIndex)
|
return Min(windowEnd, innerSeriesLastIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOffset returns the data offset.
|
// GetOffset returns the data offset.
|
||||||
|
@ -101,7 +101,7 @@ func (prs *PolynomialRegressionSeries) GetValues(index int) (x, y float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := prs.GetOffset()
|
offset := prs.GetOffset()
|
||||||
effectiveIndex := MinInt(index+offset, prs.InnerSeries.Len())
|
effectiveIndex := Min(index+offset, prs.InnerSeries.Len())
|
||||||
x, y = prs.InnerSeries.GetValues(effectiveIndex)
|
x, y = prs.InnerSeries.GetValues(effectiveIndex)
|
||||||
y = prs.apply(x)
|
y = prs.apply(x)
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,17 +7,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Sequence = (*RandomSeq)(nil)
|
_ Sequence[float64] = (*RandomSeq)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomValues returns an array of random values.
|
// RandomValues returns an array of random values.
|
||||||
func RandomValues(count int) []float64 {
|
func RandomValues(count int) []float64 {
|
||||||
return Seq{NewRandomSequence().WithLen(count)}.Values()
|
return Seq[float64]{NewRandomSequence().WithLen(count)}.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomValuesWithMax returns an array of random values with a given average.
|
// RandomValuesWithMax returns an array of random values with a given average.
|
||||||
func RandomValuesWithMax(count int, max float64) []float64 {
|
func RandomValuesWithMax(count int, max float64) []float64 {
|
||||||
return Seq{NewRandomSequence().WithMax(max).WithLen(count)}.Values()
|
return Seq[float64]{NewRandomSequence().WithMax(max).WithLen(count)}.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRandomSequence creates a new random seq.
|
// NewRandomSequence creates a new random seq.
|
||||||
|
|
130
seq.go
130
seq.go
|
@ -5,29 +5,18 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValueSequence returns a sequence for a given values set.
|
|
||||||
func ValueSequence(values ...float64) Seq {
|
|
||||||
return Seq{NewArray(values...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sequence is a provider for values for a seq.
|
|
||||||
type Sequence interface {
|
|
||||||
Len() int
|
|
||||||
GetValue(int) float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seq is a utility wrapper for seq providers.
|
// Seq is a utility wrapper for seq providers.
|
||||||
type Seq struct {
|
type Seq[A Number] struct {
|
||||||
Sequence
|
Sequence[A]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values enumerates the seq into a slice.
|
// Values enumerates the seq into a slice.
|
||||||
func (s Seq) Values() (output []float64) {
|
func (s Seq[A]) Values() (output []A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output = make([]float64, s.Len())
|
output = make([]A, s.Len())
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
output[i] = s.GetValue(i)
|
output[i] = s.GetValue(i)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +24,7 @@ func (s Seq) Values() (output []float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each applies the `mapfn` to all values in the value provider.
|
// Each applies the `mapfn` to all values in the value provider.
|
||||||
func (s Seq) Each(mapfn func(int, float64)) {
|
func (s Seq[A]) Each(mapfn func(int, A)) {
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
mapfn(i, s.GetValue(i))
|
mapfn(i, s.GetValue(i))
|
||||||
}
|
}
|
||||||
|
@ -43,55 +32,56 @@ func (s Seq) Each(mapfn func(int, float64)) {
|
||||||
|
|
||||||
// Map applies the `mapfn` to all values in the value provider,
|
// Map applies the `mapfn` to all values in the value provider,
|
||||||
// returning a new seq.
|
// returning a new seq.
|
||||||
func (s Seq) Map(mapfn func(i int, v float64) float64) Seq {
|
func (s Seq[A]) Map(mapfn func(i int, v A) A) Seq[A] {
|
||||||
output := make([]float64, s.Len())
|
output := make([]A, s.Len())
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
mapfn(i, s.GetValue(i))
|
mapfn(i, s.GetValue(i))
|
||||||
}
|
}
|
||||||
return Seq{Array(output)}
|
return Seq[A]{Sequence: Array(output...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FoldLeft collapses a seq from left to right.
|
// FoldLeft collapses a seq from left to right.
|
||||||
func (s Seq) FoldLeft(mapfn func(i int, v0, v float64) float64) (v0 float64) {
|
func (s Seq[A]) FoldLeft(mapfn func(i int, v0, v A) A) (output A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Len() == 1 {
|
if s.Len() == 1 {
|
||||||
return s.GetValue(0)
|
return s.GetValue(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
v0 = s.GetValue(0)
|
output = s.GetValue(0)
|
||||||
for i := 1; i < s.Len(); i++ {
|
for i := 1; i < s.Len(); i++ {
|
||||||
v0 = mapfn(i, v0, s.GetValue(i))
|
output = mapfn(i, output, s.GetValue(i))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FoldRight collapses a seq from right to left.
|
// FoldRight collapses a seq from right to left.
|
||||||
func (s Seq) FoldRight(mapfn func(i int, v0, v float64) float64) (v0 float64) {
|
func (s Seq[A]) FoldRight(mapfn func(i int, v0, v A) A) (output A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Len() == 1 {
|
if s.Len() == 1 {
|
||||||
return s.GetValue(0)
|
return s.GetValue(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
v0 = s.GetValue(s.Len() - 1)
|
output = s.GetValue(s.Len() - 1)
|
||||||
for i := s.Len() - 2; i >= 0; i-- {
|
for i := s.Len() - 2; i >= 0; i-- {
|
||||||
v0 = mapfn(i, v0, s.GetValue(i))
|
output = mapfn(i, output, s.GetValue(i))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Min returns the minimum value in the seq.
|
// Min returns the minimum value in the seq.
|
||||||
func (s Seq) Min() float64 {
|
func (s Seq[A]) Min() (min A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
min := s.GetValue(0)
|
|
||||||
var value float64
|
min = s.GetValue(0)
|
||||||
|
var value A
|
||||||
for i := 1; i < s.Len(); i++ {
|
for i := 1; i < s.Len(); i++ {
|
||||||
value = s.GetValue(i)
|
value = s.GetValue(i)
|
||||||
if value < min {
|
if value < min {
|
||||||
|
@ -102,12 +92,12 @@ func (s Seq) Min() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Max returns the maximum value in the seq.
|
// Max returns the maximum value in the seq.
|
||||||
func (s Seq) Max() float64 {
|
func (s Seq[A]) Max() (max A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
max := s.GetValue(0)
|
max = s.GetValue(0)
|
||||||
var value float64
|
var value A
|
||||||
for i := 1; i < s.Len(); i++ {
|
for i := 1; i < s.Len(); i++ {
|
||||||
value = s.GetValue(i)
|
value = s.GetValue(i)
|
||||||
if value > max {
|
if value > max {
|
||||||
|
@ -118,13 +108,13 @@ func (s Seq) Max() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinMax returns the minimum and the maximum in one pass.
|
// MinMax returns the minimum and the maximum in one pass.
|
||||||
func (s Seq) MinMax() (min, max float64) {
|
func (s Seq[A]) MinMax() (min, max A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
min = s.GetValue(0)
|
min = s.GetValue(0)
|
||||||
max = min
|
max = min
|
||||||
var value float64
|
var value A
|
||||||
for i := 1; i < s.Len(); i++ {
|
for i := 1; i < s.Len(); i++ {
|
||||||
value = s.GetValue(i)
|
value = s.GetValue(i)
|
||||||
if value < min {
|
if value < min {
|
||||||
|
@ -139,17 +129,19 @@ func (s Seq) MinMax() (min, max float64) {
|
||||||
|
|
||||||
// Sort returns the seq sorted in ascending order.
|
// Sort returns the seq sorted in ascending order.
|
||||||
// This fully enumerates the seq.
|
// This fully enumerates the seq.
|
||||||
func (s Seq) Sort() Seq {
|
func (s Seq[A]) Sort() Seq[A] {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
values := s.Values()
|
values := s.Values()
|
||||||
sort.Float64s(values)
|
sort.Slice(values, func(i, j int) bool {
|
||||||
return Seq{Array(values)}
|
return values[i] < values[j]
|
||||||
|
})
|
||||||
|
return Seq[A]{Array(values...)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse reverses the sequence
|
// Reverse reverses the sequence
|
||||||
func (s Seq) Reverse() Seq {
|
func (s Seq[A]) Reverse() Seq[A] {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -158,7 +150,7 @@ func (s Seq) Reverse() Seq {
|
||||||
valuesLen := len(values)
|
valuesLen := len(values)
|
||||||
valuesLen1 := len(values) - 1
|
valuesLen1 := len(values) - 1
|
||||||
valuesLen2 := valuesLen >> 1
|
valuesLen2 := valuesLen >> 1
|
||||||
var i, j float64
|
var i, j A
|
||||||
for index := 0; index < valuesLen2; index++ {
|
for index := 0; index < valuesLen2; index++ {
|
||||||
i = values[index]
|
i = values[index]
|
||||||
j = values[valuesLen1-index]
|
j = values[valuesLen1-index]
|
||||||
|
@ -166,32 +158,13 @@ func (s Seq) Reverse() Seq {
|
||||||
values[valuesLen1-index] = i
|
values[valuesLen1-index] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
return Seq{Array(values)}
|
return Seq[A]{Array(values...)}
|
||||||
}
|
|
||||||
|
|
||||||
// Median returns the median or middle value in the sorted seq.
|
|
||||||
func (s Seq) Median() (median float64) {
|
|
||||||
l := s.Len()
|
|
||||||
if l == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sorted := s.Sort()
|
|
||||||
if l%2 == 0 {
|
|
||||||
v0 := sorted.GetValue(l/2 - 1)
|
|
||||||
v1 := sorted.GetValue(l/2 + 1)
|
|
||||||
median = (v0 + v1) / 2
|
|
||||||
} else {
|
|
||||||
median = float64(sorted.GetValue(l << 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum adds all the elements of a series together.
|
// Sum adds all the elements of a series together.
|
||||||
func (s Seq) Sum() (accum float64) {
|
func (s Seq[A]) Sum() (accum A) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
@ -201,24 +174,25 @@ func (s Seq) Sum() (accum float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Average returns the float average of the values in the buffer.
|
// Average returns the float average of the values in the buffer.
|
||||||
func (s Seq) Average() float64 {
|
func (s Seq[A]) Average() (avg float64) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Sum() / float64(s.Len())
|
avg = float64(s.Sum()) / float64((s.Len()))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variance computes the variance of the buffer.
|
// Variance computes the variance of the buffer.
|
||||||
func (s Seq) Variance() float64 {
|
func (s Seq[A]) Variance() (variance float64) {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
m := s.Average()
|
m := s.Average()
|
||||||
var variance, v float64
|
var v float64
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
v = s.GetValue(i)
|
v = float64(s.GetValue(i))
|
||||||
variance += (v - m) * (v - m)
|
variance += (v - m) * (v - m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,24 +200,24 @@ func (s Seq) Variance() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StdDev returns the standard deviation.
|
// StdDev returns the standard deviation.
|
||||||
func (s Seq) StdDev() float64 {
|
func (s Seq[A]) StdDev() float64 {
|
||||||
if s.Len() == 0 {
|
if s.Len() == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return math.Pow(s.Variance(), 0.5)
|
return math.Pow(float64(s.Variance()), 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Percentile finds the relative standing in a slice of floats.
|
//Percentile finds the relative standing in a slice of floats.
|
||||||
// `percent` should be given on the interval [0,1.0).
|
// `percent` should be given on the interval [0,1.0).
|
||||||
func (s Seq) Percentile(percent float64) (percentile float64) {
|
func (s Seq[A]) Percentile(percent float64) (percentile A) {
|
||||||
l := s.Len()
|
l := s.Len()
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if percent < 0 || percent > 1.0 {
|
if percent < 0 || percent > 1.0 {
|
||||||
panic("percent out of range [0.0, 1.0)")
|
panic("percentile percent out of range [0.0, 1.0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
sorted := s.Sort()
|
sorted := s.Sort()
|
||||||
|
@ -262,14 +236,14 @@ func (s Seq) Percentile(percent float64) (percentile float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize maps every value to the interval [0, 1.0].
|
// Normalize maps every value to the interval [0, 1.0].
|
||||||
func (s Seq) Normalize() Seq {
|
func (s Seq[A]) Normalize() Seq[float64] {
|
||||||
min, max := s.MinMax()
|
min, max := s.MinMax()
|
||||||
|
|
||||||
delta := max - min
|
delta := float64(max - min)
|
||||||
output := make([]float64, s.Len())
|
output := make([]float64, s.Len())
|
||||||
for i := 0; i < s.Len(); i++ {
|
for i := 0; i < s.Len(); i++ {
|
||||||
output[i] = (s.GetValue(i) - min) / delta
|
output[i] = (float64(s.GetValue(i)) - float64(min)) / delta
|
||||||
}
|
}
|
||||||
|
|
||||||
return Seq{Array(output)}
|
return Seq[float64]{Array(output...)}
|
||||||
}
|
}
|
||||||
|
|
82
seq_test.go
82
seq_test.go
|
@ -6,95 +6,69 @@ import (
|
||||||
"github.com/wcharczuk/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSeqEach(t *testing.T) {
|
func Test_Seq_Each(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
values.Each(func(i int, v int) {
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
values.Each(func(i int, v float64) {
|
|
||||||
testutil.AssertEqual(t, i, v-1)
|
testutil.AssertEqual(t, i, v-1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeqMap(t *testing.T) {
|
func Test_Seq_Map(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
mapped := values.Map(func(i int, v int) int {
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
mapped := values.Map(func(i int, v float64) float64 {
|
|
||||||
testutil.AssertEqual(t, i, v-1)
|
testutil.AssertEqual(t, i, v-1)
|
||||||
return v * 2
|
return v * 2
|
||||||
})
|
})
|
||||||
testutil.AssertEqual(t, 4, mapped.Len())
|
testutil.AssertEqual(t, 4, mapped.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeqFoldLeft(t *testing.T) {
|
func Test_Seq_FoldLeft(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
ten := values.FoldLeft(func(_ int, vp, v int) int {
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
ten := values.FoldLeft(func(_ int, vp, v float64) float64 {
|
|
||||||
return vp + v
|
return vp + v
|
||||||
})
|
})
|
||||||
testutil.AssertEqual(t, 10, ten)
|
testutil.AssertEqual(t, 10, ten)
|
||||||
|
|
||||||
orderTest := Seq{NewArray(10, 3, 2, 1)}
|
orderTest := Seq[int]{Array(10, 3, 2, 1)}
|
||||||
four := orderTest.FoldLeft(func(_ int, vp, v float64) float64 {
|
four := orderTest.FoldLeft(func(_ int, vp, v int) int {
|
||||||
return vp - v
|
return vp - v
|
||||||
})
|
})
|
||||||
testutil.AssertEqual(t, 4, four)
|
testutil.AssertEqual(t, 4, four)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeqFoldRight(t *testing.T) {
|
func Test_Seq_FoldRight(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
ten := values.FoldRight(func(_ int, vp, v int) int {
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
ten := values.FoldRight(func(_ int, vp, v float64) float64 {
|
|
||||||
return vp + v
|
return vp + v
|
||||||
})
|
})
|
||||||
testutil.AssertEqual(t, 10, ten)
|
testutil.AssertEqual(t, 10, ten)
|
||||||
|
|
||||||
orderTest := Seq{NewArray(10, 3, 2, 1)}
|
orderTest := Seq[int]{Array(10, 3, 2, 1)}
|
||||||
notFour := orderTest.FoldRight(func(_ int, vp, v float64) float64 {
|
notFour := orderTest.FoldRight(func(_ int, vp, v int) int {
|
||||||
return vp - v
|
return vp - v
|
||||||
})
|
})
|
||||||
testutil.AssertEqual(t, -14, notFour)
|
testutil.AssertEqual(t, -14, notFour)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeqSum(t *testing.T) {
|
func Test_Seq_Sum(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
testutil.AssertEqual(t, 10, values.Sum())
|
testutil.AssertEqual(t, 10, values.Sum())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSeqAverage(t *testing.T) {
|
func Test_Seq_Average(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4)}
|
||||||
|
|
||||||
values := Seq{NewArray(1, 2, 3, 4)}
|
|
||||||
testutil.AssertEqual(t, 2.5, values.Average())
|
testutil.AssertEqual(t, 2.5, values.Average())
|
||||||
|
|
||||||
valuesOdd := Seq{NewArray(1, 2, 3, 4, 5)}
|
valuesOdd := Seq[int]{Array(1, 2, 3, 4, 5)}
|
||||||
testutil.AssertEqual(t, 3, valuesOdd.Average())
|
testutil.AssertEqual(t, 3, valuesOdd.Average())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSequenceVariance(t *testing.T) {
|
func Test_Seq_Variance(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := Seq[int]{Array(1, 2, 3, 4, 5)}
|
||||||
|
|
||||||
values := Seq{NewArray(1, 2, 3, 4, 5)}
|
|
||||||
testutil.AssertEqual(t, 2, values.Variance())
|
testutil.AssertEqual(t, 2, values.Variance())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSequenceNormalize(t *testing.T) {
|
func Test_LinearRange(t *testing.T) {
|
||||||
// replaced new assertions helper
|
|
||||||
|
|
||||||
normalized := ValueSequence(1, 2, 3, 4, 5).Normalize().Values()
|
|
||||||
|
|
||||||
testutil.AssertNotEmpty(t, normalized)
|
|
||||||
testutil.AssertLen(t, normalized, 5)
|
|
||||||
testutil.AssertEqual(t, 0, normalized[0])
|
|
||||||
testutil.AssertEqual(t, 0.25, normalized[1])
|
|
||||||
testutil.AssertEqual(t, 1, normalized[4])
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinearRange(t *testing.T) {
|
|
||||||
// replaced new assertions helper
|
// replaced new assertions helper
|
||||||
|
|
||||||
values := LinearRange(1, 100)
|
values := LinearRange(1, 100)
|
||||||
|
@ -103,7 +77,7 @@ func TestLinearRange(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 100, values[99])
|
testutil.AssertEqual(t, 100, values[99])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLinearRangeWithStep(t *testing.T) {
|
func Test_LinearRange_WithStep(t *testing.T) {
|
||||||
// replaced new assertions helper
|
// replaced new assertions helper
|
||||||
|
|
||||||
values := LinearRangeWithStep(0, 100, 5)
|
values := LinearRangeWithStep(0, 100, 5)
|
||||||
|
@ -111,7 +85,7 @@ func TestLinearRangeWithStep(t *testing.T) {
|
||||||
testutil.AssertLen(t, values, 21)
|
testutil.AssertLen(t, values, 21)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLinearRangeReversed(t *testing.T) {
|
func Test_LinearRange_reversed(t *testing.T) {
|
||||||
// replaced new assertions helper
|
// replaced new assertions helper
|
||||||
|
|
||||||
values := LinearRange(10.0, 1.0)
|
values := LinearRange(10.0, 1.0)
|
||||||
|
@ -120,7 +94,7 @@ func TestLinearRangeReversed(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 1.0, values[9])
|
testutil.AssertEqual(t, 1.0, values[9])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLinearSequenceRegression(t *testing.T) {
|
func Test_LinearSequence_Regression(t *testing.T) {
|
||||||
// replaced new assertions helper
|
// replaced new assertions helper
|
||||||
|
|
||||||
// note; this assumes a 1.0 step is implicitly set in the constructor.
|
// note; this assumes a 1.0 step is implicitly set in the constructor.
|
||||||
|
@ -129,7 +103,7 @@ func TestLinearSequenceRegression(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 100, linearProvider.End())
|
testutil.AssertEqual(t, 100, linearProvider.End())
|
||||||
testutil.AssertEqual(t, 100, linearProvider.Len())
|
testutil.AssertEqual(t, 100, linearProvider.Len())
|
||||||
|
|
||||||
values := Seq{linearProvider}.Values()
|
values := Seq[float64]{linearProvider}.Values()
|
||||||
testutil.AssertLen(t, values, 100)
|
testutil.AssertLen(t, values, 100)
|
||||||
testutil.AssertEqual(t, 1.0, values[0])
|
testutil.AssertEqual(t, 1.0, values[0])
|
||||||
testutil.AssertEqual(t, 100, values[99])
|
testutil.AssertEqual(t, 100, values[99])
|
||||||
|
|
7
sequence.go
Normal file
7
sequence.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package chart
|
||||||
|
|
||||||
|
// Sequence is a provider for values for a seq.
|
||||||
|
type Sequence[A any] interface {
|
||||||
|
Len() int
|
||||||
|
GetValue(int) A
|
||||||
|
}
|
|
@ -94,7 +94,7 @@ func (sma SMASeries) GetLastValues() (x, y float64) {
|
||||||
|
|
||||||
func (sma SMASeries) getAverage(index int) float64 {
|
func (sma SMASeries) getAverage(index int) float64 {
|
||||||
period := sma.GetPeriod()
|
period := sma.GetPeriod()
|
||||||
floor := MaxInt(0, index-period)
|
floor := Max(0, index-period)
|
||||||
var accum float64
|
var accum float64
|
||||||
var count float64
|
var count float64
|
||||||
for x := index; x >= floor; x-- {
|
for x := index; x >= floor; x-- {
|
||||||
|
|
|
@ -171,7 +171,7 @@ func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar S
|
||||||
Top: yoffset,
|
Top: yoffset,
|
||||||
Left: bxl,
|
Left: bxl,
|
||||||
Right: bxr,
|
Right: bxr,
|
||||||
Bottom: MinInt(yoffset+barHeight, canvasBox.Bottom-DefaultStrokeWidth),
|
Bottom: Min(yoffset+barHeight, canvasBox.Bottom-DefaultStrokeWidth),
|
||||||
}
|
}
|
||||||
Draw.Box(r, barBox, bv.Style.InheritFrom(sbc.styleDefaultsStackedBarValue(index)))
|
Draw.Box(r, barBox, bv.Style.InheritFrom(sbc.styleDefaultsStackedBarValue(index)))
|
||||||
yoffset += barHeight
|
yoffset += barHeight
|
||||||
|
@ -220,7 +220,7 @@ func (sbc StackedBarChart) drawHorizontalBar(r Renderer, canvasBox Box, yoffset
|
||||||
barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Width())))
|
barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Width())))
|
||||||
barBox := Box{
|
barBox := Box{
|
||||||
Top: boxTop,
|
Top: boxTop,
|
||||||
Left: MinInt(xOffset-barHeight, canvasBox.Left+DefaultStrokeWidth),
|
Left: Min(xOffset-barHeight, canvasBox.Left+DefaultStrokeWidth),
|
||||||
Right: xOffset,
|
Right: xOffset,
|
||||||
Bottom: boxBottom,
|
Bottom: boxBottom,
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ func (sbc StackedBarChart) getAdjustedCanvasBox(r Renderer, canvasBox Box) Box {
|
||||||
lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
|
lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
|
||||||
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
||||||
|
|
||||||
xaxisHeight = MaxInt(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
|
xaxisHeight = Max(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Box{
|
return Box{
|
||||||
|
@ -498,7 +498,7 @@ func (sbc StackedBarChart) getHorizontalAdjustedCanvasBox(r Renderer, canvasBox
|
||||||
lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
|
lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
|
||||||
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
||||||
|
|
||||||
yAxisWidth = MaxInt(linesBox.Height()+(2*DefaultXAxisMargin), yAxisWidth)
|
yAxisWidth = Max(linesBox.Height()+(2*DefaultXAxisMargin), yAxisWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Box{
|
return Box{
|
||||||
|
@ -552,7 +552,7 @@ func (sbc StackedBarChart) styleDefaultsTitle() Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) getScaledFontSize() float64 {
|
func (sbc StackedBarChart) getScaledFontSize() float64 {
|
||||||
effectiveDimension := MinInt(sbc.GetWidth(), sbc.GetHeight())
|
effectiveDimension := Min(sbc.GetWidth(), sbc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48.0
|
return 48.0
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
@ -566,7 +566,7 @@ func (sbc StackedBarChart) getScaledFontSize() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) getTitleFontSize() float64 {
|
func (sbc StackedBarChart) getTitleFontSize() float64 {
|
||||||
effectiveDimension := MinInt(sbc.GetWidth(), sbc.GetHeight())
|
effectiveDimension := Min(sbc.GetWidth(), sbc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
return 48
|
return 48
|
||||||
} else if effectiveDimension >= 1024 {
|
} else if effectiveDimension >= 1024 {
|
||||||
|
|
|
@ -27,7 +27,7 @@ func AssertNotNil(t *testing.T, actual interface{}, message ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertEqual asserts two arguments are equal.
|
// AssertEqual asserts two arguments are equal.
|
||||||
func AssertEqual(t *testing.T, expected, actual interface{}, message ...interface{}) {
|
func AssertEqual[A any](t *testing.T, expected, actual A, message ...interface{}) {
|
||||||
if !equal(expected, actual) {
|
if !equal(expected, actual) {
|
||||||
t.Errorf("assertion failed; expected %v to equal %v", actual, expected)
|
t.Errorf("assertion failed; expected %v to equal %v", actual, expected)
|
||||||
if len(message) > 0 {
|
if len(message) > 0 {
|
||||||
|
@ -38,7 +38,7 @@ func AssertEqual(t *testing.T, expected, actual interface{}, message ...interfac
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertNotEqual asserts two arguments are not equal.
|
// AssertNotEqual asserts two arguments are not equal.
|
||||||
func AssertNotEqual(t *testing.T, expected, actual interface{}, message ...interface{}) {
|
func AssertNotEqual[A any](t *testing.T, expected, actual A, message ...interface{}) {
|
||||||
if equal(expected, actual) {
|
if equal(expected, actual) {
|
||||||
t.Errorf("assertion failed; expected %v to not equal %v", actual, expected)
|
t.Errorf("assertion failed; expected %v to not equal %v", actual, expected)
|
||||||
if len(message) > 0 {
|
if len(message) > 0 {
|
||||||
|
|
2
text.go
2
text.go
|
@ -147,7 +147,7 @@ func (t text) MeasureLines(r Renderer, lines []string, style Style) Box {
|
||||||
var output Box
|
var output Box
|
||||||
for index, line := range lines {
|
for index, line := range lines {
|
||||||
lineBox := r.MeasureText(line)
|
lineBox := r.MeasureText(line)
|
||||||
output.Right = MaxInt(lineBox.Right, output.Right)
|
output.Right = Max(lineBox.Right, output.Right)
|
||||||
output.Bottom += lineBox.Height()
|
output.Bottom += lineBox.Height()
|
||||||
if index < len(lines)-1 {
|
if index < len(lines)-1 {
|
||||||
output.Bottom += +style.GetTextLineSpacing()
|
output.Bottom += +style.GetTextLineSpacing()
|
||||||
|
|
2
tick.go
2
tick.go
|
@ -84,7 +84,7 @@ func GenerateContinuousTicks(r Renderer, ra Range, isVertical bool, style Style,
|
||||||
tickStep := rangeDelta / float64(intermediateTickCount)
|
tickStep := rangeDelta / float64(intermediateTickCount)
|
||||||
|
|
||||||
roundTo := GetRoundToForDelta(rangeDelta) / 10
|
roundTo := GetRoundToForDelta(rangeDelta) / 10
|
||||||
intermediateTickCount = MinInt(intermediateTickCount, DefaultTickCountSanityCheck)
|
intermediateTickCount = Min(intermediateTickCount, DefaultTickCountSanityCheck)
|
||||||
|
|
||||||
for x := 1; x < intermediateTickCount; x++ {
|
for x := 1; x < intermediateTickCount; x++ {
|
||||||
var tickValue float64
|
var tickValue float64
|
||||||
|
|
2
times.go
2
times.go
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
// Assert types implement interfaces.
|
// Assert types implement interfaces.
|
||||||
var (
|
var (
|
||||||
_ Sequence = (*Times)(nil)
|
_ Sequence[float64] = (*Times)(nil)
|
||||||
_ sort.Interface = (*Times)(nil)
|
_ sort.Interface = (*Times)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"constraints"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -13,14 +14,14 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewValueBuffer creates a new value buffer with an optional set of values.
|
// NewValueBuffer creates a new value buffer with an optional set of values.
|
||||||
func NewValueBuffer(values ...float64) *ValueBuffer {
|
func NewValueBuffer[A constraints.Ordered](values ...A) *ValueBuffer[A] {
|
||||||
var tail int
|
var tail int
|
||||||
array := make([]float64, MaxInt(len(values), bufferDefaultCapacity))
|
array := make([]A, Max(len(values), bufferDefaultCapacity))
|
||||||
if len(values) > 0 {
|
if len(values) > 0 {
|
||||||
copy(array, values)
|
copy(array, values)
|
||||||
tail = len(values)
|
tail = len(values)
|
||||||
}
|
}
|
||||||
return &ValueBuffer{
|
return &ValueBuffer[A]{
|
||||||
array: array,
|
array: array,
|
||||||
head: 0,
|
head: 0,
|
||||||
tail: tail,
|
tail: tail,
|
||||||
|
@ -29,21 +30,21 @@ func NewValueBuffer(values ...float64) *ValueBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValueBufferWithCapacity creates a new ValueBuffer pre-allocated with the given capacity.
|
// NewValueBufferWithCapacity creates a new ValueBuffer pre-allocated with the given capacity.
|
||||||
func NewValueBufferWithCapacity(capacity int) *ValueBuffer {
|
func NewValueBufferWithCapacity[A any](capacity int) *ValueBuffer[A] {
|
||||||
return &ValueBuffer{
|
return &ValueBuffer[A]{
|
||||||
array: make([]float64, capacity),
|
array: make([]A, capacity),
|
||||||
head: 0,
|
head: 0,
|
||||||
tail: 0,
|
tail: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValueBuffer is a fifo datastructure that is backed by a pre-allocated array.
|
// ValueBuffer is a fifo data structure that is backed by a pre-allocated array.
|
||||||
// Instead of allocating a whole new node object for each element, array elements are re-used (which saves GC churn).
|
// Instead of allocating a whole new node object for each element, array elements are re-used (which saves GC churn).
|
||||||
// Enqueue can be O(n), Dequeue is generally O(1).
|
// Enqueue can be O(n), Dequeue is generally O(1).
|
||||||
// Buffer implements `seq.Provider`
|
// Buffer implements `seq.Provider`
|
||||||
type ValueBuffer struct {
|
type ValueBuffer[A any] struct {
|
||||||
array []float64
|
array []A
|
||||||
head int
|
head int
|
||||||
tail int
|
tail int
|
||||||
size int
|
size int
|
||||||
|
@ -51,24 +52,24 @@ type ValueBuffer struct {
|
||||||
|
|
||||||
// Len returns the length of the Buffer (as it is currently populated).
|
// Len returns the length of the Buffer (as it is currently populated).
|
||||||
// Actual memory footprint may be different.
|
// Actual memory footprint may be different.
|
||||||
func (b *ValueBuffer) Len() int {
|
func (b *ValueBuffer[A]) Len() int {
|
||||||
return b.size
|
return b.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValue implements seq provider.
|
// GetValue implements seq provider.
|
||||||
func (b *ValueBuffer) GetValue(index int) float64 {
|
func (b *ValueBuffer[A]) GetValue(index int) A {
|
||||||
effectiveIndex := (b.head + index) % len(b.array)
|
effectiveIndex := (b.head + index) % len(b.array)
|
||||||
return b.array[effectiveIndex]
|
return b.array[effectiveIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capacity returns the total size of the Buffer, including empty elements.
|
// Capacity returns the total size of the Buffer, including empty elements.
|
||||||
func (b *ValueBuffer) Capacity() int {
|
func (b *ValueBuffer[A]) Capacity() int {
|
||||||
return len(b.array)
|
return len(b.array)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCapacity sets the capacity of the Buffer.
|
// SetCapacity sets the capacity of the Buffer.
|
||||||
func (b *ValueBuffer) SetCapacity(capacity int) {
|
func (b *ValueBuffer[A]) SetCapacity(capacity int) {
|
||||||
newArray := make([]float64, capacity)
|
newArray := make([]A, capacity)
|
||||||
if b.size > 0 {
|
if b.size > 0 {
|
||||||
if b.head < b.tail {
|
if b.head < b.tail {
|
||||||
arrayCopy(b.array, b.head, newArray, 0, b.size)
|
arrayCopy(b.array, b.head, newArray, 0, b.size)
|
||||||
|
@ -87,15 +88,15 @@ func (b *ValueBuffer) SetCapacity(capacity int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes all objects from the Buffer.
|
// Clear removes all objects from the Buffer.
|
||||||
func (b *ValueBuffer) Clear() {
|
func (b *ValueBuffer[A]) Clear() {
|
||||||
b.array = make([]float64, bufferDefaultCapacity)
|
b.array = make([]A, bufferDefaultCapacity)
|
||||||
b.head = 0
|
b.head = 0
|
||||||
b.tail = 0
|
b.tail = 0
|
||||||
b.size = 0
|
b.size = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue adds an element to the "back" of the Buffer.
|
// Enqueue adds an element to the "back" of the Buffer.
|
||||||
func (b *ValueBuffer) Enqueue(value float64) {
|
func (b *ValueBuffer[A]) Enqueue(value A) {
|
||||||
if b.size == len(b.array) {
|
if b.size == len(b.array) {
|
||||||
newCapacity := int(len(b.array) * int(bufferGrowFactor/100))
|
newCapacity := int(len(b.array) * int(bufferGrowFactor/100))
|
||||||
if newCapacity < (len(b.array) + bufferMinimumGrow) {
|
if newCapacity < (len(b.array) + bufferMinimumGrow) {
|
||||||
|
@ -110,38 +111,41 @@ func (b *ValueBuffer) Enqueue(value float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dequeue removes the first element from the RingBuffer.
|
// Dequeue removes the first element from the RingBuffer.
|
||||||
func (b *ValueBuffer) Dequeue() float64 {
|
func (b *ValueBuffer[A]) Dequeue() (output A) {
|
||||||
if b.size == 0 {
|
if b.size == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
removed := b.array[b.head]
|
output = b.array[b.head]
|
||||||
b.head = (b.head + 1) % len(b.array)
|
b.head = (b.head + 1) % len(b.array)
|
||||||
b.size--
|
b.size--
|
||||||
return removed
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peek returns but does not remove the first element.
|
// Peek returns but does not remove the first element.
|
||||||
func (b *ValueBuffer) Peek() float64 {
|
func (b *ValueBuffer[A]) Peek() (output A) {
|
||||||
if b.size == 0 {
|
if b.size == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
return b.array[b.head]
|
output = b.array[b.head]
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeekBack returns but does not remove the last element.
|
// PeekBack returns but does not remove the last element.
|
||||||
func (b *ValueBuffer) PeekBack() float64 {
|
func (b *ValueBuffer[A]) PeekBack() (output A) {
|
||||||
if b.size == 0 {
|
if b.size == 0 {
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
if b.tail == 0 {
|
if b.tail == 0 {
|
||||||
return b.array[len(b.array)-1]
|
output = b.array[len(b.array)-1]
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return b.array[b.tail-1]
|
output = b.array[b.tail-1]
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrimExcess resizes the capacity of the buffer to better fit the contents.
|
// TrimExcess resizes the capacity of the buffer to better fit the contents.
|
||||||
func (b *ValueBuffer) TrimExcess() {
|
func (b *ValueBuffer[A]) TrimExcess() {
|
||||||
threshold := float64(len(b.array)) * 0.9
|
threshold := float64(len(b.array)) * 0.9
|
||||||
if b.size < int(threshold) {
|
if b.size < int(threshold) {
|
||||||
b.SetCapacity(b.size)
|
b.SetCapacity(b.size)
|
||||||
|
@ -149,8 +153,8 @@ func (b *ValueBuffer) TrimExcess() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array returns the ring buffer, in order, as an array.
|
// Array returns the ring buffer, in order, as an array.
|
||||||
func (b *ValueBuffer) Array() Array {
|
func (b *ValueBuffer[A]) Array() []A {
|
||||||
newArray := make([]float64, b.size)
|
newArray := make([]A, b.size)
|
||||||
|
|
||||||
if b.size == 0 {
|
if b.size == 0 {
|
||||||
return newArray
|
return newArray
|
||||||
|
@ -163,11 +167,11 @@ func (b *ValueBuffer) Array() Array {
|
||||||
arrayCopy(b.array, 0, newArray, len(b.array)-b.head, b.tail)
|
arrayCopy(b.array, 0, newArray, len(b.array)-b.head, b.tail)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array(newArray)
|
return newArray
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each calls the consumer for each element in the buffer.
|
// Each calls the consumer for each element in the buffer.
|
||||||
func (b *ValueBuffer) Each(mapfn func(int, float64)) {
|
func (b *ValueBuffer[A]) Each(mapfn func(int, A)) {
|
||||||
if b.size == 0 {
|
if b.size == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -191,10 +195,10 @@ func (b *ValueBuffer) Each(mapfn func(int, float64)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation for value buffers.
|
// String returns a string representation for value buffers.
|
||||||
func (b *ValueBuffer) String() string {
|
func (b *ValueBuffer[A]) String() string {
|
||||||
var values []string
|
var values []string
|
||||||
for _, elem := range b.Array() {
|
for _, elem := range b.Array() {
|
||||||
values = append(values, fmt.Sprintf("%v", elem))
|
values = append(values, fmt.Sprint(elem))
|
||||||
}
|
}
|
||||||
return strings.Join(values, " <= ")
|
return strings.Join(values, " <= ")
|
||||||
}
|
}
|
||||||
|
@ -203,14 +207,15 @@ func (b *ValueBuffer) String() string {
|
||||||
// Util methods
|
// Util methods
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
|
|
||||||
func arrayClear(source []float64, index, length int) {
|
func arrayClear[A any](source []A, index, length int) {
|
||||||
|
var zero A
|
||||||
for x := 0; x < length; x++ {
|
for x := 0; x < length; x++ {
|
||||||
absoluteIndex := x + index
|
absoluteIndex := x + index
|
||||||
source[absoluteIndex] = 0
|
source[absoluteIndex] = zero
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func arrayCopy(source []float64, sourceIndex int, destination []float64, destinationIndex, length int) {
|
func arrayCopy[A any](source []A, sourceIndex int, destination []A, destinationIndex, length int) {
|
||||||
for x := 0; x < length; x++ {
|
for x := 0; x < length; x++ {
|
||||||
from := sourceIndex + x
|
from := sourceIndex + x
|
||||||
to := destinationIndex + x
|
to := destinationIndex + x
|
||||||
|
|
|
@ -6,10 +6,8 @@ import (
|
||||||
"github.com/wcharczuk/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuffer(t *testing.T) {
|
func Test_ValueBuffer(t *testing.T) {
|
||||||
// replaced new assertions helper
|
buffer := NewValueBuffer[int]()
|
||||||
|
|
||||||
buffer := NewValueBuffer()
|
|
||||||
|
|
||||||
buffer.Enqueue(1)
|
buffer.Enqueue(1)
|
||||||
testutil.AssertEqual(t, 1, buffer.Len())
|
testutil.AssertEqual(t, 1, buffer.Len())
|
||||||
|
@ -100,10 +98,8 @@ func TestBuffer(t *testing.T) {
|
||||||
testutil.AssertZero(t, buffer.PeekBack())
|
testutil.AssertZero(t, buffer.PeekBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferClear(t *testing.T) {
|
func Test_ValueBufferClear(t *testing.T) {
|
||||||
// replaced new assertions helper
|
buffer := NewValueBuffer[int]()
|
||||||
|
|
||||||
buffer := NewValueBuffer()
|
|
||||||
buffer.Enqueue(1)
|
buffer.Enqueue(1)
|
||||||
buffer.Enqueue(1)
|
buffer.Enqueue(1)
|
||||||
buffer.Enqueue(1)
|
buffer.Enqueue(1)
|
||||||
|
@ -121,10 +117,8 @@ func TestBufferClear(t *testing.T) {
|
||||||
testutil.AssertZero(t, buffer.PeekBack())
|
testutil.AssertZero(t, buffer.PeekBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferArray(t *testing.T) {
|
func Test_ValueBuffer_Array(t *testing.T) {
|
||||||
// replaced new assertions helper
|
buffer := NewValueBuffer[int]()
|
||||||
|
|
||||||
buffer := NewValueBuffer()
|
|
||||||
buffer.Enqueue(1)
|
buffer.Enqueue(1)
|
||||||
buffer.Enqueue(2)
|
buffer.Enqueue(2)
|
||||||
buffer.Enqueue(3)
|
buffer.Enqueue(3)
|
||||||
|
@ -140,10 +134,8 @@ func TestBufferArray(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 5, contents[4])
|
testutil.AssertEqual(t, 5, contents[4])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferEach(t *testing.T) {
|
func Test_ValueBuffer_Each(t *testing.T) {
|
||||||
// replaced new assertions helper
|
buffer := NewValueBuffer[float64]()
|
||||||
|
|
||||||
buffer := NewValueBuffer()
|
|
||||||
|
|
||||||
for x := 1; x < 17; x++ {
|
for x := 1; x < 17; x++ {
|
||||||
buffer.Enqueue(float64(x))
|
buffer.Enqueue(float64(x))
|
||||||
|
@ -159,10 +151,8 @@ func TestBufferEach(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 16, called)
|
testutil.AssertEqual(t, 16, called)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewBuffer(t *testing.T) {
|
func Test_NewValueBuffer(t *testing.T) {
|
||||||
// replaced new assertions helper
|
empty := NewValueBuffer[int]()
|
||||||
|
|
||||||
empty := NewValueBuffer()
|
|
||||||
testutil.AssertNotNil(t, empty)
|
testutil.AssertNotNil(t, empty)
|
||||||
testutil.AssertZero(t, empty.Len())
|
testutil.AssertZero(t, empty.Len())
|
||||||
testutil.AssertEqual(t, bufferDefaultCapacity, empty.Capacity())
|
testutil.AssertEqual(t, bufferDefaultCapacity, empty.Capacity())
|
||||||
|
@ -170,9 +160,7 @@ func TestNewBuffer(t *testing.T) {
|
||||||
testutil.AssertZero(t, empty.PeekBack())
|
testutil.AssertZero(t, empty.PeekBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewBufferWithValues(t *testing.T) {
|
func Test_NewBuffer_withValues(t *testing.T) {
|
||||||
// replaced new assertions helper
|
|
||||||
|
|
||||||
values := NewValueBuffer(1, 2, 3, 4, 5)
|
values := NewValueBuffer(1, 2, 3, 4, 5)
|
||||||
testutil.AssertNotNil(t, values)
|
testutil.AssertNotNil(t, values)
|
||||||
testutil.AssertEqual(t, 5, values.Len())
|
testutil.AssertEqual(t, 5, values.Len())
|
||||||
|
@ -180,10 +168,8 @@ func TestNewBufferWithValues(t *testing.T) {
|
||||||
testutil.AssertEqual(t, 5, values.PeekBack())
|
testutil.AssertEqual(t, 5, values.PeekBack())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferGrowth(t *testing.T) {
|
func Test_ValueBuffer_growth(t *testing.T) {
|
||||||
// replaced new assertions helper
|
values := NewValueBuffer[float64](1, 2, 3, 4, 5)
|
||||||
|
|
||||||
values := NewValueBuffer(1, 2, 3, 4, 5)
|
|
||||||
for i := 0; i < 1<<10; i++ {
|
for i := 0; i < 1<<10; i++ {
|
||||||
values.Enqueue(float64(i))
|
values.Enqueue(float64(i))
|
||||||
}
|
}
|
||||||
|
|
8
value_sequence.go
Normal file
8
value_sequence.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package chart
|
||||||
|
|
||||||
|
// ValueSequence returns a sequence for a given values set.
|
||||||
|
func ValueSequence(values ...float64) Seq[float64] {
|
||||||
|
return Seq[float64]{
|
||||||
|
Array(values...),
|
||||||
|
}
|
||||||
|
}
|
19
value_sequence_test.go
Normal file
19
value_sequence_test.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package chart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ValueSequence_Normalize(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
|
normalized := ValueSequence(1, 2, 3, 4, 5).Normalize().Values()
|
||||||
|
|
||||||
|
testutil.AssertNotEmpty(t, normalized)
|
||||||
|
testutil.AssertLen(t, normalized, 5)
|
||||||
|
testutil.AssertEqual(t, 0, normalized[0])
|
||||||
|
testutil.AssertEqual(t, 0.25, normalized[1])
|
||||||
|
testutil.AssertEqual(t, 1, normalized[4])
|
||||||
|
}
|
512
viridis.go
512
viridis.go
|
@ -3,262 +3,262 @@ package chart
|
||||||
import "github.com/wcharczuk/go-chart/v2/drawing"
|
import "github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
|
|
||||||
var viridisColors = [256]drawing.Color{
|
var viridisColors = [256]drawing.Color{
|
||||||
drawing.Color{R: 0x44, G: 0x1, B: 0x54, A: 0xff},
|
{R: 0x44, G: 0x1, B: 0x54, A: 0xff},
|
||||||
drawing.Color{R: 0x44, G: 0x2, B: 0x55, A: 0xff},
|
{R: 0x44, G: 0x2, B: 0x55, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x3, B: 0x57, A: 0xff},
|
{R: 0x45, G: 0x3, B: 0x57, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x5, B: 0x58, A: 0xff},
|
{R: 0x45, G: 0x5, B: 0x58, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x6, B: 0x5a, A: 0xff},
|
{R: 0x45, G: 0x6, B: 0x5a, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x8, B: 0x5b, A: 0xff},
|
{R: 0x46, G: 0x8, B: 0x5b, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x9, B: 0x5d, A: 0xff},
|
{R: 0x46, G: 0x9, B: 0x5d, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0xb, B: 0x5e, A: 0xff},
|
{R: 0x46, G: 0xb, B: 0x5e, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0xc, B: 0x60, A: 0xff},
|
{R: 0x46, G: 0xc, B: 0x60, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0xe, B: 0x61, A: 0xff},
|
{R: 0x47, G: 0xe, B: 0x61, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0xf, B: 0x62, A: 0xff},
|
{R: 0x47, G: 0xf, B: 0x62, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x11, B: 0x64, A: 0xff},
|
{R: 0x47, G: 0x11, B: 0x64, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x12, B: 0x65, A: 0xff},
|
{R: 0x47, G: 0x12, B: 0x65, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x14, B: 0x66, A: 0xff},
|
{R: 0x47, G: 0x14, B: 0x66, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x15, B: 0x68, A: 0xff},
|
{R: 0x48, G: 0x15, B: 0x68, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x16, B: 0x69, A: 0xff},
|
{R: 0x48, G: 0x16, B: 0x69, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x18, B: 0x6a, A: 0xff},
|
{R: 0x48, G: 0x18, B: 0x6a, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x19, B: 0x6c, A: 0xff},
|
{R: 0x48, G: 0x19, B: 0x6c, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x1a, B: 0x6d, A: 0xff},
|
{R: 0x48, G: 0x1a, B: 0x6d, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x1c, B: 0x6e, A: 0xff},
|
{R: 0x48, G: 0x1c, B: 0x6e, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x1d, B: 0x6f, A: 0xff},
|
{R: 0x48, G: 0x1d, B: 0x6f, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x1e, B: 0x70, A: 0xff},
|
{R: 0x48, G: 0x1e, B: 0x70, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x20, B: 0x71, A: 0xff},
|
{R: 0x48, G: 0x20, B: 0x71, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x21, B: 0x73, A: 0xff},
|
{R: 0x48, G: 0x21, B: 0x73, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x22, B: 0x74, A: 0xff},
|
{R: 0x48, G: 0x22, B: 0x74, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x24, B: 0x75, A: 0xff},
|
{R: 0x48, G: 0x24, B: 0x75, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x25, B: 0x76, A: 0xff},
|
{R: 0x48, G: 0x25, B: 0x76, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x26, B: 0x77, A: 0xff},
|
{R: 0x48, G: 0x26, B: 0x77, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0x27, B: 0x78, A: 0xff},
|
{R: 0x48, G: 0x27, B: 0x78, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x29, B: 0x79, A: 0xff},
|
{R: 0x47, G: 0x29, B: 0x79, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x2a, B: 0x79, A: 0xff},
|
{R: 0x47, G: 0x2a, B: 0x79, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x2b, B: 0x7a, A: 0xff},
|
{R: 0x47, G: 0x2b, B: 0x7a, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x2c, B: 0x7b, A: 0xff},
|
{R: 0x47, G: 0x2c, B: 0x7b, A: 0xff},
|
||||||
drawing.Color{R: 0x47, G: 0x2e, B: 0x7c, A: 0xff},
|
{R: 0x47, G: 0x2e, B: 0x7c, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x2f, B: 0x7d, A: 0xff},
|
{R: 0x46, G: 0x2f, B: 0x7d, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x30, B: 0x7e, A: 0xff},
|
{R: 0x46, G: 0x30, B: 0x7e, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x31, B: 0x7e, A: 0xff},
|
{R: 0x46, G: 0x31, B: 0x7e, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0x33, B: 0x7f, A: 0xff},
|
{R: 0x46, G: 0x33, B: 0x7f, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x34, B: 0x80, A: 0xff},
|
{R: 0x45, G: 0x34, B: 0x80, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x35, B: 0x81, A: 0xff},
|
{R: 0x45, G: 0x35, B: 0x81, A: 0xff},
|
||||||
drawing.Color{R: 0x45, G: 0x36, B: 0x81, A: 0xff},
|
{R: 0x45, G: 0x36, B: 0x81, A: 0xff},
|
||||||
drawing.Color{R: 0x44, G: 0x38, B: 0x82, A: 0xff},
|
{R: 0x44, G: 0x38, B: 0x82, A: 0xff},
|
||||||
drawing.Color{R: 0x44, G: 0x39, B: 0x83, A: 0xff},
|
{R: 0x44, G: 0x39, B: 0x83, A: 0xff},
|
||||||
drawing.Color{R: 0x44, G: 0x3a, B: 0x83, A: 0xff},
|
{R: 0x44, G: 0x3a, B: 0x83, A: 0xff},
|
||||||
drawing.Color{R: 0x43, G: 0x3b, B: 0x84, A: 0xff},
|
{R: 0x43, G: 0x3b, B: 0x84, A: 0xff},
|
||||||
drawing.Color{R: 0x43, G: 0x3c, B: 0x84, A: 0xff},
|
{R: 0x43, G: 0x3c, B: 0x84, A: 0xff},
|
||||||
drawing.Color{R: 0x43, G: 0x3e, B: 0x85, A: 0xff},
|
{R: 0x43, G: 0x3e, B: 0x85, A: 0xff},
|
||||||
drawing.Color{R: 0x42, G: 0x3f, B: 0x85, A: 0xff},
|
{R: 0x42, G: 0x3f, B: 0x85, A: 0xff},
|
||||||
drawing.Color{R: 0x42, G: 0x40, B: 0x86, A: 0xff},
|
{R: 0x42, G: 0x40, B: 0x86, A: 0xff},
|
||||||
drawing.Color{R: 0x41, G: 0x41, B: 0x86, A: 0xff},
|
{R: 0x41, G: 0x41, B: 0x86, A: 0xff},
|
||||||
drawing.Color{R: 0x41, G: 0x42, B: 0x87, A: 0xff},
|
{R: 0x41, G: 0x42, B: 0x87, A: 0xff},
|
||||||
drawing.Color{R: 0x41, G: 0x43, B: 0x87, A: 0xff},
|
{R: 0x41, G: 0x43, B: 0x87, A: 0xff},
|
||||||
drawing.Color{R: 0x40, G: 0x45, B: 0x88, A: 0xff},
|
{R: 0x40, G: 0x45, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x40, G: 0x46, B: 0x88, A: 0xff},
|
{R: 0x40, G: 0x46, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x3f, G: 0x47, B: 0x88, A: 0xff},
|
{R: 0x3f, G: 0x47, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x3f, G: 0x48, B: 0x89, A: 0xff},
|
{R: 0x3f, G: 0x48, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x3e, G: 0x49, B: 0x89, A: 0xff},
|
{R: 0x3e, G: 0x49, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x3e, G: 0x4a, B: 0x89, A: 0xff},
|
{R: 0x3e, G: 0x4a, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x3d, G: 0x4b, B: 0x8a, A: 0xff},
|
{R: 0x3d, G: 0x4b, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x3d, G: 0x4d, B: 0x8a, A: 0xff},
|
{R: 0x3d, G: 0x4d, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x3c, G: 0x4e, B: 0x8a, A: 0xff},
|
{R: 0x3c, G: 0x4e, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x3c, G: 0x4f, B: 0x8a, A: 0xff},
|
{R: 0x3c, G: 0x4f, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x3b, G: 0x50, B: 0x8b, A: 0xff},
|
{R: 0x3b, G: 0x50, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x3b, G: 0x51, B: 0x8b, A: 0xff},
|
{R: 0x3b, G: 0x51, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x3a, G: 0x52, B: 0x8b, A: 0xff},
|
{R: 0x3a, G: 0x52, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x3a, G: 0x53, B: 0x8b, A: 0xff},
|
{R: 0x3a, G: 0x53, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x39, G: 0x54, B: 0x8c, A: 0xff},
|
{R: 0x39, G: 0x54, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x39, G: 0x55, B: 0x8c, A: 0xff},
|
{R: 0x39, G: 0x55, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x38, G: 0x56, B: 0x8c, A: 0xff},
|
{R: 0x38, G: 0x56, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x38, G: 0x57, B: 0x8c, A: 0xff},
|
{R: 0x38, G: 0x57, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x37, G: 0x58, B: 0x8c, A: 0xff},
|
{R: 0x37, G: 0x58, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x37, G: 0x59, B: 0x8c, A: 0xff},
|
{R: 0x37, G: 0x59, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x36, G: 0x5b, B: 0x8d, A: 0xff},
|
{R: 0x36, G: 0x5b, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x36, G: 0x5c, B: 0x8d, A: 0xff},
|
{R: 0x36, G: 0x5c, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x35, G: 0x5d, B: 0x8d, A: 0xff},
|
{R: 0x35, G: 0x5d, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x35, G: 0x5e, B: 0x8d, A: 0xff},
|
{R: 0x35, G: 0x5e, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x34, G: 0x5f, B: 0x8d, A: 0xff},
|
{R: 0x34, G: 0x5f, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x34, G: 0x60, B: 0x8d, A: 0xff},
|
{R: 0x34, G: 0x60, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x33, G: 0x61, B: 0x8d, A: 0xff},
|
{R: 0x33, G: 0x61, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x33, G: 0x62, B: 0x8d, A: 0xff},
|
{R: 0x33, G: 0x62, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x33, G: 0x63, B: 0x8d, A: 0xff},
|
{R: 0x33, G: 0x63, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x32, G: 0x64, B: 0x8e, A: 0xff},
|
{R: 0x32, G: 0x64, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x32, G: 0x65, B: 0x8e, A: 0xff},
|
{R: 0x32, G: 0x65, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x31, G: 0x66, B: 0x8e, A: 0xff},
|
{R: 0x31, G: 0x66, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x31, G: 0x67, B: 0x8e, A: 0xff},
|
{R: 0x31, G: 0x67, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x30, G: 0x68, B: 0x8e, A: 0xff},
|
{R: 0x30, G: 0x68, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x30, G: 0x69, B: 0x8e, A: 0xff},
|
{R: 0x30, G: 0x69, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2f, G: 0x6a, B: 0x8e, A: 0xff},
|
{R: 0x2f, G: 0x6a, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2f, G: 0x6b, B: 0x8e, A: 0xff},
|
{R: 0x2f, G: 0x6b, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2f, G: 0x6c, B: 0x8e, A: 0xff},
|
{R: 0x2f, G: 0x6c, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2e, G: 0x6d, B: 0x8e, A: 0xff},
|
{R: 0x2e, G: 0x6d, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2e, G: 0x6e, B: 0x8e, A: 0xff},
|
{R: 0x2e, G: 0x6e, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2d, G: 0x6f, B: 0x8e, A: 0xff},
|
{R: 0x2d, G: 0x6f, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
|
{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
|
{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2c, G: 0x71, B: 0x8e, A: 0xff},
|
{R: 0x2c, G: 0x71, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2c, G: 0x72, B: 0x8e, A: 0xff},
|
{R: 0x2c, G: 0x72, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2b, G: 0x73, B: 0x8e, A: 0xff},
|
{R: 0x2b, G: 0x73, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2b, G: 0x74, B: 0x8e, A: 0xff},
|
{R: 0x2b, G: 0x74, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2b, G: 0x75, B: 0x8e, A: 0xff},
|
{R: 0x2b, G: 0x75, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2a, G: 0x76, B: 0x8e, A: 0xff},
|
{R: 0x2a, G: 0x76, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x2a, G: 0x77, B: 0x8e, A: 0xff},
|
{R: 0x2a, G: 0x77, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x29, G: 0x78, B: 0x8e, A: 0xff},
|
{R: 0x29, G: 0x78, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x29, G: 0x79, B: 0x8e, A: 0xff},
|
{R: 0x29, G: 0x79, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x29, G: 0x7a, B: 0x8e, A: 0xff},
|
{R: 0x29, G: 0x7a, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x28, G: 0x7b, B: 0x8e, A: 0xff},
|
{R: 0x28, G: 0x7b, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x28, G: 0x7c, B: 0x8e, A: 0xff},
|
{R: 0x28, G: 0x7c, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x28, G: 0x7d, B: 0x8e, A: 0xff},
|
{R: 0x28, G: 0x7d, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x27, G: 0x7e, B: 0x8e, A: 0xff},
|
{R: 0x27, G: 0x7e, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x27, G: 0x7f, B: 0x8e, A: 0xff},
|
{R: 0x27, G: 0x7f, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x26, G: 0x80, B: 0x8e, A: 0xff},
|
{R: 0x26, G: 0x80, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x26, G: 0x81, B: 0x8e, A: 0xff},
|
{R: 0x26, G: 0x81, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x26, G: 0x82, B: 0x8e, A: 0xff},
|
{R: 0x26, G: 0x82, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
|
{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
|
{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x25, G: 0x84, B: 0x8e, A: 0xff},
|
{R: 0x25, G: 0x84, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x24, G: 0x85, B: 0x8e, A: 0xff},
|
{R: 0x24, G: 0x85, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x24, G: 0x86, B: 0x8e, A: 0xff},
|
{R: 0x24, G: 0x86, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x23, G: 0x87, B: 0x8e, A: 0xff},
|
{R: 0x23, G: 0x87, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x23, G: 0x88, B: 0x8e, A: 0xff},
|
{R: 0x23, G: 0x88, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x23, G: 0x89, B: 0x8e, A: 0xff},
|
{R: 0x23, G: 0x89, B: 0x8e, A: 0xff},
|
||||||
drawing.Color{R: 0x22, G: 0x8a, B: 0x8d, A: 0xff},
|
{R: 0x22, G: 0x8a, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x22, G: 0x8b, B: 0x8d, A: 0xff},
|
{R: 0x22, G: 0x8b, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x22, G: 0x8c, B: 0x8d, A: 0xff},
|
{R: 0x22, G: 0x8c, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x21, G: 0x8d, B: 0x8d, A: 0xff},
|
{R: 0x21, G: 0x8d, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x21, G: 0x8e, B: 0x8d, A: 0xff},
|
{R: 0x21, G: 0x8e, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x21, G: 0x8f, B: 0x8d, A: 0xff},
|
{R: 0x21, G: 0x8f, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0x90, B: 0x8d, A: 0xff},
|
{R: 0x20, G: 0x90, B: 0x8d, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0x91, B: 0x8c, A: 0xff},
|
{R: 0x20, G: 0x91, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0x92, B: 0x8c, A: 0xff},
|
{R: 0x20, G: 0x92, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0x93, B: 0x8c, A: 0xff},
|
{R: 0x20, G: 0x93, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0x93, B: 0x8c, A: 0xff},
|
{R: 0x1f, G: 0x93, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0x94, B: 0x8c, A: 0xff},
|
{R: 0x1f, G: 0x94, B: 0x8c, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0x95, B: 0x8b, A: 0xff},
|
{R: 0x1f, G: 0x95, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0x96, B: 0x8b, A: 0xff},
|
{R: 0x1f, G: 0x96, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0x97, B: 0x8b, A: 0xff},
|
{R: 0x1f, G: 0x97, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x98, B: 0x8b, A: 0xff},
|
{R: 0x1e, G: 0x98, B: 0x8b, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x99, B: 0x8a, A: 0xff},
|
{R: 0x1e, G: 0x99, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9a, B: 0x8a, A: 0xff},
|
{R: 0x1e, G: 0x9a, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9b, B: 0x8a, A: 0xff},
|
{R: 0x1e, G: 0x9b, B: 0x8a, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9c, B: 0x89, A: 0xff},
|
{R: 0x1e, G: 0x9c, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9d, B: 0x89, A: 0xff},
|
{R: 0x1e, G: 0x9d, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9e, B: 0x89, A: 0xff},
|
{R: 0x1e, G: 0x9e, B: 0x89, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0x9f, B: 0x88, A: 0xff},
|
{R: 0x1e, G: 0x9f, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x1e, G: 0xa0, B: 0x88, A: 0xff},
|
{R: 0x1e, G: 0xa0, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0xa1, B: 0x88, A: 0xff},
|
{R: 0x1f, G: 0xa1, B: 0x88, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0xa2, B: 0x87, A: 0xff},
|
{R: 0x1f, G: 0xa2, B: 0x87, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0xa3, B: 0x87, A: 0xff},
|
{R: 0x1f, G: 0xa3, B: 0x87, A: 0xff},
|
||||||
drawing.Color{R: 0x1f, G: 0xa3, B: 0x86, A: 0xff},
|
{R: 0x1f, G: 0xa3, B: 0x86, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0xa4, B: 0x86, A: 0xff},
|
{R: 0x20, G: 0xa4, B: 0x86, A: 0xff},
|
||||||
drawing.Color{R: 0x20, G: 0xa5, B: 0x86, A: 0xff},
|
{R: 0x20, G: 0xa5, B: 0x86, A: 0xff},
|
||||||
drawing.Color{R: 0x21, G: 0xa6, B: 0x85, A: 0xff},
|
{R: 0x21, G: 0xa6, B: 0x85, A: 0xff},
|
||||||
drawing.Color{R: 0x21, G: 0xa7, B: 0x85, A: 0xff},
|
{R: 0x21, G: 0xa7, B: 0x85, A: 0xff},
|
||||||
drawing.Color{R: 0x22, G: 0xa8, B: 0x84, A: 0xff},
|
{R: 0x22, G: 0xa8, B: 0x84, A: 0xff},
|
||||||
drawing.Color{R: 0x23, G: 0xa9, B: 0x83, A: 0xff},
|
{R: 0x23, G: 0xa9, B: 0x83, A: 0xff},
|
||||||
drawing.Color{R: 0x23, G: 0xaa, B: 0x83, A: 0xff},
|
{R: 0x23, G: 0xaa, B: 0x83, A: 0xff},
|
||||||
drawing.Color{R: 0x24, G: 0xab, B: 0x82, A: 0xff},
|
{R: 0x24, G: 0xab, B: 0x82, A: 0xff},
|
||||||
drawing.Color{R: 0x25, G: 0xac, B: 0x82, A: 0xff},
|
{R: 0x25, G: 0xac, B: 0x82, A: 0xff},
|
||||||
drawing.Color{R: 0x26, G: 0xad, B: 0x81, A: 0xff},
|
{R: 0x26, G: 0xad, B: 0x81, A: 0xff},
|
||||||
drawing.Color{R: 0x27, G: 0xae, B: 0x81, A: 0xff},
|
{R: 0x27, G: 0xae, B: 0x81, A: 0xff},
|
||||||
drawing.Color{R: 0x28, G: 0xaf, B: 0x80, A: 0xff},
|
{R: 0x28, G: 0xaf, B: 0x80, A: 0xff},
|
||||||
drawing.Color{R: 0x29, G: 0xaf, B: 0x7f, A: 0xff},
|
{R: 0x29, G: 0xaf, B: 0x7f, A: 0xff},
|
||||||
drawing.Color{R: 0x2a, G: 0xb0, B: 0x7f, A: 0xff},
|
{R: 0x2a, G: 0xb0, B: 0x7f, A: 0xff},
|
||||||
drawing.Color{R: 0x2b, G: 0xb1, B: 0x7e, A: 0xff},
|
{R: 0x2b, G: 0xb1, B: 0x7e, A: 0xff},
|
||||||
drawing.Color{R: 0x2c, G: 0xb2, B: 0x7d, A: 0xff},
|
{R: 0x2c, G: 0xb2, B: 0x7d, A: 0xff},
|
||||||
drawing.Color{R: 0x2e, G: 0xb3, B: 0x7c, A: 0xff},
|
{R: 0x2e, G: 0xb3, B: 0x7c, A: 0xff},
|
||||||
drawing.Color{R: 0x2f, G: 0xb4, B: 0x7c, A: 0xff},
|
{R: 0x2f, G: 0xb4, B: 0x7c, A: 0xff},
|
||||||
drawing.Color{R: 0x30, G: 0xb5, B: 0x7b, A: 0xff},
|
{R: 0x30, G: 0xb5, B: 0x7b, A: 0xff},
|
||||||
drawing.Color{R: 0x32, G: 0xb6, B: 0x7a, A: 0xff},
|
{R: 0x32, G: 0xb6, B: 0x7a, A: 0xff},
|
||||||
drawing.Color{R: 0x33, G: 0xb7, B: 0x79, A: 0xff},
|
{R: 0x33, G: 0xb7, B: 0x79, A: 0xff},
|
||||||
drawing.Color{R: 0x35, G: 0xb7, B: 0x79, A: 0xff},
|
{R: 0x35, G: 0xb7, B: 0x79, A: 0xff},
|
||||||
drawing.Color{R: 0x36, G: 0xb8, B: 0x78, A: 0xff},
|
{R: 0x36, G: 0xb8, B: 0x78, A: 0xff},
|
||||||
drawing.Color{R: 0x38, G: 0xb9, B: 0x77, A: 0xff},
|
{R: 0x38, G: 0xb9, B: 0x77, A: 0xff},
|
||||||
drawing.Color{R: 0x39, G: 0xba, B: 0x76, A: 0xff},
|
{R: 0x39, G: 0xba, B: 0x76, A: 0xff},
|
||||||
drawing.Color{R: 0x3b, G: 0xbb, B: 0x75, A: 0xff},
|
{R: 0x3b, G: 0xbb, B: 0x75, A: 0xff},
|
||||||
drawing.Color{R: 0x3d, G: 0xbc, B: 0x74, A: 0xff},
|
{R: 0x3d, G: 0xbc, B: 0x74, A: 0xff},
|
||||||
drawing.Color{R: 0x3e, G: 0xbd, B: 0x73, A: 0xff},
|
{R: 0x3e, G: 0xbd, B: 0x73, A: 0xff},
|
||||||
drawing.Color{R: 0x40, G: 0xbe, B: 0x72, A: 0xff},
|
{R: 0x40, G: 0xbe, B: 0x72, A: 0xff},
|
||||||
drawing.Color{R: 0x42, G: 0xbe, B: 0x71, A: 0xff},
|
{R: 0x42, G: 0xbe, B: 0x71, A: 0xff},
|
||||||
drawing.Color{R: 0x44, G: 0xbf, B: 0x70, A: 0xff},
|
{R: 0x44, G: 0xbf, B: 0x70, A: 0xff},
|
||||||
drawing.Color{R: 0x46, G: 0xc0, B: 0x6f, A: 0xff},
|
{R: 0x46, G: 0xc0, B: 0x6f, A: 0xff},
|
||||||
drawing.Color{R: 0x48, G: 0xc1, B: 0x6e, A: 0xff},
|
{R: 0x48, G: 0xc1, B: 0x6e, A: 0xff},
|
||||||
drawing.Color{R: 0x49, G: 0xc2, B: 0x6d, A: 0xff},
|
{R: 0x49, G: 0xc2, B: 0x6d, A: 0xff},
|
||||||
drawing.Color{R: 0x4b, G: 0xc2, B: 0x6c, A: 0xff},
|
{R: 0x4b, G: 0xc2, B: 0x6c, A: 0xff},
|
||||||
drawing.Color{R: 0x4d, G: 0xc3, B: 0x6b, A: 0xff},
|
{R: 0x4d, G: 0xc3, B: 0x6b, A: 0xff},
|
||||||
drawing.Color{R: 0x4f, G: 0xc4, B: 0x6a, A: 0xff},
|
{R: 0x4f, G: 0xc4, B: 0x6a, A: 0xff},
|
||||||
drawing.Color{R: 0x51, G: 0xc5, B: 0x69, A: 0xff},
|
{R: 0x51, G: 0xc5, B: 0x69, A: 0xff},
|
||||||
drawing.Color{R: 0x53, G: 0xc6, B: 0x68, A: 0xff},
|
{R: 0x53, G: 0xc6, B: 0x68, A: 0xff},
|
||||||
drawing.Color{R: 0x55, G: 0xc6, B: 0x66, A: 0xff},
|
{R: 0x55, G: 0xc6, B: 0x66, A: 0xff},
|
||||||
drawing.Color{R: 0x58, G: 0xc7, B: 0x65, A: 0xff},
|
{R: 0x58, G: 0xc7, B: 0x65, A: 0xff},
|
||||||
drawing.Color{R: 0x5a, G: 0xc8, B: 0x64, A: 0xff},
|
{R: 0x5a, G: 0xc8, B: 0x64, A: 0xff},
|
||||||
drawing.Color{R: 0x5c, G: 0xc9, B: 0x63, A: 0xff},
|
{R: 0x5c, G: 0xc9, B: 0x63, A: 0xff},
|
||||||
drawing.Color{R: 0x5e, G: 0xc9, B: 0x62, A: 0xff},
|
{R: 0x5e, G: 0xc9, B: 0x62, A: 0xff},
|
||||||
drawing.Color{R: 0x60, G: 0xca, B: 0x60, A: 0xff},
|
{R: 0x60, G: 0xca, B: 0x60, A: 0xff},
|
||||||
drawing.Color{R: 0x62, G: 0xcb, B: 0x5f, A: 0xff},
|
{R: 0x62, G: 0xcb, B: 0x5f, A: 0xff},
|
||||||
drawing.Color{R: 0x65, G: 0xcc, B: 0x5e, A: 0xff},
|
{R: 0x65, G: 0xcc, B: 0x5e, A: 0xff},
|
||||||
drawing.Color{R: 0x67, G: 0xcc, B: 0x5c, A: 0xff},
|
{R: 0x67, G: 0xcc, B: 0x5c, A: 0xff},
|
||||||
drawing.Color{R: 0x69, G: 0xcd, B: 0x5b, A: 0xff},
|
{R: 0x69, G: 0xcd, B: 0x5b, A: 0xff},
|
||||||
drawing.Color{R: 0x6c, G: 0xce, B: 0x5a, A: 0xff},
|
{R: 0x6c, G: 0xce, B: 0x5a, A: 0xff},
|
||||||
drawing.Color{R: 0x6e, G: 0xce, B: 0x58, A: 0xff},
|
{R: 0x6e, G: 0xce, B: 0x58, A: 0xff},
|
||||||
drawing.Color{R: 0x70, G: 0xcf, B: 0x57, A: 0xff},
|
{R: 0x70, G: 0xcf, B: 0x57, A: 0xff},
|
||||||
drawing.Color{R: 0x73, G: 0xd0, B: 0x55, A: 0xff},
|
{R: 0x73, G: 0xd0, B: 0x55, A: 0xff},
|
||||||
drawing.Color{R: 0x75, G: 0xd0, B: 0x54, A: 0xff},
|
{R: 0x75, G: 0xd0, B: 0x54, A: 0xff},
|
||||||
drawing.Color{R: 0x77, G: 0xd1, B: 0x52, A: 0xff},
|
{R: 0x77, G: 0xd1, B: 0x52, A: 0xff},
|
||||||
drawing.Color{R: 0x7a, G: 0xd2, B: 0x51, A: 0xff},
|
{R: 0x7a, G: 0xd2, B: 0x51, A: 0xff},
|
||||||
drawing.Color{R: 0x7c, G: 0xd2, B: 0x4f, A: 0xff},
|
{R: 0x7c, G: 0xd2, B: 0x4f, A: 0xff},
|
||||||
drawing.Color{R: 0x7f, G: 0xd3, B: 0x4e, A: 0xff},
|
{R: 0x7f, G: 0xd3, B: 0x4e, A: 0xff},
|
||||||
drawing.Color{R: 0x81, G: 0xd4, B: 0x4c, A: 0xff},
|
{R: 0x81, G: 0xd4, B: 0x4c, A: 0xff},
|
||||||
drawing.Color{R: 0x84, G: 0xd4, B: 0x4b, A: 0xff},
|
{R: 0x84, G: 0xd4, B: 0x4b, A: 0xff},
|
||||||
drawing.Color{R: 0x86, G: 0xd5, B: 0x49, A: 0xff},
|
{R: 0x86, G: 0xd5, B: 0x49, A: 0xff},
|
||||||
drawing.Color{R: 0x89, G: 0xd5, B: 0x48, A: 0xff},
|
{R: 0x89, G: 0xd5, B: 0x48, A: 0xff},
|
||||||
drawing.Color{R: 0x8b, G: 0xd6, B: 0x46, A: 0xff},
|
{R: 0x8b, G: 0xd6, B: 0x46, A: 0xff},
|
||||||
drawing.Color{R: 0x8e, G: 0xd7, B: 0x44, A: 0xff},
|
{R: 0x8e, G: 0xd7, B: 0x44, A: 0xff},
|
||||||
drawing.Color{R: 0x90, G: 0xd7, B: 0x43, A: 0xff},
|
{R: 0x90, G: 0xd7, B: 0x43, A: 0xff},
|
||||||
drawing.Color{R: 0x93, G: 0xd8, B: 0x41, A: 0xff},
|
{R: 0x93, G: 0xd8, B: 0x41, A: 0xff},
|
||||||
drawing.Color{R: 0x95, G: 0xd8, B: 0x3f, A: 0xff},
|
{R: 0x95, G: 0xd8, B: 0x3f, A: 0xff},
|
||||||
drawing.Color{R: 0x98, G: 0xd9, B: 0x3e, A: 0xff},
|
{R: 0x98, G: 0xd9, B: 0x3e, A: 0xff},
|
||||||
drawing.Color{R: 0x9b, G: 0xd9, B: 0x3c, A: 0xff},
|
{R: 0x9b, G: 0xd9, B: 0x3c, A: 0xff},
|
||||||
drawing.Color{R: 0x9d, G: 0xda, B: 0x3a, A: 0xff},
|
{R: 0x9d, G: 0xda, B: 0x3a, A: 0xff},
|
||||||
drawing.Color{R: 0xa0, G: 0xda, B: 0x39, A: 0xff},
|
{R: 0xa0, G: 0xda, B: 0x39, A: 0xff},
|
||||||
drawing.Color{R: 0xa3, G: 0xdb, B: 0x37, A: 0xff},
|
{R: 0xa3, G: 0xdb, B: 0x37, A: 0xff},
|
||||||
drawing.Color{R: 0xa5, G: 0xdb, B: 0x35, A: 0xff},
|
{R: 0xa5, G: 0xdb, B: 0x35, A: 0xff},
|
||||||
drawing.Color{R: 0xa8, G: 0xdc, B: 0x33, A: 0xff},
|
{R: 0xa8, G: 0xdc, B: 0x33, A: 0xff},
|
||||||
drawing.Color{R: 0xab, G: 0xdc, B: 0x32, A: 0xff},
|
{R: 0xab, G: 0xdc, B: 0x32, A: 0xff},
|
||||||
drawing.Color{R: 0xad, G: 0xdd, B: 0x30, A: 0xff},
|
{R: 0xad, G: 0xdd, B: 0x30, A: 0xff},
|
||||||
drawing.Color{R: 0xb0, G: 0xdd, B: 0x2e, A: 0xff},
|
{R: 0xb0, G: 0xdd, B: 0x2e, A: 0xff},
|
||||||
drawing.Color{R: 0xb3, G: 0xdd, B: 0x2d, A: 0xff},
|
{R: 0xb3, G: 0xdd, B: 0x2d, A: 0xff},
|
||||||
drawing.Color{R: 0xb5, G: 0xde, B: 0x2b, A: 0xff},
|
{R: 0xb5, G: 0xde, B: 0x2b, A: 0xff},
|
||||||
drawing.Color{R: 0xb8, G: 0xde, B: 0x29, A: 0xff},
|
{R: 0xb8, G: 0xde, B: 0x29, A: 0xff},
|
||||||
drawing.Color{R: 0xbb, G: 0xdf, B: 0x27, A: 0xff},
|
{R: 0xbb, G: 0xdf, B: 0x27, A: 0xff},
|
||||||
drawing.Color{R: 0xbd, G: 0xdf, B: 0x26, A: 0xff},
|
{R: 0xbd, G: 0xdf, B: 0x26, A: 0xff},
|
||||||
drawing.Color{R: 0xc0, G: 0xdf, B: 0x24, A: 0xff},
|
{R: 0xc0, G: 0xdf, B: 0x24, A: 0xff},
|
||||||
drawing.Color{R: 0xc3, G: 0xe0, B: 0x23, A: 0xff},
|
{R: 0xc3, G: 0xe0, B: 0x23, A: 0xff},
|
||||||
drawing.Color{R: 0xc5, G: 0xe0, B: 0x21, A: 0xff},
|
{R: 0xc5, G: 0xe0, B: 0x21, A: 0xff},
|
||||||
drawing.Color{R: 0xc8, G: 0xe1, B: 0x20, A: 0xff},
|
{R: 0xc8, G: 0xe1, B: 0x20, A: 0xff},
|
||||||
drawing.Color{R: 0xcb, G: 0xe1, B: 0x1e, A: 0xff},
|
{R: 0xcb, G: 0xe1, B: 0x1e, A: 0xff},
|
||||||
drawing.Color{R: 0xcd, G: 0xe1, B: 0x1d, A: 0xff},
|
{R: 0xcd, G: 0xe1, B: 0x1d, A: 0xff},
|
||||||
drawing.Color{R: 0xd0, G: 0xe2, B: 0x1c, A: 0xff},
|
{R: 0xd0, G: 0xe2, B: 0x1c, A: 0xff},
|
||||||
drawing.Color{R: 0xd3, G: 0xe2, B: 0x1b, A: 0xff},
|
{R: 0xd3, G: 0xe2, B: 0x1b, A: 0xff},
|
||||||
drawing.Color{R: 0xd5, G: 0xe2, B: 0x1a, A: 0xff},
|
{R: 0xd5, G: 0xe2, B: 0x1a, A: 0xff},
|
||||||
drawing.Color{R: 0xd8, G: 0xe3, B: 0x19, A: 0xff},
|
{R: 0xd8, G: 0xe3, B: 0x19, A: 0xff},
|
||||||
drawing.Color{R: 0xdb, G: 0xe3, B: 0x18, A: 0xff},
|
{R: 0xdb, G: 0xe3, B: 0x18, A: 0xff},
|
||||||
drawing.Color{R: 0xdd, G: 0xe3, B: 0x18, A: 0xff},
|
{R: 0xdd, G: 0xe3, B: 0x18, A: 0xff},
|
||||||
drawing.Color{R: 0xe0, G: 0xe4, B: 0x18, A: 0xff},
|
{R: 0xe0, G: 0xe4, B: 0x18, A: 0xff},
|
||||||
drawing.Color{R: 0xe2, G: 0xe4, B: 0x18, A: 0xff},
|
{R: 0xe2, G: 0xe4, B: 0x18, A: 0xff},
|
||||||
drawing.Color{R: 0xe5, G: 0xe4, B: 0x18, A: 0xff},
|
{R: 0xe5, G: 0xe4, B: 0x18, A: 0xff},
|
||||||
drawing.Color{R: 0xe8, G: 0xe5, B: 0x19, A: 0xff},
|
{R: 0xe8, G: 0xe5, B: 0x19, A: 0xff},
|
||||||
drawing.Color{R: 0xea, G: 0xe5, B: 0x19, A: 0xff},
|
{R: 0xea, G: 0xe5, B: 0x19, A: 0xff},
|
||||||
drawing.Color{R: 0xed, G: 0xe5, B: 0x1a, A: 0xff},
|
{R: 0xed, G: 0xe5, B: 0x1a, A: 0xff},
|
||||||
drawing.Color{R: 0xef, G: 0xe6, B: 0x1b, A: 0xff},
|
{R: 0xef, G: 0xe6, B: 0x1b, A: 0xff},
|
||||||
drawing.Color{R: 0xf2, G: 0xe6, B: 0x1c, A: 0xff},
|
{R: 0xf2, G: 0xe6, B: 0x1c, A: 0xff},
|
||||||
drawing.Color{R: 0xf4, G: 0xe6, B: 0x1e, A: 0xff},
|
{R: 0xf4, G: 0xe6, B: 0x1e, A: 0xff},
|
||||||
drawing.Color{R: 0xf7, G: 0xe6, B: 0x1f, A: 0xff},
|
{R: 0xf7, G: 0xe6, B: 0x1f, A: 0xff},
|
||||||
drawing.Color{R: 0xf9, G: 0xe7, B: 0x21, A: 0xff},
|
{R: 0xf9, G: 0xe7, B: 0x21, A: 0xff},
|
||||||
drawing.Color{R: 0xfb, G: 0xe7, B: 0x23, A: 0xff},
|
{R: 0xfb, G: 0xe7, B: 0x23, A: 0xff},
|
||||||
drawing.Color{R: 0xfe, G: 0xe7, B: 0x24, A: 0xff},
|
{R: 0xfe, G: 0xe7, B: 0x24, A: 0xff},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viridis creates a color map provider.
|
// Viridis creates a color map provider.
|
||||||
|
|
10
xaxis.go
10
xaxis.go
|
@ -110,9 +110,9 @@ func (xa XAxis) Measure(r Renderer, canvasBox Box, ra Range, defaults Style, tic
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
left = MinInt(left, ltx)
|
left = Min(left, ltx)
|
||||||
right = MaxInt(right, rtx)
|
right = Max(right, rtx)
|
||||||
bottom = MaxInt(bottom, ty)
|
bottom = Max(bottom, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !xa.NameStyle.Hidden && len(xa.Name) > 0 {
|
if !xa.NameStyle.Hidden && len(xa.Name) > 0 {
|
||||||
|
@ -164,7 +164,7 @@ func (xa XAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick
|
||||||
ty = canvasBox.Bottom + (2 * DefaultXAxisMargin)
|
ty = canvasBox.Bottom + (2 * DefaultXAxisMargin)
|
||||||
}
|
}
|
||||||
Draw.Text(r, t.Label, tx, ty, tickWithAxisStyle)
|
Draw.Text(r, t.Label, tx, ty, tickWithAxisStyle)
|
||||||
maxTextHeight = MaxInt(maxTextHeight, tb.Height())
|
maxTextHeight = Max(maxTextHeight, tb.Height())
|
||||||
break
|
break
|
||||||
case TickPositionBetweenTicks:
|
case TickPositionBetweenTicks:
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
|
@ -180,7 +180,7 @@ func (xa XAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick
|
||||||
}, finalTickStyle)
|
}, finalTickStyle)
|
||||||
|
|
||||||
ftb := Text.MeasureLines(r, Text.WrapFit(r, t.Label, tx-ltx, finalTickStyle), finalTickStyle)
|
ftb := Text.MeasureLines(r, Text.WrapFit(r, t.Label, tx-ltx, finalTickStyle), finalTickStyle)
|
||||||
maxTextHeight = MaxInt(maxTextHeight, ftb.Height())
|
maxTextHeight = Max(maxTextHeight, ftb.Height())
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
12
yaxis.go
12
yaxis.go
|
@ -110,18 +110,18 @@ func (ya YAxis) Measure(r Renderer, canvasBox Box, ra Range, defaults Style, tic
|
||||||
finalTextX = tx - tb.Width()
|
finalTextX = tx - tb.Width()
|
||||||
}
|
}
|
||||||
|
|
||||||
maxTextHeight = MaxInt(tb.Height(), maxTextHeight)
|
maxTextHeight = Max(tb.Height(), maxTextHeight)
|
||||||
|
|
||||||
if ya.AxisType == YAxisPrimary {
|
if ya.AxisType == YAxisPrimary {
|
||||||
minx = canvasBox.Right
|
minx = canvasBox.Right
|
||||||
maxx = MaxInt(maxx, tx+tb.Width())
|
maxx = Max(maxx, tx+tb.Width())
|
||||||
} else if ya.AxisType == YAxisSecondary {
|
} else if ya.AxisType == YAxisSecondary {
|
||||||
minx = MinInt(minx, finalTextX)
|
minx = Min(minx, finalTextX)
|
||||||
maxx = MaxInt(maxx, tx)
|
maxx = Max(maxx, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
miny = MinInt(miny, ly-tbh2)
|
miny = Min(miny, ly-tbh2)
|
||||||
maxy = MaxInt(maxy, ly+tbh2)
|
maxy = Max(maxy, ly+tbh2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ya.NameStyle.Hidden && len(ya.Name) > 0 {
|
if !ya.NameStyle.Hidden && len(ya.Name) > 0 {
|
||||||
|
|
Loading…
Reference in a new issue