1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-30 13:48:54 +08:00

Add round and suffix based value formatter for the Y-axis label representation

Signed-off-by: Xabier Larrakoetxea <slok69@gmail.com>
This commit is contained in:
Xabier Larrakoetxea 2019-05-06 07:56:04 +02:00
parent 38f40428a1
commit a5c7363f43
No known key found for this signature in database
GPG Key ID: FDAD7FD8275E1B32
2 changed files with 133 additions and 8 deletions

View File

@ -20,6 +20,7 @@ package linechart
import ( import (
"fmt" "fmt"
"math" "math"
"strings"
"time" "time"
) )
@ -42,33 +43,34 @@ func durationSingleUnitPrettyFormat(d time.Duration, decimals int) string {
return fmt.Sprintf(dFmt, d.Nanoseconds()) return fmt.Sprintf(dFmt, d.Nanoseconds())
// Microseconds. // Microseconds.
case d.Seconds()*1000*1000 < 1000: case d.Seconds()*1000*1000 < 1000:
dFmt := prefix + decimalFormat(decimals, "µs") dFmt := prefix + suffixDecimalFormat(decimals, "µs")
return fmt.Sprintf(dFmt, d.Seconds()*1000*1000) return fmt.Sprintf(dFmt, d.Seconds()*1000*1000)
// Milliseconds. // Milliseconds.
case d.Seconds()*1000 < 1000: case d.Seconds()*1000 < 1000:
dFmt := prefix + decimalFormat(decimals, "ms") dFmt := prefix + suffixDecimalFormat(decimals, "ms")
return fmt.Sprintf(dFmt, d.Seconds()*1000) return fmt.Sprintf(dFmt, d.Seconds()*1000)
// Seconds. // Seconds.
case d.Seconds() < 60: case d.Seconds() < 60:
dFmt := prefix + decimalFormat(decimals, "s") dFmt := prefix + suffixDecimalFormat(decimals, "s")
return fmt.Sprintf(dFmt, d.Seconds()) return fmt.Sprintf(dFmt, d.Seconds())
// Minutes. // Minutes.
case d.Minutes() < 60: case d.Minutes() < 60:
dFmt := prefix + decimalFormat(decimals, "m") dFmt := prefix + suffixDecimalFormat(decimals, "m")
return fmt.Sprintf(dFmt, d.Minutes()) return fmt.Sprintf(dFmt, d.Minutes())
// Hours. // Hours.
case d.Hours() < 24: case d.Hours() < 24:
dFmt := prefix + decimalFormat(decimals, "h") dFmt := prefix + suffixDecimalFormat(decimals, "h")
return fmt.Sprintf(dFmt, d.Hours()) return fmt.Sprintf(dFmt, d.Hours())
// Days. // Days.
default: default:
dFmt := prefix + decimalFormat(decimals, "d") dFmt := prefix + suffixDecimalFormat(decimals, "d")
return fmt.Sprintf(dFmt, d.Hours()/24) return fmt.Sprintf(dFmt, d.Hours()/24)
} }
} }
func decimalFormat(decimals int, unit string) string { func suffixDecimalFormat(decimals int, suffix string) string {
return fmt.Sprintf("%%.%df%s", decimals, unit) suffix = strings.ReplaceAll(suffix, "%", "%%") // safe `%` character for fmt.
return fmt.Sprintf("%%.%df%s", decimals, suffix)
} }
// ValueFormatterSingleUnitDuration is a factory to create a custom duration // ValueFormatterSingleUnitDuration is a factory to create a custom duration
@ -103,3 +105,42 @@ func ValueFormatterSingleUnitSeconds(seconds float64) string {
f := ValueFormatterSingleUnitDuration(time.Second, 0) f := ValueFormatterSingleUnitDuration(time.Second, 0)
return f(seconds) return f(seconds)
} }
// ValueFormatterRound is a formatter that will receive a float64
// value and will round to the nearest value without decimals.
func ValueFormatterRound(value float64) string {
f := ValueFormatterRoundWithSuffix("")
return f(value)
}
// ValueFormatterRoundWithSuffix is a factory that returns a formatter
// that will receive a float64 value and will round to the nearest value
// without decimals adding a suffix to the final value string representation.
func ValueFormatterRoundWithSuffix(suffix string) ValueFormatter {
return valueFormatterSuffixWithTransformer(0, suffix, math.Round)
}
// ValueFormatterSuffix is a factory that returns a formatter
// that will receive a float64 value and return a string representation with
// the desired number of decimal truncated and a suffix.
func ValueFormatterSuffix(decimals int, suffix string) ValueFormatter {
return valueFormatterSuffixWithTransformer(decimals, suffix, nil)
}
// valueFormatterSuffixWithTransformer is a factory that returns a formatter
// that will apply a tranform function to the received value before
// returning the decimal with suffix representation.
func valueFormatterSuffixWithTransformer(decimals int, suffix string, transformFunc func(float64) float64) ValueFormatter {
dFmt := suffixDecimalFormat(decimals, suffix)
return func(value float64) string {
if math.IsNaN(value) {
return ""
}
if transformFunc != nil {
value = transformFunc(value)
}
return fmt.Sprintf(dFmt, value)
}
}

View File

@ -143,6 +143,90 @@ func TestFormatters(t *testing.T) {
formatter: ValueFormatterSingleUnitDuration(time.Nanosecond, 8), formatter: ValueFormatterSingleUnitDuration(time.Nanosecond, 8),
want: "", want: "",
}, },
{
desc: "Round formatter handles NaN values",
value: math.NaN(),
formatter: ValueFormatterRound,
want: "",
},
{
desc: "Round formatter handles 0 values",
value: 0,
formatter: ValueFormatterRound,
want: "0",
},
{
desc: "Round formatter handles > x.5 values",
value: 96.7,
formatter: ValueFormatterRound,
want: "97",
},
{
desc: "Round formatter handles < x.5 values",
value: 1621.2,
formatter: ValueFormatterRound,
want: "1621",
},
{
desc: "Round formatter handles x.5 values",
value: 6.5,
formatter: ValueFormatterRound,
want: "7",
},
{
desc: "Round formatter handles minus > x.5 values",
value: -96.7,
formatter: ValueFormatterRound,
want: "-97",
},
{
desc: "Round formatter handles minus < x.5 values",
value: -1621.2,
formatter: ValueFormatterRound,
want: "-1621",
},
{
desc: "Round formatter handles minus x.5 values",
value: -6.5,
formatter: ValueFormatterRound,
want: "-7",
},
{
desc: "Round formatter handles values with suffix",
value: 96.7,
formatter: ValueFormatterRoundWithSuffix("km"),
want: "97km",
},
{
desc: "Suffix formatter handles values with decimals",
value: 11234567890.71234567890,
formatter: ValueFormatterSuffix(4, " reqps"),
want: "11234567890.7123 reqps",
},
{
desc: "Suffix formatter handles NaN values",
value: math.NaN(),
formatter: ValueFormatterSuffix(2, "test"),
want: "",
},
{
desc: "Suffix formatter handles 0 values",
value: 0,
formatter: ValueFormatterSuffix(2, "test"),
want: "0.00test",
},
{
desc: "Suffix formatters handles correctly percent suffix",
value: 96.78,
formatter: ValueFormatterSuffix(2, "%"),
want: "96.78%",
},
{
desc: "Round formatter handles values with percent suffix",
value: 96.7,
formatter: ValueFormatterRoundWithSuffix("%"),
want: "97%",
},
} }
for _, tc := range tests { for _, tc := range tests {