From 855031c600cad1c749c01aeadb5649fa57c957ac Mon Sep 17 00:00:00 2001 From: Chris Tessum Date: Sun, 26 Feb 2017 15:58:57 -0800 Subject: [PATCH] Added bar chart example with positive and negative values --- plotter/barchart_test.go | 100 ++++++++++++++++++ .../barChart_positiveNegative_golden.png | Bin 0 -> 7384 bytes 2 files changed, 100 insertions(+) create mode 100644 plotter/testdata/barChart_positiveNegative_golden.png diff --git a/plotter/barchart_test.go b/plotter/barchart_test.go index 86d6607d..778e3eed 100644 --- a/plotter/barchart_test.go +++ b/plotter/barchart_test.go @@ -7,6 +7,7 @@ package plotter import ( "image/color" "log" + "math/rand" "testing" "github.com/gonum/plot" @@ -172,3 +173,102 @@ func TestBarChart(t *testing.T) { "horizontalBarChart.png", "barChart2.png", "stackedBarChart.png") } + +// This example shows a bar chart with both positive and negative values. +func ExampleBarChart_positiveNegative() { + rnd := rand.New(rand.NewSource(1)) + + // Create random data points between -1 and 1. + const n = 6 + data1 := make(Values, n) + data2 := make(Values, n) + net := make(XYs, n) // net = data1 + data2 + for i := 0; i < n; i++ { + data1[i] = rnd.Float64()*2 - 1 + data2[i] = rnd.Float64()*2 - 1 + net[i].X = data1[i] + data2[i] + net[i].Y = float64(i) + } + + // posNeg splits an array into two arrays containing the positive and + // negative values, respectively, from the original array. + posNeg := func(d Values) (pos, neg Values) { + pos = make(Values, len(d)) + neg = make(Values, len(d)) + for i, v := range d { + if v > 0 { + pos[i] = v + } else { + neg[i] = v + } + } + return + } + + data1Pos, data1Neg := posNeg(data1) + data2Pos, data2Neg := posNeg(data2) + + const barWidth = 0.3 * vg.Centimeter + pos1, err := NewBarChart(data1Pos, barWidth) + if err != nil { + log.Panic(err) + } + pos2, err := NewBarChart(data2Pos, barWidth) + if err != nil { + log.Panic(err) + } + neg1, err := NewBarChart(data1Neg, barWidth) + if err != nil { + log.Panic(err) + } + neg2, err := NewBarChart(data2Neg, barWidth) + if err != nil { + log.Panic(err) + } + + netDots, err := NewScatter(net) + if err != nil { + log.Panic(err) + } + netDots.Radius = vg.Points(1.25) + + pos2.StackOn(pos1) // Specify that pos2 goes on top of pos1. + neg2.StackOn(neg1) // Specify that neg2 goes on top of neg1. + + color1 := color.NRGBA{R: 112, G: 22, B: 0, A: 255} + color2 := color.NRGBA{R: 91, G: 194, B: 54, A: 100} + + pos1.Color, neg1.Color = color1, color1 + pos2.Color, neg2.Color = color2, color2 + + // Specify that we want a horizontal bar chart. + pos1.Horizontal, pos2.Horizontal, neg1.Horizontal, neg2.Horizontal = true, true, true, true + + // Create a line at zero. + zero, err := NewLine(XYs{{0, 0}, {0, 5}}) + if err != nil { + log.Panic(err) + } + + p, err := plot.New() + if err != nil { + log.Panic(err) + } + p.Add(zero, pos1, pos2, neg1, neg2, netDots) + p.NominalY("Alpha", "Bravo", "Charlie", "Echo", "Foxtrot", "Golf") + + p.Legend.Add("1", pos1) + p.Legend.Add("2", pos2) + p.Legend.Add("Sum", netDots) + p.Legend.Left = true + p.Legend.ThumbnailWidth = 2 * vg.Millimeter + + err = p.Save(100, 100, "testdata/barChart_positiveNegative.png") + if err != nil { + log.Panic(err) + } +} + +func TestBarChart_positiveNegative(t *testing.T) { + cmpimg.CheckPlot(ExampleBarChart_positiveNegative, t, "barChart_positiveNegative.png") +} diff --git a/plotter/testdata/barChart_positiveNegative_golden.png b/plotter/testdata/barChart_positiveNegative_golden.png new file mode 100644 index 0000000000000000000000000000000000000000..9d158bf77ee4f6c86023b8ce37334e9aa81d2fdd GIT binary patch literal 7384 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 QCzc2`B`su$f?4SQ0Er=v`~Uy| literal 0 HcmV?d00001