diff options
Diffstat (limited to 'cmd/jp')
-rw-r--r-- | cmd/jp/bar.go | 10 | ||||
-rw-r--r-- | cmd/jp/canvas_other.go | 10 | ||||
-rw-r--r-- | cmd/jp/canvas_windows.go | 10 | ||||
-rw-r--r-- | cmd/jp/flag.go | 6 | ||||
-rw-r--r-- | cmd/jp/line.go | 12 | ||||
-rw-r--r-- | cmd/jp/main.go | 71 | ||||
-rw-r--r-- | cmd/jp/scatter.go | 56 |
7 files changed, 145 insertions, 30 deletions
diff --git a/cmd/jp/bar.go b/cmd/jp/bar.go index e1a622b..15dd196 100644 --- a/cmd/jp/bar.go +++ b/cmd/jp/bar.go @@ -4,8 +4,8 @@ import ( "fmt" "reflect" - "github.com/sgreben/jp/pkg/jp" - "github.com/sgreben/jp/pkg/jp/primitives" + "github.com/sgreben/jp/pkg/draw" + "github.com/sgreben/jp/pkg/plot" ) func barPlotData(xvv, yvv [][]reflect.Value) (x []string, y []float64) { @@ -29,10 +29,10 @@ func barPlotData(xvv, yvv [][]reflect.Value) (x []string, y []float64) { return } -func barPlot(xvv, yvv [][]reflect.Value, box primitives.Box) string { +func barPlot(xvv, yvv [][]reflect.Value, c draw.Canvas) string { groups, y := barPlotData(xvv, yvv) - chart := jp.NewBarChart(box.Width, box.Height) - data := new(jp.DataTable) + chart := plot.NewBarChart(c) + data := new(plot.DataTable) if len(groups) != len(y) { for i := range y { data.AddColumn(fmt.Sprint(i)) diff --git a/cmd/jp/canvas_other.go b/cmd/jp/canvas_other.go new file mode 100644 index 0000000..053cef7 --- /dev/null +++ b/cmd/jp/canvas_other.go @@ -0,0 +1,10 @@ +// +build !windows + +package main + +var autoCanvas = map[string]string{ + plotTypeBar: canvasTypeQuarter, + plotTypeLine: canvasTypeQuarter, + plotTypeScatter: canvasTypeBraille, + plotTypeHist: canvasTypeQuarter, +} diff --git a/cmd/jp/canvas_windows.go b/cmd/jp/canvas_windows.go new file mode 100644 index 0000000..de22e5b --- /dev/null +++ b/cmd/jp/canvas_windows.go @@ -0,0 +1,10 @@ +// +build windows + +package main + +var autoCanvas = map[string]string{ + plotTypeBar: canvasTypeFull, + plotTypeLine: canvasTypeFull, + plotTypeScatter: canvasTypeFull, + plotTypeHist: canvasTypeFull, +} diff --git a/cmd/jp/flag.go b/cmd/jp/flag.go index 533b35d..eeec98c 100644 --- a/cmd/jp/flag.go +++ b/cmd/jp/flag.go @@ -6,8 +6,8 @@ import ( ) type enumVar struct { - Choices []string // The acceptable choices the user may pass to the flag - Value string // the current value of the flag + Choices []string + Value string } // Set implements the flag.Value interface. @@ -18,7 +18,7 @@ func (so *enumVar) Set(v string) error { return nil } } - return fmt.Errorf("invalid choice; must be one of %s", strings.Join(so.Choices, ",")) + return fmt.Errorf("must be one of [%s]", strings.Join(so.Choices, " ")) } func (so *enumVar) String() string { diff --git a/cmd/jp/line.go b/cmd/jp/line.go index b47b38c..caca49f 100644 --- a/cmd/jp/line.go +++ b/cmd/jp/line.go @@ -3,8 +3,9 @@ package main import ( "reflect" - "github.com/sgreben/jp/pkg/jp" - "github.com/sgreben/jp/pkg/jp/primitives" + "github.com/sgreben/jp/pkg/draw" + + "github.com/sgreben/jp/pkg/plot" ) func linePlotData(xvv, yvv [][]reflect.Value) (x, y []float64) { @@ -31,10 +32,10 @@ func linePlotData(xvv, yvv [][]reflect.Value) (x, y []float64) { return } -func linePlot(xvv, yvv [][]reflect.Value, box primitives.Box) string { +func linePlot(xvv, yvv [][]reflect.Value, c draw.Canvas) string { x, y := linePlotData(xvv, yvv) - chart := jp.NewLineChart(box.Width, box.Height) - data := new(jp.DataTable) + chart := plot.NewLineChart(c) + data := new(plot.DataTable) data.AddColumn("x") data.AddColumn("y") n := len(x) @@ -51,6 +52,5 @@ func linePlot(xvv, yvv [][]reflect.Value, box primitives.Box) string { for i := 0; i < n; i++ { data.AddRow(x[i%len(x)], y[i%len(y)]) } - chart.Symbol = "█" return chart.Draw(data) } diff --git a/cmd/jp/main.go b/cmd/jp/main.go index c603f68..07de252 100644 --- a/cmd/jp/main.go +++ b/cmd/jp/main.go @@ -8,24 +8,34 @@ import ( "os" "reflect" - "github.com/sgreben/jp/pkg/jp/primitives" + "github.com/sgreben/jp/pkg/draw" "github.com/sgreben/jp/pkg/terminal" "github.com/sgreben/jp/pkg/jsonpath" ) type configuration struct { - Box primitives.Box - X string - Y string - XY string - PlotType enumVar + Box draw.Box + X string + Y string + XY string + PlotType enumVar + CanvasType enumVar } -const plotTypeLine = "line" -const plotTypeBar = "bar" -const plotTypeScatter = "scatter" -const plotTypeHist = "hist" +const ( + plotTypeLine = "line" + plotTypeBar = "bar" + plotTypeScatter = "scatter" + plotTypeHist = "hist" +) + +const ( + canvasTypeFull = "full" + canvasTypeQuarter = "quarter" + canvasTypeBraille = "braille" + canvasTypeAuto = "auto" +) var config = configuration{ PlotType: enumVar{ @@ -33,16 +43,29 @@ var config = configuration{ Choices: []string{ plotTypeLine, plotTypeBar, + plotTypeScatter, + }, + }, + CanvasType: enumVar{ + Value: canvasTypeAuto, + Choices: []string{ + canvasTypeFull, + canvasTypeQuarter, + canvasTypeBraille, + canvasTypeAuto, }, }, } -var xPattern *jsonpath.JSONPath -var yPattern *jsonpath.JSONPath -var xyPattern *jsonpath.JSONPath +var ( + xPattern *jsonpath.JSONPath + yPattern *jsonpath.JSONPath + xyPattern *jsonpath.JSONPath +) func init() { flag.Var(&config.PlotType, "type", fmt.Sprintf("Plot type. One of %v", config.PlotType.Choices)) + flag.Var(&config.CanvasType, "canvas", fmt.Sprintf("Canvas type. One of %v", config.CanvasType.Choices)) flag.StringVar(&config.X, "x", "", "x values (JSONPath expression)") flag.StringVar(&config.Y, "y", "", "y values (JSONPath expression)") flag.StringVar(&config.XY, "xy", "", "x,y value pairs (JSONPath expression). Overrides -x and -y if given.") @@ -75,6 +98,9 @@ func init() { if config.Box.Height == 0 { config.Box.Height = terminal.Height() - 1 } + if config.CanvasType.Value == canvasTypeAuto { + config.CanvasType.Value = autoCanvas[config.PlotType.Value] + } } func match(in interface{}, p *jsonpath.JSONPath) [][]reflect.Value { @@ -100,11 +126,24 @@ func main() { x = match(in, xPattern) y = match(in, yPattern) } + buffer := draw.NewBuffer(config.Box) + var p draw.Pixels + switch config.CanvasType.Value { + case canvasTypeBraille: + p = &draw.Braille{Buffer: buffer} + case canvasTypeQuarter: + p = &draw.Quarter{Buffer: buffer} + case canvasTypeFull: + p = &draw.Full{Buffer: buffer} + } + p.Clear() + c := draw.Canvas{Pixels: p} switch config.PlotType.Value { case plotTypeLine: - fmt.Print(linePlot(x, y, config.Box)) + fmt.Println(linePlot(x, y, c)) + case plotTypeScatter: + fmt.Println(scatterPlot(x, y, c)) case plotTypeBar: - fmt.Print(barPlot(x, y, config.Box)) + fmt.Println(barPlot(x, y, c)) } - } diff --git a/cmd/jp/scatter.go b/cmd/jp/scatter.go new file mode 100644 index 0000000..9df8b4a --- /dev/null +++ b/cmd/jp/scatter.go @@ -0,0 +1,56 @@ +package main + +import ( + "reflect" + + "github.com/sgreben/jp/pkg/draw" + + "github.com/sgreben/jp/pkg/plot" +) + +func scatterPlotData(xvv, yvv [][]reflect.Value) (x, y []float64) { + for _, xv := range xvv { + for i := range xv { + if xv[i].IsValid() && xv[i].CanInterface() { + xvi, ok := xv[i].Interface().(float64) + if ok { + x = append(x, xvi) + } + } + } + } + for _, yv := range yvv { + for i := range yv { + if yv[i].IsValid() && yv[i].CanInterface() { + yvi, ok := yv[i].Interface().(float64) + if ok { + y = append(y, yvi) + } + } + } + } + return +} + +func scatterPlot(xvv, yvv [][]reflect.Value, c draw.Canvas) string { + x, y := scatterPlotData(xvv, yvv) + chart := plot.NewScatterChart(c) + data := new(plot.DataTable) + data.AddColumn("x") + data.AddColumn("y") + n := len(x) + if len(y) > n { + n = len(y) + } + // If no valid xs are given, use the indices as x values. + if len(x) == 0 { + x = make([]float64, len(y)) + for i := 0; i < len(y); i++ { + x[i] = float64(i) + } + } + for i := 0; i < n; i++ { + data.AddRow(x[i%len(x)], y[i%len(y)]) + } + return chart.Draw(data) +} |