output/plot.go
func PlotData(interval time.Duration, r results.ResultSet, w io.Writer) {
	set := r.Reduce(interval)
	t := results.TabularResults{}
	rows := t.Tabulate(set)

	seriesY := createYSeries(rows)
	seriesX := createXSeries(rows)
	ticks := createXTicks(rows)

	graph := chart.Chart{
		Background: chart.Style{
			Padding: chart.Box{
				Top:    50,
				Left:   25,
				Right:  25,
				Bottom: 25,
			},
			FillColor: drawing.ColorFromHex("efefef"),
		},
		XAxis: chart.XAxis{
			Name:      "Elapsed Time (s)",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.0f", v)
			},
			Ticks: ticks,
		},
		YAxis: chart.YAxis{
			Name:      "Count",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.0f", v)
			},
		},
		YAxisSecondary: chart.YAxis{
			Name:      "Time (ms)",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.2f", v)
			},
		},
		Series: []chart.Series{
			chart.ContinuousSeries{
				Name:    "Success",
				XValues: seriesX["x"],
				YValues: seriesY["y.success"],
				Style: chart.Style{
					Show:        true,                             //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorGreen,               // will supercede defaults
					FillColor:   drawing.ColorGreen.WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Failure",
				XValues: seriesX["x"],
				YValues: seriesY["y.failure"],
				Style: chart.Style{
					Show:        true,                           //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorRed,               // will supercede defaults
					FillColor:   drawing.ColorRed.WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Timeout",
				XValues: seriesX["x"],
				YValues: seriesY["y.timeout"],
				Style: chart.Style{
					Show:        true,                                         //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorFromHex("FFD133"),               // will supercede defaults
					FillColor:   drawing.ColorFromHex("FFD133").WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Threads",
				XValues: seriesX["x"],
				YValues: seriesY["y.threads"],
				Style: chart.Style{
					Show:        true,                           //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorFromHex("FF338D"), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				YAxis:   chart.YAxisSecondary,
				Name:    "Request time (ms)",
				XValues: seriesX["x"],
				YValues: seriesY["y.request"],
				Style: chart.Style{
					Show:        true,              //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorBlue, // will supercede defaults
				},
			},
		},
	}

	//note we have to do this as a separate step because we need a reference to graph
	graph.Elements = []chart.Renderable{
		chart.Legend(&graph),
	}

	graph.Render(chart.PNG, w)
}
func PlotData(interval time.Duration, r results.ResultSet, w io.Writer) {
	set := r.Reduce(interval)
	t := results.TabularResults{}
	rows := t.Tabulate(set)

	seriesY := createYSeries(rows)
	seriesX := createXSeries(rows)
	ticks := createXTicks(rows)

	graph := chart.Chart{
		Background: chart.Style{
			Padding: chart.Box{
				Top:    50,
				Left:   25,
				Right:  25,
				Bottom: 25,
			},
			FillColor: drawing.ColorFromHex("efefef"),
		},
		XAxis: chart.XAxis{
			Name:      "Elapsed Time (s)",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.0f", v)
			},
			Ticks: ticks,
		},
		YAxis: chart.YAxis{
			Name:      "Count",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.0f", v)
			},
		},
		YAxisSecondary: chart.YAxis{
			Name:      "Time (ms)",
			NameStyle: chart.StyleShow(),
			Style:     chart.StyleShow(),
			ValueFormatter: func(v interface{}) string {
				return fmt.Sprintf("%.2f", v)
			},
		},
		Series: []chart.Series{
			chart.ContinuousSeries{
				Name:    "Success",
				XValues: seriesX["x"],
				YValues: seriesY["y.success"],
				Style: chart.Style{
					Show:        true,                             //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorGreen,               // will supercede defaults
					FillColor:   drawing.ColorGreen.WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Failure",
				XValues: seriesX["x"],
				YValues: seriesY["y.failure"],
				Style: chart.Style{
					Show:        true,                           //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorRed,               // will supercede defaults
					FillColor:   drawing.ColorRed.WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Timeout",
				XValues: seriesX["x"],
				YValues: seriesY["y.timeout"],
				Style: chart.Style{
					Show:        true,                                         //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorFromHex("FFD133"),               // will supercede defaults
					FillColor:   drawing.ColorFromHex("FFD133").WithAlpha(64), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				Name:    "Threads",
				XValues: seriesX["x"],
				YValues: seriesY["y.threads"],
				Style: chart.Style{
					Show:        true,                           //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorFromHex("FF338D"), // will supercede defaults
				},
			},
			chart.ContinuousSeries{
				YAxis:   chart.YAxisSecondary,
				Name:    "Request time (ms)",
				XValues: seriesX["x"],
				YValues: seriesY["y.request"],
				Style: chart.Style{
					Show:        true,              //note; if we set ANY other properties, we must set this to true.
					StrokeColor: drawing.ColorBlue, // will supercede defaults
				},
			},
		},
	}

	//note we have to do this as a separate step because we need a reference to graph
	graph.Elements = []chart.Renderable{
		chart.Legend(&graph),
	}

	graph.Render(chart.PNG, w)
}
// PlotData plots the results onto a graph and saves the output to the given writer