[feat] package charbar: 新package,用于在控制台绘制ascii柱状图

pull/2/head
q191201771 4 years ago
parent 1f3383a4d9
commit ac592538eb

2
.gitignore vendored

@ -9,7 +9,7 @@
/demo/samefile
/demo/time
/demo/temp
/demo/chartbar
/demo/analyse_git_log
/.idea
/.trash

@ -0,0 +1,36 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package main
import (
"flag"
"fmt"
"os"
"github.com/q191201771/naza/pkg/chartbar"
"github.com/q191201771/naza/pkg/nazalog"
)
func main() {
filename := parseFlag()
output, err := chartbar.WithCsv(filename)
nazalog.Assert(nil, err)
fmt.Print(output)
}
func parseFlag() string {
dir := flag.String("f", "", "csv filename")
flag.Parse()
if *dir == "" {
flag.Usage()
os.Exit(1)
}
return *dir
}

@ -0,0 +1,158 @@
// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package chartbar
import (
"encoding/csv"
"fmt"
"math"
"os"
"sort"
"strconv"
"strings"
)
const (
OrderOrigin = iota + 1 // 原始序
OrderAsc // 升序
OrderDesc // 降序
)
type Item struct {
Name string // key
Num float64 // value
count int // bar
}
var (
//barList = "▏▎▍▌▋▊▉█"
// config
maxLength = 50
order = OrderDesc
)
func WithItems(items []Item) (string, error) {
// 最大的画满柱状条,其他的按与最大占比画
maxNum := calcMaxNum(items)
for i := range items {
items[i].count = int(math.Round(items[i].Num * float64(maxLength) / maxNum))
// 最小可能和最大的比太小了
if items[i].count == 0 {
items[i].count = 1
}
}
if order == OrderDesc {
sort.Slice(items, func(i, j int) bool {
return items[i].count > items[j].count
})
}
maxNameLength := calcMaxNameLen(items)
maxCountLength := calcMaxCount(items)
tmpl := fmt.Sprintf(" %%%ds | %%-%ds | %%0.2f\n", maxNameLength, maxCountLength)
_ = maxNameLength
var out string
for _, item := range items {
bar := strings.Repeat("█", item.count)
out += fmt.Sprintf(tmpl, item.Name, bar, item.Num)
}
return out, nil
}
func WithMap(m map[string]int) (string, error) {
var items []Item
for k, v := range m {
item := Item{
Name: k,
Num: float64(v),
}
items = append(items, item)
}
return WithItems(items)
}
func WithMapFloat(m map[string]float64) (string, error) {
var items []Item
for k, v := range m {
item := Item{
Name: k,
Num: v,
}
items = append(items, item)
}
return WithItems(items)
}
func WithCsv(filename string) (string, error) {
// 读取
fp, err := os.Open(filename)
if err != nil {
return "", err
}
defer fp.Close()
r := csv.NewReader(fp)
records, err := r.ReadAll()
if err != nil {
return "", err
}
var items []Item
for _, line := range records {
var item Item
item.Name = line[0]
item.Num, err = strconv.ParseFloat(line[1], 64)
if err != nil {
return "", err
}
items = append(items, item)
}
return WithItems(items)
}
func isFloat(v string) bool {
return strings.Contains(v, ".")
}
func calcMaxNum(items []Item) float64 {
var max float64
for _, item := range items {
if item.Num > max {
max = item.Num
}
}
return max
}
func calcMaxNameLen(items []Item) int {
var max int
for _, item := range items {
if len(item.Name) > max {
max = len(item.Name)
}
}
return max
}
func calcMaxCount(items []Item) int {
var max int
for _, item := range items {
if item.count > max {
max = item.count
}
}
return max
}
Loading…
Cancel
Save