bitbucket.org/ai69/amoy@v0.2.3/render.go (about)

     1  package amoy
     2  
     3  import (
     4  	"math"
     5  	"strings"
     6  
     7  	tw "github.com/olekukonko/tablewriter"
     8  )
     9  
    10  // RenderTableString renders the rows as table and returns as string for console.
    11  func RenderTableString(header []string, rows [][]string) string {
    12  	s := strings.Builder{}
    13  	table := tw.NewWriter(&s)
    14  	table.SetHeader(header)
    15  	table.SetHeaderAlignment(tw.ALIGN_LEFT)
    16  	table.SetHeaderLine(false)
    17  	table.SetTablePadding("\t")
    18  	table.SetAlignment(tw.ALIGN_LEFT)
    19  	table.SetAutoWrapText(false)
    20  	table.SetAutoFormatHeaders(true)
    21  	table.SetBorders(tw.Border{Left: true, Top: false, Right: true, Bottom: false})
    22  	table.SetCenterSeparator(EmptyStr)
    23  	table.SetColumnSeparator(EmptyStr)
    24  	table.SetRowSeparator(EmptyStr)
    25  
    26  	for _, r := range rows {
    27  		table.Append(r)
    28  	}
    29  
    30  	table.Render()
    31  	return s.String()
    32  }
    33  
    34  var (
    35  	sparkLineLevels = []rune("▁▂▃▄▅▆▇█")
    36  	blocks          = []rune(`░▏▎▍▌▋▊▉█`)
    37  )
    38  
    39  // RenderSparkline generates a sparkline string like ▅▆▂▂▅▇▂▂▃▆▆▆▅▃ from a slice of float64.
    40  func RenderSparkline(nums []float64) string {
    41  	n := len(nums)
    42  	if n == 0 {
    43  		return ""
    44  	}
    45  	min := math.Inf(1)
    46  	max := math.Inf(-1)
    47  	for _, y := range nums {
    48  		if y < min {
    49  			min = y
    50  		}
    51  		if y > max {
    52  			max = y
    53  		}
    54  	}
    55  	if max == min {
    56  		return strings.Repeat(string(sparkLineLevels[0]), n)
    57  	}
    58  	var (
    59  		line  = make([]rune, n)
    60  		ratio = (float64(len(sparkLineLevels)) - 1) / (max - min)
    61  	)
    62  	for i := range nums {
    63  		j := int(math.Floor(ratio * (nums[i] - min)))
    64  		line[i] = sparkLineLevels[j]
    65  	}
    66  	return string(line)
    67  }
    68  
    69  // RenderPartialBlock generates a partial block string like █▍░░ from a float64 between 0 and 1.
    70  func RenderPartialBlock(num float64, length int) string {
    71  	// length must be positive
    72  	if length < 1 {
    73  		length = 1
    74  	}
    75  	// num must be between 0 and 1
    76  	if num < 0 {
    77  		num = 0
    78  	} else if num > 1 {
    79  		num = 1
    80  	}
    81  
    82  	// total number of blocks, i.e. each rune contains 8 blocks
    83  	total := length * 8
    84  	prog := int(math.Round(num * float64(total)))
    85  
    86  	var sb strings.Builder
    87  	// full blocks
    88  	if n := prog / 8; n > 0 {
    89  		sb.WriteString(strings.Repeat(string(blocks[8]), n))
    90  	}
    91  	// partial block
    92  	if n := prog % 8; n > 0 {
    93  		sb.WriteRune(blocks[n])
    94  	}
    95  	// empty blocks
    96  	if n := (total - prog) / 8; n > 0 {
    97  		sb.WriteString(strings.Repeat(string(blocks[0]), n))
    98  	}
    99  	return sb.String()
   100  }