2019-02-13 19:09:26 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-02-13 21:55:13 -05:00
|
|
|
"strings"
|
2019-02-13 19:09:26 -05:00
|
|
|
|
2019-09-10 00:05:48 -04:00
|
|
|
"github.com/wcharczuk/go-chart"
|
2019-02-13 19:09:26 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2019-02-13 22:13:29 -05:00
|
|
|
outputPath = flag.String("output", "", "The output file")
|
|
|
|
|
|
|
|
inputFormat = flag.String("format", "csv", "The input format, either 'csv' or 'tsv' (defaults to 'csv')")
|
|
|
|
inputPath = flag.String("f", "", "The input file")
|
|
|
|
reverse = flag.Bool("reverse", false, "If we should reverse the inputs")
|
|
|
|
|
|
|
|
hideLegend = flag.Bool("hide-legend", false, "If we should omit the chart legend")
|
|
|
|
hideSMA = flag.Bool("hide-sma", false, "If we should omit simple moving average")
|
|
|
|
hideLinreg = flag.Bool("hide-linreg", false, "If we should omit linear regressions")
|
|
|
|
hideLastValues = flag.Bool("hide-last-values", false, "If we should omit last values")
|
2019-02-13 19:09:26 -05:00
|
|
|
)
|
|
|
|
|
2019-02-13 21:55:13 -05:00
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
log := chart.NewLogger()
|
|
|
|
|
|
|
|
var rawData []byte
|
|
|
|
var err error
|
|
|
|
if *inputPath != "" {
|
|
|
|
if *inputPath == "-" {
|
|
|
|
rawData, err = ioutil.ReadAll(os.Stdin)
|
|
|
|
if err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rawData, err = ioutil.ReadFile(*inputPath)
|
|
|
|
if err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if len(flag.Args()) > 0 {
|
|
|
|
rawData = []byte(flag.Args()[0])
|
|
|
|
} else {
|
|
|
|
flag.Usage()
|
2019-02-13 19:09:26 -05:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2019-02-13 21:55:13 -05:00
|
|
|
var parts []string
|
|
|
|
switch *inputFormat {
|
|
|
|
case "csv":
|
|
|
|
parts = chart.SplitCSV(string(rawData))
|
|
|
|
case "tsv":
|
|
|
|
parts = strings.Split(string(rawData), "\t")
|
|
|
|
default:
|
|
|
|
log.FatalErr(fmt.Errorf("invalid format; must be 'csv' or 'tsv'"))
|
|
|
|
}
|
2019-02-13 19:09:26 -05:00
|
|
|
|
2019-02-13 21:55:13 -05:00
|
|
|
yvalues, err := chart.ParseFloats(parts...)
|
2019-02-13 19:09:26 -05:00
|
|
|
if err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
|
|
|
|
2019-02-13 22:13:29 -05:00
|
|
|
if *reverse {
|
|
|
|
yvalues = chart.ValueSequence(yvalues...).Reverse().Values()
|
|
|
|
}
|
|
|
|
|
2019-02-13 21:55:13 -05:00
|
|
|
var series []chart.Series
|
2019-02-13 19:09:26 -05:00
|
|
|
mainSeries := chart.ContinuousSeries{
|
2019-02-13 21:55:13 -05:00
|
|
|
Name: "Values",
|
|
|
|
XValues: chart.LinearRange(1, float64(len(yvalues))),
|
2019-02-13 19:09:26 -05:00
|
|
|
YValues: yvalues,
|
|
|
|
}
|
2019-02-13 21:55:13 -05:00
|
|
|
series = append(series, mainSeries)
|
2019-02-13 19:09:26 -05:00
|
|
|
|
2019-02-13 22:13:29 -05:00
|
|
|
smaSeries := &chart.SMASeries{
|
|
|
|
Name: "SMA",
|
|
|
|
Style: chart.Style{
|
|
|
|
Hidden: *hideSMA,
|
|
|
|
StrokeColor: chart.ColorRed,
|
|
|
|
StrokeDashArray: []float64{5.0, 5.0},
|
|
|
|
},
|
|
|
|
InnerSeries: mainSeries,
|
|
|
|
}
|
|
|
|
series = append(series, smaSeries)
|
|
|
|
|
|
|
|
linRegSeries := &chart.LinearRegressionSeries{
|
|
|
|
Name: "Values - Lin. Reg.",
|
|
|
|
Style: chart.Style{
|
|
|
|
Hidden: *hideLinreg,
|
|
|
|
},
|
|
|
|
InnerSeries: mainSeries,
|
2019-02-13 19:09:26 -05:00
|
|
|
}
|
2019-02-13 22:13:29 -05:00
|
|
|
series = append(series, linRegSeries)
|
|
|
|
|
|
|
|
mainLastValue := chart.LastValueAnnotationSeries(mainSeries)
|
|
|
|
mainLastValue.Style = chart.Style{
|
|
|
|
Hidden: *hideLastValues,
|
|
|
|
}
|
|
|
|
series = append(series, mainLastValue)
|
|
|
|
|
|
|
|
linregLastValue := chart.LastValueAnnotationSeries(linRegSeries)
|
|
|
|
linregLastValue.Style = chart.Style{
|
|
|
|
Hidden: (*hideLastValues || *hideLinreg),
|
|
|
|
}
|
|
|
|
series = append(series, linregLastValue)
|
|
|
|
|
|
|
|
smaLastValue := chart.LastValueAnnotationSeries(smaSeries)
|
|
|
|
smaLastValue.Style = chart.Style{
|
|
|
|
Hidden: (*hideLastValues || *hideSMA),
|
|
|
|
}
|
|
|
|
series = append(series, smaLastValue)
|
2019-02-13 19:09:26 -05:00
|
|
|
|
|
|
|
graph := chart.Chart{
|
2019-02-13 22:13:29 -05:00
|
|
|
Background: chart.Style{
|
|
|
|
Padding: chart.Box{
|
|
|
|
Top: 50,
|
|
|
|
},
|
|
|
|
},
|
2019-02-13 21:55:13 -05:00
|
|
|
Series: series,
|
2019-02-13 19:09:26 -05:00
|
|
|
}
|
|
|
|
|
2019-02-13 22:13:29 -05:00
|
|
|
if !*hideLegend {
|
|
|
|
graph.Elements = []chart.Renderable{chart.LegendThin(&graph)}
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:09:26 -05:00
|
|
|
var output *os.File
|
|
|
|
if *outputPath != "" {
|
|
|
|
output, err = os.Create(*outputPath)
|
|
|
|
if err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
output, err = ioutil.TempFile("", "*.png")
|
|
|
|
if err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := graph.Render(chart.PNG, output); err != nil {
|
|
|
|
log.FatalErr(err)
|
|
|
|
}
|
2019-02-13 21:55:13 -05:00
|
|
|
|
|
|
|
fmt.Fprintln(os.Stdout, output.Name())
|
|
|
|
os.Exit(0)
|
2019-02-13 19:09:26 -05:00
|
|
|
}
|