summaryrefslogtreecommitdiff
path: root/vendor/github.com/buger/goterm/plot.go
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
committerMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
commita031b83a09a8628435317a03f199cdc18b78262f (patch)
treebc017a96769ce6de33745b8b0b1304ccf38e9df0 /vendor/github.com/buger/goterm/plot.go
parent2b74391cd5281f6fdf391ff8ad50fd1490f6bf89 (diff)
downloadpodman-a031b83a09a8628435317a03f199cdc18b78262f.tar.gz
podman-a031b83a09a8628435317a03f199cdc18b78262f.tar.bz2
podman-a031b83a09a8628435317a03f199cdc18b78262f.zip
Initial checkin from CRI-O repo
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'vendor/github.com/buger/goterm/plot.go')
-rw-r--r--vendor/github.com/buger/goterm/plot.go328
1 files changed, 328 insertions, 0 deletions
diff --git a/vendor/github.com/buger/goterm/plot.go b/vendor/github.com/buger/goterm/plot.go
new file mode 100644
index 000000000..77b9fb097
--- /dev/null
+++ b/vendor/github.com/buger/goterm/plot.go
@@ -0,0 +1,328 @@
+package goterm
+
+import (
+ "fmt"
+ "math"
+ "strings"
+)
+
+const (
+ AXIS_LEFT = iota
+ AXIS_RIGHT
+)
+
+const (
+ DRAW_INDEPENDENT = 1 << iota
+ DRAW_RELATIVE
+)
+
+type DataTable struct {
+ columns []string
+
+ rows [][]float64
+}
+
+func (d *DataTable) AddColumn(name string) {
+ d.columns = append(d.columns, name)
+}
+
+func (d *DataTable) AddRow(elms ...float64) {
+ d.rows = append(d.rows, elms)
+}
+
+type Chart interface {
+ Draw(data DataTable, flags int) string
+}
+
+type LineChart struct {
+ Buf []string
+ chartBuf []string
+
+ data *DataTable
+
+ Width int
+ Height int
+
+ chartHeight int
+ chartWidth int
+
+ paddingX int
+
+ paddingY int
+
+ Flags int
+}
+
+func genBuf(size int) []string {
+ buf := make([]string, size)
+
+ for i := 0; i < size; i++ {
+ buf[i] = " "
+ }
+
+ return buf
+}
+
+// Format float
+func ff(num interface{}) string {
+ return fmt.Sprintf("%.1f", num)
+}
+
+func NewLineChart(width, height int) *LineChart {
+ chart := new(LineChart)
+ chart.Width = width
+ chart.Height = height
+ chart.Buf = genBuf(width * height)
+
+ // axis lines + axies text
+ chart.paddingY = 2
+
+ return chart
+}
+
+func (c *LineChart) DrawAxes(maxX, minX, maxY, minY float64, index int) {
+ side := AXIS_LEFT
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ if index%2 == 0 {
+ side = AXIS_RIGHT
+ }
+
+ c.DrawLine(c.paddingX-1, 1, c.Width-c.paddingX, 1, "-")
+ } else {
+ c.DrawLine(c.paddingX-1, 1, c.Width-1, 1, "-")
+ }
+
+ if side == AXIS_LEFT {
+ c.DrawLine(c.paddingX-1, 1, c.paddingX-1, c.Height-1, "│")
+ } else {
+ c.DrawLine(c.Width-c.paddingX, 1, c.Width-c.paddingX, c.Height-1, "│")
+ }
+
+ left := 0
+ if side == AXIS_RIGHT {
+ left = c.Width - c.paddingX + 1
+ }
+
+ if c.Flags&DRAW_RELATIVE != 0 {
+ c.writeText(ff(minY), left, 1)
+ } else {
+ if minY > 0 {
+ c.writeText("0", left, 1)
+ } else {
+ c.writeText(ff(minY), left, 1)
+ }
+ }
+
+ c.writeText(ff(maxY), left, c.Height-1)
+
+ c.writeText(ff(minX), c.paddingX, 0)
+
+ x_col := c.data.columns[0]
+ c.writeText(c.data.columns[0], c.Width/2-len(x_col)/2, 1)
+
+ if c.Flags&DRAW_INDEPENDENT != 0 || len(c.data.columns) < 3 {
+ col := c.data.columns[index]
+
+ for idx, char := range strings.Split(col, "") {
+ start_from := c.Height/2 + len(col)/2 - idx
+
+ if side == AXIS_LEFT {
+ c.writeText(char, c.paddingX-1, start_from)
+ } else {
+ c.writeText(char, c.Width-c.paddingX, start_from)
+ }
+ }
+ }
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ c.writeText(ff(maxX), c.Width-c.paddingX-len(ff(maxX)), 0)
+ } else {
+ c.writeText(ff(maxX), c.Width-len(ff(maxX)), 0)
+ }
+}
+
+func (c *LineChart) writeText(text string, x, y int) {
+ coord := y*c.Width + x
+
+ for idx, char := range strings.Split(text, "") {
+ c.Buf[coord+idx] = char
+ }
+}
+
+func (c *LineChart) Draw(data *DataTable) (out string) {
+ var scaleY, scaleX float64
+
+ c.data = data
+
+ if c.Flags&DRAW_INDEPENDENT != 0 && len(data.columns) > 3 {
+ fmt.Println("Error: Can't use DRAW_INDEPENDENT for more then 2 graphs")
+ return ""
+ }
+
+ charts := len(data.columns) - 1
+
+ prevPoint := [2]int{-1, -1}
+
+ maxX, minX, maxY, minY := getBoundaryValues(data, -1)
+
+ c.paddingX = int(math.Max(float64(len(ff(minY))), float64(len(ff(maxY))))) + 1
+
+ c.chartHeight = c.Height - c.paddingY
+
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ c.chartWidth = c.Width - 2*c.paddingX
+ } else {
+ c.chartWidth = c.Width - c.paddingX - 1
+ }
+
+ scaleX = float64(c.chartWidth) / (maxX - minX)
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ scaleY = float64(c.chartHeight) / (maxY - minY)
+ } else {
+ scaleY = float64(c.chartHeight) / maxY
+ }
+
+ for i := 1; i < charts+1; i++ {
+ if c.Flags&DRAW_INDEPENDENT != 0 {
+ maxX, minX, maxY, minY = getBoundaryValues(data, i)
+
+ scaleX = float64(c.chartWidth-1) / (maxX - minX)
+ scaleY = float64(c.chartHeight) / maxY
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ scaleY = float64(c.chartHeight) / (maxY - minY)
+ }
+ }
+
+ symbol := Color("•", i)
+
+ c_data := getChartData(data, i)
+
+ for _, point := range c_data {
+ x := int((point[0]-minX)*scaleX) + c.paddingX
+ y := int((point[1])*scaleY) + c.paddingY
+
+ if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
+ y = int((point[1]-minY)*scaleY) + c.paddingY
+ }
+
+ if prevPoint[0] == -1 {
+ prevPoint[0] = x
+ prevPoint[1] = y
+ }
+
+ if prevPoint[0] <= x {
+ c.DrawLine(prevPoint[0], prevPoint[1], x, y, symbol)
+ }
+
+ prevPoint[0] = x
+ prevPoint[1] = y
+ }
+
+ c.DrawAxes(maxX, minX, maxY, minY, i)
+ }
+
+ for row := c.Height - 1; row >= 0; row-- {
+ out += strings.Join(c.Buf[row*c.Width:(row+1)*c.Width], "") + "\n"
+ }
+
+ return
+}
+
+func (c *LineChart) DrawLine(x0, y0, x1, y1 int, symbol string) {
+ drawLine(x0, y0, x1, y1, func(x, y int) {
+ coord := y*c.Width + x
+
+ if coord > 0 && coord < len(c.Buf) {
+ c.Buf[coord] = symbol
+ }
+ })
+}
+
+func getBoundaryValues(data *DataTable, index int) (maxX, minX, maxY, minY float64) {
+ maxX = data.rows[0][0]
+ minX = data.rows[0][0]
+ maxY = data.rows[0][1]
+ minY = data.rows[0][1]
+
+ for _, r := range data.rows {
+ maxX = math.Max(maxX, r[0])
+ minX = math.Min(minX, r[0])
+
+ for idx, c := range r {
+ if idx > 0 {
+ if index == -1 || index == idx {
+ maxY = math.Max(maxY, c)
+ minY = math.Min(minY, c)
+ }
+ }
+ }
+ }
+
+ if maxY > 0 {
+ maxY = maxY * 1.1
+ } else {
+ maxY = maxY * 0.9
+ }
+
+ if minY > 0 {
+ minY = minY * 0.9
+ } else {
+ minY = minY * 1.1
+ }
+
+ return
+}
+
+// DataTable can contain data for multiple graphs, we need to extract only 1
+func getChartData(data *DataTable, index int) (out [][]float64) {
+ for _, r := range data.rows {
+ out = append(out, []float64{r[0], r[index]})
+ }
+
+ return
+}
+
+// Algorithm for drawing line between two points
+//
+// http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
+func drawLine(x0, y0, x1, y1 int, plot func(int, int)) {
+ dx := x1 - x0
+ if dx < 0 {
+ dx = -dx
+ }
+ dy := y1 - y0
+ if dy < 0 {
+ dy = -dy
+ }
+ var sx, sy int
+ if x0 < x1 {
+ sx = 1
+ } else {
+ sx = -1
+ }
+ if y0 < y1 {
+ sy = 1
+ } else {
+ sy = -1
+ }
+ err := dx - dy
+
+ for {
+ plot(x0, y0)
+ if x0 == x1 && y0 == y1 {
+ break
+ }
+ e2 := 2 * err
+ if e2 > -dy {
+ err -= dy
+ x0 += sx
+ }
+ if e2 < dx {
+ err += dx
+ y0 += sy
+ }
+ }
+}