Compare commits

...

64 Commits
v0.4.2 ... main

Author SHA1 Message Date
kojix2
cd638f7ec1
Enable workflow_dispatch for test 2024-12-26 09:02:26 +09:00
kojix2
9aabd4a877 v0.4.6 2024-07-20 15:42:36 +09:00
kojix2
48f4af10c3 Add csv to gemspec
csv  is not part of the default gems since Ruby 3.4.0
2024-07-20 15:36:48 +09:00
kojix2
b0b03053af Add Ruby 3.4 to CI 2024-07-20 15:30:16 +09:00
kojix2
2a8c621be6 Update GitHub Actions versions in ci.yml and doc.yml 2024-07-20 15:29:02 +09:00
kojix2
4c45143edb
Update README.md
Adjust the order of installation commands
2024-06-25 14:01:30 +09:00
Naser Aleisa
ef6794e32f docs: add nix command to installation 2024-06-25 13:58:23 +09:00
kojix2
7cad6753ca Remove Ruby 2.5 from GitHub Actions testing
CRuby < 2.6 does not support macos-arm64
2024-06-09 23:51:22 +09:00
Gabor Szarnyas
9b239cef89 Fix typo: baplot -> barplot 2024-06-09 23:45:48 +09:00
kojix2
6451ab40d4
Update FUNDING.yml 2024-02-10 09:27:42 +09:00
kojix2
575a780321
Added Ruby 3.3 to CI and removed 2.4 2023-12-26 14:42:00 +09:00
muxator
666df42e07
readme: fix typo for "-o" option (#47)
If you want to output to "standard input" -> "standard output"
2023-11-15 19:39:42 +09:00
kojix2
a2d04dafa3
Update README.md
How to install with Anaconda
2023-04-28 06:11:36 +09:00
kojix2
7d595d7ede
Update README.md 2023-04-10 11:08:01 +09:00
kojix2
99bdbb06d1
Add examples that work offline to the README (#42)
Fix #41
Reported by @zhangwenda0518 Thanks!
2023-04-09 16:07:48 +09:00
gemmaro
60f9cb32dd
Added Guix installation (#40)
Guix issue tracker: https://issues.guix.gnu.org/62161
2023-04-06 17:23:15 +09:00
TO226
1a3a80568d Fix a missing link 2023-02-26 11:28:47 +09:00
kojix2
3ee329908b
Update README.md
YouPlot is available via homebrew
Reported by @zachvalenta (#33) Thanks!
2023-02-13 14:35:49 +09:00
kojix2
5695bbe91f v0.4.5 2023-01-09 20:37:34 +09:00
kojix2
0e2f8014fd Improved error messages 2023-01-05 13:54:47 +09:00
kojix2
a6c054f596 Added comment 2023-01-05 13:45:39 +09:00
kojix2
26050a2f87 Added config option to allow configuration files to be specified later 2023-01-05 13:40:52 +09:00
kojix2
8eca14a70d Fix typo 2023-01-05 12:56:06 +09:00
kojix2
654dbfca62 Added configuration file paths and improved messages 2023-01-05 12:54:43 +09:00
kojix2
433c24e710
Added configuration section to README 2023-01-05 12:30:02 +09:00
kojix2
b1baa4073c Added --config option 2023-01-05 12:20:56 +09:00
kojix2
27a84a4df1 Minor refactoring 2023-01-05 12:05:11 +09:00
kojix2
f8bd152a63 Improved the way help is displayed
- Add `help` to the subcommand.
- Use same method to display help in stdout or stderr.
2023-01-05 11:57:46 +09:00
kojix2
f9ffca636f Rubocop auto correct 2023-01-05 11:48:19 +09:00
kojix2
83b1da9b96 Refactoring of config file reading 2023-01-05 11:40:51 +09:00
kojix2
1f41e79952 Add alias l for line and alias ls for lins as a trial (#17) 2023-01-05 10:53:23 +09:00
kojix2
85ed440c52
Add Ruby 3.2 to CI 2022-12-25 21:00:53 +09:00
kojix2
16525233f3
Update doc.yml
Use latest ruby
2022-12-16 21:04:44 +09:00
kojix2
4efdc79e30 Use actions/checkout v3 2022-10-19 09:22:26 +09:00
kojix2
19f05e57ac v0.4.4 2022-08-02 17:05:30 +09:00
kojix2
f11fd6babb Consistent variable names 2022-08-02 16:58:48 +09:00
kojix2
9d69c4322c
Make configuration files available (#30) 2022-07-31 22:37:50 +09:00
kojix2
41c0d37a13 Friendly error messages 2022-05-25 16:24:13 +09:00
kojix2
a1dcc532ea Friendly error messages 2022-05-25 16:03:33 +09:00
kojix2
523700348c
Create doc.yml 2022-03-24 18:47:41 +09:00
kojix2
e34ab2b097
Update README.md
Do you need commit rights to my repository?
Do you want to get admin rights and take over the project?
If so, please feel free to contact kojix2.
2022-02-13 13:05:13 +09:00
kojix2
f8fe010d27
Add Ruby3.1 to CI (#29) 2021-12-30 11:54:15 +09:00
kojix2
e76d4f279e v0.4.3 2021-11-19 14:09:46 +09:00
kojix2
3a1a29424d Remove add_development_dependency from gem 2021-11-19 14:03:57 +09:00
kojix2
b78da2388a Rubocop auto correct 2021-11-19 13:56:09 +09:00
KIKISeries
a7bb75e87d Fix a typo
S -> s
2021-07-14 09:56:47 +09:00
kojix2
ca9f97a7dc Specify the version of UnicodePlot 2021-07-12 14:56:41 +09:00
kojix2
f67a5ce913 Add comments on the run_as_executable variable 2021-07-12 14:49:34 +09:00
kojix2
dbbfd366be Remove unused variable 2021-07-11 08:59:44 +09:00
kojix2
42cadee553 Improved CI
Remove needless line
2021-07-11 08:43:47 +09:00
kojix2
e689c69838
Update CI
* Enable bundler-cache
2021-07-11 08:38:05 +09:00
kojix2
c53169e9ee
Update README.md (#24) 2021-07-03 07:22:19 +09:00
kojix2
95a35399a2 Show a error message when linecolor is specified as a number 2021-07-03 06:52:37 +09:00
kojix2
7c00f95962
Fix Readme style 2021-06-20 19:10:09 +09:00
kojix2
fcbf9305d7 Add StringIO for consistency 2021-06-18 10:43:28 +09:00
kojix2
04eddfd79b Fix typo 2021-06-17 08:19:04 +09:00
kojix2
125c2291d5 Add categorical/date to README 2021-06-17 08:13:58 +09:00
kojix2
6a72418d01 Update README 2021-06-17 07:49:51 +09:00
kojix2
72a56659de Removed -x and -y options
The -x and -y options now stand for --xlabel and --ylabel.

These options should be used to specify the series in the future.
2021-06-17 07:47:14 +09:00
kojix2
858792fa99
Fix a typo 2021-06-14 13:08:45 +09:00
kojix2
e7079c56a2
Update README.md 2021-06-14 13:07:29 +09:00
kojix2
bb8a16a327 Swap the order of count and color in help 2021-06-14 11:37:06 +09:00
kojix2
be0f706231
Update README.md 2021-06-14 11:23:52 +09:00
kojix2
e5c87fbe6f
Add recommended tools to README.md 2021-06-11 10:48:33 +09:00
13 changed files with 356 additions and 136 deletions

1
.github/FUNDING.yml vendored
View File

@ -1,2 +1 @@
github: kojix2
ko_fi: kojix2

View File

@ -1,18 +1,17 @@
name: test
on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]
jobs:
build:
name: ${{ matrix.os }} Ruby ${{ matrix.ruby }}
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
os: ['ubuntu', 'macos']
ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0' ]
os: ["ubuntu", "macos"]
ruby: ["2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4"]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- run: gem install bundler
- run: bundle install
bundler-cache: true
- run: bundle exec rake test

23
.github/workflows/doc.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: doc
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ruby
- name: Generate document
run: gem install -N yard && yard doc
- name: Publish Documentation on GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./doc

View File

@ -4,3 +4,9 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in youplot.gemspec
gemspec
group :test do
gem 'rake'
gem 'simplecov'
gem 'test-unit'
end

209
README.md
View File

@ -1,30 +1,46 @@
<div align="center">
<img src="logo.svg" width="66%" height="66%" />
<img src="logo.svg">
<hr>
<a href="https://github.com/red-data-tools/YouPlot/actions/workflows/ci.yml"><img alt="Build Status" src="https://github.com/red-data-tools/YouPlot/workflows/test/badge.svg"></a>
<a href="https://rubygems.org/gems/youplot/"><img alt="Gem Version" src="https://badge.fury.io/rb/youplot.svg"></a>
<a href="https://zenodo.org/badge/latestdoi/283230219"><img alt="DOI" src="https://zenodo.org/badge/283230219.svg"></a>
<a href="https://rubydoc.info/gems/youplot/"><img alt="Docs Stable" src="https://img.shields.io/badge/docs-stable-blue.svg"></a>
<a href="LICENSE.txt"><img alt="The MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
![Build Status](https://github.com/red-data-tools/YouPlot/workflows/test/badge.svg)
[![Gem Version](https://badge.fury.io/rb/youplot.svg)](https://badge.fury.io/rb/youplot)
[![Docs Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://rubydoc.info/gems/youplot)
[![The MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
[![DOI](https://zenodo.org/badge/283230219.svg)](https://zenodo.org/badge/latestdoi/283230219)
YouPlot is a command line tool that draws plots in a terminal.
YouPlot is a command line tool that draws plots on the terminal.
:bar_chart: Powered by [UnicodePlot](https://github.com/red-data-tools/unicode_plot.rb)
</div>
## Installation
```
brew install youplot
```
```
gem install youplot
```
```
nix shell nixpkgs#youplot
```
```
guix install youplot
```
```
conda install -c conda-forge ruby
conda install -c conda-forge compilers
gem install youplot
```
## Quick Start
* `cat data.tsv | uplot <command> [options]` or
* `uplot <command> [options] <data.tsv>`
<img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png" width=160> <img alt="histogram" src="https://user-images.githubusercontent.com/5798442/101999820-21cafc00-3d24-11eb-86db-e410d19b07df.png" width=160> <img alt="scatter" src="https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png" width=160> <img alt="density" src="https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png" width=160> <img alt="boxplot" src="https://user-images.githubusercontent.com/5798442/101999830-2e4f5480-3d24-11eb-8891-728c18bf5b35.png" width=160>
`uplot <command> [options] <data.tsv>`
### barplot
@ -36,16 +52,23 @@ curl -sL https://git.io/ISLANDScsv \
```
<p align="center">
<img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
<img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
</p>
```sh
# For offline user: Sorts files in a directory by size and shows a bar graph.
ls -l | awk '{print $9, $5}' | sort -nk 2 | uplot bar -d ' '
```
### histogram
```sh
echo -e "from numpy import random;" \
"n = random.randn(10000);" \
"print('\\\n'.join(str(i) for i in n))" \
| python \
| python3 \
| uplot hist --nbins 20
```
@ -65,6 +88,14 @@ curl -sL https://git.io/AirPassengers \
<img alt="lineplot" src="https://user-images.githubusercontent.com/5798442/101999825-24c5ec80-3d24-11eb-99f4-c642e8d221bc.png">
</p>
```sh
# For offline users: Calculates sin values (0-2*pi) and plots a sine wave.
python3 -c '
from math import sin, pi
data = "\n".join(f"{i*pi/50}\t{sin(i*pi/50)}" for i in range(101))
print(data)' | uplot line
```
### scatter
```sh
@ -77,6 +108,12 @@ curl -sL https://git.io/IRIStsv \
<img alt="scatter" src="https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png">
</p>
```sh
# For offline users
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot scatter -H -d, -t IRIS
```
### density
```sh
@ -89,6 +126,11 @@ curl -sL https://git.io/IRIStsv \
<img alt="density" src="https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png">
</p>
```sh
# For offline users
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot density -H -d, -t IRIS
```
### boxplot
```sh
@ -101,11 +143,20 @@ curl -sL https://git.io/IRIStsv \
<img alt="boxplot" src="https://user-images.githubusercontent.com/5798442/101999830-2e4f5480-3d24-11eb-8891-728c18bf5b35.png">
</p>
```sh
# For offline users
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot boxplot -H -d, -t IRIS
```
### count
In this example, YouPlot counts the number of chromosomes where the gene is located from the human gene annotation file and it creates a bar chart. The human gene annotation file can be downloaded from the following website.
Count processes by user ID.
* https://www.gencodegenes.org/human/
```sh
ps aux | awk '{print $1}' | uplot count
```
Count the number of chromosomes where genes are located.
```sh
cat gencode.v35.annotation.gff3 \
@ -117,23 +168,20 @@ cat gencode.v35.annotation.gff3 \
<img alt="count" src="https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png">
</p>
* [GENCODE - Human Release](https://www.gencodegenes.org/human/)
Note: `count` is not very fast because it runs in a Ruby script.
This is fine in most cases, as long as the data size is small. If you want to visualize huge data, it is faster to use a combination of common Unix commands as shown below.
```sh
cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
| sort | uniq -c | sort -nrk2 | awk '{print $2,$1}' \
| uplot bar -d ' ' -t "The number of human gene annotations per chromosome" -c blue
| sort | uniq -c | sort -nrk1 \
| uplot bar --fmt yx -d ' ' -t "The number of human gene annotations per chromosome" -c blue
```
## Usage
### Why YouPlot?
Wouldn't it be a pain to have to run R, Python, Julia, gnuplot or whatever REPL just to check your data?
YouPlot is a command line tool for this purpose. With YouPlot, you can continue working without leaving your terminal and shell.
### How to use YouPlot?
### Commands
`uplot` is the shortened form of `youplot`. You can use either.
@ -143,18 +191,7 @@ YouPlot is a command line tool for this purpose. With YouPlot, you can continue
| `uplot <command> [options] data.tsv ...` | Take input from files |
| `pipeline1 \| uplot <command> -O \| pipeline2` | Outputs data from stdin to stdout |
### Where to output the plot?
By default, the plot is output to *standard error output*.
The output file or stream for the plot can be specified with the `-o` option.
### Where to output the input data?
By default, the input data is not shown anywhere.
The `-O` option, with no arguments, outputs the input data directly to the standard output.
This is useful when passing data to a subsequent pipeline.
### What types of plots are available?
### Subcommands
The following sub-commands are available.
@ -167,66 +204,83 @@ The following sub-commands are available.
| scatter | s | draw a scatter plot |
| density | d | draw a density plot |
| boxplot | box | draw a horizontal boxplot |
| | | |
| count | c | draw a barplot based on the number of occurrences (slow) |
| | | |
| colors | color | show the list of available colors |
See Quick Start for `count`.
### Output the plot
| command | short | how it works |
|-----------|-------|----------------------------------------------------------|
| count | c | draw a barplot based on the number of occurrences (slow) |
* `-o`
* By default, the plot is output to **standard error output**.
* If you want to output to standard output, Use hyphen ` -o -` or no argument `uplot s -o | `.
### What if the header line is included?
### Output the input data
If your input data contains a header line, you need to specify the `-H` option.
* `-O`
* By default, the input data is not shown anywhere.
* If you want to pass the input data directly to the standard output, Use hyphen `-O -` or no argument `uplot s -O |`.
* This is useful when passing data to a subsequent pipeline.
### How to specify the delimiter?
### Header
Use the `-d` option. To specify a blank space, you can use `uplot bar -d ' ' data.txt`.
You do not need to use `-d` option for tab-delimited text since the default value is tab.
* `-H`
* If input data contains a header line, you need to specify the `-H` option.
### Is there a way to specify a column as the x-axis or y-axis?
### Delimiter
Not yet.
YouPlot treats the first column as the X axis and the second column as the Y axis.
When working with multiple series, the first column is the X axis, the second column is series Y1, the third column is series Y2, and so on.
If you pass only one column of data for `line` and `bar`, YouPlot will automatically use a sequential number starting from 1 as the X-axis.
* `-d`
* You do not need to use `-d` option for tab-delimited text since the default value is tab.
* To specify a blank space, you can use `uplot bar -d ' ' data.txt`.
* `--fmt xyy` `--fmt xyxy` `--fmt yx` options give you a few more choices.
See `youplot <command> --help` for more details.
### Real-time data
* Use `awk '{print $2, $1}'` to swap lines.
* Use `paste` to concatenate series.
* `-p` `--progress`
* Experimental progressive mode is currently under development.
* `ruby -e 'loop{puts rand(100)}' | uplot line --progress`
### How to plot real-time data?
### Show detailed options for subcommands
Experimental progressive mode is currently under development.
* `--help`
* The `--help` option will show more detailed options for each subcommand.
* `uplot hist --help`
```sh
ruby -e 'loop{puts rand(100)}' | uplot line --progress
```
### Set columns as x-axis or y-axis
### How to view detailed command line options?
* YouPlot treats the first column as the X axis and the second column as the Y axis. When working with multiple series, the first column is the X axis, the second column is series Y1, the third column is series Y2, and so on.
* If you pass only one column of data for `line` and `bar`, YouPlot will automatically use a sequential number starting from 1 as the X-axis.
Use `--help` to print command-specific options.
* `--fmt`
* `--fmt xyy` `--fmt xyxy` `--fmt yx` options give you a few more choices. See `youplot <command> --help` for more details.
* The fmt option may be renamed in the future.
* The `-x` and `-y` options might be used to specify columns in the future.
`uplot hist --help`
* Use `awk '{print $2, $1}'` to swap columns. Use `paste` to concatenate series.
### Categorical data
* With GNU datamash, you can manage to handle categorized data.
* `cat test/fixtures/iris.csv | sed '/^$/d' | datamash --header-in --output-delimiter=: -t, -g5 collapse 3,4 | cut -f2-3 -d: | sed 's/:/\n/g' | uplot s -d, -T --fmt xyxy`
* This is not so easy...
### Time series
* Not yet supported.
### YouPlot Configuration (youplotrc)
You can specify default options in a configuration file in YAML format. For more information, enter the following command.
```
Usage: uplot histogram [options] <in.tsv>
Options for histogram:
--symbol VAL character to be used to plot the bars
--closed VAL side of the intervals to be closed [left]
-n, --nbins VAL approximate number of bins
Options:
...
uplot --config
```
### How to view the list of available colors?
## Tools that are useful to use with YouPlot
```sh
uplot colors
```
* [csvtk](https://github.com/shenwei356/csvtk)
* [GNU datamash](https://www.gnu.org/software/datamash/)
* [awk](https://www.gnu.org/software/gawk/)
* [xsv](https://github.com/BurntSushi/xsv)
## Contributing
@ -248,8 +302,13 @@ git clone https://github.com/your_name/YouPlot
bundle install # Install the gem dependencies
bundle exec rake test # Run the test
bundle exec rake install # Installation from source code
bundle exec exe/uplot # Run youplot (Try out the edited code)
```
Do you need commit rights to my repository?
Do you want to get admin rights and take over the project?
If so, please feel free to contact us.
### Acknowledgements
* [sampo grafiikka](https://jypg.net/sampo_grafiikka) - Project logo creation

View File

@ -6,6 +6,12 @@ require_relative 'youplot/parameters'
require_relative 'youplot/command'
module YouPlot
# @run_as_executable = true / false
# YouPlot behaves slightly differently when run as a command line tool
# and when run as a script (e.g. for testing). In the event of an error,
# when run as a command line tool, YouPlot will display a short error message
# and exit abnormally. When run as a script, it will just raise an error.
@run_as_executable = false
class << self
attr_accessor :run_as_executable
@ -13,5 +19,4 @@ module YouPlot
@run_as_executable
end
end
@run_as_executable = false
end

View File

@ -6,6 +6,27 @@
require_relative 'processing'
require 'unicode_plot'
# If the line color is specified as a number, the program will display an error
# message to the user and exit. Remove this patch when UnicodePlot is improved.
module UnicodePlot
class << self
alias lineplot_original lineplot
def lineplot(*args, **kw)
if kw[:color].is_a? Numeric
warn <<~EOS
YouPlot: Line colors cannot be specified by numerical values.
For more information, please see the following issue.
https://github.com/red-data-tools/unicode_plot.rb/issues/34
EOS
YouPlot.run_as_executable ? exit(1) : raise(Error)
end
lineplot_original(*args, **kw)
end
end
end
module YouPlot
# plotting functions.
module Backends
@ -106,11 +127,10 @@ module YouPlot
def plot_xyxy(data, method1, params)
headers = data.headers
series = data.series
series2 = data.series
.map { |s| s.map(&:to_f) }
.each_slice(2).to_a
method2 = get_method2(method1)
series.map! { |s| s.map(&:to_f) }
series2 = series.each_slice(2).to_a
series = nil
params.name ||= headers[0] if headers
params.xlim ||= series2.map(&:first).flatten.minmax # why need?
params.ylim ||= series2.map(&:last).flatten.minmax # why need?
@ -182,7 +202,7 @@ module YouPlot
series = data.series
if series.size == 1
warn <<~EOS
youplot: There is only one series of input data. Please check the delimiter.
YouPlot: There is only one series of input data. Please check the delimiter.
Headers: \e[35m#{data.headers.inspect}\e[0m
The first item is: \e[35m\"#{series[0][0]}\"\e[0m

View File

@ -63,9 +63,15 @@ module YouPlot
# normal mode
else
# Sometimes the input file does not end with a newline code.
while (input = Kernel.gets(nil))
begin
begin
input = Kernel.gets(nil)
rescue Errno::ENOENT => e
warn e.message
next
end
main(input)
end
end until input
end
end
@ -135,7 +141,12 @@ module YouPlot
rescue CSV::MalformedCSVError => e
warn 'Failed to parse the text. '
warn 'Please try to set the correct character encoding with --encoding option.'
raise e
warn e.backtrace.grep(/youplot/).first
exit 1
rescue ArgumentError => e
warn 'Failed to parse the text. '
warn e.backtrace.grep(/youplot/).first
exit 1
end
data
@ -149,9 +160,9 @@ module YouPlot
@backend.barplot(data, params, count: true, reverse: options[:reverse])
when :hist, :histogram
@backend.histogram(data, params)
when :line, :lineplot
when :line, :lineplot, :l
@backend.line(data, params, options[:fmt])
when :lines, :lineplots
when :lines, :lineplots, :ls
@backend.lines(data, params, options[:fmt])
when :scatter, :s
@backend.scatter(data, params, options[:fmt])
@ -169,7 +180,7 @@ module YouPlot
def output_data(input)
# Pass the input to subsequent pipelines
case options[:pass]
when IO
when IO, StringIO
options[:pass].print(input)
else
if options[:pass]

View File

@ -9,7 +9,8 @@ module YouPlot
class Error < StandardError; end
attr_reader :command, :options, :params,
:main_parser, :sub_parser
:main_parser, :sub_parser,
:config_file, :config
def initialize
@command = nil
@ -30,6 +31,61 @@ module YouPlot
@params = Parameters.new
end
def apply_config_file
return if !config_file && find_config_file.nil?
read_config_file
configure
end
def config_file_candidate_paths
# keep the order of the paths
paths = []
paths << ENV['MYYOUPLOTRC'] if ENV['MYYOUPLOTRC']
paths << '.youplot.yml'
paths << '.youplotrc'
if ENV['HOME']
paths << File.join(ENV['HOME'], '.youplotrc')
paths << File.join(ENV['HOME'], '.youplot.yml')
paths << File.join(ENV['HOME'], '.config', 'youplot', 'youplotrc')
paths << File.join(ENV['HOME'], '.config', 'youplot', 'youplot.yml')
end
paths
end
def find_config_file
config_file_candidate_paths.each do |file|
path = File.expand_path(file)
next unless File.exist?(path)
@config_file = path
ENV['MYYOUPLOTRC'] = path
return @config_file
end
nil
end
def read_config_file
require 'yaml'
@config = YAML.load_file(config_file)
end
def configure
option_members = @options.members
param_members = @params.members
# It would be more useful to be able to configure by plot type
config.each do |k, v|
k = k.to_sym
if option_members.include?(k)
@options[k] ||= v
elsif param_members.include?(k)
@params[k] ||= v
else
raise Error, "Unknown option/param in config file: #{k}"
end
end
end
def create_base_parser
OptionParser.new do |parser|
parser.program_name = 'YouPlot'
@ -58,10 +114,10 @@ module YouPlot
parser.on('-t', '--title STR', String, 'print string on the top of plot') do |v|
params.title = v
end
parser.on('-x', '--xlabel STR', String, 'print string on the bottom of the plot') do |v|
parser.on('--xlabel STR', String, 'print string on the bottom of the plot') do |v|
params.xlabel = v
end
parser.on('-y', '--ylabel STR', String, 'print string on the far left of the plot') do |v|
parser.on('--ylabel STR', String, 'print string on the far left of the plot') do |v|
params.ylabel = v
end
parser.on('-w', '--width INT', Numeric, 'number of characters per row') do |v|
@ -95,7 +151,7 @@ module YouPlot
parser.on('-M', '--monochrome', TrueClass, 'no colouring even if writing to a tty') do |_v|
UnicodePlot::IOContext.define_method(:color?) { false } # FIXME
end
parser.on('--encoding STR', String, 'Specify the input encoding') do |v|
parser.on('--encoding STR', String, 'specify the input encoding') do |v|
options[:encoding] = v
end
# Optparse adds the help option, but it doesn't show up in usage.
@ -104,6 +160,9 @@ module YouPlot
puts parser.help
exit if YouPlot.run_as_executable?
end
parser.on('--config FILE', 'specify a config file') do |v|
@config_file = v
end
parser.on('--debug', TrueClass, 'print preprocessed data') do |v|
options[:debug] = v
end
@ -130,12 +189,12 @@ module YouPlot
scatter s draw a scatter plot
density d draw a density plot
boxplot box draw a horizontal boxplot
count c draw a barplot based on the number of
occurrences (slow)
colors color show the list of available colors
count c draw a baplot based on the number of
occurrences (slow)
General options:
--config print config file info
--help print command specific help menu
--version print the version of YouPlot
MSG
@ -143,10 +202,36 @@ module YouPlot
# Help for the main parser is simple.
# Simply show the banner above.
main_parser.on('--help', 'print sub-command help menu') do
puts main_parser.banner
puts
exit if YouPlot.run_as_executable?
show_main_help
end
main_parser.on('--config', 'show config file info') do
show_config_info
end
end
def show_main_help(out = $stdout)
out.puts main_parser.banner
out.puts
exit if YouPlot.run_as_executable?
end
def show_config_info
if ENV['MYYOUPLOTRC']
puts "config file : #{ENV['MYYOUPLOTRC']}"
puts config.inspect
else
puts <<~EOS
Configuration file not found.
It should be a YAML file, like this example:
width : 40
height : 20
By default, YouPlot will look for the configuration file in these locations:
#{config_file_candidate_paths.map { |s| ' ' + s }.join("\n")}
If you have the file elsewhere, you can specify its location with the `MYYOUPLOTRC` environment variable.
EOS
end
exit if YouPlot.run_as_executable?
end
def sub_parser_add_symbol
@ -216,10 +301,13 @@ module YouPlot
case command
# If you type only `uplot` in the terminal.
# Output help to standard error output.
when nil
warn main_parser.banner
warn "\n"
exit 1 if YouPlot.run_as_executable?
show_main_help($stderr)
# Output help to standard output.
when :help
show_main_help
when :barplot, :bar
sub_parser_add_symbol
@ -242,14 +330,14 @@ module YouPlot
params.nbins = v
end
when :lineplot, :line
when :lineplot, :line, :l
sub_parser_add_canvas
sub_parser_add_grid
sub_parser_add_fmt_yx
sub_parser_add_ylim
sub_parser_add_xlim
when :lineplots, :lines
when :lineplots, :lines, :ls
sub_parser_add_canvas
sub_parser_add_grid
sub_parser_add_fmt_xyxy
@ -278,14 +366,19 @@ module YouPlot
options[:color_names] = v
end
# Currently it simply displays the configuration file,
# but in the future this may be changed to open a text editor like Vim
# to edit the configuration file.
when :config
show_config_info
else
error_message = "uplot: unrecognized command '#{command}'"
if YouPlot.run_as_executable?
warn error_message
exit 1
else
raise Error, error_message
end
error_message = "YouPlot: unrecognized command '#{command}'"
raise Error, error_message unless YouPlot.run_as_executable?
warn error_message
exit 1
end
end
@ -293,7 +386,7 @@ module YouPlot
begin
create_main_parser.order!(argv)
rescue OptionParser::ParseError => e
warn "uplot: #{e.message}"
warn "YouPlot: #{e.message}"
exit 1 if YouPlot.run_as_executable?
end
@ -302,7 +395,14 @@ module YouPlot
begin
create_sub_parser&.parse!(argv)
rescue OptionParser::ParseError => e
warn "uplot: #{e.message}"
warn "YouPlot: #{e.message}"
exit 1 if YouPlot.run_as_executable?
end
begin
apply_config_file
rescue StandardError => e
warn "YouPlot: #{e.message}"
exit 1 if YouPlot.run_as_executable?
end
end

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true
module YouPlot
VERSION = '0.4.2'
VERSION = '0.4.6'
end

View File

@ -69,6 +69,12 @@ class YouPlotIRISTest < Test::Unit::TestCase
assert_equal fixture('iris-lineplot.txt'), @stderr_file.read
end
# l is an undocumented alias of lineplot.
test :l do
YouPlot::Command.new(['l', '-H', '-d,', '-t', 'IRIS-LINEPLOT']).run
assert_equal fixture('iris-lineplot.txt'), @stderr_file.read
end
test :lineplots do
YouPlot::Command.new(['lineplots', '-H', '-d,', '-t', 'IRIS-LINEPLOTS']).run
assert_equal fixture('iris-lineplots.txt'), @stderr_file.read
@ -79,6 +85,12 @@ class YouPlotIRISTest < Test::Unit::TestCase
assert_equal fixture('iris-lineplots.txt'), @stderr_file.read
end
# ls is an undocumented alias of lineplots.
test :ls do
YouPlot::Command.new(['lines', '-H', '-d,', '-t', 'IRIS-LINEPLOTS']).run
assert_equal fixture('iris-lineplots.txt'), @stderr_file.read
end
test :scatter do
YouPlot::Command.new(['scatter', '-H', '-d,', '-t', 'IRIS-SCATTER']).run
assert_equal fixture('iris-scatter.txt'), @stderr_file.read

View File

@ -155,21 +155,11 @@ class YouPlotSimpleTest < Test::Unit::TestCase
assert_equal fixture('simple-lineplot-xlabel.txt'), @stderr_file.read
end
test :line_x do
YouPlot::Command.new(['line', '-x', 'X-LABEL']).run
assert_equal fixture('simple-lineplot-xlabel.txt'), @stderr_file.read
end
test :line_ylabel do
YouPlot::Command.new(['line', '--ylabel', 'Y-LABEL']).run
assert_equal fixture('simple-lineplot-ylabel.txt'), @stderr_file.read
end
test :line_y do
YouPlot::Command.new(['line', '-y', 'Y-LABEL']).run
assert_equal fixture('simple-lineplot-ylabel.txt'), @stderr_file.read
end
test :line_width do
YouPlot::Command.new(['line', '--width', '17']).run
assert_equal fixture('simple-lineplot-width-17.txt'), @stderr_file.read

View File

@ -12,17 +12,13 @@ Gem::Specification.new do |spec|
spec.description = 'A command line tool for Unicode Plotting'
spec.homepage = 'https://github.com/red-data-tools/YouPlot'
spec.license = 'MIT'
spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
spec.files = Dir['*.{md,txt}', '{lib,exe}/**/*']
spec.bindir = 'exe'
spec.executables = %w[uplot youplot]
spec.require_paths = ['lib']
spec.add_runtime_dependency 'unicode_plot'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rubocop'
spec.add_development_dependency 'simplecov'
spec.add_development_dependency 'test-unit'
spec.add_dependency 'csv'
spec.add_dependency 'unicode_plot', '>= 0.0.5'
end