Compare commits
2 commits
main
...
will/go1.1
Author | SHA1 | Date | |
---|---|---|---|
|
f23b63bae4 | ||
|
db4dcecf1f |
14
.circleci/config.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
working_directory: /go/src/github.com/wcharczuk/go-chart
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.15
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: new-install
|
||||||
|
command: make new-install
|
||||||
|
- run:
|
||||||
|
name: Continuous Integration
|
||||||
|
command: make
|
33
.github/workflows/ci.yml
vendored
|
@ -1,33 +0,0 @@
|
||||||
name: "Continuous Integration"
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
paths: [ "*.go" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
paths: [ "*.go" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
name: "Tests"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
env:
|
|
||||||
GOOS: "linux"
|
|
||||||
GOARCH: "amd64"
|
|
||||||
GO111MODULE: "on"
|
|
||||||
CGO_ENABLED: "0"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: 1.21
|
|
||||||
|
|
||||||
- name: Check out go-incr
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Run all tests
|
|
||||||
run: go test ./...
|
|
3
.gitignore
vendored
|
@ -16,5 +16,4 @@
|
||||||
# Other
|
# Other
|
||||||
.vscode
|
.vscode
|
||||||
.DS_Store
|
.DS_Store
|
||||||
coverage.html
|
coverage.html
|
||||||
.idea
|
|
1
LICENSE
|
@ -1,7 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2016 William Charczuk.
|
Copyright (c) 2016 William Charczuk.
|
||||||
Copyright (c) 2024 Zeni Kim.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
21
README.md
|
@ -1,9 +1,8 @@
|
||||||
go-chart
|
go-chart
|
||||||
========
|
========
|
||||||
|
[![CircleCI](https://circleci.com/gh/wcharczuk/go-chart.svg?style=svg)](https://circleci.com/gh/wcharczuk/go-chart) [![Go Report Card](https://goreportcard.com/badge/github.com/wcharczuk/go-chart)](https://goreportcard.com/report/github.com/wcharczuk/go-chart)
|
||||||
|
|
||||||
This project starts from a full copy from [https://git.smarteching.com/zeni/go-chart](https://git.smarteching.com/zeni/go-chart). 28 Oct 2024.
|
Package `chart` is a very simple golang native charting library that supports timeseries and continuous line charts.
|
||||||
|
|
||||||
-
|
|
||||||
|
|
||||||
Master should now be on the v3.x codebase, which overhauls the api significantly. Per usual, see `examples` for more information.
|
Master should now be on the v3.x codebase, which overhauls the api significantly. Per usual, see `examples` for more information.
|
||||||
|
|
||||||
|
@ -12,7 +11,7 @@ Master should now be on the v3.x codebase, which overhauls the api significantly
|
||||||
To install `chart` run the following:
|
To install `chart` run the following:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> go get git.smarteching.com/zeni/go-chart/v2@latest
|
> go get -u github.com/wcharczuk/go-chart
|
||||||
```
|
```
|
||||||
|
|
||||||
Most of the components are interchangeable so feel free to crib whatever you want.
|
Most of the components are interchangeable so feel free to crib whatever you want.
|
||||||
|
@ -21,27 +20,27 @@ Most of the components are interchangeable so feel free to crib whatever you wan
|
||||||
|
|
||||||
Spark Lines:
|
Spark Lines:
|
||||||
|
|
||||||
![](https://git.smarteching.com/zeni/go-chart/raw/branch/main/_images/tvix_ltm.png)
|
![](https://raw.githubusercontent.com/wcharczuk/go-chart/master/_images/tvix_ltm.png)
|
||||||
|
|
||||||
Single axis:
|
Single axis:
|
||||||
|
|
||||||
![](https://git.smarteching.com/zeni/go-chart/raw/branch/main/_images/goog_ltm.png)
|
![](https://raw.githubusercontent.com/wcharczuk/go-chart/master/_images/goog_ltm.png)
|
||||||
|
|
||||||
Two axis:
|
Two axis:
|
||||||
|
|
||||||
![](https://git.smarteching.com/zeni/go-chart/raw/branch/main/_images/two_axis.png)
|
![](https://raw.githubusercontent.com/wcharczuk/go-chart/master/_images/two_axis.png)
|
||||||
|
|
||||||
# Other Chart Types
|
# Other Chart Types
|
||||||
|
|
||||||
Pie Chart:
|
Pie Chart:
|
||||||
|
|
||||||
![](https://git.smarteching.com/zeni/go-chart/raw/branch/main/_images/pie_chart.png)
|
![](https://raw.githubusercontent.com/wcharczuk/go-chart/master/_images/pie_chart.png)
|
||||||
|
|
||||||
The code for this chart can be found in `examples/pie_chart/main.go`.
|
The code for this chart can be found in `examples/pie_chart/main.go`.
|
||||||
|
|
||||||
Stacked Bar:
|
Stacked Bar:
|
||||||
|
|
||||||
![](https://git.smarteching.com/zeni/go-chart/raw/branch/main/_images/stacked_bar.png)
|
![](https://raw.githubusercontent.com/wcharczuk/go-chart/master/_images/stacked_bar.png)
|
||||||
|
|
||||||
The code for this chart can be found in `examples/stacked_bar/main.go`.
|
The code for this chart can be found in `examples/stacked_bar/main.go`.
|
||||||
|
|
||||||
|
@ -49,8 +48,6 @@ The code for this chart can be found in `examples/stacked_bar/main.go`.
|
||||||
|
|
||||||
Actual chart configurations and examples can be found in the `./examples/` directory. They are simple CLI programs that write to `output.png` (they are also updated with `go generate`.
|
Actual chart configurations and examples can be found in the `./examples/` directory. They are simple CLI programs that write to `output.png` (they are also updated with `go generate`.
|
||||||
|
|
||||||
If folder ends in "web", has web servers, so start them with `go run main.go` then access `http://localhost:8080` to see the output.
|
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
Everything starts with the `chart.Chart` object. The bare minimum to draw a chart would be the following:
|
Everything starts with the `chart.Chart` object. The bare minimum to draw a chart would be the following:
|
||||||
|
@ -61,7 +58,7 @@ import (
|
||||||
...
|
...
|
||||||
"bytes"
|
"bytes"
|
||||||
...
|
...
|
||||||
"git.smarteching.com/zeni/go-chart/v2" //exposes "chart"
|
"github.com/wcharczuk/go-chart" //exposes "chart"
|
||||||
)
|
)
|
||||||
|
|
||||||
graph := chart.Chart{
|
graph := chart.Chart{
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
aliceblue #f0f8ff 240,248,255
|
|
||||||
antiquewhite #faebd7 250,235,215
|
|
||||||
aqua #00ffff 0,255,255
|
|
||||||
aquamarine #7fffd4 127,255,212
|
|
||||||
azure #f0ffff 240,255,255
|
|
||||||
beige #f5f5dc 245,245,220
|
|
||||||
bisque #ffe4c4 255,228,196
|
|
||||||
black #000000 0,0,0
|
|
||||||
blanchedalmond #ffebcd 255,235,205
|
|
||||||
blue #0000ff 0,0,255
|
|
||||||
blueviolet #8a2be2 138,43,226
|
|
||||||
brown #a52a2a 165,42,42
|
|
||||||
burlywood #deb887 222,184,135
|
|
||||||
cadetblue #5f9ea0 95,158,160
|
|
||||||
chartreuse #7fff00 127,255,0
|
|
||||||
chocolate #d2691e 210,105,30
|
|
||||||
coral #ff7f50 255,127,80
|
|
||||||
cornflowerblue #6495ed 100,149,237
|
|
||||||
cornsilk #fff8dc 255,248,220
|
|
||||||
crimson #dc143c 220,20,60
|
|
||||||
cyan #00ffff 0,255,255
|
|
||||||
darkblue #00008b 0,0,139
|
|
||||||
darkcyan #008b8b 0,139,139
|
|
||||||
darkgoldenrod #b8860b 184,134,11
|
|
||||||
darkgray #a9a9a9 169,169,169
|
|
||||||
darkgreen #006400 0,100,0
|
|
||||||
darkgrey #a9a9a9 169,169,169
|
|
||||||
darkkhaki #bdb76b 189,183,107
|
|
||||||
darkmagenta #8b008b 139,0,139
|
|
||||||
darkolivegreen #556b2f 85,107,47
|
|
||||||
darkorange #ff8c00 255,140,0
|
|
||||||
darkorchid #9932cc 153,50,204
|
|
||||||
darkred #8b0000 139,0,0
|
|
||||||
darksalmon #e9967a 233,150,122
|
|
||||||
darkseagreen #8fbc8f 143,188,143
|
|
||||||
darkslateblue #483d8b 72,61,139
|
|
||||||
darkslategray #2f4f4f 47,79,79
|
|
||||||
darkslategrey #2f4f4f 47,79,79
|
|
||||||
darkturquoise #00ced1 0,206,209
|
|
||||||
darkviolet #9400d3 148,0,211
|
|
||||||
deeppink #ff1493 255,20,147
|
|
||||||
deepskyblue #00bfff 0,191,255
|
|
||||||
dimgray #696969 105,105,105
|
|
||||||
dimgrey #696969 105,105,105
|
|
||||||
dodgerblue #1e90ff 30,144,255
|
|
||||||
firebrick #b22222 178,34,34
|
|
||||||
floralwhite #fffaf0 255,250,240
|
|
||||||
forestgreen #228b22 34,139,34
|
|
||||||
fuchsia #ff00ff 255,0,255
|
|
||||||
gainsboro #dcdcdc 220,220,220
|
|
||||||
ghostwhite #f8f8ff 248,248,255
|
|
||||||
gold #ffd700 255,215,0
|
|
||||||
goldenrod #daa520 218,165,32
|
|
||||||
gray #808080 128,128,128
|
|
||||||
green #008000 0,128,0
|
|
||||||
greenyellow #adff2f 173,255,47
|
|
||||||
grey #808080 128,128,128
|
|
||||||
honeydew #f0fff0 240,255,240
|
|
||||||
hotpink #ff69b4 255,105,180
|
|
||||||
indianred #cd5c5c 205,92,92
|
|
||||||
indigo #4b0082 75,0,130
|
|
||||||
ivory #fffff0 255,255,240
|
|
||||||
khaki #f0e68c 240,230,140
|
|
||||||
lavender #e6e6fa 230,230,250
|
|
||||||
lavenderblush #fff0f5 255,240,245
|
|
||||||
lawngreen #7cfc00 124,252,0
|
|
||||||
lemonchiffon #fffacd 255,250,205
|
|
||||||
lightblue #add8e6 173,216,230
|
|
||||||
lightcoral #f08080 240,128,128
|
|
||||||
lightcyan #e0ffff 224,255,255
|
|
||||||
lightgoldenrodyellow #fafad2 250,250,210
|
|
||||||
lightgray #d3d3d3 211,211,211
|
|
||||||
lightgreen #90ee90 144,238,144
|
|
||||||
lightgrey #d3d3d3 211,211,211
|
|
||||||
lightpink #ffb6c1 255,182,193
|
|
||||||
lightsalmon #ffa07a 255,160,122
|
|
||||||
lightseagreen #20b2aa 32,178,170
|
|
||||||
lightskyblue #87cefa 135,206,250
|
|
||||||
lightslategray #778899 119,136,153
|
|
||||||
lightslategrey #778899 119,136,153
|
|
||||||
lightsteelblue #b0c4de 176,196,222
|
|
||||||
lightyellow #ffffe0 255,255,224
|
|
||||||
lime #00ff00 0,255,0
|
|
||||||
limegreen #32cd32 50,205,50
|
|
||||||
linen #faf0e6 250,240,230
|
|
||||||
magenta #ff00ff 255,0,255
|
|
||||||
maroon #800000 128,0,0
|
|
||||||
mediumaquamarine #66cdaa 102,205,170
|
|
||||||
mediumblue #0000cd 0,0,205
|
|
||||||
mediumorchid #ba55d3 186,85,211
|
|
||||||
mediumpurple #9370db 147,112,219
|
|
||||||
mediumseagreen #3cb371 60,179,113
|
|
||||||
mediumslateblue #7b68ee 123,104,238
|
|
||||||
mediumspringgreen #00fa9a 0,250,154
|
|
||||||
mediumturquoise #48d1cc 72,209,204
|
|
||||||
mediumvioletred #c71585 199,21,133
|
|
||||||
midnightblue #191970 25,25,112
|
|
||||||
mintcream #f5fffa 245,255,250
|
|
||||||
mistyrose #ffe4e1 255,228,225
|
|
||||||
moccasin #ffe4b5 255,228,181
|
|
||||||
navajowhite #ffdead 255,222,173
|
|
||||||
navy #000080 0,0,128
|
|
||||||
oldlace #fdf5e6 253,245,230
|
|
||||||
olive #808000 128,128,0
|
|
||||||
olivedrab #6b8e23 107,142,35
|
|
||||||
orange #ffa500 255,165,0
|
|
||||||
orangered #ff4500 255,69,0
|
|
||||||
orchid #da70d6 218,112,214
|
|
||||||
palegoldenrod #eee8aa 238,232,170
|
|
||||||
palegreen #98fb98 152,251,152
|
|
||||||
paleturquoise #afeeee 175,238,238
|
|
||||||
palevioletred #db7093 219,112,147
|
|
||||||
papayawhip #ffefd5 255,239,213
|
|
||||||
peachpuff #ffdab9 255,218,185
|
|
||||||
peru #cd853f 205,133,63
|
|
||||||
pink #ffc0cb 255,192,203
|
|
||||||
plum #dda0dd 221,160,221
|
|
||||||
powderblue #b0e0e6 176,224,230
|
|
||||||
purple #800080 128,0,128
|
|
||||||
red #ff0000 255,0,0
|
|
||||||
rosybrown #bc8f8f 188,143,143
|
|
||||||
royalblue #4169e1 65,105,225
|
|
||||||
saddlebrown #8b4513 139,69,19
|
|
||||||
salmon #fa8072 250,128,114
|
|
||||||
sandybrown #f4a460 244,164,96
|
|
||||||
seagreen #2e8b57 46,139,87
|
|
||||||
seashell #fff5ee 255,245,238
|
|
||||||
sienna #a0522d 160,82,45
|
|
||||||
silver #c0c0c0 192,192,192
|
|
||||||
skyblue #87ceeb 135,206,235
|
|
||||||
slateblue #6a5acd 106,90,205
|
|
||||||
slategray #708090 112,128,144
|
|
||||||
slategrey #708090 112,128,144
|
|
||||||
snow #fffafa 255,250,250
|
|
||||||
springgreen #00ff7f 0,255,127
|
|
||||||
steelblue #4682b4 70,130,180
|
|
||||||
tan #d2b48c 210,180,140
|
|
||||||
teal #008080 0,128,128
|
|
||||||
thistle #d8bfd8 216,191,216
|
|
||||||
tomato #ff6347 255,99,71
|
|
||||||
turquoise #40e0d0 64,224,208
|
|
||||||
violet #ee82ee 238,130,238
|
|
||||||
wheat #f5deb3 245,222,179
|
|
||||||
white #ffffff 255,255,255
|
|
||||||
whitesmoke #f5f5f5 245,245,245
|
|
||||||
yellow #ffff00 255,255,0
|
|
||||||
yellowgreen #9acd32 154,205,50
|
|
|
@ -3,8 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -23,7 +23,7 @@ func main() {
|
||||||
|
|
||||||
stackedBarChart := chart.StackedBarChart{
|
stackedBarChart := chart.StackedBarChart{
|
||||||
Title: "Quarterly Sales",
|
Title: "Quarterly Sales",
|
||||||
TitleStyle: chart.Shown(),
|
TitleStyle: chart.StyleShow(),
|
||||||
Background: chart.Style{
|
Background: chart.Style{
|
||||||
Padding: chart.Box{
|
Padding: chart.Box{
|
||||||
Top: 75,
|
Top: 75,
|
||||||
|
@ -31,8 +31,8 @@ func main() {
|
||||||
},
|
},
|
||||||
Width: 800,
|
Width: 800,
|
||||||
Height: 600,
|
Height: 600,
|
||||||
XAxis: chart.Shown(),
|
XAxis: chart.StyleShow(),
|
||||||
YAxis: chart.Shown(),
|
YAxis: chart.StyleShow(),
|
||||||
BarSpacing: 40,
|
BarSpacing: 40,
|
||||||
IsHorizontal: true,
|
IsHorizontal: true,
|
||||||
Bars: []chart.StackedBar{
|
Bars: []chart.StackedBar{
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
@ -3,8 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -23,7 +23,7 @@ func main() {
|
||||||
|
|
||||||
stackedBarChart := chart.StackedBarChart{
|
stackedBarChart := chart.StackedBarChart{
|
||||||
Title: "Quarterly Sales",
|
Title: "Quarterly Sales",
|
||||||
TitleStyle: chart.Shown(),
|
TitleStyle: chart.StyleShow(),
|
||||||
Background: chart.Style{
|
Background: chart.Style{
|
||||||
Padding: chart.Box{
|
Padding: chart.Box{
|
||||||
Top: 100,
|
Top: 100,
|
||||||
|
@ -31,8 +31,8 @@ func main() {
|
||||||
},
|
},
|
||||||
Width: 810,
|
Width: 810,
|
||||||
Height: 500,
|
Height: 500,
|
||||||
XAxis: chart.Shown(),
|
XAxis: chart.StyleShow(),
|
||||||
YAxis: chart.Shown(),
|
YAxis: chart.StyleShow(),
|
||||||
BarSpacing: 50,
|
BarSpacing: 50,
|
||||||
Bars: []chart.StackedBar{
|
Bars: []chart.StackedBar{
|
||||||
{
|
{
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
@ -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
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAnnotationSeriesMeasure(t *testing.T) {
|
func TestAnnotationSeriesMeasure(t *testing.T) {
|
||||||
|
|
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]
|
||||||
}
|
}
|
||||||
|
|
31
bar_chart.go
|
@ -264,7 +264,32 @@ func (bc BarChart) drawXAxis(r Renderer, canvasBox Box) {
|
||||||
|
|
||||||
func (bc BarChart) drawYAxis(r Renderer, canvasBox Box, yr Range, ticks []Tick) {
|
func (bc BarChart) drawYAxis(r Renderer, canvasBox Box, yr Range, ticks []Tick) {
|
||||||
if !bc.YAxis.Style.Hidden {
|
if !bc.YAxis.Style.Hidden {
|
||||||
bc.YAxis.Render(r, canvasBox, yr, bc.styleDefaultsAxes(), ticks)
|
axisStyle := bc.YAxis.Style.InheritFrom(bc.styleDefaultsAxes())
|
||||||
|
axisStyle.WriteToRenderer(r)
|
||||||
|
|
||||||
|
r.MoveTo(canvasBox.Right, canvasBox.Top)
|
||||||
|
r.LineTo(canvasBox.Right, canvasBox.Bottom)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
r.MoveTo(canvasBox.Right, canvasBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, canvasBox.Bottom)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
var ty int
|
||||||
|
var tb Box
|
||||||
|
for _, t := range ticks {
|
||||||
|
ty = canvasBox.Bottom - yr.Translate(t.Value)
|
||||||
|
|
||||||
|
axisStyle.GetStrokeOptions().WriteToRenderer(r)
|
||||||
|
r.MoveTo(canvasBox.Right, ty)
|
||||||
|
r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, ty)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
axisStyle.GetTextOptions().WriteToRenderer(r)
|
||||||
|
tb = r.MeasureText(t.Label)
|
||||||
|
Draw.Text(r, t.Label, canvasBox.Right+DefaultYAxisMargin+5, ty+(tb.Height()>>1), axisStyle)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,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 {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBarChartRender(t *testing.T) {
|
func TestBarChartRender(t *testing.T) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBollingerBandSeries(t *testing.T) {
|
func TestBollingerBandSeries(t *testing.T) {
|
||||||
|
|
60
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
|
||||||
}
|
}
|
||||||
|
@ -254,22 +254,6 @@ func (b Box) OuterConstrain(bounds, other Box) Box {
|
||||||
return newBox
|
return newBox
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Box) Validate() error {
|
|
||||||
if b.Left < 0 {
|
|
||||||
return fmt.Errorf("invalid left; must be >= 0")
|
|
||||||
}
|
|
||||||
if b.Right < 0 {
|
|
||||||
return fmt.Errorf("invalid right; must be > 0")
|
|
||||||
}
|
|
||||||
if b.Top < 0 {
|
|
||||||
return fmt.Errorf("invalid top; must be > 0")
|
|
||||||
}
|
|
||||||
if b.Bottom < 0 {
|
|
||||||
return fmt.Errorf("invalid bottom; must be > 0")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoxCorners is a box with independent corners.
|
// BoxCorners is a box with independent corners.
|
||||||
type BoxCorners struct {
|
type BoxCorners struct {
|
||||||
TopLeft, TopRight, BottomRight, BottomLeft Point
|
TopLeft, TopRight, BottomRight, BottomLeft Point
|
||||||
|
@ -278,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
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBoxClone(t *testing.T) {
|
func TestBoxClone(t *testing.T) {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChartGetDPI(t *testing.T) {
|
func TestChartGetDPI(t *testing.T) {
|
||||||
|
@ -573,22 +573,3 @@ func TestChartE2ELineWithFill(t *testing.T) {
|
||||||
testutil.AssertEqual(t, defaultSeriesColor, at(i, 0, 49))
|
testutil.AssertEqual(t, defaultSeriesColor, at(i, 0, 49))
|
||||||
testutil.AssertEqual(t, defaultSeriesColor, at(i, 49, 0))
|
testutil.AssertEqual(t, defaultSeriesColor, at(i, 49, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Chart_cve(t *testing.T) {
|
|
||||||
poc := StackedBarChart{
|
|
||||||
Title: "poc",
|
|
||||||
Bars: []StackedBar{
|
|
||||||
{
|
|
||||||
Name: "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
|
||||||
Values: []Value{
|
|
||||||
{Value: 1, Label: "infinite"},
|
|
||||||
{Value: 1, Label: "loop"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var imgContent bytes.Buffer
|
|
||||||
err := poc.Render(PNG, &imgContent)
|
|
||||||
testutil.AssertNotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import "git.smarteching.com/zeni/go-chart/v2/drawing"
|
import "github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ColorWhite is white.
|
// ColorWhite is white.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConcatSeries(t *testing.T) {
|
func TestConcatSeries(t *testing.T) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRangeTranslate(t *testing.T) {
|
func TestRangeTranslate(t *testing.T) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContinuousSeries(t *testing.T) {
|
func TestContinuousSeries(t *testing.T) {
|
||||||
|
|
|
@ -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,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDonutChart(t *testing.T) {
|
func TestDonutChart(t *testing.T) {
|
||||||
|
|
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()
|
||||||
}
|
}
|
||||||
|
|
162
drawing/color.go
|
@ -2,46 +2,27 @@ package drawing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Basic Colors from:
|
|
||||||
// https://www.w3.org/wiki/CSS/Properties/color/keywords
|
|
||||||
var (
|
var (
|
||||||
// ColorTransparent is a fully transparent color.
|
// ColorTransparent is a fully transparent color.
|
||||||
ColorTransparent = Color{R: 255, G: 255, B: 255, A: 0}
|
ColorTransparent = Color{}
|
||||||
|
|
||||||
// ColorWhite is white.
|
// ColorWhite is white.
|
||||||
ColorWhite = Color{R: 255, G: 255, B: 255, A: 255}
|
ColorWhite = Color{R: 255, G: 255, B: 255, A: 255}
|
||||||
|
|
||||||
// ColorBlack is black.
|
// ColorBlack is black.
|
||||||
ColorBlack = Color{R: 0, G: 0, B: 0, A: 255}
|
ColorBlack = Color{R: 0, G: 0, B: 0, A: 255}
|
||||||
|
|
||||||
// ColorRed is red.
|
// ColorRed is red.
|
||||||
ColorRed = Color{R: 255, G: 0, B: 0, A: 255}
|
ColorRed = Color{R: 255, G: 0, B: 0, A: 255}
|
||||||
|
|
||||||
// ColorGreen is green.
|
// ColorGreen is green.
|
||||||
ColorGreen = Color{R: 0, G: 128, B: 0, A: 255}
|
ColorGreen = Color{R: 0, G: 255, B: 0, A: 255}
|
||||||
|
|
||||||
// ColorBlue is blue.
|
// ColorBlue is blue.
|
||||||
ColorBlue = Color{R: 0, G: 0, B: 255, A: 255}
|
ColorBlue = Color{R: 0, G: 0, B: 255, A: 255}
|
||||||
// ColorSilver is a known color.
|
|
||||||
ColorSilver = Color{R: 192, G: 192, B: 192, A: 255}
|
|
||||||
// ColorMaroon is a known color.
|
|
||||||
ColorMaroon = Color{R: 128, G: 0, B: 0, A: 255}
|
|
||||||
// ColorPurple is a known color.
|
|
||||||
ColorPurple = Color{R: 128, G: 0, B: 128, A: 255}
|
|
||||||
// ColorFuchsia is a known color.
|
|
||||||
ColorFuchsia = Color{R: 255, G: 0, B: 255, A: 255}
|
|
||||||
// ColorLime is a known color.
|
|
||||||
ColorLime = Color{R: 0, G: 255, B: 0, A: 255}
|
|
||||||
// ColorOlive is a known color.
|
|
||||||
ColorOlive = Color{R: 128, G: 128, B: 0, A: 255}
|
|
||||||
// ColorYellow is a known color.
|
|
||||||
ColorYellow = Color{R: 255, G: 255, B: 0, A: 255}
|
|
||||||
// ColorNavy is a known color.
|
|
||||||
ColorNavy = Color{R: 0, G: 0, B: 128, A: 255}
|
|
||||||
// ColorTeal is a known color.
|
|
||||||
ColorTeal = Color{R: 0, G: 128, B: 128, A: 255}
|
|
||||||
// ColorAqua is a known color.
|
|
||||||
ColorAqua = Color{R: 0, G: 255, B: 255, A: 255}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseHex(hex string) uint8 {
|
func parseHex(hex string) uint8 {
|
||||||
|
@ -49,97 +30,8 @@ func parseHex(hex string) uint8 {
|
||||||
return uint8(v)
|
return uint8(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseColor parses a color from a string.
|
|
||||||
func ParseColor(rawColor string) Color {
|
|
||||||
if strings.HasPrefix(rawColor, "rgba") {
|
|
||||||
return ColorFromRGBA(rawColor)
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(rawColor, "rgb") {
|
|
||||||
return ColorFromRGB(rawColor)
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(rawColor, "#") {
|
|
||||||
return ColorFromHex(rawColor)
|
|
||||||
}
|
|
||||||
return ColorFromKnown(rawColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
var rgbaexpr = regexp.MustCompile(`rgba\((?P<R>.+),(?P<G>.+),(?P<B>.+),(?P<A>.+)\)`)
|
|
||||||
|
|
||||||
// ColorFromRGBA returns a color from an `rgba()` css function.
|
|
||||||
func ColorFromRGBA(rgba string) (output Color) {
|
|
||||||
values := rgbaexpr.FindStringSubmatch(rgba)
|
|
||||||
for i, name := range rgbaexpr.SubexpNames() {
|
|
||||||
if i == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if i >= len(values) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
switch name {
|
|
||||||
case "R":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.R = uint8(parsed)
|
|
||||||
case "G":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.G = uint8(parsed)
|
|
||||||
case "B":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.B = uint8(parsed)
|
|
||||||
case "A":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseFloat(value, 32)
|
|
||||||
if parsed > 1 {
|
|
||||||
parsed = 1
|
|
||||||
} else if parsed < 0 {
|
|
||||||
parsed = 0
|
|
||||||
}
|
|
||||||
output.A = uint8(parsed * 255)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var rgbexpr = regexp.MustCompile(`rgb\((?P<R>.+),(?P<G>.+),(?P<B>.+)\)`)
|
|
||||||
|
|
||||||
// ColorFromRGB returns a color from an `rgb()` css function.
|
|
||||||
func ColorFromRGB(rgb string) (output Color) {
|
|
||||||
output.A = 255
|
|
||||||
values := rgbexpr.FindStringSubmatch(rgb)
|
|
||||||
for i, name := range rgbaexpr.SubexpNames() {
|
|
||||||
if i == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if i >= len(values) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
switch name {
|
|
||||||
case "R":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.R = uint8(parsed)
|
|
||||||
case "G":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.G = uint8(parsed)
|
|
||||||
case "B":
|
|
||||||
value := strings.TrimSpace(values[i])
|
|
||||||
parsed, _ := strconv.ParseInt(value, 10, 16)
|
|
||||||
output.B = uint8(parsed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColorFromHex returns a color from a css hex code.
|
// ColorFromHex returns a color from a css hex code.
|
||||||
//
|
|
||||||
// NOTE: it will trim a leading '#' character if present.
|
|
||||||
func ColorFromHex(hex string) Color {
|
func ColorFromHex(hex string) Color {
|
||||||
if strings.HasPrefix(hex, "#") {
|
|
||||||
hex = strings.TrimPrefix(hex, "#")
|
|
||||||
}
|
|
||||||
var c Color
|
var c Color
|
||||||
if len(hex) == 3 {
|
if len(hex) == 3 {
|
||||||
c.R = parseHex(string(hex[0])) * 0x11
|
c.R = parseHex(string(hex[0])) * 0x11
|
||||||
|
@ -154,46 +46,6 @@ func ColorFromHex(hex string) Color {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// ColorFromKnown returns an internal color from a known (basic) color name.
|
|
||||||
func ColorFromKnown(known string) Color {
|
|
||||||
switch strings.ToLower(known) {
|
|
||||||
case "transparent":
|
|
||||||
return ColorTransparent
|
|
||||||
case "white":
|
|
||||||
return ColorWhite
|
|
||||||
case "black":
|
|
||||||
return ColorBlack
|
|
||||||
case "red":
|
|
||||||
return ColorRed
|
|
||||||
case "blue":
|
|
||||||
return ColorBlue
|
|
||||||
case "green":
|
|
||||||
return ColorGreen
|
|
||||||
case "silver":
|
|
||||||
return ColorSilver
|
|
||||||
case "maroon":
|
|
||||||
return ColorMaroon
|
|
||||||
case "purple":
|
|
||||||
return ColorPurple
|
|
||||||
case "fuchsia":
|
|
||||||
return ColorFuchsia
|
|
||||||
case "lime":
|
|
||||||
return ColorLime
|
|
||||||
case "olive":
|
|
||||||
return ColorOlive
|
|
||||||
case "yellow":
|
|
||||||
return ColorYellow
|
|
||||||
case "navy":
|
|
||||||
return ColorNavy
|
|
||||||
case "teal":
|
|
||||||
return ColorTeal
|
|
||||||
case "aqua":
|
|
||||||
return ColorAqua
|
|
||||||
default:
|
|
||||||
return Color{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColorFromAlphaMixedRGBA returns the system alpha mixed rgba values.
|
// ColorFromAlphaMixedRGBA returns the system alpha mixed rgba values.
|
||||||
func ColorFromAlphaMixedRGBA(r, g, b, a uint32) Color {
|
func ColorFromAlphaMixedRGBA(r, g, b, a uint32) Color {
|
||||||
fa := float64(a) / 255.0
|
fa := float64(a) / 255.0
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package drawing
|
package drawing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestColorFromHex(t *testing.T) {
|
func TestColorFromHex(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
white := ColorFromHex("FFFFFF")
|
white := ColorFromHex("FFFFFF")
|
||||||
testutil.AssertEqual(t, ColorWhite, white)
|
testutil.AssertEqual(t, ColorWhite, white)
|
||||||
|
|
||||||
|
@ -28,11 +29,11 @@ func TestColorFromHex(t *testing.T) {
|
||||||
shortRed := ColorFromHex("F00")
|
shortRed := ColorFromHex("F00")
|
||||||
testutil.AssertEqual(t, ColorRed, shortRed)
|
testutil.AssertEqual(t, ColorRed, shortRed)
|
||||||
|
|
||||||
green := ColorFromHex("008000")
|
green := ColorFromHex("00FF00")
|
||||||
testutil.AssertEqual(t, ColorGreen, green)
|
testutil.AssertEqual(t, ColorGreen, green)
|
||||||
|
|
||||||
// shortGreen := ColorFromHex("0F0")
|
shortGreen := ColorFromHex("0F0")
|
||||||
// testutil.AssertEqual(t, ColorGreen, shortGreen)
|
testutil.AssertEqual(t, ColorGreen, shortGreen)
|
||||||
|
|
||||||
blue := ColorFromHex("0000FF")
|
blue := ColorFromHex("0000FF")
|
||||||
testutil.AssertEqual(t, ColorBlue, blue)
|
testutil.AssertEqual(t, ColorBlue, blue)
|
||||||
|
@ -41,74 +42,12 @@ func TestColorFromHex(t *testing.T) {
|
||||||
testutil.AssertEqual(t, ColorBlue, shortBlue)
|
testutil.AssertEqual(t, ColorBlue, shortBlue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColorFromHex_handlesHash(t *testing.T) {
|
|
||||||
withHash := ColorFromHex("#FF0000")
|
|
||||||
testutil.AssertEqual(t, ColorRed, withHash)
|
|
||||||
|
|
||||||
withoutHash := ColorFromHex("#FF0000")
|
|
||||||
testutil.AssertEqual(t, ColorRed, withoutHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorFromAlphaMixedRGBA(t *testing.T) {
|
func TestColorFromAlphaMixedRGBA(t *testing.T) {
|
||||||
|
// replaced new assertions helper
|
||||||
|
|
||||||
black := ColorFromAlphaMixedRGBA(color.Black.RGBA())
|
black := ColorFromAlphaMixedRGBA(color.Black.RGBA())
|
||||||
testutil.AssertTrue(t, black.Equals(ColorBlack), black.String())
|
testutil.AssertTrue(t, black.Equals(ColorBlack), black.String())
|
||||||
|
|
||||||
white := ColorFromAlphaMixedRGBA(color.White.RGBA())
|
white := ColorFromAlphaMixedRGBA(color.White.RGBA())
|
||||||
testutil.AssertTrue(t, white.Equals(ColorWhite), white.String())
|
testutil.AssertTrue(t, white.Equals(ColorWhite), white.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_ColorFromRGBA(t *testing.T) {
|
|
||||||
value := "rgba(192, 192, 192, 1.0)"
|
|
||||||
parsed := ColorFromRGBA(value)
|
|
||||||
testutil.AssertEqual(t, ColorSilver, parsed)
|
|
||||||
|
|
||||||
value = "rgba(192,192,192,1.0)"
|
|
||||||
parsed = ColorFromRGBA(value)
|
|
||||||
testutil.AssertEqual(t, ColorSilver, parsed)
|
|
||||||
|
|
||||||
value = "rgba(192,192,192,1.5)"
|
|
||||||
parsed = ColorFromRGBA(value)
|
|
||||||
testutil.AssertEqual(t, ColorSilver, parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseColor(t *testing.T) {
|
|
||||||
testCases := [...]struct {
|
|
||||||
Input string
|
|
||||||
Expected Color
|
|
||||||
}{
|
|
||||||
{"", Color{}},
|
|
||||||
{"white", ColorWhite},
|
|
||||||
{"WHITE", ColorWhite}, // caps!
|
|
||||||
{"black", ColorBlack},
|
|
||||||
{"red", ColorRed},
|
|
||||||
{"green", ColorGreen},
|
|
||||||
{"blue", ColorBlue},
|
|
||||||
{"silver", ColorSilver},
|
|
||||||
{"maroon", ColorMaroon},
|
|
||||||
{"purple", ColorPurple},
|
|
||||||
{"fuchsia", ColorFuchsia},
|
|
||||||
{"lime", ColorLime},
|
|
||||||
{"olive", ColorOlive},
|
|
||||||
{"yellow", ColorYellow},
|
|
||||||
{"navy", ColorNavy},
|
|
||||||
{"teal", ColorTeal},
|
|
||||||
{"aqua", ColorAqua},
|
|
||||||
|
|
||||||
{"rgba(192, 192, 192, 1.0)", ColorSilver},
|
|
||||||
{"rgba(192,192,192,1.0)", ColorSilver},
|
|
||||||
{"rgb(192, 192, 192)", ColorSilver},
|
|
||||||
{"rgb(192,192,192)", ColorSilver},
|
|
||||||
|
|
||||||
{"#FF0000", ColorRed},
|
|
||||||
{"#008000", ColorGreen},
|
|
||||||
{"#0000FF", ColorBlue},
|
|
||||||
{"#F00", ColorRed},
|
|
||||||
{"#080", Color{0, 136, 0, 255}},
|
|
||||||
{"#00F", ColorBlue},
|
|
||||||
}
|
|
||||||
|
|
||||||
for index, tc := range testCases {
|
|
||||||
actual := ParseColor(tc.Input)
|
|
||||||
testutil.AssertEqual(t, tc.Expected, actual, fmt.Sprintf("test case: %d -> %s", index, tc.Input))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package drawing
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type point struct {
|
type point struct {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
@ -5,8 +5,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
//go:generate go run main.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
|
||||||
graph := chart.BarChart{
|
|
||||||
Title: "Test Bar Chart",
|
|
||||||
Background: chart.Style{
|
|
||||||
Padding: chart.Box{
|
|
||||||
Top: 40,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Height: 512,
|
|
||||||
BarWidth: 60,
|
|
||||||
Bars: []chart.Value{
|
|
||||||
{Value: 5.25, Label: "Blue"},
|
|
||||||
{Value: 4.88, Label: "Green"},
|
|
||||||
{Value: 4.74, Label: "Gray"},
|
|
||||||
{Value: 3.22, Label: "Orange"},
|
|
||||||
{Value: 3, Label: "Test"},
|
|
||||||
{Value: 2.27, Label: "??"},
|
|
||||||
{Value: 1, Label: "!!"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Header().Set("Content-Type", "image/png")
|
|
||||||
err := graph.Render(chart.PNG, res)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error rendering chart: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func port() string {
|
|
||||||
if len(os.Getenv("PORT")) > 0 {
|
|
||||||
return os.Getenv("PORT")
|
|
||||||
}
|
|
||||||
return "8080"
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
listenPort := fmt.Sprintf(":%s", port())
|
|
||||||
fmt.Printf("Listening on %s\n", listenPort)
|
|
||||||
http.HandleFunc("/", drawChart)
|
|
||||||
log.Fatal(http.ListenAndServe(listenPort, nil))
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func random(min, max float64) float64 {
|
func random(min, max float64) float64 {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Note: Additional examples on how to add Stylesheets are in the custom_stylesheets example
|
// Note: Additional examples on how to add Stylesheets are in the custom_stylesheets example
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,8 +5,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -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(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,8 +5,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const style = "svg .background { fill: white; }" +
|
const style = "svg .background { fill: white; }" +
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -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.
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
//go:generate go run main.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
/*
|
|
||||||
In this example we set the primary YAxis to have logarithmic range.
|
|
||||||
*/
|
|
||||||
|
|
||||||
graph := chart.Chart{
|
|
||||||
Background: chart.Style{
|
|
||||||
Padding: chart.Box{
|
|
||||||
Top: 20,
|
|
||||||
Left: 20,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Series: []chart.Series{
|
|
||||||
chart.ContinuousSeries{
|
|
||||||
Name: "A test series",
|
|
||||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
|
||||||
YValues: []float64{1, 10, 100, 1000, 10000},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
YAxis: chart.YAxis{
|
|
||||||
Style: chart.Shown(),
|
|
||||||
NameStyle: chart.Shown(),
|
|
||||||
Range: &chart.LogarithmicRange{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
f, _ := os.Create("output.png")
|
|
||||||
defer f.Close()
|
|
||||||
graph.Render(chart.PNG, f)
|
|
||||||
}
|
|
Before Width: | Height: | Size: 16 KiB |
|
@ -5,14 +5,14 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
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{
|
||||||
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
|
||||||
pie := chart.PieChart{
|
|
||||||
Width: 512,
|
|
||||||
Height: 512,
|
|
||||||
Values: []chart.Value{
|
|
||||||
{Value: 5, Label: "Blue"},
|
|
||||||
{Value: 5, Label: "Green"},
|
|
||||||
{Value: 4, Label: "Gray"},
|
|
||||||
{Value: 4, Label: "Orange"},
|
|
||||||
{Value: 3, Label: "Deep Blue"},
|
|
||||||
{Value: 3, Label: "??"},
|
|
||||||
{Value: 1, Label: "!!"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Header().Set("Content-Type", "image/png")
|
|
||||||
err := pie.Render(chart.PNG, res)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func drawChartRegression(res http.ResponseWriter, req *http.Request) {
|
|
||||||
pie := chart.PieChart{
|
|
||||||
Width: 512,
|
|
||||||
Height: 512,
|
|
||||||
Values: []chart.Value{
|
|
||||||
{Value: 5, Label: "Blue"},
|
|
||||||
{Value: 2, Label: "Two"},
|
|
||||||
{Value: 1, Label: "One"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Header().Set("Content-Type", chart.ContentTypeSVG)
|
|
||||||
err := pie.Render(chart.SVG, res)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/", drawChart)
|
|
||||||
http.HandleFunc("/reg", drawChartRegression)
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -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{
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lock sync.Mutex
|
var lock sync.Mutex
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
|
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -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(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -5,8 +5,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
chart "git.smarteching.com/zeni/go-chart/v2"
|
chart "github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2"
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFirstValueAnnotation(t *testing.T) {
|
func TestFirstValueAnnotation(t *testing.T) {
|
||||||
|
|
2
font.go
|
@ -3,8 +3,8 @@ package chart
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/roboto"
|
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
|
"github.com/wcharczuk/go-chart/v2/roboto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
6
go.mod
|
@ -1,8 +1,8 @@
|
||||||
module git.smarteching.com/zeni/go-chart/v2
|
module github.com/wcharczuk/go-chart/v2
|
||||||
|
|
||||||
go 1.23.1
|
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.21.0
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||||
)
|
)
|
||||||
|
|
6
go.sum
|
@ -1,4 +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.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||||
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
|
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
|
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=
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerateGridLines(t *testing.T) {
|
func TestGenerateGridLines(t *testing.T) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHistogramSeries(t *testing.T) {
|
func TestHistogramSeries(t *testing.T) {
|
||||||
|
|
2
jet.go
|
@ -1,6 +1,6 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import "git.smarteching.com/zeni/go-chart/v2/drawing"
|
import "github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
|
|
||||||
// Jet is a color map provider based on matlab's jet color map.
|
// Jet is a color map provider based on matlab's jet color map.
|
||||||
func Jet(v, vmin, vmax float64) drawing.Color {
|
func Jet(v, vmin, vmax float64) drawing.Color {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLastValueAnnotationSeries(t *testing.T) {
|
func TestLastValueAnnotationSeries(t *testing.T) {
|
||||||
|
|
10
legend.go
|
@ -1,7 +1,7 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Legend returns a legend renderable function.
|
// Legend returns a legend renderable function.
|
||||||
|
@ -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++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLegend(t *testing.T) {
|
func TestLegend(t *testing.T) {
|
||||||
|
|
|
@ -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++ {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLinearRegressionSeries(t *testing.T) {
|
func TestLinearRegressionSeries(t *testing.T) {
|
||||||
|
|
|
@ -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
|
@ -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])
|
||||||
|
}
|
|
@ -1,94 +0,0 @@
|
||||||
package chart
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogarithmicRange represents a boundary for a set of numbers.
|
|
||||||
type LogarithmicRange struct {
|
|
||||||
Min float64
|
|
||||||
Max float64
|
|
||||||
Domain int
|
|
||||||
Descending bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDescending returns if the range is descending.
|
|
||||||
func (r LogarithmicRange) IsDescending() bool {
|
|
||||||
return r.Descending
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsZero returns if the LogarithmicRange has been set or not.
|
|
||||||
func (r LogarithmicRange) IsZero() bool {
|
|
||||||
return (r.Min == 0 || math.IsNaN(r.Min)) &&
|
|
||||||
(r.Max == 0 || math.IsNaN(r.Max)) &&
|
|
||||||
r.Domain == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMin gets the min value for the continuous range.
|
|
||||||
func (r LogarithmicRange) GetMin() float64 {
|
|
||||||
return r.Min
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMin sets the min value for the continuous range.
|
|
||||||
func (r *LogarithmicRange) SetMin(min float64) {
|
|
||||||
r.Min = min
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMax returns the max value for the continuous range.
|
|
||||||
func (r LogarithmicRange) GetMax() float64 {
|
|
||||||
return r.Max
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMax sets the max value for the continuous range.
|
|
||||||
func (r *LogarithmicRange) SetMax(max float64) {
|
|
||||||
r.Max = max
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDelta returns the difference between the min and max value.
|
|
||||||
func (r LogarithmicRange) GetDelta() float64 {
|
|
||||||
return r.Max - r.Min
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDomain returns the range domain.
|
|
||||||
func (r LogarithmicRange) GetDomain() int {
|
|
||||||
return r.Domain
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDomain sets the range domain.
|
|
||||||
func (r *LogarithmicRange) SetDomain(domain int) {
|
|
||||||
r.Domain = domain
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a simple string for the LogarithmicRange.
|
|
||||||
func (r LogarithmicRange) String() string {
|
|
||||||
return fmt.Sprintf("LogarithmicRange [%.2f,%.2f] => %d", r.Min, r.Max, r.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate maps a given value into the LogarithmicRange space. Modified version from ContinuousRange.
|
|
||||||
func (r LogarithmicRange) Translate(value float64) int {
|
|
||||||
if value < 1 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
normalized := math.Max(value-r.Min, 1)
|
|
||||||
ratio := math.Log10(normalized) / math.Log10(r.GetDelta())
|
|
||||||
|
|
||||||
if r.IsDescending() {
|
|
||||||
return r.Domain - int(math.Ceil(ratio*float64(r.Domain)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(math.Ceil(ratio * float64(r.Domain)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTicks calculates the needed ticks for the axis, in log scale. Only supports Y values > 0.
|
|
||||||
func (r LogarithmicRange) GetTicks(render Renderer, defaults Style, vf ValueFormatter) []Tick {
|
|
||||||
var ticks []Tick
|
|
||||||
exponentStart := int64(math.Max(0, math.Floor(math.Log10(r.Min)))) // one below min
|
|
||||||
exponentEnd := int64(math.Max(0, math.Ceil(math.Log10(r.Max)))) // one above max
|
|
||||||
for exp:=exponentStart; exp<=exponentEnd; exp++ {
|
|
||||||
tickVal := math.Pow(10, float64(exp))
|
|
||||||
ticks = append(ticks, Tick{Value: tickVal, Label: vf(tickVal)})
|
|
||||||
}
|
|
||||||
|
|
||||||
return ticks
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package chart
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLogRangeTranslate(t *testing.T) {
|
|
||||||
values := []float64{1, 10, 100, 1000, 10000, 100000, 1000000}
|
|
||||||
r := LogarithmicRange{Domain: 1000}
|
|
||||||
r.Min, r.Max = MinMax(values...)
|
|
||||||
|
|
||||||
testutil.AssertEqual(t, 0, r.Translate(0)) // goes to bottom
|
|
||||||
testutil.AssertEqual(t, 0, r.Translate(1)) // goes to bottom
|
|
||||||
testutil.AssertEqual(t, 160, r.Translate(10)) // roughly 1/6th of max
|
|
||||||
testutil.AssertEqual(t, 500, r.Translate(1000)) // roughly 1/2 of max (1.0e6 / 1.0e3)
|
|
||||||
testutil.AssertEqual(t, 1000, r.Translate(1000000)) // max value
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetTicks(t *testing.T) {
|
|
||||||
values := []float64{35, 512, 1525122}
|
|
||||||
r := LogarithmicRange{Domain: 1000}
|
|
||||||
r.Min, r.Max = MinMax(values...)
|
|
||||||
|
|
||||||
ticks := r.GetTicks(nil, Style{}, FloatValueFormatter)
|
|
||||||
testutil.AssertEqual(t, 7, len(ticks))
|
|
||||||
testutil.AssertEqual(t, 10, ticks[0].Value)
|
|
||||||
testutil.AssertEqual(t, 100, ticks[1].Value)
|
|
||||||
testutil.AssertEqual(t, 10000000, ticks[6].Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetTicksFromHigh(t *testing.T) {
|
|
||||||
values := []float64{1412, 352144, 1525122} // min tick should be 1000
|
|
||||||
r := LogarithmicRange{}
|
|
||||||
r.Min, r.Max = MinMax(values...)
|
|
||||||
|
|
||||||
ticks := r.GetTicks(nil, Style{}, FloatValueFormatter)
|
|
||||||
testutil.AssertEqual(t, 5, len(ticks))
|
|
||||||
testutil.AssertEqual(t, float64(1000), ticks[0].Value)
|
|
||||||
testutil.AssertEqual(t, float64(10000), ticks[1].Value)
|
|
||||||
testutil.AssertEqual(t, float64(10000000), ticks[4].Value)
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
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++ {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package matrix
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package matrix
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPoly(t *testing.T) {
|
func TestPoly(t *testing.T) {
|
||||||
|
|
|
@ -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++ {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPercentageDifferenceSeries(t *testing.T) {
|
func TestPercentageDifferenceSeries(t *testing.T) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPieChart(t *testing.T) {
|
func TestPieChart(t *testing.T) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/matrix"
|
"github.com/wcharczuk/go-chart/v2/matrix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface Assertions.
|
// Interface Assertions.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -3,8 +3,8 @@ package chart
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/matrix"
|
"github.com/wcharczuk/go-chart/v2/matrix"
|
||||||
"git.smarteching.com/zeni/go-chart/v2/testutil"
|
"github.com/wcharczuk/go-chart/v2/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPolynomialRegression(t *testing.T) {
|
func TestPolynomialRegression(t *testing.T) {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PNG returns a new png/raster renderer.
|
// PNG returns a new png/raster renderer.
|
||||||
|
|
|
@ -3,8 +3,8 @@ package chart
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.smarteching.com/zeni/go-chart/v2/drawing"
|
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
|
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Renderer represents the basic methods required to draw a chart.
|
// Renderer represents the basic methods required to draw a chart.
|
||||||
|
|