Skip to content

Commit

Permalink
Add histogram plot type, display bar chart labels on the right instea…
Browse files Browse the repository at this point in the history
…d of overlapping.
  • Loading branch information
sgreben committed Mar 29, 2018
1 parent 3791de7 commit ef658b5
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 99 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = 1.1.2
VERSION = 1.1.3

APP := jp
PACKAGES := $(shell go list -f {{.Dir}} ./...)
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ Or [download the binary](https://github.com/sgreben/jp/releases/latest) from the

```bash
# Linux
curl -LO https://github.com/sgreben/jp/releases/download/1.1.2/jp_1.1.2_linux_x86_64.zip
unzip jp_1.1.2_linux_x86_64.zip
curl -LO https://github.com/sgreben/jp/releases/download/1.1.3/jp_1.1.3_linux_x86_64.zip
unzip jp_1.1.3_linux_x86_64.zip

# OS X
curl -LO https://github.com/sgreben/jp/releases/download/1.1.2/jp_1.1.2_osx_x86_64.zip
unzip jp_1.1.2_osx_x86_64.zip
curl -LO https://github.com/sgreben/jp/releases/download/1.1.3/jp_1.1.3_osx_x86_64.zip
unzip jp_1.1.3_osx_x86_64.zip

# Windows
curl -LO https://github.com/sgreben/jp/releases/download/1.1.2/jp_1.1.2_windows_x86_64.zip
unzip jp_1.1.2_windows_x86_64.zip
curl -LO https://github.com/sgreben/jp/releases/download/1.1.3/jp_1.1.3_windows_x86_64.zip
unzip jp_1.1.3_windows_x86_64.zip
```

## Use it
Expand Down
33 changes: 17 additions & 16 deletions cmd/jp/bar.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,38 @@ package main

import (
"fmt"
"log"
"reflect"

"github.com/sgreben/jp/pkg/data"
"github.com/sgreben/jp/pkg/draw"
"github.com/sgreben/jp/pkg/plot"
)

func barPlotData(xvv, yvv [][]reflect.Value) (x []string, y []float64) {
for _, xv := range xvv {
for i := range xv {
if xv[i].IsValid() && xv[i].CanInterface() {
x = append(x, fmt.Sprint(xv[i].Interface()))
}
func barPlotData(xv, yv []reflect.Value) (x []string, y []float64) {
for i := range xv {
if xv[i].IsValid() && xv[i].CanInterface() {
x = append(x, fmt.Sprint(xv[i].Interface()))
}
}
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)
}
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 barPlot(xvv, yvv [][]reflect.Value, c draw.Canvas) string {
groups, y := barPlotData(xvv, yvv)
func barPlot(xv, yv []reflect.Value, c draw.Canvas) string {
groups, y := barPlotData(xv, yv)
chart := plot.NewBarChart(c)
data := new(plot.DataTable)
data := new(data.Table)
if len(y) == 0 {
log.Fatal("no valid y values given")
}
if len(groups) != len(y) {
for i := range y {
data.AddColumn(fmt.Sprint(i))
Expand Down
50 changes: 50 additions & 0 deletions cmd/jp/hist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package main

import (
"log"
"reflect"

"github.com/sgreben/jp/pkg/data"
"github.com/sgreben/jp/pkg/draw"
"github.com/sgreben/jp/pkg/plot"
)

func histogramData(xv []reflect.Value, nbins uint) (groups []string, counts []float64) {
var x []float64
for i := range xv {
if xv[i].IsValid() && xv[i].CanInterface() {
xvi, ok := xv[i].Interface().(float64)
if ok {
x = append(x, xvi)
}
}
}
if len(x) == 0 {
log.Fatal("no valid x values given")
}
bins := data.NewBins(x)
bins.Number = int(nbins)
if nbins == 0 {
bins.ChooseSturges()
}
hist := data.Histogram(x, bins)
groups = make([]string, len(hist))
counts = make([]float64, len(hist))
for i, b := range hist {
groups[i] = b.String()
counts[i] = float64(b.Count)
}
return
}

func histogram(xv []reflect.Value, c draw.Canvas, nbins uint) string {
groups, counts := histogramData(xv, nbins)
chart := plot.NewBarChart(c)
chart.BarPaddingX = 0
data := new(data.Table)
for _, g := range groups {
data.AddColumn(g)
}
data.AddRow(counts...)
return chart.Draw(data)
}
37 changes: 19 additions & 18 deletions cmd/jp/line.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
package main

import (
"log"
"reflect"

"github.com/sgreben/jp/pkg/data"
"github.com/sgreben/jp/pkg/draw"

"github.com/sgreben/jp/pkg/plot"
)

func linePlotData(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)
}
func linePlotData(xv, yv []reflect.Value) (x, y []float64) {
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)
}
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 linePlot(xvv, yvv [][]reflect.Value, c draw.Canvas) string {
x, y := linePlotData(xvv, yvv)
func linePlot(xv, yv []reflect.Value, c draw.Canvas) string {
x, y := linePlotData(xv, yv)
chart := plot.NewLineChart(c)
data := new(plot.DataTable)
data := new(data.Table)
data.AddColumn("x")
data.AddColumn("y")
n := len(x)
if len(y) > n {
n = len(y)
}
if len(y) == 0 {
log.Fatal("no valid y values given")
}
// If no valid xs are given, use the indices as x values.
if len(x) == 0 {
x = make([]float64, len(y))
Expand Down
13 changes: 9 additions & 4 deletions cmd/jp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type configuration struct {
PlotType enumVar
CanvasType enumVar
InputType enumVar
HistBins uint
}

const (
Expand Down Expand Up @@ -51,6 +52,7 @@ var config = configuration{
plotTypeLine,
plotTypeBar,
plotTypeScatter,
plotTypeHist,
},
},
CanvasType: enumVar{
Expand Down Expand Up @@ -86,8 +88,10 @@ func init() {
flag.StringVar(&config.XY, "xy", "", "x,y value pairs (JSONPath expression). Overrides -x and -y if given.")
flag.IntVar(&config.Box.Width, "width", 0, "Plot width (default 0 (auto))")
flag.IntVar(&config.Box.Height, "height", 0, "Plot height (default 0 (auto))")
flag.UintVar(&config.HistBins, "bins", 0, "Number of histogram bins (default 0 (auto))")
flag.Parse()
log.SetOutput(os.Stderr)
log.SetFlags(log.LstdFlags | log.Lshortfile)

var err error
xPattern = jsonpath.New("x")
Expand Down Expand Up @@ -143,12 +147,12 @@ func main() {
}
in = parseRows(rows)
}
var x, y [][]reflect.Value
var x, y []reflect.Value
if xyPattern != nil {
x, y = split(match(in, xyPattern))
} else {
x = match(in, xPattern)
y = match(in, yPattern)
x = flatten(match(in, xPattern))
y = flatten(match(in, yPattern))
}
buffer := draw.NewBuffer(config.Box)
var p draw.Pixels
Expand All @@ -162,13 +166,14 @@ func main() {
}
p.Clear()
c := draw.Canvas{Pixels: p}
fmt.Println()
switch config.PlotType.Value {
case plotTypeLine:
fmt.Println(linePlot(x, y, c))
case plotTypeScatter:
fmt.Println(scatterPlot(x, y, c))
case plotTypeBar:
fmt.Println(barPlot(x, y, c))
case plotTypeHist:
fmt.Println(histogram(x, c, config.HistBins))
}
}
34 changes: 15 additions & 19 deletions cmd/jp/scatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,35 @@ package main
import (
"reflect"

"github.com/sgreben/jp/pkg/data"
"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)
}
func scatterPlotData(xv, yv []reflect.Value) (x, y []float64) {
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)
}
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)
func scatterPlot(xv, yv []reflect.Value, c draw.Canvas) string {
x, y := scatterPlotData(xv, yv)
chart := plot.NewScatterChart(c)
data := new(plot.DataTable)
data := new(data.Table)
data.AddColumn("x")
data.AddColumn("y")
n := len(x)
Expand Down
6 changes: 3 additions & 3 deletions cmd/jp/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ func flatten(in [][]reflect.Value) (out []reflect.Value) {
return
}

func split(in [][]reflect.Value) (x, y [][]reflect.Value) {
func split(in [][]reflect.Value) (x, y []reflect.Value) {
flat := flatten(in)
n := len(flat)
x = [][]reflect.Value{flat[:n/2]}
y = [][]reflect.Value{flat[n/2:]}
x = flat[:n/2]
y = flat[n/2:]
return
}
Loading

0 comments on commit ef658b5

Please sign in to comment.