youplot 0.3.0 → 0.3.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d270d30bd2d7d0766d6e26704383ec25fd742d2ed12b8e3738f91c985e2b4f80
4
- data.tar.gz: '01149b5a5bd05dbbfc544e207ea4345c602468f68e39d3965025c4f7c1ddb13f'
3
+ metadata.gz: 6bfd3292028fb88c3a5c902884d6c3dd17f59292eb4980b09a75396c921cb46f
4
+ data.tar.gz: '00524329ddcea39543d4a064e5f930c417544f86a853f538823eb6ece37ac255'
5
5
  SHA512:
6
- metadata.gz: 80c2894983ca5cc3a9e9833a95f7d11a8928db454fecc0b97b585a4903dd0ae77cf89a1929dc4cb526dc6e7b0f8b0019d5d0769ab6f1a63ab4acb3db8a125c35
7
- data.tar.gz: 4c6b532a8b95ab2b9ba8aa5def4b368edd93fe5e9af224d1f7fc4f87a4b40d0a07cf7f874565c10f7630d257e393fb8175ec087e6da9e4740b4e31e76c3d1d12
6
+ metadata.gz: 3b37389aab9904bc7129397a8c04b6a1d6e244bc1af986f57d21131eec55cf7051308a7eabc2e81d17e8e4838d45d9c5d6cc65169375329e9884726a2ea49408
7
+ data.tar.gz: 6a1c8605980520e8d0bae43b0302d6e07d5511e6bf85d0fd3def1c6c994ed5e1375a076af69ef843b2a1a0f5e7bbbb877148ef03bf833a734c53c1115e59c0fd
data/README.md CHANGED
@@ -1,11 +1,14 @@
1
- # YouPlot
1
+ <p align="center">
2
+ <img src="logo.svg" width="60%" height="60%" />
3
+ </7>
2
4
 
3
5
  ![Build Status](https://github.com/kojix2/youplot/workflows/test/badge.svg)
4
6
  [![Gem Version](https://badge.fury.io/rb/youplot.svg)](https://badge.fury.io/rb/youplot)
5
- [![Docs Latest](https://img.shields.io/badge/docs-latest-blue.svg)](https://rubydoc.info/gems/youplot)
7
+ [![Docs Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://rubydoc.info/gems/youplot)
6
8
  [![The MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
9
+ [![DOI](https://zenodo.org/badge/283230219.svg)](https://zenodo.org/badge/latestdoi/283230219)
7
10
 
8
- Create ASCII charts on the terminal with data from standard streams in the pipeline.
11
+ YouPlot is a command line tool for Unicode Plotting working with data from standard stream.
9
12
 
10
13
  :bar_chart: Powered by [UnicodePlot](https://github.com/red-data-tools/unicode_plot.rb)
11
14
 
@@ -15,16 +18,25 @@ Create ASCII charts on the terminal with data from standard streams in the pipel
15
18
  gem install youplot
16
19
  ```
17
20
 
18
- ## Screenshots
21
+ ## Quick Start
19
22
 
20
- **histogram**
23
+ * `cat data.tsv | uplot <command> [options]` or
24
+ * `uplot <command> [options] <data.tsv>`
25
+
26
+ ### barplot
21
27
 
22
28
  ```sh
23
- ruby -r numo/narray -e "puts Numo::DFloat.new(1000).rand_norm.to_a" \
24
- | uplot hist --nbins 15
29
+ curl -sL https://git.io/ISLANDScsv \
30
+ | sort -nk2 -t, \
31
+ | tail -n15 \
32
+ | uplot bar -d, -t "Areas of the World's Major Landmasses"
25
33
  ```
26
34
 
27
- <img src="https://i.imgur.com/wpsoGJq.png" width="75%" height="75%">
35
+ <p align="center">
36
+ <img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
37
+ </p>
38
+
39
+ ### histogram
28
40
 
29
41
  ```sh
30
42
  echo -e "from numpy import random;" \
@@ -34,91 +46,152 @@ echo -e "from numpy import random;" \
34
46
  | uplot hist --nbins 20
35
47
  ```
36
48
 
37
- <img src="https://i.imgur.com/97R2MQx.png" width="75%" height="75%">
49
+ <p align="center">
50
+ <img alt="histogram" src="https://user-images.githubusercontent.com/5798442/101999820-21cafc00-3d24-11eb-86db-e410d19b07df.png">
51
+ </p>
38
52
 
39
- **scatter**
53
+ ### lineplot
40
54
 
41
55
  ```sh
42
- curl -s https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv \
43
- | cut -f1-4 -d, \
44
- | uplot scatter -H -d, -t IRIS
56
+ curl -sL https://git.io/AirPassengers \
57
+ | cut -f2,3 -d, \
58
+ | uplot line -d, -w 50 -h 15 -t AirPassengers --xlim 1950,1960 --ylim 0,600
45
59
  ```
46
60
 
47
- <img src="https://i.imgur.com/STX7bFT.png" width="75%" height="75%">
61
+ <p align="center">
62
+ <img alt="lineplot" src="https://user-images.githubusercontent.com/5798442/101999825-24c5ec80-3d24-11eb-99f4-c642e8d221bc.png">
63
+ </p>
48
64
 
49
- **line**
65
+ ### scatter
50
66
 
51
67
  ```sh
52
- curl -s https://www.mhlw.go.jp/content/pcr_positive_daily.csv \
53
- | cut -f2 -d, \
54
- | uplot line -w 50 -h 15 -t 'PCR positive tests' --xlabel Date --ylabel number
68
+ curl -sL https://git.io/IRIStsv \
69
+ | cut -f1-4 \
70
+ | uplot scatter -H -t IRIS
55
71
  ```
56
72
 
57
- <img src="https://i.imgur.com/PVl5dsa.png" width="75%" height="75%">
73
+ <p align="center">
74
+ <img alt="scatter" src="https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png">
75
+ </p>
58
76
 
59
- **box**
77
+ ### density
60
78
 
61
79
  ```sh
62
- curl -s https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv \
63
- | cut -f1-4 -d, \
64
- | uplot box -H -d, -t IRIS
80
+ curl -sL https://git.io/IRIStsv \
81
+ | cut -f1-4 \
82
+ | uplot density -H -t IRIS
65
83
  ```
66
84
 
67
- <img src="https://i.imgur.com/sNI4SmN.png" width="75%" height="75%">
85
+ <p align="center">
86
+ <img alt="density" src="https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png">
87
+ </p>
68
88
 
69
- **colors**
89
+ ### boxplot
70
90
 
71
91
  ```sh
72
- uplot colors
92
+ curl -sL https://git.io/IRIStsv \
93
+ | cut -f1-4 \
94
+ | uplot boxplot -H -t IRIS
73
95
  ```
74
96
 
75
- <img src="https://i.imgur.com/LxyHQsz.png">
97
+ <p align="center">
98
+ <img alt="boxplot" src="https://user-images.githubusercontent.com/5798442/101999830-2e4f5480-3d24-11eb-8891-728c18bf5b35.png">
99
+ </p>
76
100
 
77
- ## Usage
101
+ ### count
102
+
103
+ 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.
78
104
 
79
- `uplot --help`
105
+ * https://www.gencodegenes.org/human/
80
106
 
107
+ ```sh
108
+ cat gencode.v35.annotation.gff3 \
109
+ | grep -v '#' | grep 'gene' | cut -f1 | \
110
+ uplot count -t "The number of human gene annotations per chromosome" -c blue
81
111
  ```
82
- Program: YouPlot (Tools for plotting on the terminal)
83
- Version: 0.2.7 (using UnicodePlot 0.0.4)
84
- Source: https://github.com/kojix2/youplot
85
112
 
86
- Usage: uplot <command> [options] <in.tsv>
113
+ <p align="center">
114
+ <img alt="count" src="https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png">
115
+ </p>
87
116
 
88
- Commands:
89
- barplot bar
90
- histogram hist
91
- lineplot line
92
- lineplots lines
93
- scatter s
94
- density d
95
- boxplot box
96
- colors show the list of available colors
117
+ Note: `count` is not very fast because it runs in a Ruby script.
118
+ 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.
97
119
 
98
- count c baplot based on the number of occurrences
99
- (slower than `sort | uniq -c | sort -n -k1`)
120
+ ```sh
121
+ cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
122
+ |sort | uniq -c | sort -nrk2 | awk '{print $2,$1}' \
123
+ | uplot bar -d ' ' -t "The number of human gene annotations per chromosome" -c blue
124
+ ```
100
125
 
101
- Options:
102
- -O, --pass [VAL] file to output standard input data to [stdout]
103
- for inserting YouPlot in the middle of Unix pipes
104
- -o, --output VAL file to output results to [stderr]
105
- -d, --delimiter VAL use DELIM instead of TAB for field delimiter
106
- -H, --headers specify that the input has header row
107
- -T, --transpose transpose the axes of the input data
108
- -t, --title VAL print string on the top of plot
109
- -x, --xlabel VAL print string on the bottom of the plot
110
- -y, --ylabel VAL print string on the far left of the plot
111
- -w, --width VAL number of characters per row
112
- -h, --height VAL number of rows
113
- -b, --border VAL specify the style of the bounding box
114
- -m, --margin VAL number of spaces to the left of the plot
115
- -p, --padding VAL space of the left and right of the plot
116
- -c, --color VAL color of the drawing
117
- --[no-]labels hide the labels
118
- --fmt VAL xyxy : header is like x1, y1, x2, y2, x3, y3...
119
- xyy : header is like x, y1, y2, y2, y3...
126
+ ## Usage
127
+
128
+ ### Why YouPlot?
129
+
130
+ Wouldn't it be a pain to have to run R, Python, Julia, gnuplot or whatever REPL just to check your data?
131
+ YouPlot is a command line tool for this purpose. With YouPlot, you can continue working without leaving your terminal and shell.
132
+
133
+ ### how to use YouPlot?
134
+
135
+ `uplot` is the shortened form of `youplot`. You can use either.
136
+
137
+ | | |
138
+ |-----------------------------------|------------------------------------------------|
139
+ | Reads data from standard input | `cat data.tsv \| uplot <command> [options]` |
140
+ | Reads data from files | `uplot <command> [options] data.tsv ...` |
141
+ | Outputs data from stdin to stdout | `pipeline1 \| uplot <command> -O \| pipeline2` |
142
+
143
+ ### Where to output the plot?
144
+
145
+ By default, the plot is output to *standard error output*.
146
+ The output file or stream for the plot can be specified with the `-o` option.
147
+
148
+ ### Where to output the input data?
149
+
150
+ By default, the input data is not shown anywhere.
151
+ 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.
152
+
153
+ ### What types of plots are available?
154
+
155
+ The following sub-commands are available.
156
+
157
+ | command | short | how it works |
158
+ |-----------|-------|----------------------------------------|
159
+ | barplot | bar | draw a horizontal barplot |
160
+ | histogram | hist | draw a horizontal histogram |
161
+ | lineplot | line | draw a line chart |
162
+ | lineplots | lines | draw a line chart with multiple series |
163
+ | scatter | s | draw a scatter plot |
164
+ | density | d | draw a density plot |
165
+ | boxplot | box | draw a horizontal boxplot |
166
+
167
+ See Quick Start for `count`.
168
+
169
+ | command | short | how it works |
170
+ |-----------|-------|----------------------------------------------------------|
171
+ | count | c | draw a barplot based on the number of occurrences (slow) |
172
+
173
+ ### What if the header line is included?
174
+
175
+ If your input data contains a header line, you need to specify the `-H` option.
176
+
177
+ ### How to specify the delimiter?
178
+
179
+ 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.
180
+
181
+ ### Is there a way to specify a column as the x-axis or y-axis?
182
+
183
+ Not yet. In principle, YouPlot treats the first column as the X axis and the second column as the Y axis. When working with multiple series, the first row is the X axis, the second row is series 1, the third row is series 2, 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. The `--fmt xyy`, `--fmt xyxy` and `--fmt yx` options give you a few more choices. See `youplot <command> --help` for more details. YouPlot has limited functionalities, but you can use shell scripts such as `awk '{print $2, $1}'` to swap lines.
184
+
185
+ ### How to plot real-time data?
186
+
187
+ Experimental progressive mode is currently under development.
188
+
189
+ ```sh
190
+ ruby -e 'loop{puts rand(100)}' | uplot line --progress
120
191
  ```
121
192
 
193
+ ### How to view detailed command line options?
194
+
122
195
  Use `--help` to print command-specific options.
123
196
 
124
197
  `uplot hist --help`
@@ -128,20 +201,45 @@ Usage: uplot histogram [options] <in.tsv>
128
201
 
129
202
  Options for histogram:
130
203
  --symbol VAL character to be used to plot the bars
131
- --closed VAL
204
+ --closed VAL side of the intervals to be closed [left]
132
205
  -n, --nbins VAL approximate number of bins
133
206
 
134
207
  Options:
135
208
  ...
136
209
  ```
137
210
 
138
- ## Development
211
+ ### How to view the list of available colors?
139
212
 
140
- Let's keep it simple.
213
+ ```sh
214
+ uplot colors
215
+ ```
141
216
 
142
217
  ## Contributing
143
218
 
144
- Bug reports and pull requests are welcome on GitHub at [https://github.com/kojix2/youplot](https://github.com/kojix2/youplot).
219
+ YouPlot is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
220
+
221
+ * [Report bugs](https://github.com/kojix2/youplot/issues)
222
+ * Fix bugs and [submit pull requests](https://github.com/kojix2/youplot/pulls)
223
+ * Write, clarify, or fix documentation
224
+ * English corrections by native speakers are welcome.
225
+ * Suggest or add new features
226
+
227
+
228
+ ### Development
229
+
230
+ ```sh
231
+ # fork the main repository by clicking the Fork button.
232
+ git clone https://github.com/your_name/YouPlot
233
+ bundle install # Install the gem dependencies
234
+ bundle exec rake test # Run the test
235
+ bundle exec rake install # Installation from source code
236
+ ```
237
+
238
+ ### Acknowledgements
239
+
240
+ * [Red Data Tools](https://github.com/red-data-tools) - Technical support
241
+ * [sampo grafiikka](https://jypg.net/sampo_grafiikka) - Project logo creation
242
+ * [yutaas](https://github.com/yutaas) - English proofreading
145
243
 
146
244
  ## License
147
245
 
data/exe/uplot CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require 'youplot'
5
5
 
6
- YouPlot::Command.new.run
6
+ YouPlot::Command.new.run_as_executable
data/exe/youplot CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require 'youplot'
5
5
 
6
- YouPlot::Command.new.run
6
+ YouPlot::Command.new.run_as_executable
data/lib/youplot.rb CHANGED
@@ -2,8 +2,16 @@
2
2
 
3
3
  require 'unicode_plot'
4
4
  require 'youplot/version'
5
- require 'youplot/preprocessing'
5
+ require 'youplot/dsv'
6
6
  require 'youplot/command'
7
7
 
8
8
  module YouPlot
9
+ class << self
10
+ attr_accessor :run_as_executable
11
+
12
+ def run_as_executable?
13
+ @run_as_executable
14
+ end
15
+ end
16
+ @run_as_executable = false
9
17
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YouPlot
4
+ # plotting functions.
5
+ module Backends
6
+ module Processing
7
+ module_function
8
+
9
+ def count_values(arr, tally: true)
10
+ # tally was added in Ruby 2.7
11
+ if tally && Enumerable.method_defined?(:tally)
12
+ arr.tally
13
+ else
14
+ # https://github.com/marcandre/backports
15
+ arr.each_with_object(Hash.new(0)) { |item, res| res[item] += 1 }
16
+ .tap { |h| h.default = nil }
17
+ end
18
+ .sort { |a, b| a[1] <=> b[1] }
19
+ .reverse
20
+ .transpose
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,30 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'processing'
3
4
  require 'unicode_plot'
4
5
 
5
6
  module YouPlot
6
7
  # plotting functions.
7
8
  module Backends
8
9
  module UnicodePlotBackend
10
+ class Error < StandardError; end
11
+
9
12
  module_function
10
13
 
11
- def barplot(data, params, count: false)
14
+ def barplot(data, params, fmt = nil, count: false)
12
15
  headers = data.headers
13
16
  series = data.series
14
17
  # `uplot count`
15
18
  if count
16
- series = Preprocessing.count_values(series[0])
19
+ series = Processing.count_values(series[0])
17
20
  params.title = headers[0] if headers
18
21
  end
19
22
  if series.size == 1
20
- # If there is only one series, use the line number for label.
23
+ # If there is only one series.use the line number for label.
21
24
  params.title ||= headers[0] if headers
22
25
  labels = Array.new(series[0].size) { |i| (i + 1).to_s }
23
26
  values = series[0].map(&:to_f)
24
27
  else
25
- params.title ||= headers[1] if headers
26
- labels = series[0]
27
- values = series[1].map(&:to_f)
28
+ # If there are 2 or more series...
29
+ if fmt == 'yx'
30
+ # assume that the first 2 series are the y and x series respectively.
31
+ x_col = 1
32
+ y_col = 0
33
+ else
34
+ # assume that the first 2 series are the x and y series respectively.
35
+ x_col = 0
36
+ y_col = 1
37
+ end
38
+ params.title ||= headers[y_col] if headers
39
+ labels = series[x_col]
40
+ values = series[y_col].map(&:to_f)
28
41
  end
29
42
  UnicodePlot.barplot(labels, values, **params.to_hc)
30
43
  end
@@ -37,7 +50,7 @@ module YouPlot
37
50
  UnicodePlot.histogram(values, **params.to_hc)
38
51
  end
39
52
 
40
- def line(data, params)
53
+ def line(data, params, fmt = nil)
41
54
  headers = data.headers
42
55
  series = data.series
43
56
  if series.size == 1
@@ -46,14 +59,22 @@ module YouPlot
46
59
  y = series[0].map(&:to_f)
47
60
  UnicodePlot.lineplot(y, **params.to_hc)
48
61
  else
49
- # If there are 2 or more series,
50
- # assume that the first 2 series are the x and y series respectively.
62
+ # If there are 2 or more series...
63
+ if fmt == 'yx'
64
+ # assume that the first 2 series are the y and x series respectively.
65
+ x_col = 1
66
+ y_col = 0
67
+ else
68
+ # assume that the first 2 series are the x and y series respectively.
69
+ x_col = 0
70
+ y_col = 1
71
+ end
51
72
  if headers
52
- params.xlabel ||= headers[0]
53
- params.ylabel ||= headers[1]
73
+ params.xlabel ||= headers[x_col]
74
+ params.ylabel ||= headers[y_col]
54
75
  end
55
- x = series[0].map(&:to_f)
56
- y = series[1].map(&:to_f)
76
+ x = series[x_col].map(&:to_f)
77
+ y = series[y_col].map(&:to_f)
57
78
  UnicodePlot.lineplot(x, y, **params.to_hc)
58
79
  end
59
80
  end
@@ -71,6 +92,7 @@ module YouPlot
71
92
  params.name ||= headers[1]
72
93
  params.xlabel ||= headers[0]
73
94
  end
95
+ params.xlim ||= series[0].flatten.minmax # why need?
74
96
  params.ylim ||= series[1..-1].flatten.minmax # why need?
75
97
  plot = UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
76
98
  2.upto(series.size - 1) do |i|
@@ -84,13 +106,14 @@ module YouPlot
84
106
  series = data.series
85
107
  method2 = get_method2(method1)
86
108
  series.map! { |s| s.map(&:to_f) }
87
- series = series.each_slice(2).to_a
109
+ series2 = series.each_slice(2).to_a
110
+ series = nil
88
111
  params.name ||= headers[0] if headers
89
- params.xlim = series.map(&:first).flatten.minmax # why need?
90
- params.ylim = series.map(&:last).flatten.minmax # why need?
91
- x1, y1 = series.shift
112
+ params.xlim ||= series2.map(&:first).flatten.minmax # why need?
113
+ params.ylim ||= series2.map(&:last).flatten.minmax # why need?
114
+ x1, y1 = series2.shift
92
115
  plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
93
- series.each_with_index do |(xi, yi), i|
116
+ series2.each_with_index do |(xi, yi), i|
94
117
  UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
95
118
  end
96
119
  plot
@@ -102,6 +125,8 @@ module YouPlot
102
125
  plot_xyy(data, method1, params)
103
126
  when 'xyxy'
104
127
  plot_xyxy(data, method1, params)
128
+ when 'yx'
129
+ raise "Incorrect format: #{fmt}"
105
130
  else
106
131
  raise "Unknown format: #{fmt}"
107
132
  end
@@ -131,35 +156,47 @@ module YouPlot
131
156
  end
132
157
 
133
158
  def colors(color_names = false)
159
+ # FIXME
160
+ s = String.new
134
161
  UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
135
- print v
136
- print k
162
+ s << v
163
+ s << k.to_s
137
164
  unless color_names
138
- print "\t"
139
- print ' ●'
165
+ s << "\t"
166
+ s << ' ●'
140
167
  end
141
- print "\033[0m"
142
- print "\t"
168
+ s << "\033[0m"
169
+ s << "\t"
143
170
  end
144
- puts
171
+ s << "\n"
172
+ def s.render(obj)
173
+ obj.print(self)
174
+ end
175
+ s
145
176
  end
146
177
 
147
178
  def check_series_size(data, fmt)
148
179
  series = data.series
149
180
  if series.size == 1
150
- warn 'youplot: There is only one series of input data. Please check the delimiter.'
151
- warn ''
152
- warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
153
- warn " The first item is: \e[35m\"#{series[0][0]}\"\e[0m"
154
- warn " The last item is : \e[35m\"#{series[0][-1]}\"\e[0m"
155
- exit 1
181
+ warn <<~EOS
182
+ youplot: There is only one series of input data. Please check the delimiter.
183
+
184
+ Headers: \e[35m#{data.headers.inspect}\e[0m
185
+ The first item is: \e[35m\"#{series[0][0]}\"\e[0m
186
+ The last item is : \e[35m\"#{series[0][-1]}\"\e[0m
187
+ EOS
188
+ # NOTE: Error messages cannot be colored.
189
+ YouPlot.run_as_executable ? exit(1) : raise(Error)
156
190
  end
157
191
  if fmt == 'xyxy' && series.size.odd?
158
- warn 'YouPlot: In the xyxy format, the number of series must be even.'
159
- warn ''
160
- warn " Number of series: \e[35m#{series.size}\e[0m"
161
- warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
162
- exit 1
192
+ warn <<~EOS
193
+ YouPlot: In the xyxy format, the number of series must be even.
194
+
195
+ Number of series: \e[35m#{series.size}\e[0m
196
+ Headers: \e[35m#{data.headers.inspect}\e[0m
197
+ EOS
198
+ # NOTE: Error messages cannot be colored.
199
+ YouPlot.run_as_executable ? exit(1) : raise(Error)
163
200
  end
164
201
  end
165
202
  end