youplot 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -0
- data/README.md +87 -24
- data/lib/youplot/aggregation.rb +140 -0
- data/lib/youplot/backends/unicode_plot.rb +52 -24
- data/lib/youplot/command.rb +185 -67
- data/lib/youplot/dsv.rb +16 -8
- data/lib/youplot/options.rb +20 -0
- data/lib/youplot/parser.rb +61 -33
- data/lib/youplot/version.rb +1 -1
- data/logo.svg +319 -0
- data/sig/youplot/aggregation.rbs +5 -0
- metadata +21 -8
- data/lib/youplot/backends/processing.rb +0 -36
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c344612a2c9055f37b06ea9e6cceb5199e18a261b1ce4bb4c2d3ec74f77657ad
|
|
4
|
+
data.tar.gz: 736041b6139ebc559b78176f3ed0908469e6fc8c21e0119ff4f62641a357ffc8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b318d624ece5511feacd5f1a9c50ea929b6c1c1f05d951a50f61869e52a66b8adf7d613c3042345b0455b2c36eca56088144ee0967f188c3cd7c12910ecf7579
|
|
7
|
+
data.tar.gz: 2570196b9263edea40227244909e5e9fe287854e7daa2d5d2f44bd1fa617faa5716b38979eed40a84c1687aac71be8b6005ed902d83aa1f6dce54fea60f4dd66
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="logo.svg">
|
|
3
3
|
<hr>
|
|
4
|
-
<img alt="Build Status" src="https://github.com/red-data-tools/YouPlot/workflows/test/badge.svg">
|
|
4
|
+
<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>
|
|
5
5
|
<a href="https://rubygems.org/gems/youplot/"><img alt="Gem Version" src="https://badge.fury.io/rb/youplot.svg"></a>
|
|
6
|
-
<a href="https://zenodo.org/badge/latestdoi/283230219"><img alt="DOI" src="https://zenodo.org/badge/283230219.svg"></a>
|
|
7
6
|
<a href="https://rubydoc.info/gems/youplot/"><img alt="Docs Stable" src="https://img.shields.io/badge/docs-stable-blue.svg"></a>
|
|
8
7
|
<a href="LICENSE.txt"><img alt="The MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
9
8
|
|
|
@@ -14,10 +13,30 @@
|
|
|
14
13
|
|
|
15
14
|
## Installation
|
|
16
15
|
|
|
16
|
+
```
|
|
17
|
+
brew install youplot
|
|
18
|
+
```
|
|
19
|
+
|
|
17
20
|
```
|
|
18
21
|
gem install youplot
|
|
19
22
|
```
|
|
20
23
|
|
|
24
|
+
```
|
|
25
|
+
nix shell nixpkgs#youplot
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
guix install youplot
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
conda install -c conda-forge ruby
|
|
34
|
+
conda install -c conda-forge compilers
|
|
35
|
+
gem install youplot
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
:crystal_ball: [YouPlot2](https://github.com/red-data-tools/YouPlot2) - Experimental project with pre-built binaries
|
|
39
|
+
|
|
21
40
|
## Quick Start
|
|
22
41
|
|
|
23
42
|
<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>
|
|
@@ -37,13 +56,19 @@ curl -sL https://git.io/ISLANDScsv \
|
|
|
37
56
|
<img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
|
|
38
57
|
</p>
|
|
39
58
|
|
|
59
|
+
For offline users: sorts files in a directory by size and shows a bar graph.
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
ls -l | awk '{print $9, $5}' | sort -nk 2 | uplot bar -d ' '
|
|
63
|
+
```
|
|
64
|
+
|
|
40
65
|
### histogram
|
|
41
66
|
|
|
42
67
|
```sh
|
|
43
68
|
echo -e "from numpy import random;" \
|
|
44
69
|
"n = random.randn(10000);" \
|
|
45
70
|
"print('\\\n'.join(str(i) for i in n))" \
|
|
46
|
-
|
|
|
71
|
+
| python3 \
|
|
47
72
|
| uplot hist --nbins 20
|
|
48
73
|
```
|
|
49
74
|
|
|
@@ -63,6 +88,17 @@ curl -sL https://git.io/AirPassengers \
|
|
|
63
88
|
<img alt="lineplot" src="https://user-images.githubusercontent.com/5798442/101999825-24c5ec80-3d24-11eb-99f4-c642e8d221bc.png">
|
|
64
89
|
</p>
|
|
65
90
|
|
|
91
|
+
For offline users: calculates sin values from 0 to 2*pi and plots a sine wave.
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
python3 - <<'PY' | uplot line
|
|
95
|
+
from math import sin, pi
|
|
96
|
+
|
|
97
|
+
for i in range(101):
|
|
98
|
+
print(f"{i*pi/50}\t{sin(i*pi/50)}")
|
|
99
|
+
PY
|
|
100
|
+
```
|
|
101
|
+
|
|
66
102
|
### scatter
|
|
67
103
|
|
|
68
104
|
```sh
|
|
@@ -75,6 +111,13 @@ curl -sL https://git.io/IRIStsv \
|
|
|
75
111
|
<img alt="scatter" src="https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png">
|
|
76
112
|
</p>
|
|
77
113
|
|
|
114
|
+
|
|
115
|
+
For offline users:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot scatter -H -d, -t IRIS
|
|
119
|
+
```
|
|
120
|
+
|
|
78
121
|
### density
|
|
79
122
|
|
|
80
123
|
```sh
|
|
@@ -87,6 +130,12 @@ curl -sL https://git.io/IRIStsv \
|
|
|
87
130
|
<img alt="density" src="https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png">
|
|
88
131
|
</p>
|
|
89
132
|
|
|
133
|
+
For offline users:
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot density -H -d, -t IRIS
|
|
137
|
+
```
|
|
138
|
+
|
|
90
139
|
### boxplot
|
|
91
140
|
|
|
92
141
|
```sh
|
|
@@ -99,8 +148,22 @@ curl -sL https://git.io/IRIStsv \
|
|
|
99
148
|
<img alt="boxplot" src="https://user-images.githubusercontent.com/5798442/101999830-2e4f5480-3d24-11eb-8891-728c18bf5b35.png">
|
|
100
149
|
</p>
|
|
101
150
|
|
|
151
|
+
For offline users:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
cat test/fixtures/iris.csv | cut -f1-4 -d, | uplot boxplot -H -d, -t IRIS
|
|
155
|
+
```
|
|
156
|
+
|
|
102
157
|
### count
|
|
103
158
|
|
|
159
|
+
Count processes by user ID.
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
ps aux | awk '{print $1}' | uplot count
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Count the number of chromosomes where genes are located.
|
|
166
|
+
|
|
104
167
|
```sh
|
|
105
168
|
cat gencode.v35.annotation.gff3 \
|
|
106
169
|
| grep -v '#' | grep 'gene' | cut -f1 \
|
|
@@ -111,7 +174,6 @@ cat gencode.v35.annotation.gff3 \
|
|
|
111
174
|
<img alt="count" src="https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png">
|
|
112
175
|
</p>
|
|
113
176
|
|
|
114
|
-
In this example, YouPlot counts the number of chromosomes where genes are located.
|
|
115
177
|
* [GENCODE - Human Release](https://www.gencodegenes.org/human/)
|
|
116
178
|
|
|
117
179
|
Note: `count` is not very fast because it runs in a Ruby script.
|
|
@@ -130,7 +192,7 @@ cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
|
|
|
130
192
|
`uplot` is the shortened form of `youplot`. You can use either.
|
|
131
193
|
|
|
132
194
|
| Command | Description |
|
|
133
|
-
|
|
195
|
+
| ---------------------------------------------- | --------------------------------- |
|
|
134
196
|
| `cat data.tsv \| uplot <command> [options]` | Take input from stdin |
|
|
135
197
|
| `uplot <command> [options] data.tsv ...` | Take input from files |
|
|
136
198
|
| `pipeline1 \| uplot <command> -O \| pipeline2` | Outputs data from stdin to stdout |
|
|
@@ -139,25 +201,25 @@ cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
|
|
|
139
201
|
|
|
140
202
|
The following sub-commands are available.
|
|
141
203
|
|
|
142
|
-
| command | short | how it works
|
|
143
|
-
|
|
144
|
-
| barplot | bar | draw a horizontal barplot
|
|
145
|
-
| histogram | hist | draw a horizontal histogram
|
|
146
|
-
| lineplot | line | draw a line chart
|
|
147
|
-
| lineplots | lines | draw a line chart with multiple series
|
|
148
|
-
| scatter | s | draw a scatter plot
|
|
149
|
-
| density | d | draw a density plot
|
|
150
|
-
| boxplot | box | draw a horizontal boxplot
|
|
151
|
-
| | |
|
|
204
|
+
| command | short | how it works |
|
|
205
|
+
| --------- | ----- | -------------------------------------------------------- |
|
|
206
|
+
| barplot | bar | draw a horizontal barplot |
|
|
207
|
+
| histogram | hist | draw a horizontal histogram |
|
|
208
|
+
| lineplot | line | draw a line chart |
|
|
209
|
+
| lineplots | lines | draw a line chart with multiple series |
|
|
210
|
+
| scatter | s | draw a scatter plot |
|
|
211
|
+
| density | d | draw a density plot |
|
|
212
|
+
| boxplot | box | draw a horizontal boxplot |
|
|
213
|
+
| | | |
|
|
152
214
|
| count | c | draw a barplot based on the number of occurrences (slow) |
|
|
153
|
-
| | |
|
|
154
|
-
| colors | color | show the list of available colors
|
|
215
|
+
| | | |
|
|
216
|
+
| colors | color | show the list of available colors |
|
|
155
217
|
|
|
156
218
|
### Output the plot
|
|
157
219
|
|
|
158
220
|
* `-o`
|
|
159
221
|
* By default, the plot is output to **standard error output**.
|
|
160
|
-
* If you want to output to standard
|
|
222
|
+
* If you want to output to standard output, Use hyphen ` -o -` or no argument `uplot s -o | `.
|
|
161
223
|
|
|
162
224
|
### Output the input data
|
|
163
225
|
|
|
@@ -240,13 +302,14 @@ Please feel free to send us your pull requests.
|
|
|
240
302
|
|
|
241
303
|
### Development
|
|
242
304
|
|
|
305
|
+
Fork the main repository by clicking the Fork button.
|
|
306
|
+
|
|
243
307
|
```sh
|
|
244
|
-
# fork the main repository by clicking the Fork button.
|
|
245
308
|
git clone https://github.com/your_name/YouPlot
|
|
246
|
-
bundle install
|
|
247
|
-
bundle exec rake test
|
|
248
|
-
bundle exec rake install
|
|
249
|
-
bundle exec exe/uplot
|
|
309
|
+
bundle install
|
|
310
|
+
bundle exec rake test
|
|
311
|
+
bundle exec rake install
|
|
312
|
+
bundle exec exe/uplot
|
|
250
313
|
```
|
|
251
314
|
|
|
252
315
|
Do you need commit rights to my repository?
|
|
@@ -255,7 +318,7 @@ bundle exec exe/uplot # Run youplot (Try out the edited code)
|
|
|
255
318
|
|
|
256
319
|
### Acknowledgements
|
|
257
320
|
|
|
258
|
-
* [sampo grafiikka](https://
|
|
321
|
+
* [sampo grafiikka](https://lepo.sampo-grafiikka.com/) - Project logo creation
|
|
259
322
|
* [yutaas](https://github.com/yutaas) - English proofreading
|
|
260
323
|
|
|
261
324
|
## License
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YouPlot
|
|
4
|
+
module Aggregation
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def count_values(arr, tally: true, reverse: false)
|
|
8
|
+
# tally was added in Ruby 2.7
|
|
9
|
+
result = \
|
|
10
|
+
if tally && Enumerable.method_defined?(:tally)
|
|
11
|
+
arr.tally
|
|
12
|
+
else
|
|
13
|
+
# value_counts Enumerable::Statistics
|
|
14
|
+
arr.value_counts(dropna: false)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
sort_cache = {}
|
|
18
|
+
|
|
19
|
+
# sorting
|
|
20
|
+
result = result.sort do |a, b|
|
|
21
|
+
# compare values
|
|
22
|
+
r = b[1] <=> a[1]
|
|
23
|
+
# If the values are the same, compare by name
|
|
24
|
+
r = natural_compare(a[0], b[0], sort_cache) if r.zero?
|
|
25
|
+
r
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# --reverse option
|
|
29
|
+
result.reverse! if reverse
|
|
30
|
+
|
|
31
|
+
# prepare for barplot
|
|
32
|
+
result.transpose
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Natural order comparison for tie-breaking when counts are equal.
|
|
36
|
+
# Fast paths handle text-only and pure numeric labels.
|
|
37
|
+
# Mixed labels still use chunked comparison (e.g. "chr1" vs "chr10").
|
|
38
|
+
def natural_compare(a, b, cache = nil)
|
|
39
|
+
aa = natural_sort_key(a, cache)
|
|
40
|
+
bb = natural_sort_key(b, cache)
|
|
41
|
+
|
|
42
|
+
# Fast path: both labels are text-only, so plain string comparison is enough.
|
|
43
|
+
return aa[:string] <=> bb[:string] if aa[:type] == :text && bb[:type] == :text
|
|
44
|
+
|
|
45
|
+
# Fast path: both labels are pure numbers, so compare numerically first.
|
|
46
|
+
if aa[:type] == :numeric && bb[:type] == :numeric
|
|
47
|
+
r = aa[:numeric] <=> bb[:numeric]
|
|
48
|
+
return r unless r.zero?
|
|
49
|
+
|
|
50
|
+
# Tiebreaker for equivalent numeric values (e.g. "1" and "01")
|
|
51
|
+
return aa[:string] <=> bb[:string]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Fallback path: at least one label mixes text and digits.
|
|
55
|
+
ta = ensure_natural_tokens(aa)
|
|
56
|
+
tb = ensure_natural_tokens(bb)
|
|
57
|
+
max = [ta.size, tb.size].max
|
|
58
|
+
|
|
59
|
+
0.upto(max - 1) do |i|
|
|
60
|
+
xa = ta[i]
|
|
61
|
+
xb = tb[i]
|
|
62
|
+
|
|
63
|
+
return -1 if xa.nil?
|
|
64
|
+
return 1 if xb.nil?
|
|
65
|
+
|
|
66
|
+
r = if xa[0] == :num && xb[0] == :num
|
|
67
|
+
compare_integer_strings(xa[1], xb[1])
|
|
68
|
+
else
|
|
69
|
+
xa[1] <=> xb[1]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
return r unless r.zero?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
aa[:string] <=> bb[:string]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Classifies a value for natural sorting and caches the result per label.
|
|
79
|
+
def natural_sort_key(value, cache = nil)
|
|
80
|
+
str = value.to_s
|
|
81
|
+
return cache[str] if cache && cache.key?(str)
|
|
82
|
+
|
|
83
|
+
key = if str.match?(/\d/)
|
|
84
|
+
numeric = parse_numeric(str)
|
|
85
|
+
if numeric
|
|
86
|
+
# Pure numeric labels get a dedicated fast path.
|
|
87
|
+
{ type: :numeric, string: str, numeric: numeric }
|
|
88
|
+
else
|
|
89
|
+
# Mixed labels fall back to chunked natural comparison.
|
|
90
|
+
{ type: :mixed, string: str, tokens: nil }
|
|
91
|
+
end
|
|
92
|
+
else
|
|
93
|
+
# Text-only labels get a dedicated fast path.
|
|
94
|
+
{ type: :text, string: str, tokens: nil }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
cache ? cache[str] = key : key
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Memoizes token pairs for fallback chunked comparison.
|
|
101
|
+
def ensure_natural_tokens(key)
|
|
102
|
+
key[:tokens] ||= natural_tokens(key[:string])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Parses a string as a numeric value if it matches pure number format.
|
|
106
|
+
# Returns Float or nil.
|
|
107
|
+
def parse_numeric(str)
|
|
108
|
+
return nil unless str.match?(/\A[+-]?(?:\d+(?:\.\d+)?|\.\d+)\z/)
|
|
109
|
+
|
|
110
|
+
str.to_f
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Splits a string into [type, token] pairs for natural comparison.
|
|
114
|
+
# Type is :num for digit-only chunks, :text for anything else.
|
|
115
|
+
# E.g. "chr10" => [[:text, "chr"], [:num, "10"]]
|
|
116
|
+
def natural_tokens(str)
|
|
117
|
+
str.scan(/\d+|\D+/).map do |tok|
|
|
118
|
+
kind = tok.match?(/\A\d+\z/) ? :num : :text
|
|
119
|
+
[kind, tok]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Compares two numeric strings, handling leading zeros.
|
|
124
|
+
# Order: by length (sans leading zeros), then numeric value, then original.
|
|
125
|
+
def compare_integer_strings(a, b)
|
|
126
|
+
aa = a.sub(/\A0+/, '')
|
|
127
|
+
bb = b.sub(/\A0+/, '')
|
|
128
|
+
aa = '0' if aa.empty?
|
|
129
|
+
bb = '0' if bb.empty?
|
|
130
|
+
|
|
131
|
+
r = aa.length <=> bb.length
|
|
132
|
+
return r unless r.zero?
|
|
133
|
+
|
|
134
|
+
r = aa <=> bb
|
|
135
|
+
return r unless r.zero?
|
|
136
|
+
|
|
137
|
+
a <=> b
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# UnicodePlot - Plot your data by Unicode characters
|
|
4
4
|
# https://github.com/red-data-tools/unicode_plot.rb
|
|
5
5
|
|
|
6
|
-
require_relative '
|
|
6
|
+
require_relative '../aggregation'
|
|
7
7
|
require 'unicode_plot'
|
|
8
8
|
|
|
9
9
|
# If the line color is specified as a number, the program will display an error
|
|
@@ -40,13 +40,14 @@ module YouPlot
|
|
|
40
40
|
series = data.series
|
|
41
41
|
# `uplot count`
|
|
42
42
|
if count
|
|
43
|
-
series =
|
|
43
|
+
series = YouPlot::Aggregation.count_values(series[0], reverse: reverse)
|
|
44
44
|
params.title = headers[0] if headers
|
|
45
45
|
end
|
|
46
46
|
if series.size == 1
|
|
47
47
|
# If there is only one series.use the line number for label.
|
|
48
48
|
params.title ||= headers[0] if headers
|
|
49
49
|
labels = Array.new(series[0].size) { |i| (i + 1).to_s }
|
|
50
|
+
raw_values = series[0]
|
|
50
51
|
values = series[0].map(&:to_f)
|
|
51
52
|
else
|
|
52
53
|
# If there are 2 or more series...
|
|
@@ -61,11 +62,28 @@ module YouPlot
|
|
|
61
62
|
end
|
|
62
63
|
params.title ||= headers[y_col] if headers
|
|
63
64
|
labels = series[x_col]
|
|
64
|
-
|
|
65
|
+
raw_values = series[y_col]
|
|
66
|
+
values = if count
|
|
67
|
+
series[y_col].map(&:to_i)
|
|
68
|
+
else
|
|
69
|
+
series[y_col].map(&:to_f)
|
|
70
|
+
end
|
|
65
71
|
end
|
|
72
|
+
values = values.map(&:to_i) if count || integer_display_values?(values, raw_values)
|
|
66
73
|
::UnicodePlot.barplot(labels, values, **params.to_hc)
|
|
67
74
|
end
|
|
68
75
|
|
|
76
|
+
# True only for integer literals: "3" => true, "3.0" => false.
|
|
77
|
+
def integer_display_values?(values, raw_values)
|
|
78
|
+
values.all? { |v| v.finite? && v == v.to_i } &&
|
|
79
|
+
raw_values.all? { |v| integer_literal?(v) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def integer_literal?(value)
|
|
83
|
+
# Matches "3" and "-12", but not "3.0".
|
|
84
|
+
value.to_s.match?(/\A[+-]?\d+\z/)
|
|
85
|
+
end
|
|
86
|
+
|
|
69
87
|
def histogram(data, params)
|
|
70
88
|
headers = data.headers
|
|
71
89
|
series = data.series
|
|
@@ -200,27 +218,37 @@ module YouPlot
|
|
|
200
218
|
|
|
201
219
|
def check_series_size(data, fmt)
|
|
202
220
|
series = data.series
|
|
203
|
-
if series.size == 1
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
raise_if_single_series(data, series) if series.size == 1
|
|
222
|
+
raise_if_odd_series_for_xyxy(data, fmt, series)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def raise_if_single_series(data, series)
|
|
226
|
+
warn <<~EOS
|
|
227
|
+
YouPlot: There is only one series of input data. Please check the delimiter.
|
|
228
|
+
|
|
229
|
+
Headers: \e[35m#{data.headers.inspect}\e[0m
|
|
230
|
+
The first item is: \e[35m\"#{series[0][0]}\"\e[0m
|
|
231
|
+
The last item is : \e[35m\"#{series[0][-1]}\"\e[0m
|
|
232
|
+
EOS
|
|
233
|
+
raise_plot_error
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def raise_if_odd_series_for_xyxy(data, fmt, series)
|
|
237
|
+
return unless fmt == 'xyxy'
|
|
238
|
+
return if series.size.even?
|
|
239
|
+
|
|
240
|
+
warn <<~EOS
|
|
241
|
+
YouPlot: In the xyxy format, the number of series must be even.
|
|
242
|
+
|
|
243
|
+
Number of series: \e[35m#{series.size}\e[0m
|
|
244
|
+
Headers: \e[35m#{data.headers.inspect}\e[0m
|
|
245
|
+
EOS
|
|
246
|
+
raise_plot_error
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def raise_plot_error
|
|
250
|
+
# NOTE: Error messages cannot be colored.
|
|
251
|
+
YouPlot.run_as_executable ? exit(1) : raise(Error)
|
|
224
252
|
end
|
|
225
253
|
end
|
|
226
254
|
end
|