Giter Site home page Giter Site logo

guptarohit / asciigraph Goto Github PK

View Code? Open in Web Editor NEW
2.6K 30.0 99.0 138 KB

Go package to make lightweight ASCII line graph ╭┈╯ in command line apps with no other dependencies.

Home Page: https://pkg.go.dev/github.com/guptarohit/asciigraph

License: BSD 3-Clause "New" or "Revised" License

Go 99.21% Dockerfile 0.79%
asciigraph graph plot chart ascii-chart line-chart golang go utility command-line

asciigraph's People

Contributors

carlosms avatar dmke avatar ewanme avatar guptarohit avatar jeffrey-jiao-epic avatar karlheitmann avatar kroitor avatar loic5 avatar nathanbaulch avatar quackduck avatar sinkevichmm avatar xordspar0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

asciigraph's Issues

Confused about the Offset option

I'm a bit confused about the meaning of the Offset option.

for i := 0; i < 10; i++ {
	println("offset", i, ":", Plot([]float64{0}, Offset(i)))
}
offset 0 :  0.00 ┼
offset 1 : ┼
offset 2 :  0.00┼
offset 3 :  0.00 ┼
offset 4 :  0.00  ┼
offset 5 :  0.00   ┼
offset 6 :   0.00   ┼
offset 7 :    0.00   ┼
offset 8 :     0.00   ┼
offset 9 :      0.00   ┼

This is pretty odd behavior that raises a few questions. Is the purpose of this option to add space before or after the y-axis label? It seems to do a bit of both in an inconsistent way.

NaN numbers

It would be great it the library can accept NaN float64 values. It can simply create a discontinuity in the the graph.
Currently I have to do a validation to prevent the package from panicking.

Two options: ColorAbove and ColorBelow

Hi.

I've added some code to enable options to color the parts of the graph that is above/below a certain value. So this graph:
bilde

Is produced by the following code:

func main() {
	series := []float64{1, 2, 3, 4, 5, 4, 3, 2, 1}
	graph := asciigraph.Plot(series, asciigraph.Height(10),
		asciigraph.Width(50),
		asciigraph.Caption("A simple line graph"),
		asciigraph.ColorAbove(asciigraph.Red, 4.0),
		asciigraph.ColorBelow(asciigraph.DarkGreen, 2.0),
	)
	fmt.Println(graph)
}

Lemme know if you want me to contribute this in a proper manner. If so I'll but a bow on it and hand it over.

Cheers,

Per.

Print X-Axis values

Hi there, pretty awesome lib!

How complex would it be to add an option to print the x-axis in addition to the y-axis?
I want to use your library in my fan2go project to print fan curve data to console, and it would be very helpful for users to see the x-axis values (0-255).

Thx!

Add legend to graph

I would like to be able to add a graph legend which would help with deciphering colored graphs. My idea is to add an extra line underneath the caption with colored boxes for each line on the graph with an explanation of what each color represents.

I'm already working on an implementation. If this is a feature you'd like, I thougth I could perhaps open a PR when I'm finished?

Panics if data is flat

If each data point in the input is the same, asciigraph panics. This can be demonstrated simply using the command line interface:

> echo 1 1 | asciigraph
panic: runtime error: index out of range

goroutine 1 [running]:
github.com/guptarohit/asciigraph.Plot(0xc420057c18, 0x2, 0x40, 0xc420057eb8, 0x4, 0x4, 0x17, 0x115f6c0)
        /home/me/go/src/github.com/guptarohit/asciigraph/asciigraph.go:92 +0x1525
main.main()
        /home/me/go/src/github.com/guptarohit/asciigraph/cmd/asciigraph/main.go:56 +0x5e0

I've also written a test that demonstrates it: xordspar0@f02e7a5

Axis cross (┼) is in the wrong place at some scales

For some inputs and at certain scales, the axis cross doesn't line up with the plotted data:
screen shot 2019-02-02 at 2 37 29 pm

I can reproduce this with the following inputs:

echo '3084
3056
3047
3043
3041
3043
3043
3036
3033
3042
3042
3040
3032
3039
3018
2925
2926
2925
2923
2922
2924
2920
2910
2906
2907
2908
2908
2908
2908
2917
2914
2911
2914
2909
2913
2910
2914
2915
2894
2915
2913
2915
2907
2908
2916
2911
2910
2912
2903
2914
2911
2905
2903
2901
2910
2899
2901
2901
2902
2909
2904
2908
2893
2901
2903
2903
2908
2910
2900
2898
2903
2895' | asciigraph -h 24

PlotMany() modifies caller data slices, yielding incorrect plots when called multiple times when a fixed Width is set

Hi, this is a neat little library, thanks for developing it!

However I've encountered some surprising behavior by PlotMany() that can lead to wildly incorrect output graphs if not guarded against. Thanks for taking a look at this and any fixes you can make.

What I observe:

Repeated calls to PlotMany() with the same data slices (with new values appended for each new call) result in the passed data slices being unexpectedly modified by the method.

This appears to happen when a fixed Width() is specified, here:
https://github.com/guptarohit/asciigraph/blob/master/asciigraph.go#L30-L39

This results in incorrect distortions in the output plots (the lines should be straight), such as:

 996 ┤                                                                                              ╭────
 946 ┤                                                                                     ╭────────╯
 896 ┤                                                                             ╭───────╯
 847 ┤                                                                     ╭───────╯
 797 ┤                                                               ╭─────╯
 747 ┤                                                         ╭─────╯
 697 ┤                                                   ╭─────╯
 647 ┤                                              ╭────╯
 598 ┤                                          ╭───╯
 548 ┤                                      ╭───╯
 498 ┤                                  ╭───╯
 448 ┤                               ╭──╯
 398 ┤                            ╭──╯
 349 ┤                         ╭──╯                                                                 ╭────
 299 ┤                       ╭─╯                                           ╭────────────────────────╯
 249 ┤                     ╭─╯                           ╭─────────────────╯
 199 ┤                   ╭─╯                ╭────────────╯
 149 ┤                 ╭─╯        ╭─────────╯
 100 ┤               ╭─╯   ╭──────╯
  50 ┤            ╭──╭─────╯
   0 ┼───────────────╯
                                  Default: reuse data slices (observed output)

What I expect:

Without very clear documentation, I expect that library API calls will not modify the length or contents of passed data slices.
In the case of this library, there is no reason to expect that the data passed in for plotting will be modified, as that is not typical behavior for plotting packages.

At a minimum the documentation should be updated to warn users of this side-effect. But ideally, the library would make internal copies of data that needs to be modified.

The expected output (straight lines) is:

 996 ┤                                                                                                ╭──
 946 ┤                                                                                           ╭────╯
 896 ┤                                                                                      ╭────╯
 847 ┤                                                                                 ╭────╯
 797 ┤                                                                            ╭────╯
 747 ┤                                                                       ╭────╯
 697 ┤                                                                  ╭────╯
 647 ┤                                                             ╭────╯
 598 ┤                                                        ╭────╯
 548 ┤                                                   ╭────╯
 498 ┤                                              ╭────╯
 448 ┤                                          ╭───╯
 398 ┤                                     ╭────╯
 349 ┤                                ╭────╯                                                          ╭──
 299 ┤                           ╭────╯                                                ╭──────────────╯
 249 ┤                      ╭────╯                                      ╭──────────────╯
 199 ┤                 ╭────╯                            ╭──────────────╯
 149 ┤            ╭────╯                   ╭─────────────╯
 100 ┤       ╭────╯         ╭──────────────╯
  50 ┤  ╭────╭──────────────╯
   0 ┼───────╯
                             Workaround: freshly copy data slices (expected output)

Reproduction:

import (
	"fmt"
	"github.com/guptarohit/asciigraph"
)

func main() {
	data := [][]float64{nil, nil}
	data2 := [][]float64{nil, nil}
	dataCopy := [][]float64{nil, nil}

	for x := 1; x < 1000; x += 5 {
		data[0] = append(data[0], float64(x))
		data[1] = append(data[1], float64(x)/3.0)
		data2[0] = append(data2[0], float64(x))
		data2[1] = append(data2[1], float64(x)/3.0)

		dataCopy[0] = make([]float64, len(data[0]))
		copy(dataCopy[0], data[0])
		dataCopy[1] = make([]float64, len(data[1]))
		copy(dataCopy[1], data[1])

		_ = asciigraph.PlotMany(dataCopy, asciigraph.Height(20), asciigraph.Width(100), asciigraph.LowerBound(0))
		_ = asciigraph.PlotMany(data2, asciigraph.Height(20), asciigraph.Width(100), asciigraph.LowerBound(0))
	}

	fmt.Println(asciigraph.PlotMany(data, asciigraph.Height(20), asciigraph.Width(100), asciigraph.LowerBound(0), asciigraph.Caption("Workaround: freshly copy data slices (expected output)")))
	fmt.Println("\n")
	fmt.Println(asciigraph.PlotMany(data2, asciigraph.Height(20), asciigraph.Width(100), asciigraph.LowerBound(0), asciigraph.Caption("Default: reuse data slices (observed output)")))
}

Reformat Code

It would be nice if instead of having only one function that just generates a string, we had a struct named 'struct graph' for example, that had this method, configurations and other utilities inside. Subsequently, it would be easier to change implementations of other methods without changing the interface.

Besides that, we can add other methods, e.g. one could be to plot several graphs together or show statistics. However, (from my standpoint) it is essential to rewrite code so that it supports structure which will implement methods. In addition, it would encourage other users to write code for this project and making contributions much easier.

DISCLAIMER: I don't mean to delete old code, because other projects might be using it, so I will just extend it to support classes.

PlotMany from command line

I'd like di plot different series in the same chart, providing inputs from stdin (pipe).

Is there any way to do so?

CLI: for realtime data stream, clear old graph before plotting new data

Currently, when we pass data stream to cli of asciigraph it outputs the graph to stdout by default.

While this works fine in general, it becomes problematic when plotting in realtime mode as terminal retains the previous graph outputs.

To address this, it would be nice to keep only the latest plot copy in the terminal. To achieve it, clear the already plotted graph first before plotting new when we plotting realtime graph from stdin.

Possible solution: we can utilise ANSI escape sequences to move the cursor and clear the old graph. The following snippets might be helpful:

Move cursor n lines up: fmt.Sprintf("\033[%dA", n)
Clear the line: fmt.Sprintf("\033[2K")

Panic when no positive values provided

When no positive floats are provided to Plot(), a panic is observed:

Examples:

package main

import "github.com/guptarohit/asciigraph"

func main() {
	println(asciigraph.Plot([]float64{0}))
}
package main

import "github.com/guptarohit/asciigraph"

func main() {
	println(asciigraph.Plot([]float64{-1}))
}

Result:

PS C:\Users\Lee\test> go run .\main.go
panic: runtime error: index out of range

goroutine 1 [running]:
github.com/guptarohit/asciigraph.Plot(0xc00007df78, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0)
        C:/Users/Lee/go/pkg/mod/github.com/guptarohit/[email protected]/asciigraph.go:92 +0x13aa
main.main()
        C:/Users/Lee/test/main.go:6 +0x67
exit status 2

Line 92 is as follows:

plot[rows-y0][config.Offset-1] = "┼" // first value

How to install now that `go get` is deprecated

This looks really neat. But I'm having trouble installing it. Anyone know of a workaround now that go get is deprecated?

  • macOS 13.4.1
  • Go 1.20.5

go get

$ go get github.com/guptarohit/asciigraph
go: go.mod file not found in current directory or any parent directory.
	'go get' is no longer supported outside a module.
	To build and install a command, use 'go install' with a version,
	like 'go install example.com/cmd@latest'
	For more information, see https://golang.org/doc/go-get-install-deprecation
	or run 'go help get' or 'go help install'.

go install

$ go install github.com/guptarohit/asciigraph@latest
package github.com/guptarohit/asciigraph is not a main package

Can I plot bar graphs?

I would like to know if I could use this library for plotting bar graphs. I could not find any examples that show bar plot using this library.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.