18
vendor/github.com/guptarohit/asciigraph/.gitignore
generated
vendored
Normal file
18
vendor/github.com/guptarohit/asciigraph/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# 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
|
||||
|
||||
# build dirs
|
||||
*dist*
|
||||
74
vendor/github.com/guptarohit/asciigraph/.goreleaser.yml
generated
vendored
Normal file
74
vendor/github.com/guptarohit/asciigraph/.goreleaser.yml
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# Build customization
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
main: ./cmd/asciigraph/main.go
|
||||
ldflags: '-s -w'
|
||||
# GOOS list to build in.
|
||||
# For more info refer to https://golang.org/doc/install/source#environment
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
# GOARCH to build in.
|
||||
# For more info refer to https://golang.org/doc/install/source#environment
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
checksum:
|
||||
name_template: '{{ .ProjectName }}_{{ .Version }}_sha512-checksums.txt'
|
||||
algorithm: sha512
|
||||
# Archive customization
|
||||
archives:
|
||||
- id: tar
|
||||
format: tar.gz
|
||||
files:
|
||||
- LICENSE
|
||||
- README.md
|
||||
name_template: >-
|
||||
{{- .ProjectName }}_
|
||||
{{- .Version }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end -}}
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
release:
|
||||
github:
|
||||
owner: guptarohit
|
||||
name: asciigraph
|
||||
# If set to true, will not auto-publish the release.
|
||||
# Default is false.
|
||||
draft: true
|
||||
dockers:
|
||||
- image_templates:
|
||||
- 'ghcr.io/guptarohit/asciigraph:{{ .Version }}'
|
||||
- 'ghcr.io/guptarohit/asciigraph:{{ .Tag }}'
|
||||
- 'ghcr.io/guptarohit/asciigraph:v{{ .Major }}'
|
||||
- 'ghcr.io/guptarohit/asciigraph:v{{ .Major }}.{{ .Minor }}'
|
||||
- 'ghcr.io/guptarohit/asciigraph:latest'
|
||||
dockerfile: goreleaser.dockerfile
|
||||
build_flag_templates:
|
||||
- '--label=org.opencontainers.image.title={{ .ProjectName }}'
|
||||
- '--label=org.opencontainers.image.name={{ .ProjectName }}'
|
||||
- '--label=org.opencontainers.image.description=Go package to make lightweight line graphs ╭┈╯ in CLI'
|
||||
- '--label=org.opencontainers.image.url=https://github.com/guptarohit/asciigraph'
|
||||
- '--label=org.opencontainers.image.source=https://github.com/guptarohit/asciigraph'
|
||||
- '--label=org.opencontainers.image.version={{ .Version }}'
|
||||
- '--label=org.opencontainers.image.created={{ .Date }}'
|
||||
- '--label=org.opencontainers.image.revision={{ .FullCommit }}'
|
||||
- '--label=org.opencontainers.image.licenses=BSD-3-Clause'
|
||||
113
vendor/github.com/guptarohit/asciigraph/CHANGELOG.md
generated
vendored
Normal file
113
vendor/github.com/guptarohit/asciigraph/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.7.3] - 2024-10-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- Incorrect plot height calculation for small value ranges (#59)
|
||||
|
||||
## [0.7.2] - 2024-08-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unintended modification of input data (#55)
|
||||
|
||||
## [0.7.1] - 2024-03-30
|
||||
|
||||
### Added
|
||||
|
||||
- CLI: Option to specify legends for series (`sl`)
|
||||
|
||||
## [0.7.0] - 2024-03-30
|
||||
|
||||
### Added
|
||||
|
||||
- CLI: Options to specify delimiter (`d`) and number of series (`sn`)
|
||||
|
||||
### Changed
|
||||
|
||||
- CLI: Option (`sc`) to specify series colors
|
||||
|
||||
## [0.6.0] - 2024-03-25
|
||||
|
||||
### Added
|
||||
|
||||
- Option to add legends for colored graphs
|
||||
|
||||
## [0.5.6] - 2023-06-24
|
||||
|
||||
### Added
|
||||
|
||||
- Options to set upper & lower bound of graph
|
||||
|
||||
## [0.5.5] - 2022-05-03
|
||||
|
||||
### Added
|
||||
|
||||
- Ansi colors support for graphs
|
||||
|
||||
## [0.5.4] - 2022-05-03
|
||||
|
||||
### Added
|
||||
|
||||
- Option to plot multiple series together (#34)
|
||||
- Dockerfile file support (#33)
|
||||
|
||||
## [0.5.3] - 2022-02-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Handled NaN first value (#32)
|
||||
- Fixed incorrect y-axis start value tick (#31)
|
||||
|
||||
## [0.5.2] - 2021-03-28
|
||||
|
||||
### Added
|
||||
|
||||
- added support to set custom precision of data point labels along the y-axis
|
||||
- added go module support
|
||||
|
||||
### Changed
|
||||
|
||||
- updated README to markdown format
|
||||
|
||||
## [0.5.1] - 2020-09-14
|
||||
|
||||
### Added
|
||||
|
||||
- added support for NaN values in series
|
||||
- added option to control fps of plot rendering via cli for real-time data
|
||||
|
||||
### Changed
|
||||
|
||||
- removed use of append() method
|
||||
- make caption centered
|
||||
- removed trailing spaces from plot
|
||||
|
||||
## [0.5.0] - 2020-06-28
|
||||
|
||||
### Added
|
||||
|
||||
- added support for the realtime plot of data points (from stdin) for CLI.
|
||||
|
||||
## [0.4.2] - 2020-06-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Prevent panics when data is flat. (#8)
|
||||
- Prevent BADPREC issue when maximum and minimum values in a series are 0. (#10)
|
||||
|
||||
[0.7.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.2
|
||||
[0.7.1]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.1
|
||||
[0.7.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.7.0
|
||||
[0.6.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.6.0
|
||||
[0.5.6]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.6
|
||||
[0.5.5]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.5
|
||||
[0.5.4]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.4
|
||||
[0.5.3]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.3
|
||||
[0.5.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.2
|
||||
[0.5.1]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.1
|
||||
[0.5.0]: https://github.com/guptarohit/asciigraph/releases/tag/v0.5.0
|
||||
[0.4.2]: https://github.com/guptarohit/asciigraph/releases/tag/v0.4.2
|
||||
133
vendor/github.com/guptarohit/asciigraph/CODE_OF_CONDUCT.md
generated
vendored
Normal file
133
vendor/github.com/guptarohit/asciigraph/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
https://github.com/guptarohit.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
10
vendor/github.com/guptarohit/asciigraph/Dockerfile
generated
vendored
Normal file
10
vendor/github.com/guptarohit/asciigraph/Dockerfile
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM golang:1.23-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY cmd ./cmd
|
||||
COPY go.mod ./
|
||||
COPY *.go ./
|
||||
RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app/asciigraph ./cmd/asciigraph/main.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /app/asciigraph /asciigraph
|
||||
ENTRYPOINT ["/asciigraph"]
|
||||
29
vendor/github.com/guptarohit/asciigraph/LICENSE
generated
vendored
Normal file
29
vendor/github.com/guptarohit/asciigraph/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 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.
|
||||
292
vendor/github.com/guptarohit/asciigraph/README.md
generated
vendored
Normal file
292
vendor/github.com/guptarohit/asciigraph/README.md
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
# asciigraph
|
||||
|
||||
[![Build status][]][1] [![Go Report Card][]][2] [![Coverage Status][]][3] [![GoDoc][]][4] [![License][]][5] [![Mentioned in Awesome Go][]][6]
|
||||
|
||||
Go package to make lightweight ASCII line graphs ╭┈╯.
|
||||
|
||||
![image][]
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
go get -u github.com/guptarohit/asciigraph@latest
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic graph
|
||||
|
||||
```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:
|
||||
```bash
|
||||
10.00 ┤ ╭╮
|
||||
9.00 ┤ ╭╮ ││
|
||||
8.00 ┤ ││ ╭╮││
|
||||
7.00 ┤ ││ ││││╭╮
|
||||
6.00 ┤ │╰╮ ││││││ ╭
|
||||
5.00 ┤ │ │ ╭╯╰╯│││╭╯
|
||||
4.00 ┤╭╯ │╭╯ ││││
|
||||
3.00 ┼╯ ││ ││││
|
||||
2.00 ┤ ╰╯ ╰╯╰╯
|
||||
```
|
||||
|
||||
### Multiple Series
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guptarohit/asciigraph"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := [][]float64{{0, 1, 2, 3, 3, 3, 2, 0}, {5, 4, 2, 1, 4, 6, 6}}
|
||||
graph := asciigraph.PlotMany(data)
|
||||
|
||||
fmt.Println(graph)
|
||||
}
|
||||
```
|
||||
|
||||
Running this example would render the following graph:
|
||||
```bash
|
||||
6.00 ┤ ╭─
|
||||
5.00 ┼╮ │
|
||||
4.00 ┤╰╮ ╭╯
|
||||
3.00 ┤ │╭│─╮
|
||||
2.00 ┤ ╰╮│ ╰╮
|
||||
1.00 ┤╭╯╰╯ │
|
||||
0.00 ┼╯ ╰
|
||||
```
|
||||
|
||||
### Colored graphs
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guptarohit/asciigraph"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := make([][]float64, 4)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
for x := -20; x <= 20; x++ {
|
||||
v := math.NaN()
|
||||
if r := 20 - i; x >= -r && x <= r {
|
||||
v = math.Sqrt(math.Pow(float64(r), 2)-math.Pow(float64(x), 2)) / 2
|
||||
}
|
||||
data[i] = append(data[i], v)
|
||||
}
|
||||
}
|
||||
graph := asciigraph.PlotMany(data, asciigraph.Precision(0), asciigraph.SeriesColors(
|
||||
asciigraph.Red,
|
||||
asciigraph.Yellow,
|
||||
asciigraph.Green,
|
||||
asciigraph.Blue,
|
||||
))
|
||||
|
||||
fmt.Println(graph)
|
||||
}
|
||||
```
|
||||
|
||||
Running this example would render the following graph:
|
||||
|
||||
![colored_graph_image][]
|
||||
|
||||
### Legends for colored graphs
|
||||
|
||||
The graph can include legends for each series, making it easier to interpret.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guptarohit/asciigraph"
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := make([][]float64, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
for x := -12; x <= 12; x++ {
|
||||
v := math.NaN()
|
||||
if r := 12 - i; x >= -r && x <= r {
|
||||
v = math.Sqrt(math.Pow(float64(r), 2)-math.Pow(float64(x), 2)) / 2
|
||||
}
|
||||
data[i] = append(data[i], v)
|
||||
}
|
||||
}
|
||||
graph := asciigraph.PlotMany(data,
|
||||
asciigraph.Precision(0),
|
||||
asciigraph.SeriesColors(asciigraph.Red, asciigraph.Green, asciigraph.Blue),
|
||||
asciigraph.SeriesLegends("Red", "Green", "Blue"),
|
||||
asciigraph.Caption("Series with legends"))
|
||||
fmt.Println(graph)
|
||||
}
|
||||
```
|
||||
Running this example would render the following graph:
|
||||
|
||||
![graph_with_legends_image][]
|
||||
|
||||
|
||||
## CLI Installation
|
||||
|
||||
This package also brings a small utility for command line usage.
|
||||
|
||||
Assuming `$GOPATH/bin` is in your `$PATH`, install CLI with following command:
|
||||
```bash
|
||||
go install github.com/guptarohit/asciigraph/cmd/asciigraph@latest
|
||||
```
|
||||
|
||||
or pull Docker image:
|
||||
```bash
|
||||
docker pull ghcr.io/guptarohit/asciigraph:latest
|
||||
```
|
||||
|
||||
or download binaries from the [releases][] page.
|
||||
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash ✘ 0|125 16:19:23
|
||||
> asciigraph --help
|
||||
Usage of asciigraph:
|
||||
asciigraph [options]
|
||||
Options:
|
||||
-ac axis color
|
||||
y-axis color of the plot
|
||||
-b buffer
|
||||
data points buffer when realtime graph enabled, default equal to `width`
|
||||
-c caption
|
||||
caption for the graph
|
||||
-cc caption color
|
||||
caption color of the plot
|
||||
-d delimiter
|
||||
data delimiter for splitting data points in the input stream (default ",")
|
||||
-f fps
|
||||
set fps to control how frequently graph to be rendered when realtime graph enabled (default 24)
|
||||
-h height
|
||||
height in text rows, 0 for auto-scaling
|
||||
-lb lower bound
|
||||
lower bound set the minimum value for the vertical axis (ignored if series contains lower values) (default +Inf)
|
||||
-lc label color
|
||||
y-axis label color of the plot
|
||||
-o offset
|
||||
offset in columns, for the label (default 3)
|
||||
-p precision
|
||||
precision of data point labels along the y-axis (default 2)
|
||||
-r realtime
|
||||
enables realtime graph for data stream
|
||||
-sc series colors
|
||||
comma-separated series colors corresponding to each series
|
||||
-sl series legends
|
||||
comma-separated series legends corresponding to each series
|
||||
-sn number of series
|
||||
number of series (columns) in the input data (default 1)
|
||||
-ub upper bound
|
||||
upper bound set the maximum value for the vertical axis (ignored if series contains larger values) (default -Inf)
|
||||
-w width
|
||||
width in columns, 0 for auto-scaling
|
||||
asciigraph expects data points from stdin. Invalid values are logged to stderr.
|
||||
```
|
||||
|
||||
|
||||
Feed it data points via stdin:
|
||||
```bash
|
||||
seq 1 72 | asciigraph -h 10 -c "plot data from stdin"
|
||||
```
|
||||
|
||||
or use Docker image:
|
||||
```bash
|
||||
seq 1 72 | docker run -i --rm ghcr.io/guptarohit/asciigraph -h 10 -c "plot data from stdin"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```bash
|
||||
72.00 ┤ ╭────
|
||||
64.90 ┤ ╭──────╯
|
||||
57.80 ┤ ╭──────╯
|
||||
50.70 ┤ ╭──────╯
|
||||
43.60 ┤ ╭──────╯
|
||||
36.50 ┤ ╭───────╯
|
||||
29.40 ┤ ╭──────╯
|
||||
22.30 ┤ ╭──────╯
|
||||
15.20 ┤ ╭──────╯
|
||||
8.10 ┤ ╭──────╯
|
||||
1.00 ┼──╯
|
||||
plot data from stdin
|
||||
```
|
||||
|
||||
|
||||
Example of **real-time graph** for data points stream via stdin:
|
||||
|
||||
<a href="https://asciinema.org/a/382383" target="_blank"><img width="500" alt="Realtime graph for data points via stdin (google ping) using asciigraph" src="https://asciinema.org/a/382383.svg" /></a>
|
||||
|
||||
<details>
|
||||
<summary>command for above graph</summary>
|
||||
|
||||
```sh
|
||||
ping -i.2 google.com | grep -oP '(?<=time=).*(?=ms)' --line-buffered | asciigraph -r -h 10 -w 40 -c "realtime plot data (google ping in ms) from stdin"
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
Example of **multi-series real-time graph** for data points stream via stdin:
|
||||
|
||||
<a href="https://asciinema.org/a/649906" target="_blank"><img width="500" alt="Ping latency comparison: Google (Blue) vs. DuckDuckGo (Red) with asciigraph" src="https://asciinema.org/a/649906.svg" /></a>
|
||||
|
||||
<details>
|
||||
<summary>command for above graph</summary>
|
||||
|
||||
```sh
|
||||
{unbuffer paste -d, <(ping -i 0.4 google.com | sed -u -n -E 's/.*time=(.*)ms.*/\1/p') <(ping -i 0.4 duckduckgo.com | sed -u -n -E 's/.*time=(.*)ms.*/\1/p') } | asciigraph -r -h 15 -w 60 -sn 2 -sc "blue,red" -c "Ping Latency Comparison" -sl "Google, DuckDuckGo"
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## Acknowledgement
|
||||
|
||||
This package started as golang port of [asciichart][].
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to make a pull request! :octocat:
|
||||
|
||||
|
||||
[Build status]: https://github.com/guptarohit/asciigraph/actions/workflows/test.yml/badge.svg
|
||||
[1]: https://github.com/guptarohit/asciigraph/actions/workflows/test.yml
|
||||
[Go Report Card]: https://goreportcard.com/badge/github.com/guptarohit/asciigraph
|
||||
[2]: https://goreportcard.com/report/github.com/guptarohit/asciigraph
|
||||
[Coverage Status]: https://coveralls.io/repos/github/guptarohit/asciigraph/badge.svg?branch=master
|
||||
[3]: https://coveralls.io/github/guptarohit/asciigraph?branch=master
|
||||
[GoDoc]: https://godoc.org/github.com/guptarohit/asciigraph?status.svg
|
||||
[4]: https://godoc.org/github.com/guptarohit/asciigraph
|
||||
[License]: https://img.shields.io/badge/licence-BSD-blue.svg
|
||||
[5]: https://github.com/guptarohit/asciigraph/blob/master/LICENSE
|
||||
[Mentioned in Awesome Go]: https://awesome.re/mentioned-badge-flat.svg
|
||||
[6]: https://github.com/avelino/awesome-go#advanced-console-uis
|
||||
[image]: https://user-images.githubusercontent.com/7895001/41509956-b1b2b3d0-7279-11e8-9d19-d7dea17d5e44.png
|
||||
[colored_graph_image]: https://user-images.githubusercontent.com/7895001/166443444-40ad8113-2c0f-46d7-9c75-1cf08435ce15.png
|
||||
[releases]: https://github.com/guptarohit/asciigraph/releases
|
||||
[asciichart]: https://github.com/kroitor/asciichart
|
||||
[graph_with_legends_image]: https://github.com/guptarohit/asciigraph/assets/7895001/4066ee95-55ca-42a4-8a03-e73ce20df5d3
|
||||
265
vendor/github.com/guptarohit/asciigraph/asciigraph.go
generated
vendored
Normal file
265
vendor/github.com/guptarohit/asciigraph/asciigraph.go
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
package asciigraph
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Plot returns ascii graph for a series.
|
||||
func Plot(series []float64, options ...Option) string {
|
||||
return PlotMany([][]float64{series}, options...)
|
||||
}
|
||||
|
||||
// PlotMany returns ascii graph for multiple series.
|
||||
func PlotMany(data [][]float64, options ...Option) string {
|
||||
var logMaximum float64
|
||||
config := configure(config{
|
||||
Offset: 3,
|
||||
Precision: 2,
|
||||
}, options)
|
||||
|
||||
// Create a deep copy of the input data
|
||||
dataCopy := make([][]float64, len(data))
|
||||
for i, series := range data {
|
||||
dataCopy[i] = make([]float64, len(series))
|
||||
copy(dataCopy[i], series)
|
||||
}
|
||||
data = dataCopy
|
||||
|
||||
lenMax := 0
|
||||
for i := range data {
|
||||
if l := len(data[i]); l > lenMax {
|
||||
lenMax = l
|
||||
}
|
||||
}
|
||||
|
||||
if config.Width > 0 {
|
||||
for i := range data {
|
||||
for j := len(data[i]); j < lenMax; j++ {
|
||||
data[i] = append(data[i], math.NaN())
|
||||
}
|
||||
data[i] = interpolateArray(data[i], config.Width)
|
||||
}
|
||||
|
||||
lenMax = config.Width
|
||||
}
|
||||
|
||||
minimum, maximum := math.Inf(1), math.Inf(-1)
|
||||
for i := range data {
|
||||
minVal, maxVal := minMaxFloat64Slice(data[i])
|
||||
if minVal < minimum {
|
||||
minimum = minVal
|
||||
}
|
||||
if maxVal > maximum {
|
||||
maximum = maxVal
|
||||
}
|
||||
}
|
||||
if config.LowerBound != nil && *config.LowerBound < minimum {
|
||||
minimum = *config.LowerBound
|
||||
}
|
||||
if config.UpperBound != nil && *config.UpperBound > maximum {
|
||||
maximum = *config.UpperBound
|
||||
}
|
||||
interval := math.Abs(maximum - minimum)
|
||||
|
||||
if config.Height <= 0 {
|
||||
config.Height = calculateHeight(interval)
|
||||
}
|
||||
|
||||
if config.Offset <= 0 {
|
||||
config.Offset = 3
|
||||
}
|
||||
|
||||
var ratio float64
|
||||
if interval != 0 {
|
||||
ratio = float64(config.Height) / interval
|
||||
} else {
|
||||
ratio = 1
|
||||
}
|
||||
min2 := round(minimum * ratio)
|
||||
max2 := round(maximum * ratio)
|
||||
|
||||
intmin2 := int(min2)
|
||||
intmax2 := int(max2)
|
||||
|
||||
rows := int(math.Abs(float64(intmax2 - intmin2)))
|
||||
width := lenMax + config.Offset
|
||||
|
||||
type cell struct {
|
||||
Text string
|
||||
Color AnsiColor
|
||||
}
|
||||
plot := make([][]cell, rows+1)
|
||||
|
||||
// initialise empty 2D grid
|
||||
for i := 0; i < rows+1; i++ {
|
||||
line := make([]cell, width)
|
||||
for j := 0; j < width; j++ {
|
||||
line[j].Text = " "
|
||||
line[j].Color = Default
|
||||
}
|
||||
plot[i] = line
|
||||
}
|
||||
|
||||
precision := config.Precision
|
||||
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 += uint(math.Abs(logMaximum))
|
||||
} else {
|
||||
precision += uint(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].Text = label
|
||||
plot[w][h].Color = config.LabelColor
|
||||
plot[w][config.Offset-1].Text = "┤"
|
||||
plot[w][config.Offset-1].Color = config.AxisColor
|
||||
}
|
||||
|
||||
for i := range data {
|
||||
series := data[i]
|
||||
|
||||
color := Default
|
||||
if i < len(config.SeriesColors) {
|
||||
color = config.SeriesColors[i]
|
||||
}
|
||||
|
||||
var y0, y1 int
|
||||
|
||||
if !math.IsNaN(series[0]) {
|
||||
y0 = int(round(series[0]*ratio) - min2)
|
||||
plot[rows-y0][config.Offset-1].Text = "┼" // first value
|
||||
plot[rows-y0][config.Offset-1].Color = config.AxisColor
|
||||
}
|
||||
|
||||
for x := 0; x < len(series)-1; x++ { // plot the line
|
||||
d0 := series[x]
|
||||
d1 := series[x+1]
|
||||
|
||||
if math.IsNaN(d0) && math.IsNaN(d1) {
|
||||
continue
|
||||
}
|
||||
|
||||
if math.IsNaN(d1) && !math.IsNaN(d0) {
|
||||
y0 = int(round(d0*ratio) - float64(intmin2))
|
||||
plot[rows-y0][x+config.Offset].Text = "╴"
|
||||
plot[rows-y0][x+config.Offset].Color = color
|
||||
continue
|
||||
}
|
||||
|
||||
if math.IsNaN(d0) && !math.IsNaN(d1) {
|
||||
y1 = int(round(d1*ratio) - float64(intmin2))
|
||||
plot[rows-y1][x+config.Offset].Text = "╶"
|
||||
plot[rows-y1][x+config.Offset].Color = color
|
||||
continue
|
||||
}
|
||||
|
||||
y0 = int(round(d0*ratio) - float64(intmin2))
|
||||
y1 = int(round(d1*ratio) - float64(intmin2))
|
||||
|
||||
if y0 == y1 {
|
||||
plot[rows-y0][x+config.Offset].Text = "─"
|
||||
} else {
|
||||
if y0 > y1 {
|
||||
plot[rows-y1][x+config.Offset].Text = "╰"
|
||||
plot[rows-y0][x+config.Offset].Text = "╮"
|
||||
} else {
|
||||
plot[rows-y1][x+config.Offset].Text = "╭"
|
||||
plot[rows-y0][x+config.Offset].Text = "╯"
|
||||
}
|
||||
|
||||
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].Text = "│"
|
||||
}
|
||||
}
|
||||
|
||||
start := int(math.Min(float64(y0), float64(y1)))
|
||||
end := int(math.Max(float64(y0), float64(y1)))
|
||||
for y := start; y <= end; y++ {
|
||||
plot[rows-y][x+config.Offset].Color = color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// join columns
|
||||
var lines bytes.Buffer
|
||||
for h, horizontal := range plot {
|
||||
if h != 0 {
|
||||
lines.WriteRune('\n')
|
||||
}
|
||||
|
||||
// remove trailing spaces
|
||||
lastCharIndex := 0
|
||||
for i := width - 1; i >= 0; i-- {
|
||||
if horizontal[i].Text != " " {
|
||||
lastCharIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c := Default
|
||||
for _, v := range horizontal[:lastCharIndex+1] {
|
||||
if v.Color != c {
|
||||
c = v.Color
|
||||
lines.WriteString(c.String())
|
||||
}
|
||||
|
||||
lines.WriteString(v.Text)
|
||||
}
|
||||
if c != Default {
|
||||
lines.WriteString(Default.String())
|
||||
}
|
||||
}
|
||||
|
||||
// add caption if not empty
|
||||
if config.Caption != "" {
|
||||
lines.WriteRune('\n')
|
||||
lines.WriteString(strings.Repeat(" ", config.Offset+maxWidth))
|
||||
if len(config.Caption) < lenMax {
|
||||
lines.WriteString(strings.Repeat(" ", (lenMax-len(config.Caption))/2))
|
||||
}
|
||||
if config.CaptionColor != Default {
|
||||
lines.WriteString(config.CaptionColor.String())
|
||||
}
|
||||
lines.WriteString(config.Caption)
|
||||
if config.CaptionColor != Default {
|
||||
lines.WriteString(Default.String())
|
||||
}
|
||||
}
|
||||
|
||||
if len(config.SeriesLegends) > 0 {
|
||||
addLegends(&lines, config, lenMax, config.Offset+maxWidth)
|
||||
}
|
||||
|
||||
return lines.String()
|
||||
}
|
||||
312
vendor/github.com/guptarohit/asciigraph/color.go
generated
vendored
Normal file
312
vendor/github.com/guptarohit/asciigraph/color.go
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
package asciigraph
|
||||
|
||||
import "fmt"
|
||||
|
||||
type AnsiColor byte
|
||||
|
||||
var (
|
||||
Default AnsiColor = 0
|
||||
AliceBlue AnsiColor = 255
|
||||
AntiqueWhite AnsiColor = 255
|
||||
Aqua AnsiColor = 14
|
||||
Aquamarine AnsiColor = 122
|
||||
Azure AnsiColor = 15
|
||||
Beige AnsiColor = 230
|
||||
Bisque AnsiColor = 224
|
||||
Black AnsiColor = 188 // dummy value
|
||||
BlanchedAlmond AnsiColor = 230
|
||||
Blue AnsiColor = 12
|
||||
BlueViolet AnsiColor = 92
|
||||
Brown AnsiColor = 88
|
||||
BurlyWood AnsiColor = 180
|
||||
CadetBlue AnsiColor = 73
|
||||
Chartreuse AnsiColor = 118
|
||||
Chocolate AnsiColor = 166
|
||||
Coral AnsiColor = 209
|
||||
CornflowerBlue AnsiColor = 68
|
||||
Cornsilk AnsiColor = 230
|
||||
Crimson AnsiColor = 161
|
||||
Cyan AnsiColor = 14
|
||||
DarkBlue AnsiColor = 18
|
||||
DarkCyan AnsiColor = 30
|
||||
DarkGoldenrod AnsiColor = 136
|
||||
DarkGray AnsiColor = 248
|
||||
DarkGreen AnsiColor = 22
|
||||
DarkKhaki AnsiColor = 143
|
||||
DarkMagenta AnsiColor = 90
|
||||
DarkOliveGreen AnsiColor = 59
|
||||
DarkOrange AnsiColor = 208
|
||||
DarkOrchid AnsiColor = 134
|
||||
DarkRed AnsiColor = 88
|
||||
DarkSalmon AnsiColor = 173
|
||||
DarkSeaGreen AnsiColor = 108
|
||||
DarkSlateBlue AnsiColor = 60
|
||||
DarkSlateGray AnsiColor = 238
|
||||
DarkTurquoise AnsiColor = 44
|
||||
DarkViolet AnsiColor = 92
|
||||
DeepPink AnsiColor = 198
|
||||
DeepSkyBlue AnsiColor = 39
|
||||
DimGray AnsiColor = 242
|
||||
DodgerBlue AnsiColor = 33
|
||||
Firebrick AnsiColor = 124
|
||||
FloralWhite AnsiColor = 15
|
||||
ForestGreen AnsiColor = 28
|
||||
Fuchsia AnsiColor = 13
|
||||
Gainsboro AnsiColor = 253
|
||||
GhostWhite AnsiColor = 15
|
||||
Gold AnsiColor = 220
|
||||
Goldenrod AnsiColor = 178
|
||||
Gray AnsiColor = 8
|
||||
Green AnsiColor = 2
|
||||
GreenYellow AnsiColor = 155
|
||||
Honeydew AnsiColor = 15
|
||||
HotPink AnsiColor = 205
|
||||
IndianRed AnsiColor = 167
|
||||
Indigo AnsiColor = 54
|
||||
Ivory AnsiColor = 15
|
||||
Khaki AnsiColor = 222
|
||||
Lavender AnsiColor = 254
|
||||
LavenderBlush AnsiColor = 255
|
||||
LawnGreen AnsiColor = 118
|
||||
LemonChiffon AnsiColor = 230
|
||||
LightBlue AnsiColor = 152
|
||||
LightCoral AnsiColor = 210
|
||||
LightCyan AnsiColor = 195
|
||||
LightGoldenrodYellow AnsiColor = 230
|
||||
LightGray AnsiColor = 252
|
||||
LightGreen AnsiColor = 120
|
||||
LightPink AnsiColor = 217
|
||||
LightSalmon AnsiColor = 216
|
||||
LightSeaGreen AnsiColor = 37
|
||||
LightSkyBlue AnsiColor = 117
|
||||
LightSlateGray AnsiColor = 103
|
||||
LightSteelBlue AnsiColor = 152
|
||||
LightYellow AnsiColor = 230
|
||||
Lime AnsiColor = 10
|
||||
LimeGreen AnsiColor = 77
|
||||
Linen AnsiColor = 255
|
||||
Magenta AnsiColor = 13
|
||||
Maroon AnsiColor = 1
|
||||
MediumAquamarine AnsiColor = 79
|
||||
MediumBlue AnsiColor = 20
|
||||
MediumOrchid AnsiColor = 134
|
||||
MediumPurple AnsiColor = 98
|
||||
MediumSeaGreen AnsiColor = 72
|
||||
MediumSlateBlue AnsiColor = 99
|
||||
MediumSpringGreen AnsiColor = 48
|
||||
MediumTurquoise AnsiColor = 80
|
||||
MediumVioletRed AnsiColor = 162
|
||||
MidnightBlue AnsiColor = 17
|
||||
MintCream AnsiColor = 15
|
||||
MistyRose AnsiColor = 224
|
||||
Moccasin AnsiColor = 223
|
||||
NavajoWhite AnsiColor = 223
|
||||
Navy AnsiColor = 4
|
||||
OldLace AnsiColor = 230
|
||||
Olive AnsiColor = 3
|
||||
OliveDrab AnsiColor = 64
|
||||
Orange AnsiColor = 214
|
||||
OrangeRed AnsiColor = 202
|
||||
Orchid AnsiColor = 170
|
||||
PaleGoldenrod AnsiColor = 223
|
||||
PaleGreen AnsiColor = 120
|
||||
PaleTurquoise AnsiColor = 159
|
||||
PaleVioletRed AnsiColor = 168
|
||||
PapayaWhip AnsiColor = 230
|
||||
PeachPuff AnsiColor = 223
|
||||
Peru AnsiColor = 173
|
||||
Pink AnsiColor = 218
|
||||
Plum AnsiColor = 182
|
||||
PowderBlue AnsiColor = 152
|
||||
Purple AnsiColor = 5
|
||||
Red AnsiColor = 9
|
||||
RosyBrown AnsiColor = 138
|
||||
RoyalBlue AnsiColor = 63
|
||||
SaddleBrown AnsiColor = 94
|
||||
Salmon AnsiColor = 210
|
||||
SandyBrown AnsiColor = 215
|
||||
SeaGreen AnsiColor = 29
|
||||
SeaShell AnsiColor = 15
|
||||
Sienna AnsiColor = 131
|
||||
Silver AnsiColor = 7
|
||||
SkyBlue AnsiColor = 117
|
||||
SlateBlue AnsiColor = 62
|
||||
SlateGray AnsiColor = 66
|
||||
Snow AnsiColor = 15
|
||||
SpringGreen AnsiColor = 48
|
||||
SteelBlue AnsiColor = 67
|
||||
Tan AnsiColor = 180
|
||||
Teal AnsiColor = 6
|
||||
Thistle AnsiColor = 182
|
||||
Tomato AnsiColor = 203
|
||||
Turquoise AnsiColor = 80
|
||||
Violet AnsiColor = 213
|
||||
Wheat AnsiColor = 223
|
||||
White AnsiColor = 15
|
||||
WhiteSmoke AnsiColor = 255
|
||||
Yellow AnsiColor = 11
|
||||
YellowGreen AnsiColor = 149
|
||||
)
|
||||
|
||||
var ColorNames = map[string]AnsiColor{
|
||||
"default": Default,
|
||||
"aliceblue": AliceBlue,
|
||||
"antiquewhite": AntiqueWhite,
|
||||
"aqua": Aqua,
|
||||
"aquamarine": Aquamarine,
|
||||
"azure": Azure,
|
||||
"beige": Beige,
|
||||
"bisque": Bisque,
|
||||
"black": Black,
|
||||
"blanchedalmond": BlanchedAlmond,
|
||||
"blue": Blue,
|
||||
"blueviolet": BlueViolet,
|
||||
"brown": Brown,
|
||||
"burlywood": BurlyWood,
|
||||
"cadetblue": CadetBlue,
|
||||
"chartreuse": Chartreuse,
|
||||
"chocolate": Chocolate,
|
||||
"coral": Coral,
|
||||
"cornflowerblue": CornflowerBlue,
|
||||
"cornsilk": Cornsilk,
|
||||
"crimson": Crimson,
|
||||
"cyan": Cyan,
|
||||
"darkblue": DarkBlue,
|
||||
"darkcyan": DarkCyan,
|
||||
"darkgoldenrod": DarkGoldenrod,
|
||||
"darkgray": DarkGray,
|
||||
"darkgreen": DarkGreen,
|
||||
"darkkhaki": DarkKhaki,
|
||||
"darkmagenta": DarkMagenta,
|
||||
"darkolivegreen": DarkOliveGreen,
|
||||
"darkorange": DarkOrange,
|
||||
"darkorchid": DarkOrchid,
|
||||
"darkred": DarkRed,
|
||||
"darksalmon": DarkSalmon,
|
||||
"darkseagreen": DarkSeaGreen,
|
||||
"darkslateblue": DarkSlateBlue,
|
||||
"darkslategray": DarkSlateGray,
|
||||
"darkturquoise": DarkTurquoise,
|
||||
"darkviolet": DarkViolet,
|
||||
"deeppink": DeepPink,
|
||||
"deepskyblue": DeepSkyBlue,
|
||||
"dimgray": DimGray,
|
||||
"dodgerblue": DodgerBlue,
|
||||
"firebrick": Firebrick,
|
||||
"floralwhite": FloralWhite,
|
||||
"forestgreen": ForestGreen,
|
||||
"fuchsia": Fuchsia,
|
||||
"gainsboro": Gainsboro,
|
||||
"ghostwhite": GhostWhite,
|
||||
"gold": Gold,
|
||||
"goldenrod": Goldenrod,
|
||||
"gray": Gray,
|
||||
"green": Green,
|
||||
"greenyellow": GreenYellow,
|
||||
"honeydew": Honeydew,
|
||||
"hotpink": HotPink,
|
||||
"indianred": IndianRed,
|
||||
"indigo": Indigo,
|
||||
"ivory": Ivory,
|
||||
"khaki": Khaki,
|
||||
"lavender": Lavender,
|
||||
"lavenderblush": LavenderBlush,
|
||||
"lawngreen": LawnGreen,
|
||||
"lemonchiffon": LemonChiffon,
|
||||
"lightblue": LightBlue,
|
||||
"lightcoral": LightCoral,
|
||||
"lightcyan": LightCyan,
|
||||
"lightgoldenrodyellow": LightGoldenrodYellow,
|
||||
"lightgray": LightGray,
|
||||
"lightgreen": LightGreen,
|
||||
"lightpink": LightPink,
|
||||
"lightsalmon": LightSalmon,
|
||||
"lightseagreen": LightSeaGreen,
|
||||
"lightskyblue": LightSkyBlue,
|
||||
"lightslategray": LightSlateGray,
|
||||
"lightsteelblue": LightSteelBlue,
|
||||
"lightyellow": LightYellow,
|
||||
"lime": Lime,
|
||||
"limegreen": LimeGreen,
|
||||
"linen": Linen,
|
||||
"magenta": Magenta,
|
||||
"maroon": Maroon,
|
||||
"mediumaquamarine": MediumAquamarine,
|
||||
"mediumblue": MediumBlue,
|
||||
"mediumorchid": MediumOrchid,
|
||||
"mediumpurple": MediumPurple,
|
||||
"mediumseagreen": MediumSeaGreen,
|
||||
"mediumslateblue": MediumSlateBlue,
|
||||
"mediumspringgreen": MediumSpringGreen,
|
||||
"mediumturquoise": MediumTurquoise,
|
||||
"mediumvioletred": MediumVioletRed,
|
||||
"midnightblue": MidnightBlue,
|
||||
"mintcream": MintCream,
|
||||
"mistyrose": MistyRose,
|
||||
"moccasin": Moccasin,
|
||||
"navajowhite": NavajoWhite,
|
||||
"navy": Navy,
|
||||
"oldlace": OldLace,
|
||||
"olive": Olive,
|
||||
"olivedrab": OliveDrab,
|
||||
"orange": Orange,
|
||||
"orangered": OrangeRed,
|
||||
"orchid": Orchid,
|
||||
"palegoldenrod": PaleGoldenrod,
|
||||
"palegreen": PaleGreen,
|
||||
"paleturquoise": PaleTurquoise,
|
||||
"palevioletred": PaleVioletRed,
|
||||
"papayawhip": PapayaWhip,
|
||||
"peachpuff": PeachPuff,
|
||||
"peru": Peru,
|
||||
"pink": Pink,
|
||||
"plum": Plum,
|
||||
"powderblue": PowderBlue,
|
||||
"purple": Purple,
|
||||
"red": Red,
|
||||
"rosybrown": RosyBrown,
|
||||
"royalblue": RoyalBlue,
|
||||
"saddlebrown": SaddleBrown,
|
||||
"salmon": Salmon,
|
||||
"sandybrown": SandyBrown,
|
||||
"seagreen": SeaGreen,
|
||||
"seashell": SeaShell,
|
||||
"sienna": Sienna,
|
||||
"silver": Silver,
|
||||
"skyblue": SkyBlue,
|
||||
"slateblue": SlateBlue,
|
||||
"slategray": SlateGray,
|
||||
"snow": Snow,
|
||||
"springgreen": SpringGreen,
|
||||
"steelblue": SteelBlue,
|
||||
"tan": Tan,
|
||||
"teal": Teal,
|
||||
"thistle": Thistle,
|
||||
"tomato": Tomato,
|
||||
"turquoise": Turquoise,
|
||||
"violet": Violet,
|
||||
"wheat": Wheat,
|
||||
"white": White,
|
||||
"whitesmoke": WhiteSmoke,
|
||||
"yellow": Yellow,
|
||||
"yellowgreen": YellowGreen,
|
||||
}
|
||||
|
||||
func (c AnsiColor) String() string {
|
||||
if c == Default {
|
||||
return "\x1b[0m"
|
||||
}
|
||||
if c == Black {
|
||||
c = 0
|
||||
}
|
||||
if c <= Silver {
|
||||
// 3-bit color
|
||||
return fmt.Sprintf("\x1b[%dm", 30+byte(c))
|
||||
}
|
||||
if c <= White {
|
||||
// 4-bit color
|
||||
return fmt.Sprintf("\x1b[%dm", 82+byte(c))
|
||||
}
|
||||
// 8-bit color
|
||||
return fmt.Sprintf("\x1b[38;5;%dm", byte(c))
|
||||
}
|
||||
3
vendor/github.com/guptarohit/asciigraph/goreleaser.dockerfile
generated
vendored
Normal file
3
vendor/github.com/guptarohit/asciigraph/goreleaser.dockerfile
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM scratch
|
||||
COPY asciigraph /asciigraph
|
||||
ENTRYPOINT ["/asciigraph"]
|
||||
45
vendor/github.com/guptarohit/asciigraph/legend.go
generated
vendored
Normal file
45
vendor/github.com/guptarohit/asciigraph/legend.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package asciigraph
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Create legend item as a colored box and text
|
||||
func createLegendItem(text string, color AnsiColor) (string, int) {
|
||||
return fmt.Sprintf(
|
||||
"%s■%s %s",
|
||||
color.String(),
|
||||
Default.String(),
|
||||
text,
|
||||
),
|
||||
// Can't use len() because of AnsiColor, add 2 for box and space
|
||||
utf8.RuneCountInString(text) + 2
|
||||
}
|
||||
|
||||
// Add legend for each series added to the graph
|
||||
func addLegends(lines *bytes.Buffer, config *config, lenMax int, leftPad int) {
|
||||
lines.WriteString("\n\n")
|
||||
lines.WriteString(strings.Repeat(" ", leftPad))
|
||||
|
||||
var legendsText string
|
||||
var legendsTextLen int
|
||||
rightPad := 3
|
||||
for i, text := range config.SeriesLegends {
|
||||
item, itemLen := createLegendItem(text, config.SeriesColors[i])
|
||||
legendsText += item
|
||||
legendsTextLen += itemLen
|
||||
|
||||
if i < len(config.SeriesLegends)-1 {
|
||||
legendsText += strings.Repeat(" ", rightPad)
|
||||
legendsTextLen += rightPad
|
||||
}
|
||||
}
|
||||
|
||||
if legendsTextLen < lenMax {
|
||||
lines.WriteString(strings.Repeat(" ", (lenMax-legendsTextLen)/2))
|
||||
}
|
||||
lines.WriteString(legendsText)
|
||||
}
|
||||
126
vendor/github.com/guptarohit/asciigraph/options.go
generated
vendored
Normal file
126
vendor/github.com/guptarohit/asciigraph/options.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package 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
|
||||
LowerBound, UpperBound *float64
|
||||
Offset int
|
||||
Caption string
|
||||
Precision uint
|
||||
CaptionColor AnsiColor
|
||||
AxisColor AnsiColor
|
||||
LabelColor AnsiColor
|
||||
SeriesColors []AnsiColor
|
||||
SeriesLegends []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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// LowerBound sets the graph's minimum value for the vertical axis. It will be ignored
|
||||
// if the series contains a lower value.
|
||||
func LowerBound(min float64) Option {
|
||||
return optionFunc(func(c *config) { c.LowerBound = &min })
|
||||
}
|
||||
|
||||
// UpperBound sets the graph's maximum value for the vertical axis. It will be ignored
|
||||
// if the series contains a bigger value.
|
||||
func UpperBound(max float64) Option {
|
||||
return optionFunc(func(c *config) { c.UpperBound = &max })
|
||||
}
|
||||
|
||||
// Offset sets the graphs offset.
|
||||
func Offset(o int) Option {
|
||||
return optionFunc(func(c *config) { c.Offset = o })
|
||||
}
|
||||
|
||||
// Precision sets the graphs precision.
|
||||
func Precision(p uint) Option {
|
||||
return optionFunc(func(c *config) { c.Precision = p })
|
||||
}
|
||||
|
||||
// Caption sets the graphs caption.
|
||||
func Caption(caption string) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.Caption = strings.TrimSpace(caption)
|
||||
})
|
||||
}
|
||||
|
||||
// CaptionColor sets the caption color.
|
||||
func CaptionColor(ac AnsiColor) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.CaptionColor = ac
|
||||
})
|
||||
}
|
||||
|
||||
// AxisColor sets the axis color.
|
||||
func AxisColor(ac AnsiColor) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.AxisColor = ac
|
||||
})
|
||||
}
|
||||
|
||||
// LabelColor sets the axis label color.
|
||||
func LabelColor(ac AnsiColor) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.LabelColor = ac
|
||||
})
|
||||
}
|
||||
|
||||
// SeriesColors sets the series colors.
|
||||
func SeriesColors(ac ...AnsiColor) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.SeriesColors = ac
|
||||
})
|
||||
}
|
||||
|
||||
// SeriesLegends sets the legend text for the corresponding series.
|
||||
func SeriesLegends(text ...string) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.SeriesLegends = text
|
||||
})
|
||||
}
|
||||
105
vendor/github.com/guptarohit/asciigraph/utils.go
generated
vendored
Normal file
105
vendor/github.com/guptarohit/asciigraph/utils.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package asciigraph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// clear terminal screen
|
||||
var Clear func()
|
||||
|
||||
func init() {
|
||||
platform := runtime.GOOS
|
||||
|
||||
if platform == "windows" {
|
||||
Clear = func() {
|
||||
cmd := exec.Command("cmd", "/c", "cls")
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Clear = func() {
|
||||
fmt.Print("\033[2J\033[H")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calculateHeight(interval float64) int {
|
||||
if interval >= 1 {
|
||||
return int(interval)
|
||||
}
|
||||
|
||||
scaleFactor := math.Pow(10, math.Floor(math.Log10(interval)))
|
||||
scaledDelta := interval / scaleFactor
|
||||
|
||||
if scaledDelta < 2 {
|
||||
return int(math.Ceil(scaledDelta))
|
||||
}
|
||||
return int(math.Floor(scaledDelta))
|
||||
}
|
||||
Reference in New Issue
Block a user