switching to generators
44
examples/annotations/main.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
In this example we add an `Annotation` series, which is a special type of series that
|
||||
draws annotation labels at given X and Y values (as translated by their respective ranges).
|
||||
|
||||
It is important to not that the chart automatically sizes the canvas box to fit the annotations,
|
||||
As well as automatically assign a series color for the `Stroke` or border component of the series.
|
||||
|
||||
The annotation series is most often used by the original author to show the last value of another series, but
|
||||
they can be used in other capacities as well.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
chart.AnnotationSeries{
|
||||
Annotations: []chart.Value2{
|
||||
{XValue: 1.0, YValue: 1.0, Label: "One"},
|
||||
{XValue: 2.0, YValue: 2.0, Label: "Two"},
|
||||
{XValue: 3.0, YValue: 3.0, Label: "Three"},
|
||||
{XValue: 4.0, YValue: 4.0, Label: "Four"},
|
||||
{XValue: 5.0, YValue: 5.0, Label: "Five"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/annotations/output.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
34
examples/axes/main.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
The below will draw the same chart as the `basic` example, except with both the x and y axes turned on.
|
||||
In this case, both the x and y axis ticks are generated automatically, the x and y ranges are established automatically, the canvas "box" is adjusted to fit the space the axes occupy so as not to clip.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
FillColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
},
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/axes/output.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
40
examples/axes_labels/main.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
The below will draw the same chart as the `basic` example, except with both the x and y axes turned on.
|
||||
In this case, both the x and y axis ticks are generated automatically, the x and y ranges are established automatically, the canvas "box" is adjusted to fit the space the axes occupy so as not to clip.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
XAxis: chart.XAxis{
|
||||
Name: "The XAxis",
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Name: "The YAxis",
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
FillColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
},
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/axes_labels/output.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
35
examples/bar_chart/main.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
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: "!!"},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/bar_chart/output.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
62
examples/bar_chart_base_value/main.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
profitStyle := chart.Style{
|
||||
FillColor: drawing.ColorFromHex("13c158"),
|
||||
StrokeColor: drawing.ColorFromHex("13c158"),
|
||||
StrokeWidth: 0,
|
||||
}
|
||||
|
||||
lossStyle := chart.Style{
|
||||
FillColor: drawing.ColorFromHex("c11313"),
|
||||
StrokeColor: drawing.ColorFromHex("c11313"),
|
||||
StrokeWidth: 0,
|
||||
}
|
||||
|
||||
sbc := chart.BarChart{
|
||||
Title: "Bar Chart Using BaseValue",
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 40,
|
||||
},
|
||||
},
|
||||
Height: 512,
|
||||
BarWidth: 60,
|
||||
YAxis: chart.YAxis{
|
||||
Ticks: []chart.Tick{
|
||||
{Value: -4.0, Label: "-4"},
|
||||
{Value: -2.0, Label: "-2"},
|
||||
{Value: 0, Label: "0"},
|
||||
{Value: 2.0, Label: "2"},
|
||||
{Value: 4.0, Label: "4"},
|
||||
{Value: 6.0, Label: "6"},
|
||||
{Value: 8.0, Label: "8"},
|
||||
{Value: 10.0, Label: "10"},
|
||||
{Value: 12.0, Label: "12"},
|
||||
},
|
||||
},
|
||||
UseBaseValue: true,
|
||||
BaseValue: 0.0,
|
||||
Bars: []chart.Value{
|
||||
{Value: 10.0, Style: profitStyle, Label: "Profit"},
|
||||
{Value: 12.0, Style: profitStyle, Label: "More Profit"},
|
||||
{Value: 8.0, Style: profitStyle, Label: "Still Profit"},
|
||||
{Value: -4.0, Style: lossStyle, Label: "Loss!"},
|
||||
{Value: 3.0, Style: profitStyle, Label: "Phew Ok"},
|
||||
{Value: -2.0, Style: lossStyle, Label: "Oh No!"},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
sbc.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/bar_chart_base_value/output.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
23
examples/basic/main.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/basic/output.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
52
examples/benchmark_line_charts/main.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func random(min, max float64) float64 {
|
||||
return rand.Float64()*(max-min) + min
|
||||
}
|
||||
|
||||
func main() {
|
||||
numValues := 1024
|
||||
numSeries := 100
|
||||
series := make([]chart.Series, numSeries)
|
||||
|
||||
for i := 0; i < numSeries; i++ {
|
||||
xValues := make([]time.Time, numValues)
|
||||
yValues := make([]float64, numValues)
|
||||
|
||||
for j := 0; j < numValues; j++ {
|
||||
xValues[j] = time.Now().AddDate(0, 0, (numValues-j)*-1)
|
||||
yValues[j] = random(float64(-500), float64(500))
|
||||
}
|
||||
|
||||
series[i] = chart.TimeSeries{
|
||||
Name: fmt.Sprintf("aaa.bbb.hostname-%v.ccc.ddd.eee.fff.ggg.hhh.iii.jjj.kkk.lll.mmm.nnn.value", i),
|
||||
XValues: xValues,
|
||||
YValues: yValues,
|
||||
}
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
XAxis: chart.XAxis{
|
||||
Name: "Time",
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Name: "Value",
|
||||
},
|
||||
Series: series,
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/benchmark_line_charts/output.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
59
examples/css_classes/main.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
// Note: Additional examples on how to add Stylesheets are in the custom_stylesheets example
|
||||
|
||||
func inlineSVGWithClasses(res http.ResponseWriter, req *http.Request) {
|
||||
res.Write([]byte(
|
||||
"<!DOCTYPE html><html><head>" +
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/main.css\">" +
|
||||
"</head>" +
|
||||
"<body>"))
|
||||
|
||||
pie := chart.PieChart{
|
||||
// Notes: * Setting ClassName will cause all other inline styles to be dropped!
|
||||
// * The following type classes may be added additionally: stroke, fill, text
|
||||
Background: chart.Style{ClassName: "background"},
|
||||
Canvas: chart.Style{
|
||||
ClassName: "canvas",
|
||||
},
|
||||
Width: 512,
|
||||
Height: 512,
|
||||
Values: []chart.Value{
|
||||
{Value: 5, Label: "Blue", Style: chart.Style{ClassName: "blue"}},
|
||||
{Value: 5, Label: "Green", Style: chart.Style{ClassName: "green"}},
|
||||
{Value: 4, Label: "Gray", Style: chart.Style{ClassName: "gray"}},
|
||||
},
|
||||
}
|
||||
|
||||
err := pie.Render(chart.SVG, res)
|
||||
if err != nil {
|
||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
||||
}
|
||||
res.Write([]byte("</body>"))
|
||||
}
|
||||
|
||||
func css(res http.ResponseWriter, req *http.Request) {
|
||||
res.Header().Set("Content-Type", "text/css")
|
||||
res.Write([]byte("svg .background { fill: white; }" +
|
||||
"svg .canvas { fill: white; }" +
|
||||
"svg .blue.fill.stroke { fill: blue; stroke: lightblue; }" +
|
||||
"svg .green.fill.stroke { fill: green; stroke: lightgreen; }" +
|
||||
"svg .gray.fill.stroke { fill: gray; stroke: lightgray; }" +
|
||||
"svg .blue.text { fill: white; }" +
|
||||
"svg .green.text { fill: white; }" +
|
||||
"svg .gray.text { fill: white; }"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", inlineSVGWithClasses)
|
||||
http.HandleFunc("/main.css", css)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
38
examples/custom_formatters/main.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
In this example we use a custom `ValueFormatter` for the y axis, letting us specify how to format text of the y-axis ticks.
|
||||
You can also do this for the x-axis, or the secondary y-axis.
|
||||
This example also shows what the chart looks like with the x-axis left off or not shown.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
YAxis: chart.YAxis{
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
if vf, isFloat := v.(float64); isFloat {
|
||||
return fmt.Sprintf("%0.6f", vf)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/custom_formatters/output.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
34
examples/custom_padding/main.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
graph := chart.Chart{
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 50,
|
||||
Left: 25,
|
||||
Right: 25,
|
||||
Bottom: 10,
|
||||
},
|
||||
FillColor: drawing.ColorFromHex("efefef"),
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(100).WithMax(512)}.Values(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/custom_padding/output.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
34
examples/custom_ranges/main.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
In this example we set a custom range for the y-axis, overriding the automatic range generation.
|
||||
Note: the chart will still generate the ticks automatically based on the custom range, so the intervals may be a bit weird.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 0.0,
|
||||
Max: 10.0,
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/custom_ranges/output.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
38
examples/custom_styles/main.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
In this example we set some custom colors for the series and the chart background and canvas.
|
||||
*/
|
||||
graph := chart.Chart{
|
||||
Background: chart.Style{
|
||||
FillColor: drawing.ColorBlue,
|
||||
},
|
||||
Canvas: chart.Style{
|
||||
FillColor: drawing.ColorFromHex("efefef"),
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: drawing.ColorRed, // will supercede defaults
|
||||
FillColor: drawing.ColorRed.WithAlpha(64), // will supercede defaults
|
||||
},
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/custom_styles/output.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
21
examples/custom_stylesheets/inlineOutput.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512">\n<style type="text/css"><![CDATA[svg .background { fill: white; }svg .canvas { fill: white; }svg path.blue { fill: blue; stroke: lightblue; }svg path.green { fill: green; stroke: lightgreen; }svg path.gray { fill: gray; stroke: lightgray; }svg text.blue { fill: white; }svg text.green { fill: white; }svg text.gray { fill: white; }]]></style><path d="M 0 0
|
||||
L 512 0
|
||||
L 512 512
|
||||
L 0 512
|
||||
L 0 0" class="background"/><path d="M 5 5
|
||||
L 507 5
|
||||
L 507 507
|
||||
L 5 507
|
||||
L 5 5" class="canvas"/><path d="M 256 256
|
||||
L 507 256
|
||||
A 251 251 128.56 0 1 100 452
|
||||
L 256 256
|
||||
Z" class="blue"/><path d="M 256 256
|
||||
L 100 452
|
||||
A 251 251 128.56 0 1 201 12
|
||||
L 256 256
|
||||
Z" class="green"/><path d="M 256 256
|
||||
L 201 12
|
||||
A 251 251 102.85 0 1 506 256
|
||||
L 256 256
|
||||
Z" class="gray"/><text x="313" y="413" class="blue">Blue</text><text x="73" y="226" class="green">Green</text><text x="344" y="133" class="gray">Gray</text></svg>
|
||||
|
After Width: | Height: | Size: 987 B |
88
examples/custom_stylesheets/main.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
const style = "svg .background { fill: white; }" +
|
||||
"svg .canvas { fill: white; }" +
|
||||
"svg .blue.fill.stroke { fill: blue; stroke: lightblue; }" +
|
||||
"svg .green.fill.stroke { fill: green; stroke: lightgreen; }" +
|
||||
"svg .gray.fill.stroke { fill: gray; stroke: lightgray; }" +
|
||||
"svg .blue.text { fill: white; }" +
|
||||
"svg .green.text { fill: white; }" +
|
||||
"svg .gray.text { fill: white; }"
|
||||
|
||||
func svgWithCustomInlineCSS(res http.ResponseWriter, _ *http.Request) {
|
||||
res.Header().Set("Content-Type", chart.ContentTypeSVG)
|
||||
|
||||
// Render the CSS with custom css
|
||||
err := pieChart().Render(chart.SVGWithCSS(style, ""), res)
|
||||
if err != nil {
|
||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func svgWithCustomInlineCSSNonce(res http.ResponseWriter, _ *http.Request) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
|
||||
// This should be randomly generated on every request!
|
||||
const nonce = "RAND0MBASE64"
|
||||
|
||||
res.Header().Set("Content-Security-Policy", fmt.Sprintf("style-src 'nonce-%s'", nonce))
|
||||
res.Header().Set("Content-Type", chart.ContentTypeSVG)
|
||||
|
||||
// Render the CSS with custom css and a nonce.
|
||||
// Try changing the nonce to a different string - your browser should block the CSS.
|
||||
err := pieChart().Render(chart.SVGWithCSS(style, nonce), res)
|
||||
if err != nil {
|
||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func svgWithCustomExternalCSS(res http.ResponseWriter, _ *http.Request) {
|
||||
// Add external CSS
|
||||
res.Write([]byte(
|
||||
`<?xml version="1.0" standalone="no"?>` +
|
||||
`<?xml-stylesheet href="/main.css" type="text/css"?>` +
|
||||
`<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">`))
|
||||
|
||||
res.Header().Set("Content-Type", chart.ContentTypeSVG)
|
||||
err := pieChart().Render(chart.SVG, res)
|
||||
if err != nil {
|
||||
fmt.Printf("Error rendering pie chart: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func pieChart() chart.PieChart {
|
||||
return chart.PieChart{
|
||||
// Note that setting ClassName will cause all other inline styles to be dropped!
|
||||
Background: chart.Style{ClassName: "background"},
|
||||
Canvas: chart.Style{
|
||||
ClassName: "canvas",
|
||||
},
|
||||
Width: 512,
|
||||
Height: 512,
|
||||
Values: []chart.Value{
|
||||
{Value: 5, Label: "Blue", Style: chart.Style{ClassName: "blue"}},
|
||||
{Value: 5, Label: "Green", Style: chart.Style{ClassName: "green"}},
|
||||
{Value: 4, Label: "Gray", Style: chart.Style{ClassName: "gray"}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func css(res http.ResponseWriter, req *http.Request) {
|
||||
res.Header().Set("Content-Type", "text/css")
|
||||
res.Write([]byte(style))
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", svgWithCustomInlineCSS)
|
||||
http.HandleFunc("/nonce", svgWithCustomInlineCSSNonce)
|
||||
http.HandleFunc("/external", svgWithCustomExternalCSS)
|
||||
http.HandleFunc("/main.css", css)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
42
examples/custom_ticks/main.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
In this example we set a custom set of ticks to use for the y-axis. It can be (almost) whatever you want, including some custom labels for ticks.
|
||||
Custom ticks will supercede a custom range, which will supercede automatic generation based on series values.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 0.0,
|
||||
Max: 4.0,
|
||||
},
|
||||
Ticks: []chart.Tick{
|
||||
{Value: 0.0, Label: "0.00"},
|
||||
{Value: 2.0, Label: "2.00"},
|
||||
{Value: 4.0, Label: "4.00"},
|
||||
{Value: 6.0, Label: "6.00"},
|
||||
{Value: 8.0, Label: "Eight"},
|
||||
{Value: 10.0, Label: "Ten"},
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/custom_ticks/output.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
49
examples/descending/main.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
The below will draw the same chart as the `basic` example, except with both the x and y axes turned on.
|
||||
In this case, both the x and y axis ticks are generated automatically, the x and y ranges are established automatically,
|
||||
the canvas "box" is adjusted to fit the space the axes occupy so as not to clip.
|
||||
Additionally, it shows how you can use the "Descending" property of continuous ranges to change the ordering of
|
||||
how values (including ticks) are drawn.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
Height: 500,
|
||||
Width: 500,
|
||||
XAxis: chart.XAxis{
|
||||
/*Range: &chart.ContinuousRange{
|
||||
Descending: true,
|
||||
},*/
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Descending: true,
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
FillColor: chart.GetDefaultColor(0).WithAlpha(64),
|
||||
},
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/descending/output.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
28
examples/donut_chart/main.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pie := chart.DonutChart{
|
||||
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: "test"},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
pie.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/donut_chart/output.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
25
examples/donut_chart/reg.svg
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512">\n<path d="M 0 0
|
||||
L 512 0
|
||||
L 512 512
|
||||
L 0 512
|
||||
L 0 0" style="stroke-width:0;stroke:rgba(255,255,255,1.0);fill:rgba(255,255,255,1.0)"/><path d="M 5 5
|
||||
L 507 5
|
||||
L 507 507
|
||||
L 5 507
|
||||
L 5 5" style="stroke-width:0;stroke:rgba(255,255,255,1.0);fill:rgba(255,255,255,1.0)"/><path d="M 256 256
|
||||
L 438 256
|
||||
A 182 182 225.00 1 1 127 127
|
||||
L 256 256
|
||||
Z" style="stroke-width:4;stroke:rgba(255,255,255,1.0);fill:rgba(106,195,203,1.0)"/><path d="M 256 256
|
||||
L 127 127
|
||||
A 182 182 90.00 0 1 385 127
|
||||
L 256 256
|
||||
Z" style="stroke-width:4;stroke:rgba(255,255,255,1.0);fill:rgba(42,190,137,1.0)"/><path d="M 256 256
|
||||
L 385 127
|
||||
A 182 182 45.00 0 1 438 256
|
||||
L 256 256
|
||||
Z" style="stroke-width:4;stroke:rgba(255,255,255,1.0);fill:rgba(110,128,139,1.0)"/><path d="M 256 256
|
||||
L 321 256
|
||||
A 65 65 359.00 1 1 321 255
|
||||
L 256 256
|
||||
Z" style="stroke-width:4;stroke:rgba(255,255,255,1.0);fill:rgba(255,255,255,1.0)"/><text x="159" y="461" style="stroke-width:0;stroke:none;fill:rgba(51,51,51,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif">Blue</text><text x="241" y="48" style="stroke-width:0;stroke:none;fill:rgba(51,51,51,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif">Two</text><text x="440" y="181" style="stroke-width:0;stroke:none;fill:rgba(51,51,51,1.0);font-size:15.3px;font-family:'Roboto Medium',sans-serif">One</text></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
27
examples/image_writer/main.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
collector := &chart.ImageWriter{}
|
||||
graph.Render(chart.PNG, collector)
|
||||
|
||||
image, err := collector.Image()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Final Image: %dx%d\n", image.Bounds().Size().X, image.Bounds().Size().Y)
|
||||
}
|
||||
43
examples/legend/main.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
In this example we add a `Renderable` or a custom component to the `Elements` array.
|
||||
In this specific case it is a pre-built renderable (`CreateLegend`) that draws a legend for the chart's series.
|
||||
If you like, you can use `CreateLegend` as a template for writing your own renderable, or even your own legend.
|
||||
*/
|
||||
|
||||
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.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
//note we have to do this as a separate step because we need a reference to graph
|
||||
graph.Elements = []chart.Renderable{
|
||||
chart.Legend(&graph),
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/legend/output.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
103
examples/legend_left/main.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
In this example we add a `Renderable` or a custom component to the `Elements` array.
|
||||
In this specific case it is a pre-built renderable (`CreateLegend`) that draws a legend for the chart's series.
|
||||
If you like, you can use `CreateLegend` as a template for writing your own renderable, or even your own legend.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 20,
|
||||
Left: 260,
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Name: "A test series",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Another test series",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Yet Another test series",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Even More series",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Foo Bar",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Bar Baz",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Moo Bar",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Zoo Bar Baz",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "Fast and the Furious",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{5.0, 4.0, 3.0, 2.0, 1.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "2 Fast 2 Furious",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{5.0, 4.0, 3.0, 2.0, 1.0},
|
||||
},
|
||||
|
||||
chart.ContinuousSeries{
|
||||
Name: "They only get more fast and more furious",
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{5.0, 4.0, 3.0, 2.0, 1.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
//note we have to do this as a separate step because we need a reference to graph
|
||||
graph.Elements = []chart.Renderable{
|
||||
chart.LegendLeft(&graph),
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/legend_left/output.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
40
examples/linear_regression/main.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
In this example we add a new type of series, a `SimpleMovingAverageSeries` that takes another series as a required argument.
|
||||
InnerSeries only needs to implement `ValuesProvider`, so really you could chain `SimpleMovingAverageSeries` together if you wanted.
|
||||
*/
|
||||
|
||||
mainSeries := chart.ContinuousSeries{
|
||||
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.
|
||||
YValues: chart.Seq{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.
|
||||
// we need to use a reference because `.Render()` needs to modify state within the series.
|
||||
linRegSeries := &chart.LinearRegressionSeries{
|
||||
InnerSeries: mainSeries,
|
||||
} // we can optionally set the `WindowSize` property which alters how the moving average is calculated.
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
mainSeries,
|
||||
linRegSeries,
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/linear_regression/output.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
61
examples/min_max/main.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mainSeries := chart.ContinuousSeries{
|
||||
Name: "A test series",
|
||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
|
||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(50).WithMax(150)}.Values(),
|
||||
}
|
||||
|
||||
minSeries := &chart.MinSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray,
|
||||
StrokeDashArray: []float64{5.0, 5.0},
|
||||
},
|
||||
InnerSeries: mainSeries,
|
||||
}
|
||||
|
||||
maxSeries := &chart.MaxSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray,
|
||||
StrokeDashArray: []float64{5.0, 5.0},
|
||||
},
|
||||
InnerSeries: mainSeries,
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
Width: 1920,
|
||||
Height: 1080,
|
||||
YAxis: chart.YAxis{
|
||||
Name: "Random Values",
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 25,
|
||||
Max: 175,
|
||||
},
|
||||
},
|
||||
XAxis: chart.XAxis{
|
||||
Name: "Random Other Values",
|
||||
},
|
||||
Series: []chart.Series{
|
||||
mainSeries,
|
||||
minSeries,
|
||||
maxSeries,
|
||||
chart.LastValueAnnotationSeries(minSeries),
|
||||
chart.LastValueAnnotationSeries(maxSeries),
|
||||
},
|
||||
}
|
||||
|
||||
graph.Elements = []chart.Renderable{chart.Legend(&graph)}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/min_max/output.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
29
examples/pie_chart/main.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
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: "!!"},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
pie.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/pie_chart/output.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
17
examples/pie_chart/reg.svg
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512">
|
||||
<path d="M 256 256
|
||||
L 507 256
|
||||
A 251 251 225.00 1 1 79 79
|
||||
L 256 256
|
||||
Z" style="stroke-width:5;stroke:rgba(255,255,255,1.0);fill:rgba(106,195,203,1.0)"/>
|
||||
<path d="M 256 256
|
||||
L 79 79
|
||||
A 251 251 90.00 0 1 433 79
|
||||
L 256 256
|
||||
Z" style="stroke-width:5;stroke:rgba(255,255,255,1.0);fill:rgba(42,190,137,1.0)"/>
|
||||
<path d="M 256 256
|
||||
L 433 79
|
||||
A 251 251 45.00 0 1 507 256
|
||||
L 256 256
|
||||
Z" style="stroke-width:5;stroke:rgba(255,255,255,1.0);fill:rgba(110,128,139,1.0)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 565 B |
39
examples/poly_regression/main.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
In this example we add a new type of series, a `PolynomialRegressionSeries` that takes another series as a required argument.
|
||||
InnerSeries only needs to implement `ValuesProvider`, so really you could chain `PolynomialRegressionSeries` together if you wanted.
|
||||
*/
|
||||
|
||||
mainSeries := chart.ContinuousSeries{
|
||||
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.
|
||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(0).WithMax(100)}.Values(), //generates a []float64 randomly from 0 to 100 with 100 elements.
|
||||
}
|
||||
|
||||
polyRegSeries := &chart.PolynomialRegressionSeries{
|
||||
Degree: 3,
|
||||
InnerSeries: mainSeries,
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
mainSeries,
|
||||
polyRegSeries,
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/poly_regression/output.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
133
examples/request_timings/main.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := chart.NewLogger()
|
||||
drawChart(log)
|
||||
}
|
||||
|
||||
func parseInt(str string) int {
|
||||
v, _ := strconv.Atoi(str)
|
||||
return v
|
||||
}
|
||||
|
||||
func parseFloat64(str string) float64 {
|
||||
v, _ := strconv.ParseFloat(str, 64)
|
||||
return v
|
||||
}
|
||||
|
||||
func readData() ([]time.Time, []float64) {
|
||||
var xvalues []time.Time
|
||||
var yvalues []float64
|
||||
err := chart.ReadLines("requests.csv", func(line string) error {
|
||||
parts := chart.SplitCSV(line)
|
||||
year := parseInt(parts[0])
|
||||
month := parseInt(parts[1])
|
||||
day := parseInt(parts[2])
|
||||
hour := parseInt(parts[3])
|
||||
elapsedMillis := parseFloat64(parts[4])
|
||||
xvalues = append(xvalues, time.Date(year, time.Month(month), day, hour, 0, 0, 0, time.UTC))
|
||||
yvalues = append(yvalues, elapsedMillis)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return xvalues, yvalues
|
||||
}
|
||||
|
||||
func releases() []chart.GridLine {
|
||||
return []chart.GridLine{
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 1, 9, 30, 0, 0, time.UTC))},
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 2, 9, 30, 0, 0, time.UTC))},
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 2, 15, 30, 0, 0, time.UTC))},
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 4, 9, 30, 0, 0, time.UTC))},
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 5, 9, 30, 0, 0, time.UTC))},
|
||||
{Value: chart.TimeToFloat64(time.Date(2016, 8, 6, 9, 30, 0, 0, time.UTC))},
|
||||
}
|
||||
}
|
||||
|
||||
func drawChart(log chart.Logger) http.HandlerFunc {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
xvalues, yvalues := readData()
|
||||
mainSeries := chart.TimeSeries{
|
||||
Name: "Prod Request Timings",
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorBlue,
|
||||
FillColor: chart.ColorBlue.WithAlpha(100),
|
||||
},
|
||||
XValues: xvalues,
|
||||
YValues: yvalues,
|
||||
}
|
||||
|
||||
linreg := &chart.LinearRegressionSeries{
|
||||
Name: "Linear Regression",
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateBlue,
|
||||
StrokeDashArray: []float64{5.0, 5.0},
|
||||
},
|
||||
InnerSeries: mainSeries,
|
||||
}
|
||||
|
||||
sma := &chart.SMASeries{
|
||||
Name: "SMA",
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorRed,
|
||||
StrokeDashArray: []float64{5.0, 5.0},
|
||||
},
|
||||
InnerSeries: mainSeries,
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
Log: log,
|
||||
Width: 1280,
|
||||
Height: 720,
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 50,
|
||||
},
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Name: "Elapsed Millis",
|
||||
TickStyle: chart.Style{
|
||||
TextRotationDegrees: 45.0,
|
||||
},
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
return fmt.Sprintf("%d ms", int(v.(float64)))
|
||||
},
|
||||
},
|
||||
XAxis: chart.XAxis{
|
||||
ValueFormatter: chart.TimeHourValueFormatter,
|
||||
GridMajorStyle: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray,
|
||||
StrokeWidth: 1.0,
|
||||
},
|
||||
GridLines: releases(),
|
||||
},
|
||||
Series: []chart.Series{
|
||||
mainSeries,
|
||||
linreg,
|
||||
chart.LastValueAnnotationSeries(linreg),
|
||||
sma,
|
||||
chart.LastValueAnnotationSeries(sma),
|
||||
},
|
||||
}
|
||||
|
||||
graph.Elements = []chart.Renderable{chart.LegendThin(&graph)}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
}
|
||||
BIN
examples/request_timings/output.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
170
examples/request_timings/requests.csv
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
2016,7,31,16,51.1948264984227130
|
||||
2016,7,31,17,1.7940833333333333
|
||||
2016,7,31,18,10.0383889931207000
|
||||
2016,7,31,19,6.1413707865168539
|
||||
2016,7,31,20,8.3973734513274336
|
||||
2016,7,31,21,73.5405406633348480
|
||||
2016,7,31,22,159.8895444957152270
|
||||
2016,7,31,23,34.0708326693227090
|
||||
2016,8,1,0,69.7564325518178730
|
||||
2016,8,1,1,48.1574708470847080
|
||||
2016,8,1,2,17.4290324074074070
|
||||
2016,8,1,3,5.5943366336633663
|
||||
2016,8,1,4,9.1419949109414758
|
||||
2016,8,1,5,14.4151891117478510
|
||||
2016,8,1,6,1.5541666666666667
|
||||
2016,8,1,7,15.7282261904761900
|
||||
2016,8,1,8,21.1564157175398630
|
||||
2016,8,1,9,1.5934583333333333
|
||||
2016,8,1,10,4.3529166666666667
|
||||
2016,8,1,11,87.5080657894736840
|
||||
2016,8,1,12,1.5835000000000000
|
||||
2016,8,1,13,29.9959344262295080
|
||||
2016,8,1,14,46.8553964079538170
|
||||
2016,8,1,15,20.0111057531630460
|
||||
2016,8,1,16,94.6157284061696660
|
||||
2016,8,1,17,58.6487434362045140
|
||||
2016,8,1,18,20.8815984522785900
|
||||
2016,8,1,19,72.4154909266876360
|
||||
2016,8,1,20,58.9246686590436590
|
||||
2016,8,1,21,84.3067604562737640
|
||||
2016,8,1,22,122.5261538745387450
|
||||
2016,8,1,23,85.1076058098020120
|
||||
2016,8,2,0,101.7361568656277570
|
||||
2016,8,2,1,24.3167470952749810
|
||||
2016,8,2,2,122.0310546659304250
|
||||
2016,8,2,3,74.2989314442413160
|
||||
2016,8,2,4,129.6967691387559810
|
||||
2016,8,2,5,71.1511239448219070
|
||||
2016,8,2,6,1.9676388888888889
|
||||
2016,8,2,7,45.3233373493975900
|
||||
2016,8,2,8,0.52597727272727272730
|
||||
2016,8,2,9,0.47493750000000000000
|
||||
2016,8,2,10,0.36689583333333333330
|
||||
2016,8,2,11,12.2201858407079650
|
||||
2016,8,2,12,58.0710813743218810
|
||||
2016,8,2,13,75.9720821672048800
|
||||
2016,8,2,14,86.0020336538461540
|
||||
2016,8,2,15,22.4082420588235290
|
||||
2016,8,2,16,93.1733733049989880
|
||||
2016,8,2,17,55.2889921111945910
|
||||
2016,8,2,18,56.7059533689400160
|
||||
2016,8,2,19,84.2515716615033430
|
||||
2016,8,2,20,101.4842500290866780
|
||||
2016,8,2,21,136.8598881478658540
|
||||
2016,8,2,22,62.5393413387838530
|
||||
2016,8,2,23,47.6955947622329430
|
||||
2016,8,3,0,28.6536128110975110
|
||||
2016,8,3,1,68.2935053282915090
|
||||
2016,8,3,2,65.4284130561492130
|
||||
2016,8,3,3,102.4286141260973660
|
||||
2016,8,3,4,56.5472182066809920
|
||||
2016,8,3,5,18.6264831460674160
|
||||
2016,8,3,6,67.8456661764705880
|
||||
2016,8,3,7,92.5702828579829460
|
||||
2016,8,3,8,0.41591666666666666670
|
||||
2016,8,3,9,0.38620833333333333330
|
||||
2016,8,3,10,2.4085945945945946
|
||||
2016,8,3,11,10.7638414634146340
|
||||
2016,8,3,12,31.4489252873563220
|
||||
2016,8,3,13,153.4695363601385150
|
||||
2016,8,3,14,271.2642420287705770
|
||||
2016,8,3,15,36.5611996434937610
|
||||
2016,8,3,16,29.2185496806617110
|
||||
2016,8,3,17,126.9859396924555500
|
||||
2016,8,3,18,163.7181875191189970
|
||||
2016,8,3,19,21.4754753134796240
|
||||
2016,8,3,20,34.1040598911070780
|
||||
2016,8,3,21,75.1127804170444240
|
||||
2016,8,3,22,39.4469905441016900
|
||||
2016,8,3,23,5.1409929328621908
|
||||
2016,8,4,0,255.8132918813695180
|
||||
2016,8,4,1,214.4145150846210450
|
||||
2016,8,4,2,36.1957284522706210
|
||||
2016,8,4,3,78.4117736768802230
|
||||
2016,8,4,4,9.9754722222222222
|
||||
2016,8,4,5,34.1333243123336290
|
||||
2016,8,4,6,0.39741666666666666670
|
||||
2016,8,4,7,3.5579206349206349
|
||||
2016,8,4,8,0.33243750000000000000
|
||||
2016,8,4,9,0.27264583333333333330
|
||||
2016,8,4,10,15.6974805194805190
|
||||
2016,8,4,11,33.3286867469879520
|
||||
2016,8,4,12,69.0402700057570520
|
||||
2016,8,4,13,63.8368957232099950
|
||||
2016,8,4,14,46.5617178867403310
|
||||
2016,8,4,15,9.4975930656934307
|
||||
2016,8,4,16,70.3660450209843570
|
||||
2016,8,4,17,40.3501840688912810
|
||||
2016,8,4,18,111.0351848094324100
|
||||
2016,8,4,19,63.0629592505854800
|
||||
2016,8,4,20,94.2470022670596240
|
||||
2016,8,4,21,10.0634637203166230
|
||||
2016,8,4,22,49.0879200762388820
|
||||
2016,8,4,23,23.7079982971477220
|
||||
2016,8,5,0,28.9202116946399570
|
||||
2016,8,5,1,60.5840482187837350
|
||||
2016,8,5,2,34.2454046076313890
|
||||
2016,8,5,3,26.3180027100271000
|
||||
2016,8,5,4,27.4047251497005990
|
||||
2016,8,5,5,22.3780671462829740
|
||||
2016,8,5,6,41.4588378921962990
|
||||
2016,8,5,7,62.6991675955414010
|
||||
2016,8,5,8,88.7716758230236950
|
||||
2016,8,5,9,40.4319411764705880
|
||||
2016,8,5,10,72.9793152507676560
|
||||
2016,8,5,11,10.6647535971223020
|
||||
2016,8,5,12,159.3556583236321300
|
||||
2016,8,5,13,64.6945072587532020
|
||||
2016,8,5,14,74.9644142216085610
|
||||
2016,8,5,15,62.0095938270477580
|
||||
2016,8,5,16,36.5669031007751940
|
||||
2016,8,5,17,128.6374414414414410
|
||||
2016,8,5,18,112.1804886168910650
|
||||
2016,8,5,19,161.8682954545454550
|
||||
2016,8,5,20,95.8026952301719360
|
||||
2016,8,5,21,240.8415338457264560
|
||||
2016,8,5,22,155.3652810287871640
|
||||
2016,8,5,23,388.9544503679476700
|
||||
2016,8,6,0,15.9398834146341460
|
||||
2016,8,6,1,190.7137858942065490
|
||||
2016,8,6,2,11.4065349143610010
|
||||
2016,8,6,3,236.7059518272425250
|
||||
2016,8,6,4,248.0312605042016810
|
||||
2016,8,6,5,0.24320833333333333330
|
||||
2016,8,6,6,0.26987500000000000000
|
||||
2016,8,6,7,0.31525000000000000000
|
||||
2016,8,6,8,1.2495535714285714
|
||||
2016,8,6,9,5.4469130434782609
|
||||
2016,8,6,10,0.33695833333333333330
|
||||
2016,8,6,11,91.8210377113133940
|
||||
2016,8,6,12,0.31939583333333333330
|
||||
2016,8,6,13,7.5832362869198312
|
||||
2016,8,6,14,7.8081323155216285
|
||||
2016,8,6,15,54.4206174812030080
|
||||
2016,8,6,16,1.6644098360655738
|
||||
2016,8,6,17,120.0108195020746890
|
||||
2016,8,6,18,128.2539524348810870
|
||||
2016,8,6,19,93.8680571705426360
|
||||
2016,8,6,20,1.6764107142857143
|
||||
2016,8,6,21,24.4085034965034970
|
||||
2016,8,6,22,96.0146023560209420
|
||||
2016,8,6,23,7.2911171450737005
|
||||
2016,8,7,0,22.7146944444444440
|
||||
2016,8,7,1,0.41214583333333333330
|
||||
2016,8,7,2,0.30702083333333333330
|
||||
2016,8,7,3,2.8580312500000000
|
||||
2016,8,7,4,0.26483333333333333330
|
||||
2016,8,7,5,0.26022916666666666670
|
||||
2016,8,7,6,0.27406250000000000000
|
||||
2016,8,7,7,0.31931250000000000000
|
||||
2016,8,7,8,0.35614583333333333330
|
||||
2016,8,7,9,4.6068000000000000
|
||||
2016,8,7,10,0.36356250000000000000
|
||||
2016,8,7,11,0.30760416666666666670
|
||||
2016,8,7,12,23.8985191570881230
|
||||
2016,8,7,13,4.0653140495867769
|
||||
2016,8,7,14,61.0720150753768840
|
||||
2016,8,7,15,14.6478756410256410
|
||||
2016,8,7,16,53.9795638455827770
|
||||
2016,8,7,17,97.2232321428571430
|
||||
|
48
examples/rerender/main.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
var lock sync.Mutex
|
||||
var graph *chart.Chart
|
||||
var ts *chart.TimeSeries
|
||||
|
||||
func addData(t time.Time, e time.Duration) {
|
||||
lock.Lock()
|
||||
ts.XValues = append(ts.XValues, t)
|
||||
ts.YValues = append(ts.YValues, chart.TimeMillis(e))
|
||||
lock.Unlock()
|
||||
}
|
||||
|
||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
addData(start, time.Since(start))
|
||||
}()
|
||||
if len(ts.XValues) == 0 {
|
||||
http.Error(res, "no data (yet)", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
res.Header().Set("Content-Type", "image/png")
|
||||
if err := graph.Render(chart.PNG, res); err != nil {
|
||||
log.Printf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ts = &chart.TimeSeries{
|
||||
XValues: []time.Time{},
|
||||
YValues: []float64{},
|
||||
}
|
||||
graph = &chart.Chart{
|
||||
Series: []chart.Series{ts},
|
||||
}
|
||||
http.HandleFunc("/", drawChart)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
69
examples/scatter/main.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||
|
||||
viridisByY := func(xr, yr chart.Range, index int, x, y float64) drawing.Color {
|
||||
return chart.Viridis(y, yr.GetMin(), yr.GetMax())
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
Style: chart.Style{
|
||||
StrokeWidth: chart.Disabled,
|
||||
DotWidth: 5,
|
||||
DotColorProvider: viridisByY,
|
||||
},
|
||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(127)}.Values(),
|
||||
YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(128).WithMin(0).WithMax(1024)}.Values(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res.Header().Set("Content-Type", chart.ContentTypePNG)
|
||||
err := graph.Render(chart.PNG, res)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func unit(res http.ResponseWriter, req *http.Request) {
|
||||
graph := chart.Chart{
|
||||
Height: 50,
|
||||
Width: 50,
|
||||
Canvas: chart.Style{
|
||||
Padding: chart.BoxZero,
|
||||
},
|
||||
Background: chart.Style{
|
||||
Padding: chart.BoxZero,
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
||||
YValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res.Header().Set("Content-Type", chart.ContentTypePNG)
|
||||
err := graph.Render(chart.PNG, res)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", drawChart)
|
||||
http.HandleFunc("/unit", unit)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
BIN
examples/scatter/output.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
34
examples/simple_moving_average/main.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mainSeries := chart.ContinuousSeries{
|
||||
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.
|
||||
YValues: chart.Seq{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.
|
||||
// we need to use a reference because `.Render()` needs to modify state within the series.
|
||||
smaSeries := &chart.SMASeries{
|
||||
InnerSeries: mainSeries,
|
||||
} // we can optionally set the `WindowSize` property which alters how the moving average is calculated.
|
||||
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
mainSeries,
|
||||
smaSeries,
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/simple_moving_average/output.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
53
examples/stacked_bar/main.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sbc := chart.StackedBarChart{
|
||||
Title: "Test Stacked Bar Chart",
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 40,
|
||||
},
|
||||
},
|
||||
Height: 512,
|
||||
Bars: []chart.StackedBar{
|
||||
{
|
||||
Name: "This is a very long string to test word break wrapping.",
|
||||
Values: []chart.Value{
|
||||
{Value: 5, Label: "Blue"},
|
||||
{Value: 5, Label: "Green"},
|
||||
{Value: 4, Label: "Gray"},
|
||||
{Value: 3, Label: "Orange"},
|
||||
{Value: 3, Label: "Test"},
|
||||
{Value: 2, Label: "??"},
|
||||
{Value: 1, Label: "!!"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Test",
|
||||
Values: []chart.Value{
|
||||
{Value: 10, Label: "Blue"},
|
||||
{Value: 5, Label: "Green"},
|
||||
{Value: 1, Label: "Gray"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Test 2",
|
||||
Values: []chart.Value{
|
||||
{Value: 10, Label: "Blue"},
|
||||
{Value: 6, Label: "Green"},
|
||||
{Value: 4, Label: "Gray"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
sbc.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/stacked_bar/output.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
78
examples/stock_analysis/main.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
xv, yv := xvalues(), yvalues()
|
||||
|
||||
priceSeries := chart.TimeSeries{
|
||||
Name: "SPY",
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.GetDefaultColor(0),
|
||||
},
|
||||
XValues: xv,
|
||||
YValues: yv,
|
||||
}
|
||||
|
||||
smaSeries := chart.SMASeries{
|
||||
Name: "SPY - SMA",
|
||||
Style: chart.Style{
|
||||
StrokeColor: drawing.ColorRed,
|
||||
StrokeDashArray: []float64{5.0, 5.0},
|
||||
},
|
||||
InnerSeries: priceSeries,
|
||||
}
|
||||
|
||||
bbSeries := &chart.BollingerBandsSeries{
|
||||
Name: "SPY - Bol. Bands",
|
||||
Style: chart.Style{
|
||||
StrokeColor: drawing.ColorFromHex("efefef"),
|
||||
FillColor: drawing.ColorFromHex("efefef").WithAlpha(64),
|
||||
},
|
||||
InnerSeries: priceSeries,
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
XAxis: chart.XAxis{
|
||||
TickPosition: chart.TickPositionBetweenTicks,
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Max: 220.0,
|
||||
Min: 180.0,
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
bbSeries,
|
||||
priceSeries,
|
||||
smaSeries,
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
|
||||
func xvalues() []time.Time {
|
||||
rawx := []string{"2015-07-17", "2015-07-20", "2015-07-21", "2015-07-22", "2015-07-23", "2015-07-24", "2015-07-27", "2015-07-28", "2015-07-29", "2015-07-30", "2015-07-31", "2015-08-03", "2015-08-04", "2015-08-05", "2015-08-06", "2015-08-07", "2015-08-10", "2015-08-11", "2015-08-12", "2015-08-13", "2015-08-14", "2015-08-17", "2015-08-18", "2015-08-19", "2015-08-20", "2015-08-21", "2015-08-24", "2015-08-25", "2015-08-26", "2015-08-27", "2015-08-28", "2015-08-31", "2015-09-01", "2015-09-02", "2015-09-03", "2015-09-04", "2015-09-08", "2015-09-09", "2015-09-10", "2015-09-11", "2015-09-14", "2015-09-15", "2015-09-16", "2015-09-17", "2015-09-18", "2015-09-21", "2015-09-22", "2015-09-23", "2015-09-24", "2015-09-25", "2015-09-28", "2015-09-29", "2015-09-30", "2015-10-01", "2015-10-02", "2015-10-05", "2015-10-06", "2015-10-07", "2015-10-08", "2015-10-09", "2015-10-12", "2015-10-13", "2015-10-14", "2015-10-15", "2015-10-16", "2015-10-19", "2015-10-20", "2015-10-21", "2015-10-22", "2015-10-23", "2015-10-26", "2015-10-27", "2015-10-28", "2015-10-29", "2015-10-30", "2015-11-02", "2015-11-03", "2015-11-04", "2015-11-05", "2015-11-06", "2015-11-09", "2015-11-10", "2015-11-11", "2015-11-12", "2015-11-13", "2015-11-16", "2015-11-17", "2015-11-18", "2015-11-19", "2015-11-20", "2015-11-23", "2015-11-24", "2015-11-25", "2015-11-27", "2015-11-30", "2015-12-01", "2015-12-02", "2015-12-03", "2015-12-04", "2015-12-07", "2015-12-08", "2015-12-09", "2015-12-10", "2015-12-11", "2015-12-14", "2015-12-15", "2015-12-16", "2015-12-17", "2015-12-18", "2015-12-21", "2015-12-22", "2015-12-23", "2015-12-24", "2015-12-28", "2015-12-29", "2015-12-30", "2015-12-31", "2016-01-04", "2016-01-05", "2016-01-06", "2016-01-07", "2016-01-08", "2016-01-11", "2016-01-12", "2016-01-13", "2016-01-14", "2016-01-15", "2016-01-19", "2016-01-20", "2016-01-21", "2016-01-22", "2016-01-25", "2016-01-26", "2016-01-27", "2016-01-28", "2016-01-29", "2016-02-01", "2016-02-02", "2016-02-03", "2016-02-04", "2016-02-05", "2016-02-08", "2016-02-09", "2016-02-10", "2016-02-11", "2016-02-12", "2016-02-16", "2016-02-17", "2016-02-18", "2016-02-19", "2016-02-22", "2016-02-23", "2016-02-24", "2016-02-25", "2016-02-26", "2016-02-29", "2016-03-01", "2016-03-02", "2016-03-03", "2016-03-04", "2016-03-07", "2016-03-08", "2016-03-09", "2016-03-10", "2016-03-11", "2016-03-14", "2016-03-15", "2016-03-16", "2016-03-17", "2016-03-18", "2016-03-21", "2016-03-22", "2016-03-23", "2016-03-24", "2016-03-28", "2016-03-29", "2016-03-30", "2016-03-31", "2016-04-01", "2016-04-04", "2016-04-05", "2016-04-06", "2016-04-07", "2016-04-08", "2016-04-11", "2016-04-12", "2016-04-13", "2016-04-14", "2016-04-15", "2016-04-18", "2016-04-19", "2016-04-20", "2016-04-21", "2016-04-22", "2016-04-25", "2016-04-26", "2016-04-27", "2016-04-28", "2016-04-29", "2016-05-02", "2016-05-03", "2016-05-04", "2016-05-05", "2016-05-06", "2016-05-09", "2016-05-10", "2016-05-11", "2016-05-12", "2016-05-13", "2016-05-16", "2016-05-17", "2016-05-18", "2016-05-19", "2016-05-20", "2016-05-23", "2016-05-24", "2016-05-25", "2016-05-26", "2016-05-27", "2016-05-31", "2016-06-01", "2016-06-02", "2016-06-03", "2016-06-06", "2016-06-07", "2016-06-08", "2016-06-09", "2016-06-10", "2016-06-13", "2016-06-14", "2016-06-15", "2016-06-16", "2016-06-17", "2016-06-20", "2016-06-21", "2016-06-22", "2016-06-23", "2016-06-24", "2016-06-27", "2016-06-28", "2016-06-29", "2016-06-30", "2016-07-01", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-11", "2016-07-12", "2016-07-13", "2016-07-14", "2016-07-15"}
|
||||
|
||||
var dates []time.Time
|
||||
for _, ts := range rawx {
|
||||
parsed, _ := time.Parse(chart.DefaultDateFormat, ts)
|
||||
dates = append(dates, parsed)
|
||||
}
|
||||
return dates
|
||||
}
|
||||
|
||||
func yvalues() []float64 {
|
||||
return []float64{212.47, 212.59, 211.76, 211.37, 210.18, 208.00, 206.79, 209.33, 210.77, 210.82, 210.50, 209.79, 209.38, 210.07, 208.35, 207.95, 210.57, 208.66, 208.92, 208.66, 209.42, 210.59, 209.98, 208.32, 203.97, 197.83, 189.50, 187.27, 194.46, 199.27, 199.28, 197.67, 191.77, 195.41, 195.55, 192.59, 197.43, 194.79, 195.85, 196.74, 196.01, 198.45, 200.18, 199.73, 195.45, 196.46, 193.90, 193.60, 192.90, 192.87, 188.01, 188.12, 191.63, 192.13, 195.00, 198.47, 197.79, 199.41, 201.21, 201.33, 201.52, 200.25, 199.29, 202.35, 203.27, 203.37, 203.11, 201.85, 205.26, 207.51, 207.00, 206.60, 208.95, 208.83, 207.93, 210.39, 211.00, 210.36, 210.15, 210.04, 208.08, 208.56, 207.74, 204.84, 202.54, 205.62, 205.47, 208.73, 208.55, 209.31, 209.07, 209.35, 209.32, 209.56, 208.69, 210.68, 208.53, 205.61, 209.62, 208.35, 206.95, 205.34, 205.87, 201.88, 202.90, 205.03, 208.03, 204.86, 200.02, 201.67, 203.50, 206.02, 205.68, 205.21, 207.40, 205.93, 203.87, 201.02, 201.36, 198.82, 194.05, 191.92, 192.11, 193.66, 188.83, 191.93, 187.81, 188.06, 185.65, 186.69, 190.52, 187.64, 190.20, 188.13, 189.11, 193.72, 193.65, 190.16, 191.30, 191.60, 187.95, 185.42, 185.43, 185.27, 182.86, 186.63, 189.78, 192.88, 192.09, 192.00, 194.78, 192.32, 193.20, 195.54, 195.09, 193.56, 198.11, 199.00, 199.78, 200.43, 200.59, 198.40, 199.38, 199.54, 202.76, 202.50, 202.17, 203.34, 204.63, 204.38, 204.67, 204.56, 203.21, 203.12, 203.24, 205.12, 206.02, 205.52, 206.92, 206.25, 204.19, 206.42, 203.95, 204.50, 204.02, 205.92, 208.00, 208.01, 207.78, 209.24, 209.90, 210.10, 208.97, 208.97, 208.61, 208.92, 209.35, 207.45, 206.33, 207.97, 206.16, 205.01, 204.97, 205.72, 205.89, 208.45, 206.50, 206.56, 204.76, 206.78, 204.85, 204.91, 204.20, 205.49, 205.21, 207.87, 209.28, 209.34, 210.24, 209.84, 210.27, 210.91, 210.28, 211.35, 211.68, 212.37, 212.08, 210.07, 208.45, 208.04, 207.75, 208.37, 206.52, 207.85, 208.44, 208.10, 210.81, 203.24, 199.60, 203.20, 206.66, 209.48, 209.92, 208.41, 209.66, 209.53, 212.65, 213.40, 214.95, 214.92, 216.12, 215.83}
|
||||
}
|
||||
BIN
examples/stock_analysis/output.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
51
examples/text_rotation/main.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f, _ := chart.GetDefaultFont()
|
||||
r, _ := chart.PNG(1024, 1024)
|
||||
|
||||
chart.Draw.Text(r, "Test", 64, 64, chart.Style{
|
||||
FontColor: drawing.ColorBlack,
|
||||
FontSize: 18,
|
||||
Font: f,
|
||||
})
|
||||
|
||||
chart.Draw.Text(r, "Test", 64, 64, chart.Style{
|
||||
FontColor: drawing.ColorBlack,
|
||||
FontSize: 18,
|
||||
Font: f,
|
||||
TextRotationDegrees: 45.0,
|
||||
})
|
||||
|
||||
tb := chart.Draw.MeasureText(r, "Test", chart.Style{
|
||||
FontColor: drawing.ColorBlack,
|
||||
FontSize: 18,
|
||||
Font: f,
|
||||
}).Shift(64, 64)
|
||||
|
||||
tbc := tb.Corners().Rotate(45)
|
||||
|
||||
chart.Draw.BoxCorners(r, tbc, chart.Style{
|
||||
StrokeColor: drawing.ColorRed,
|
||||
StrokeWidth: 2,
|
||||
})
|
||||
|
||||
tbcb := tbc.Box()
|
||||
chart.Draw.Box(r, tbcb, chart.Style{
|
||||
StrokeColor: drawing.ColorBlue,
|
||||
StrokeWidth: 2,
|
||||
})
|
||||
|
||||
file, _ := os.Create("output.png")
|
||||
defer file.Close()
|
||||
r.Save(file)
|
||||
}
|
||||
BIN
examples/text_rotation/output.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
79
examples/timeseries/main.go
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||
/*
|
||||
This is an example of using the `TimeSeries` to automatically coerce time.Time values into a continuous xrange.
|
||||
Note: chart.TimeSeries implements `ValueFormatterProvider` and as a result gives the XAxis the appropriate formatter to use for the ticks.
|
||||
*/
|
||||
graph := chart.Chart{
|
||||
Series: []chart.Series{
|
||||
chart.TimeSeries{
|
||||
XValues: []time.Time{
|
||||
time.Now().AddDate(0, 0, -10),
|
||||
time.Now().AddDate(0, 0, -9),
|
||||
time.Now().AddDate(0, 0, -8),
|
||||
time.Now().AddDate(0, 0, -7),
|
||||
time.Now().AddDate(0, 0, -6),
|
||||
time.Now().AddDate(0, 0, -5),
|
||||
time.Now().AddDate(0, 0, -4),
|
||||
time.Now().AddDate(0, 0, -3),
|
||||
time.Now().AddDate(0, 0, -2),
|
||||
time.Now().AddDate(0, 0, -1),
|
||||
time.Now(),
|
||||
},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res.Header().Set("Content-Type", "image/png")
|
||||
graph.Render(chart.PNG, res)
|
||||
}
|
||||
|
||||
func drawCustomChart(res http.ResponseWriter, req *http.Request) {
|
||||
/*
|
||||
This is basically the other timeseries example, except we switch to hour intervals and specify a different formatter from default for the xaxis tick labels.
|
||||
*/
|
||||
graph := chart.Chart{
|
||||
XAxis: chart.XAxis{
|
||||
ValueFormatter: chart.TimeHourValueFormatter,
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.TimeSeries{
|
||||
XValues: []time.Time{
|
||||
time.Now().Add(-10 * time.Hour),
|
||||
time.Now().Add(-9 * time.Hour),
|
||||
time.Now().Add(-8 * time.Hour),
|
||||
time.Now().Add(-7 * time.Hour),
|
||||
time.Now().Add(-6 * time.Hour),
|
||||
time.Now().Add(-5 * time.Hour),
|
||||
time.Now().Add(-4 * time.Hour),
|
||||
time.Now().Add(-3 * time.Hour),
|
||||
time.Now().Add(-2 * time.Hour),
|
||||
time.Now().Add(-1 * time.Hour),
|
||||
time.Now(),
|
||||
},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res.Header().Set("Content-Type", "image/png")
|
||||
graph.Render(chart.PNG, res)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", drawChart)
|
||||
http.HandleFunc("/favicon.ico", func(res http.ResponseWriter, req *http.Request) {
|
||||
res.Write([]byte{})
|
||||
})
|
||||
http.HandleFunc("/custom", drawCustomChart)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
BIN
examples/timeseries/output.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
45
examples/twoaxis/main.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
/*
|
||||
In this example we add a second series, and assign it to the secondary y axis, giving that series it's own range.
|
||||
|
||||
We also enable all of the axes by setting the `Show` propery of their respective styles to `true`.
|
||||
*/
|
||||
|
||||
graph := chart.Chart{
|
||||
XAxis: chart.XAxis{
|
||||
TickPosition: chart.TickPositionBetweenTicks,
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
typed := v.(float64)
|
||||
typedDate := chart.TimeFromFloat64(typed)
|
||||
return fmt.Sprintf("%d-%d\n%d", typedDate.Month(), typedDate.Day(), typedDate.Year())
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
},
|
||||
chart.ContinuousSeries{
|
||||
YAxis: chart.YAxisSecondary,
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{50.0, 40.0, 30.0, 20.0, 10.0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f, _ := os.Create("output.png")
|
||||
defer f.Close()
|
||||
graph.Render(chart.PNG, f)
|
||||
}
|
||||
BIN
examples/twoaxis/output.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
63
examples/twopoint/main.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package main
|
||||
|
||||
//go:generate go run main.go
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var b float64
|
||||
b = 1000
|
||||
|
||||
ts1 := chart.ContinuousSeries{ //TimeSeries{
|
||||
Name: "Time Series",
|
||||
XValues: []float64{10 * b, 20 * b, 30 * b, 40 * b, 50 * b, 60 * b, 70 * b, 80 * b},
|
||||
YValues: []float64{1.0, 2.0, 30.0, 4.0, 50.0, 6.0, 7.0, 88.0},
|
||||
}
|
||||
|
||||
ts2 := chart.ContinuousSeries{ //TimeSeries{
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.GetDefaultColor(1),
|
||||
},
|
||||
|
||||
XValues: []float64{10 * b, 20 * b, 30 * b, 40 * b, 50 * b, 60 * b, 70 * b, 80 * b},
|
||||
YValues: []float64{15.0, 52.0, 30.0, 42.0, 50.0, 26.0, 77.0, 38.0},
|
||||
}
|
||||
|
||||
graph := chart.Chart{
|
||||
|
||||
XAxis: chart.XAxis{
|
||||
Name: "The XAxis",
|
||||
ValueFormatter: chart.TimeMinuteValueFormatter, //TimeHourValueFormatter,
|
||||
},
|
||||
|
||||
YAxis: chart.YAxis{
|
||||
Name: "The YAxis",
|
||||
},
|
||||
|
||||
Series: []chart.Series{
|
||||
ts1,
|
||||
ts2,
|
||||
},
|
||||
}
|
||||
|
||||
buffer := bytes.NewBuffer([]byte{})
|
||||
err := graph.Render(chart.PNG, buffer)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fo, err := os.Create("output.png")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, err := fo.Write(buffer.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
BIN
examples/twopoint/output.png
Normal file
|
After Width: | Height: | Size: 40 KiB |