pax_global_header00006660000000000000000000000064135303114060014506gustar00rootroot0000000000000052 comment=6a0632d4b157ee545e0878dbbf5e83b44622d2af golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/000077500000000000000000000000001353031140600236005ustar00rootroot00000000000000golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/.gitignore000066400000000000000000000003151353031140600255670ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # ide .idea golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/.travis.yml000066400000000000000000000004101353031140600257040ustar00rootroot00000000000000language: go go: - "1.x" - "1.8.x" - "1.9.x" - "1.10.x" - master install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover script: - go test -v -race ./. - goveralls -service=travis-ci notifications: email: false golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/LICENSE000066400000000000000000000027471353031140600246170ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2018, Rohit Gupta All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/README.rst000066400000000000000000000062621353031140600252750ustar00rootroot00000000000000.. -*-restructuredtext-*- asciigraph =========== .. image:: https://travis-ci.org/guptarohit/asciigraph.svg?branch=master :target: https://travis-ci.org/guptarohit/asciigraph :alt: Build status .. image:: https://goreportcard.com/badge/github.com/guptarohit/asciigraph :target: https://goreportcard.com/report/github.com/guptarohit/asciigraph :alt: Go Report Card .. image:: https://coveralls.io/repos/github/guptarohit/asciigraph/badge.svg?branch=master :target: https://coveralls.io/github/guptarohit/asciigraph?branch=master :alt: Coverage Status .. image:: https://godoc.org/github.com/guptarohit/asciigraph?status.svg :target: https://godoc.org/github.com/guptarohit/asciigraph :alt: GoDoc .. image:: https://img.shields.io/badge/licence-BSD-blue.svg :target: https://github.com/guptarohit/asciigraph/blob/master/LICENSE :alt: License | Go package to make lightweight ASCII line graphs ╭┈╯. .. image:: https://user-images.githubusercontent.com/7895001/41509956-b1b2b3d0-7279-11e8-9d19-d7dea17d5e44.png Installation ------------ :: go get github.com/guptarohit/asciigraph Usage ----- Basic graph ^^^^^^^^^^^ .. code:: go package main import ( "fmt" "github.com/guptarohit/asciigraph" ) func main() { data := []float64{3, 4, 9, 6, 2, 4, 5, 8, 5, 10, 2, 7, 2, 5, 6} graph := asciigraph.Plot(data) fmt.Println(graph) } Running this example would render the following graph: :: 10.00 ┤ ╭╮ 9.00 ┤ ╭╮ ││ 8.00 ┤ ││ ╭╮││ 7.00 ┤ ││ ││││╭╮ 6.00 ┤ │╰╮ ││││││ ╭ 5.00 ┤ │ │ ╭╯╰╯│││╭╯ 4.00 ┤╭╯ │╭╯ ││││ 3.00 ┼╯ ││ ││││ 2.00 ┤ ╰╯ ╰╯╰╯ .. Command line interface ---------------------- This package also brings a small utility for command line usage. Assuming ``$GOPATH/bin`` is in your ``$PATH``, simply ``go get`` it then install CLI. CLI Installation ^^^^^^^^^^^^^^^^ :: go install github.com/guptarohit/asciigraph/cmd/asciigraph Feed it data points via stdin: :: $ seq 1 72 | asciigraph -h 10 -c "plot data from stdin" 72.00 ┼ 65.55 ┤ ╭──── 59.09 ┤ ╭──────╯ 52.64 ┤ ╭──────╯ 46.18 ┤ ╭──────╯ 39.73 ┤ ╭──────╯ 33.27 ┤ ╭───────╯ 26.82 ┤ ╭──────╯ 20.36 ┤ ╭──────╯ 13.91 ┤ ╭──────╯ 7.45 ┤ ╭──────╯ 1.00 ┼──╯ plot data from stdin .. Acknowledgement ---------------- This package is golang port of library `asciichart `_ written by `@kroitor `_. Contributing ------------ Feel free to make a pull request! :octocat: golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/asciigraph.go000066400000000000000000000074151353031140600262500ustar00rootroot00000000000000package asciigraph import ( "bytes" "fmt" "math" "strings" ) // Plot returns ascii graph for a series. func Plot(series []float64, options ...Option) string { var logMaximum float64 config := configure(config{ Offset: 3, }, options) if config.Width > 0 { series = interpolateArray(series, config.Width) } minimum, maximum := minMaxFloat64Slice(series) if config.Min != nil && *config.Min < minimum { minimum = *config.Min } if config.Max != nil && *config.Max > maximum { maximum = *config.Max } interval := math.Abs(maximum - minimum) if config.Height <= 0 { if int(interval) <= 0 { config.Height = int(interval * math.Pow10(int(math.Ceil(-math.Log10(interval))))) } else { config.Height = int(interval) } } if config.Offset <= 0 { config.Offset = 3 } var min2 float64 var max2 float64 var ratio float64 padding := 0.0 // if we set height to 10 but min and max are both 0, we need 10 units of padding if interval != 0 { ratio = float64(config.Height) / interval } else { ratio = 1 if config.Height > 0 { padding = float64(config.Height) } } min2 = round(minimum * ratio) max2 = round((maximum + padding) * ratio) intmin2 := int(min2) intmax2 := int(max2) rows := int(math.Abs(float64(intmax2 - intmin2))) width := len(series) + config.Offset var plot [][]string // initialise empty 2D grid for i := 0; i < rows+1; i++ { var line []string for j := 0; j < width; j++ { line = append(line, " ") } plot = append(plot, line) } precision := 2 logMaximum = math.Log10(math.Max(math.Abs(maximum), math.Abs(minimum))) //to find number of zeros after decimal if minimum == float64(0) && maximum == float64(0) { logMaximum = float64(-1) } if logMaximum < 0 { // negative log if math.Mod(logMaximum, 1) != 0 { // non-zero digits after decimal precision = precision + int(math.Abs(logMaximum)) } else { precision = precision + int(math.Abs(logMaximum)-1.0) } } else if logMaximum > 2 { precision = 0 } maxNumLength := len(fmt.Sprintf("%0.*f", precision, maximum)) minNumLength := len(fmt.Sprintf("%0.*f", precision, minimum)) maxWidth := int(math.Max(float64(maxNumLength), float64(minNumLength))) // axis and labels for y := intmin2; y < intmax2+1; y++ { var magnitude float64 if rows > 0 { magnitude = maximum - (float64(y-intmin2) * interval / float64(rows)) } else { magnitude = float64(y) } label := fmt.Sprintf("%*.*f", maxWidth+1, precision, magnitude) w := y - intmin2 h := int(math.Max(float64(config.Offset)-float64(len(label)), 0)) plot[w][h] = label if y == 0 { plot[w][config.Offset-1] = "┼" } else { plot[w][config.Offset-1] = "┤" } } y0 := int(round(series[0]*ratio) - min2) var y1 int plot[rows-y0][config.Offset-1] = "┼" // first value for x := 0; x < len(series)-1; x++ { // plot the line y0 = int(round(series[x+0]*ratio) - float64(intmin2)) y1 = int(round(series[x+1]*ratio) - float64(intmin2)) if y0 == y1 { plot[rows-y0][x+config.Offset] = "─" } else { if y0 > y1 { plot[rows-y1][x+config.Offset] = "╰" plot[rows-y0][x+config.Offset] = "╮" } else { plot[rows-y1][x+config.Offset] = "╭" plot[rows-y0][x+config.Offset] = "╯" } start := int(math.Min(float64(y0), float64(y1))) + 1 end := int(math.Max(float64(y0), float64(y1))) for y := start; y < end; y++ { plot[rows-y][x+config.Offset] = "│" } } } // join columns var lines bytes.Buffer for h, horizontal := range plot { if h != 0 { lines.WriteRune('\n') } for _, v := range horizontal { lines.WriteString(v) } } // add caption if not empty if config.Caption != "" { lines.WriteRune('\n') lines.WriteString(strings.Repeat(" ", config.Offset+maxWidth+2)) lines.WriteString(config.Caption) } return lines.String() } golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/asciigraph_test.go000066400000000000000000000257471353031140600273170ustar00rootroot00000000000000package asciigraph import ( "fmt" "testing" ) func TestPlot(t *testing.T) { cases := []struct { data []float64 opts []Option expected string }{ { []float64{1, 1, 1, 1, 1}, nil, ` 1.00 ┼──── `}, { []float64{0, 0, 0, 0, 0}, nil, ` 0.00 ┼──── `}, { []float64{0, 0, 0, 0, 0}, []Option{Height(2)}, ` 0.00 ┼ 0.00 ┤ 0.00 ┼──── `, }, { []float64{2, 1, 1, 2, -2, 5, 7, 11, 3, 7, 1}, nil, ` 11.00 ┤ ╭╮ 10.00 ┤ ││ 9.00 ┼ ││ 8.00 ┤ ││ 7.00 ┤ ╭╯│╭╮ 6.00 ┤ │ │││ 5.00 ┤ ╭╯ │││ 4.00 ┤ │ │││ 3.00 ┤ │ ╰╯│ 2.00 ┼╮ ╭╮│ │ 1.00 ┤╰─╯││ ╰ 0.00 ┤ ││ -1.00 ┤ ││ -2.00 ┤ ╰╯ `}, { []float64{2, 1, 1, 2, -2, 5, 7, 11, 3, 7, 4, 5, 6, 9, 4, 0, 6, 1, 5, 3, 6, 2}, []Option{Caption("Plot using asciigraph.")}, ` 11.00 ┤ ╭╮ 10.00 ┤ ││ 9.00 ┼ ││ ╭╮ 8.00 ┤ ││ ││ 7.00 ┤ ╭╯│╭╮ ││ 6.00 ┤ │ │││ ╭╯│ ╭╮ ╭╮ 5.00 ┤ ╭╯ │││╭╯ │ ││╭╮││ 4.00 ┤ │ ││╰╯ ╰╮││││││ 3.00 ┤ │ ╰╯ ││││╰╯│ 2.00 ┼╮ ╭╮│ ││││ ╰ 1.00 ┤╰─╯││ ││╰╯ 0.00 ┤ ││ ╰╯ -1.00 ┤ ││ -2.00 ┤ ╰╯ Plot using asciigraph.`}, { []float64{.2, .1, .2, 2, -.9, .7, .91, .3, .7, .4, .5}, []Option{Caption("Plot using asciigraph.")}, ` 2.00 ┤ ╭╮ ╭╮ 0.55 ┼──╯│╭╯╰─── -0.90 ┤ ╰╯ Plot using asciigraph.`}, { []float64{2, 1, 1, 2, -2, 5, 7, 11, 3, 7, 1}, []Option{Height(4), Offset(3)}, ` 11.00 ┤ ╭╮ 7.75 ┼ ╭─╯│╭╮ 4.50 ┼╮ ╭╮│ ╰╯│ 1.25 ┤╰─╯││ ╰ -2.00 ┤ ╰╯ `}, { []float64{.453, .141, .951, .251, .223, .581, .771, .191, .393, .617, .478}, nil, ` 0.95 ┤ ╭╮ 0.85 ┤ ││ ╭╮ 0.75 ┤ ││ ││ 0.65 ┤ ││ ╭╯│ ╭╮ 0.55 ┤ ││ │ │ │╰ 0.44 ┼╮││ │ │╭╯ 0.34 ┤│││ │ ││ 0.24 ┤││╰─╯ ╰╯ 0.14 ┤╰╯ `}, { []float64{.01, .004, .003, .0042, .0083, .0033, 0.0079}, nil, ` 0.010 ┼╮ 0.009 ┤│ 0.008 ┤│ ╭╮╭ 0.007 ┤│ │││ 0.006 ┤│ │││ 0.005 ┤│ │││ 0.004 ┤╰╮╭╯││ 0.003 ┤ ╰╯ ╰╯ `}, { []float64{192, 431, 112, 449, -122, 375, 782, 123, 911, 1711, 172}, []Option{Height(10)}, ` 1711 ┤ ╭╮ 1528 ┼ ││ 1344 ┤ ││ 1161 ┤ ││ 978 ┤ ╭╯│ 794 ┤ ╭╮│ │ 611 ┤ │││ │ 428 ┤╭╮╭╮╭╯││ │ 245 ┼╯╰╯││ ╰╯ ╰ 61 ┤ ││ -122 ┤ ╰╯ `}, { []float64{0.3189989805, 0.149949026, 0.30142492354, 0.195129182935, 0.3142492354, 0.1674974513, 0.3142492354, 0.1474974513, 0.3047974513}, []Option{Width(30), Height(5), Caption("Plot with custom height & width.")}, ` 0.32 ┼╮ ╭─╮ ╭╮ ╭ 0.29 ┤╰╮ ╭─╮ ╭╯ │ ╭╯│ │ 0.26 ┤ │ ╭╯ ╰╮ ╭╯ ╰╮ ╭╯ ╰╮ ╭╯ 0.23 ┤ ╰╮ ╭╯ ╰╮│ ╰╮╭╯ ╰╮ ╭╯ 0.20 ┤ ╰╮│ ╰╯ ╰╯ │╭╯ 0.16 ┤ ╰╯ ╰╯ Plot with custom height & width.`}, { []float64{ 0, 0, 0, 0, 1.5, 0, 0, -0.5, 9, -3, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1.5, 0, 0, -0.5, 8, -3, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1.5, 0, 0, -0.5, 10, -3, 0, 0, 1, 2, 1, 0, 0, 0, 0, }, []Option{Offset(10), Height(10), Caption("I'm a doctor, not an engineer.")}, ` 10.00 ┤ ╭╮ 8.70 ┤ ╭╮ ││ 7.40 ┼ ││ ╭╮ ││ 6.10 ┤ ││ ││ ││ 4.80 ┤ ││ ││ ││ 3.50 ┤ ││ ││ ││ 2.20 ┤ ││ ╭╮ ││ ╭╮ ││ ╭╮ 0.90 ┤ ╭╮ ││ ╭╯╰╮ ╭╮ ││ ╭╯╰╮ ╭╮ ││ ╭╯╰╮ -0.40 ┼───╯╰──╯│╭─╯ ╰───────╯╰──╯│╭─╯ ╰───────╯╰──╯│╭─╯ ╰─── -1.70 ┤ ││ ││ ││ -3.00 ┤ ╰╯ ╰╯ ╰╯ I'm a doctor, not an engineer.`}, { []float64{-5, -2, -3, -4, 0, -5, -6, -7, -8, 0, -9, -3, -5, -2, -9, -3, -1}, nil, ` 0.00 ┤ ╭╮ ╭╮ -1.00 ┤ ││ ││ ╭ -2.00 ┤╭╮ ││ ││ ╭╮ │ -3.00 ┤│╰╮││ ││╭╮││╭╯ -4.00 ┤│ ╰╯│ │││││││ -5.00 ┼╯ ╰╮ │││╰╯││ -6.00 ┤ ╰╮ │││ ││ -7.00 ┤ ╰╮│││ ││ -8.00 ┤ ╰╯││ ││ -9.00 ┼ ╰╯ ╰╯ `}, { []float64{-0.000018527, -0.021, -.00123, .00000021312, -.0434321234, -.032413241234, .0000234234}, []Option{Height(5), Width(45)}, ` 0.000 ┼─╮ ╭────────╮ ╭ -0.008 ┤ ╰──╮ ╭──╯ ╰─╮ ╭─╯ -0.017 ┤ ╰─────╯ ╰╮ ╭─╯ -0.025 ┤ ╰─╮ ╭─╯ -0.034 ┤ ╰╮ ╭────╯ -0.042 ┼ ╰───╯ `}, { []float64{57.76, 54.04, 56.31, 57.02, 59.5, 52.63, 52.97, 56.44, 56.75, 52.96, 55.54, 55.09, 58.22, 56.85, 60.61, 59.62, 59.73, 59.93, 56.3, 54.69, 55.32, 54.03, 50.98, 50.48, 54.55, 47.49, 55.3, 46.74, 46, 45.8, 49.6, 48.83, 47.64, 46.61, 54.72, 42.77, 50.3, 42.79, 41.84, 44.19, 43.36, 45.62, 45.09, 44.95, 50.36, 47.21, 47.77, 52.04, 47.46, 44.19, 47.22, 45.55, 40.65, 39.64, 37.26, 40.71, 42.15, 36.45, 39.14, 36.62}, []Option{Width(-10), Height(-10), Offset(-1)}, ` 60.61 ┤ ╭╮ ╭╮ 59.60 ┤ ╭╮ │╰─╯│ 58.60 ┤ ││ ╭╮│ │ 57.59 ┼╮ ╭╯│ │││ │ 56.58 ┤│╭╯ │ ╭─╮ │╰╯ ╰╮ 55.58 ┤││ │ │ │╭─╯ │╭╮ ╭╮ 54.57 ┤╰╯ │ │ ││ ╰╯╰╮ ╭╮││ ╭╮ 53.56 ┤ │╭╯ ╰╯ │ ││││ ││ 52.56 ┤ ╰╯ │ ││││ ││ ╭╮ 51.55 ┤ ╰╮││││ ││ ││ 50.54 ┤ ╰╯│││ ││╭╮ ╭╮ ││ 49.54 ┤ │││ ╭─╮ ││││ ││ ││ 48.53 ┤ │││ │ │ ││││ ││ ││ 47.52 ┤ ╰╯│ │ ╰╮││││ │╰─╯╰╮╭╮ 46.52 ┤ ╰─╮│ ╰╯│││ │ │││ 45.51 ┤ ╰╯ │││ ╭──╯ ││╰╮ 44.50 ┤ │││ ╭╮│ ╰╯ │ 43.50 ┤ ││╰╮│╰╯ │ 42.49 ┤ ╰╯ ╰╯ │ ╭╮ 41.48 ┤ │ ││ 40.48 ┤ ╰╮ ╭╯│ 39.47 ┤ ╰╮│ │╭╮ 38.46 ┤ ││ │││ 37.46 ┤ ╰╯ │││ 36.45 ┤ ╰╯╰ `}, { []float64{2, 1, 1, 2, -2, 5, 7, 11, 3, 7, 4, 5, 6, 9, 4, 0, 6, 1, 5, 3, 6, 2}, []Option{Min(-3), Max(13)}, ` 13.00 ┤ 12.00 ┤ 11.00 ┤ ╭╮ 10.00 ┼ ││ 9.00 ┤ ││ ╭╮ 8.00 ┤ ││ ││ 7.00 ┤ ╭╯│╭╮ ││ 6.00 ┤ │ │││ ╭╯│ ╭╮ ╭╮ 5.00 ┤ ╭╯ │││╭╯ │ ││╭╮││ 4.00 ┤ │ ││╰╯ ╰╮││││││ 3.00 ┤ │ ╰╯ ││││╰╯│ 2.00 ┼╮ ╭╮│ ││││ ╰ 1.00 ┤╰─╯││ ││╰╯ 0.00 ┤ ││ ╰╯ -1.00 ┤ ││ -2.00 ┤ ╰╯ -3.00 ┤ `}, { []float64{2, 1, 1, 2, -2, 5, 7, 11, 3, 7, 4, 5, 6, 9, 4, 0, 6, 1, 5, 3, 6, 2}, []Option{Min(0), Max(3)}, ` 11.00 ┤ ╭╮ 10.00 ┤ ││ 9.00 ┼ ││ ╭╮ 8.00 ┤ ││ ││ 7.00 ┤ ╭╯│╭╮ ││ 6.00 ┤ │ │││ ╭╯│ ╭╮ ╭╮ 5.00 ┤ ╭╯ │││╭╯ │ ││╭╮││ 4.00 ┤ │ ││╰╯ ╰╮││││││ 3.00 ┤ │ ╰╯ ││││╰╯│ 2.00 ┼╮ ╭╮│ ││││ ╰ 1.00 ┤╰─╯││ ││╰╯ 0.00 ┤ ││ ╰╯ -1.00 ┤ ││ -2.00 ┤ ╰╯ `}, } for i := range cases { name := fmt.Sprintf("%d", i) t.Run(name, func(t *testing.T) { c := cases[i] actual := Plot(c.data, c.opts...) if actual != c.expected { conf := configure(config{}, c.opts) t.Errorf("Plot(%f, %#v)", c.data, conf) t.Logf("expected:\n%s\n", c.expected) } t.Logf("actual:\n%s\n", actual) }) } } golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/cmd/000077500000000000000000000000001353031140600243435ustar00rootroot00000000000000golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/cmd/asciigraph/000077500000000000000000000000001353031140600264555ustar00rootroot00000000000000golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/cmd/asciigraph/main.go000066400000000000000000000025601353031140600277330ustar00rootroot00000000000000package main import ( "bufio" "flag" "fmt" "log" "os" "strconv" "github.com/guptarohit/asciigraph" ) var ( height uint width uint offset uint = 3 caption string ) func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) fmt.Fprintf(os.Stderr, " %s [options]\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Options:\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "%s expects data points from stdin. Invalid values are logged to stderr.\n", os.Args[0]) } flag.UintVar(&height, "h", height, "`height` in text rows, 0 for auto-scaling") flag.UintVar(&width, "w", width, "`width` in columns, 0 for auto-scaling") flag.UintVar(&offset, "o", offset, "`offset` in columns, for the label") flag.StringVar(&caption, "c", caption, "`caption` for the graph") flag.Parse() data := make([]float64, 0, 64) s := bufio.NewScanner(os.Stdin) s.Split(bufio.ScanWords) for s.Scan() { word := s.Text() p, err := strconv.ParseFloat(word, 64) if err != nil { log.Printf("ignore %q: cannot parse value", word) continue } data = append(data, p) } if err := s.Err(); err != nil { log.Fatal(err) } if len(data) == 0 { log.Fatal("no data") } plot := asciigraph.Plot(data, asciigraph.Height(int(height)), asciigraph.Width(int(width)), asciigraph.Offset(int(offset)), asciigraph.Caption(caption)) fmt.Println(plot) } golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/examples/000077500000000000000000000000001353031140600254165ustar00rootroot00000000000000golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/examples/SineCurve.go000066400000000000000000000033621353031140600276540ustar00rootroot00000000000000package main import ( "fmt" "math" "github.com/guptarohit/asciigraph" ) func main() { var data []float64 // sine curve for i := 0; i < 105; i++ { data = append(data, 15*math.Sin(float64(i)*((math.Pi*4)/120.0))) } graph := asciigraph.Plot(data, asciigraph.Height(10)) fmt.Println(graph) // Output: // 15.00 ┤ ╭────────╮ ╭────────╮ // 12.00 ┤ ╭──╯ ╰──╮ ╭──╯ ╰──╮ // 9.00 ┤ ╭──╯ ╰─╮ ╭──╯ ╰─╮ // 6.00 ┤ ╭─╯ ╰──╮ ╭─╯ ╰──╮ // 3.00 ┤╭─╯ ╰─╮ ╭─╯ ╰─╮ // 0.00 ┼╯ ╰╮ ╭╯ ╰╮ // -3.00 ┤ ╰─╮ ╭─╯ ╰─╮ // -6.00 ┤ ╰─╮ ╭──╯ ╰─╮ // -9.00 ┤ ╰──╮ ╭─╯ ╰──╮ // -12.00 ┤ ╰──╮ ╭──╯ ╰──╮ // -15.00 ┤ ╰────────╯ ╰─── } golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/options.go000066400000000000000000000034331353031140600256250ustar00rootroot00000000000000package asciigraph import ( "strings" ) // Option represents a configuration setting. type Option interface { apply(c *config) } // config holds various graph options type config struct { Width, Height int Min, Max *float64 Offset int Caption string } // An optionFunc applies an option. type optionFunc func(*config) // apply implements the Option interface. func (of optionFunc) apply(c *config) { of(c) } func configure(defaults config, options []Option) *config { for _, o := range options { o.apply(&defaults) } return &defaults } // Width sets the graphs width. By default, the width of the graph is // determined by the number of data points. If the value given is a // positive number, the data points are interpolated on the x axis. // Values <= 0 reset the width to the default value. func Width(w int) Option { return optionFunc(func(c *config) { if w > 0 { c.Width = w } else { c.Width = 0 } }) } // Height sets the graphs height. func Height(h int) Option { return optionFunc(func(c *config) { if h > 0 { c.Height = h } else { c.Height = 0 } }) } // Min sets the graph's minimum value for the vertical axis. It will be ignored // if the series contains a lower value. func Min(min float64) Option { return optionFunc(func(c *config) { c.Min = &min }) } // Max sets the graph's maximum value for the vertical axis. It will be ignored // if the series contains a bigger value. func Max(max float64) Option { return optionFunc(func(c *config) { c.Max = &max }) } // Offset sets the graphs offset. func Offset(o int) Option { return optionFunc(func(c *config) { c.Offset = o }) } // Caption sets the graphs caption. func Caption(caption string) Option { return optionFunc(func(c *config) { c.Caption = strings.TrimSpace(caption) }) } golang-github-jesseduffield-asciigraph-0.4.1+git20190605.6d88e39/utils.go000066400000000000000000000023741353031140600252750ustar00rootroot00000000000000package asciigraph import "math" func minMaxFloat64Slice(v []float64) (min, max float64) { min = math.Inf(1) max = math.Inf(-1) if len(v) == 0 { panic("Empty slice") } for _, e := range v { if e < min { min = e } if e > max { max = e } } return } func round(input float64) float64 { if math.IsNaN(input) { return math.NaN() } sign := 1.0 if input < 0 { sign = -1 input *= -1 } _, decimal := math.Modf(input) var rounded float64 if decimal >= 0.5 { rounded = math.Ceil(input) } else { rounded = math.Floor(input) } return rounded * sign } func linearInterpolate(before, after, atPoint float64) float64 { return before + (after-before)*atPoint } func interpolateArray(data []float64, fitCount int) []float64 { var interpolatedData []float64 springFactor := float64(len(data)-1) / float64(fitCount-1) interpolatedData = append(interpolatedData, data[0]) for i := 1; i < fitCount-1; i++ { spring := float64(i) * springFactor before := math.Floor(spring) after := math.Ceil(spring) atPoint := spring - before interpolatedData = append(interpolatedData, linearInterpolate(data[int(before)], data[int(after)], atPoint)) } interpolatedData = append(interpolatedData, data[len(data)-1]) return interpolatedData }