switching to generators

This commit is contained in:
Will Charczuk 2019-09-09 21:02:48 -07:00
parent 2d5aeaf824
commit 45fad0cfb8
94 changed files with 402 additions and 691 deletions

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

34
examples/axes/main.go Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

23
examples/basic/main.go Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

View 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))
}

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View 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

View 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))
}

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View 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

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

61
examples/min_max/main.go Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View 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

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View 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)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View 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
1 2016 7 31 16 51.1948264984227130
2 2016 7 31 17 1.7940833333333333
3 2016 7 31 18 10.0383889931207000
4 2016 7 31 19 6.1413707865168539
5 2016 7 31 20 8.3973734513274336
6 2016 7 31 21 73.5405406633348480
7 2016 7 31 22 159.8895444957152270
8 2016 7 31 23 34.0708326693227090
9 2016 8 1 0 69.7564325518178730
10 2016 8 1 1 48.1574708470847080
11 2016 8 1 2 17.4290324074074070
12 2016 8 1 3 5.5943366336633663
13 2016 8 1 4 9.1419949109414758
14 2016 8 1 5 14.4151891117478510
15 2016 8 1 6 1.5541666666666667
16 2016 8 1 7 15.7282261904761900
17 2016 8 1 8 21.1564157175398630
18 2016 8 1 9 1.5934583333333333
19 2016 8 1 10 4.3529166666666667
20 2016 8 1 11 87.5080657894736840
21 2016 8 1 12 1.5835000000000000
22 2016 8 1 13 29.9959344262295080
23 2016 8 1 14 46.8553964079538170
24 2016 8 1 15 20.0111057531630460
25 2016 8 1 16 94.6157284061696660
26 2016 8 1 17 58.6487434362045140
27 2016 8 1 18 20.8815984522785900
28 2016 8 1 19 72.4154909266876360
29 2016 8 1 20 58.9246686590436590
30 2016 8 1 21 84.3067604562737640
31 2016 8 1 22 122.5261538745387450
32 2016 8 1 23 85.1076058098020120
33 2016 8 2 0 101.7361568656277570
34 2016 8 2 1 24.3167470952749810
35 2016 8 2 2 122.0310546659304250
36 2016 8 2 3 74.2989314442413160
37 2016 8 2 4 129.6967691387559810
38 2016 8 2 5 71.1511239448219070
39 2016 8 2 6 1.9676388888888889
40 2016 8 2 7 45.3233373493975900
41 2016 8 2 8 0.52597727272727272730
42 2016 8 2 9 0.47493750000000000000
43 2016 8 2 10 0.36689583333333333330
44 2016 8 2 11 12.2201858407079650
45 2016 8 2 12 58.0710813743218810
46 2016 8 2 13 75.9720821672048800
47 2016 8 2 14 86.0020336538461540
48 2016 8 2 15 22.4082420588235290
49 2016 8 2 16 93.1733733049989880
50 2016 8 2 17 55.2889921111945910
51 2016 8 2 18 56.7059533689400160
52 2016 8 2 19 84.2515716615033430
53 2016 8 2 20 101.4842500290866780
54 2016 8 2 21 136.8598881478658540
55 2016 8 2 22 62.5393413387838530
56 2016 8 2 23 47.6955947622329430
57 2016 8 3 0 28.6536128110975110
58 2016 8 3 1 68.2935053282915090
59 2016 8 3 2 65.4284130561492130
60 2016 8 3 3 102.4286141260973660
61 2016 8 3 4 56.5472182066809920
62 2016 8 3 5 18.6264831460674160
63 2016 8 3 6 67.8456661764705880
64 2016 8 3 7 92.5702828579829460
65 2016 8 3 8 0.41591666666666666670
66 2016 8 3 9 0.38620833333333333330
67 2016 8 3 10 2.4085945945945946
68 2016 8 3 11 10.7638414634146340
69 2016 8 3 12 31.4489252873563220
70 2016 8 3 13 153.4695363601385150
71 2016 8 3 14 271.2642420287705770
72 2016 8 3 15 36.5611996434937610
73 2016 8 3 16 29.2185496806617110
74 2016 8 3 17 126.9859396924555500
75 2016 8 3 18 163.7181875191189970
76 2016 8 3 19 21.4754753134796240
77 2016 8 3 20 34.1040598911070780
78 2016 8 3 21 75.1127804170444240
79 2016 8 3 22 39.4469905441016900
80 2016 8 3 23 5.1409929328621908
81 2016 8 4 0 255.8132918813695180
82 2016 8 4 1 214.4145150846210450
83 2016 8 4 2 36.1957284522706210
84 2016 8 4 3 78.4117736768802230
85 2016 8 4 4 9.9754722222222222
86 2016 8 4 5 34.1333243123336290
87 2016 8 4 6 0.39741666666666666670
88 2016 8 4 7 3.5579206349206349
89 2016 8 4 8 0.33243750000000000000
90 2016 8 4 9 0.27264583333333333330
91 2016 8 4 10 15.6974805194805190
92 2016 8 4 11 33.3286867469879520
93 2016 8 4 12 69.0402700057570520
94 2016 8 4 13 63.8368957232099950
95 2016 8 4 14 46.5617178867403310
96 2016 8 4 15 9.4975930656934307
97 2016 8 4 16 70.3660450209843570
98 2016 8 4 17 40.3501840688912810
99 2016 8 4 18 111.0351848094324100
100 2016 8 4 19 63.0629592505854800
101 2016 8 4 20 94.2470022670596240
102 2016 8 4 21 10.0634637203166230
103 2016 8 4 22 49.0879200762388820
104 2016 8 4 23 23.7079982971477220
105 2016 8 5 0 28.9202116946399570
106 2016 8 5 1 60.5840482187837350
107 2016 8 5 2 34.2454046076313890
108 2016 8 5 3 26.3180027100271000
109 2016 8 5 4 27.4047251497005990
110 2016 8 5 5 22.3780671462829740
111 2016 8 5 6 41.4588378921962990
112 2016 8 5 7 62.6991675955414010
113 2016 8 5 8 88.7716758230236950
114 2016 8 5 9 40.4319411764705880
115 2016 8 5 10 72.9793152507676560
116 2016 8 5 11 10.6647535971223020
117 2016 8 5 12 159.3556583236321300
118 2016 8 5 13 64.6945072587532020
119 2016 8 5 14 74.9644142216085610
120 2016 8 5 15 62.0095938270477580
121 2016 8 5 16 36.5669031007751940
122 2016 8 5 17 128.6374414414414410
123 2016 8 5 18 112.1804886168910650
124 2016 8 5 19 161.8682954545454550
125 2016 8 5 20 95.8026952301719360
126 2016 8 5 21 240.8415338457264560
127 2016 8 5 22 155.3652810287871640
128 2016 8 5 23 388.9544503679476700
129 2016 8 6 0 15.9398834146341460
130 2016 8 6 1 190.7137858942065490
131 2016 8 6 2 11.4065349143610010
132 2016 8 6 3 236.7059518272425250
133 2016 8 6 4 248.0312605042016810
134 2016 8 6 5 0.24320833333333333330
135 2016 8 6 6 0.26987500000000000000
136 2016 8 6 7 0.31525000000000000000
137 2016 8 6 8 1.2495535714285714
138 2016 8 6 9 5.4469130434782609
139 2016 8 6 10 0.33695833333333333330
140 2016 8 6 11 91.8210377113133940
141 2016 8 6 12 0.31939583333333333330
142 2016 8 6 13 7.5832362869198312
143 2016 8 6 14 7.8081323155216285
144 2016 8 6 15 54.4206174812030080
145 2016 8 6 16 1.6644098360655738
146 2016 8 6 17 120.0108195020746890
147 2016 8 6 18 128.2539524348810870
148 2016 8 6 19 93.8680571705426360
149 2016 8 6 20 1.6764107142857143
150 2016 8 6 21 24.4085034965034970
151 2016 8 6 22 96.0146023560209420
152 2016 8 6 23 7.2911171450737005
153 2016 8 7 0 22.7146944444444440
154 2016 8 7 1 0.41214583333333333330
155 2016 8 7 2 0.30702083333333333330
156 2016 8 7 3 2.8580312500000000
157 2016 8 7 4 0.26483333333333333330
158 2016 8 7 5 0.26022916666666666670
159 2016 8 7 6 0.27406250000000000000
160 2016 8 7 7 0.31931250000000000000
161 2016 8 7 8 0.35614583333333333330
162 2016 8 7 9 4.6068000000000000
163 2016 8 7 10 0.36356250000000000000
164 2016 8 7 11 0.30760416666666666670
165 2016 8 7 12 23.8985191570881230
166 2016 8 7 13 4.0653140495867769
167 2016 8 7 14 61.0720150753768840
168 2016 8 7 15 14.6478756410256410
169 2016 8 7 16 53.9795638455827770
170 2016 8 7 17 97.2232321428571430

48
examples/rerender/main.go Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View 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}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View 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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

45
examples/twoaxis/main.go Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

63
examples/twopoint/main.go Normal file
View 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)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB