Last active
November 18, 2015 16:41
-
-
Save ajstarks/75cd99c95dc817116341 to your computer and use it in GitHub Desktop.
Sparkline experiment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"github.com/ajstarks/svgo" | |
"os" | |
) | |
var canvas = svg.New(os.Stdout) | |
// sparkline defines the components of the sparkline: | |
// text: label, data: data points, min/max: data range, rmin/rmax: highlighted range | |
type sparkline struct { | |
text string | |
data []float64 | |
min, max, rmin, rmax float64 | |
} | |
// vmap maps one range to another | |
func vmap(value, low1, high1, low2, high2 float64) float64 { | |
return low2 + (high2-low2)*(value-low1)/(high1-low1) | |
} | |
// datarange draws a datarange | |
func (s *sparkline) datarange(x, y, w, h int, color string) { | |
if s.rmin >= s.rmax || s.rmin < s.min || s.rmax > s.max { | |
return | |
} | |
_, dy1 := s.sparkdim(x, y, w, h, 0, s.rmax) | |
_, dy2 := s.sparkdim(x, y, w, h, 0, s.rmin) | |
canvas.Rect(x, y-dy1, w, dy1-dy2, "fill-opacity:0.2;fill:"+color) | |
} | |
// sparkdim returns the device coordinates | |
func (s *sparkline) sparkdim(x, y, w, h, i int, v float64) (int, int) { | |
dx := int(vmap(float64(i), 0, float64(len(s.data)), float64(x), float64(x+w))) | |
dy := int(vmap(v, s.min, s.max, 0, float64(h))) | |
return dx, dy | |
} | |
// label makes the sparkline label | |
func (s *sparkline) label(x, y, w, h int) { | |
canvas.Text(x-5, y, s.text, "text-anchor:end") | |
} | |
// bar makes a barchart | |
func (s *sparkline) bar(x, y, w, h int, color string) { | |
s.label(x, y, w, h) | |
canvas.Gstyle("stroke:" + color) | |
for i, v := range s.data { | |
dx, dy := s.sparkdim(x, y, w, h, i, v) | |
canvas.Line(dx, y, dx, y-dy) | |
} | |
canvas.Gend() | |
s.datarange(x, y, w, h, color) | |
} | |
// line makes a line graph | |
func (s *sparkline) line(x, y, w, h int, color string) { | |
s.label(x, y, w, h) | |
canvas.Gstyle("stroke:" + color) | |
for i := 0; i < len(s.data)-1; i++ { | |
dx1, dy1 := s.sparkdim(x, y, w, h, i, s.data[i]) | |
dx2, dy2 := s.sparkdim(x, y, w, h, i+1, s.data[i+1]) | |
canvas.Line(dx1, y-dy1, dx2, y-dy2) | |
} | |
canvas.Gend() | |
s.datarange(x, y, w, h, color) | |
} | |
// area makes a area chart sparkline | |
func (s *sparkline) area(x, y, w, h int, color string) { | |
s.label(x, y, w, h) | |
xa := make([]int, len(s.data)+1) | |
ya := make([]int, len(s.data)+1) | |
var dx, dy int | |
for i, v := range s.data { | |
dx, dy = s.sparkdim(x, y, w, h, i, v) | |
if i == 0 { | |
xa[0] = dx | |
ya[0] = y | |
} | |
xa[i+1] = dx | |
ya[i+1] = y - dy | |
} | |
xa = append(xa, dx) | |
ya = append(ya, y) | |
canvas.Polygon(xa, ya, "fill-opacity:0.7;fill:"+color) | |
s.datarange(x, y, w, h, color) | |
} | |
func main() { | |
sparks := []sparkline{ | |
{text: "SNY", data: []float64{47.47, 46.64, 46.70, 47.49, 47.99, 48.24, 47.83, 49.41, 49.32, 50.86, 50.36, 49.76, 49.72, 50.23, 49.77, 49.69, 50.01, 48.45, 49.57, 49.23, 48.11}, min: 45, max: 55, rmin: 48, rmax: 50}, | |
{text: "GOOG", data: []float64{608.42, 594.97, 594.89, 611.97, 625.80, 622.36, 622.69, 635.44, 629.25, 642.90, 635.98, 635.14, 623.24, 625.77, 621.35, 612.72, 614.66, 600.70, 606.25, 614.34, 597.79}, min: 570, max: 650, rmin: 600, rmax: 620}, | |
{text: "AAPL", data: []float64{109.83, 108.60, 111.96, 114.22, 114.51, 113.83, 112.92, 114.72, 112.97, 113.43, 115.91, 115.78, 114.82, 113.72, 112.09, 109.68, 111.83, 108.80, 109.90, 111.86, 107.26}, min: 100, max: 120, rmin: 110, rmax: 115}, | |
{text: "FAKE", data: []float64{10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150}, min: 0, max: 200, rmin: 20, rmax: 50}, | |
} | |
width, height := 700, 700 | |
x, y := 100, 200 | |
linespacing := 75 | |
canvas.Start(width, height) | |
canvas.Gstyle("font-family:sans-serif,Calibri;font-size:14pt") | |
for _, s := range sparks { | |
s.bar(x, y, 100, 50, "rgb(127,0,0)") | |
s.area(x+200, y, 100, 50, "lightsteelblue") | |
s.line(x+400, y, 100, 50, "black") | |
y += linespacing | |
} | |
canvas.Gend() | |
canvas.End() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment