youplot 0.3.5 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bfd3292028fb88c3a5c902884d6c3dd17f59292eb4980b09a75396c921cb46f
4
- data.tar.gz: '00524329ddcea39543d4a064e5f930c417544f86a853f538823eb6ece37ac255'
3
+ metadata.gz: 5b3b1cbdabc0a74b4010d13fa59fe9724ac9c07783414a7a7584f8cab27b49ec
4
+ data.tar.gz: f5cf98b592a248c4d74e06078d97050e85c892e94c0dd78ec17e92f6bdc856d0
5
5
  SHA512:
6
- metadata.gz: 3b37389aab9904bc7129397a8c04b6a1d6e244bc1af986f57d21131eec55cf7051308a7eabc2e81d17e8e4838d45d9c5d6cc65169375329e9884726a2ea49408
7
- data.tar.gz: 6a1c8605980520e8d0bae43b0302d6e07d5511e6bf85d0fd3def1c6c994ed5e1375a076af69ef843b2a1a0f5e7bbbb877148ef03bf833a734c53c1115e59c0fd
6
+ metadata.gz: aebe50c600b66e9cb8e3a64da3ddafff70472f495d51b812987cc835017ca19fd1347fbe2ee88fac66e111837ffef59bf6c271f2f6515ae7e60a526050ded5b3
7
+ data.tar.gz: b37e2a5a2d8eb33700690d28b6e6f5851fbefb0e88ae10bcb6d9f65f06f966c31b81c7587135c6d296bde0caefbc81239046ec06535cefa9329f2ac6d8a8788f
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
- <p align="center">
2
- <img src="logo.svg" width="60%" height="60%" />
3
- </7>
4
-
5
- ![Build Status](https://github.com/kojix2/youplot/workflows/test/badge.svg)
6
- [![Gem Version](https://badge.fury.io/rb/youplot.svg)](https://badge.fury.io/rb/youplot)
7
- [![Docs Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://rubydoc.info/gems/youplot)
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)
10
-
11
- YouPlot is a command line tool for Unicode Plotting working with data from standard stream.
12
-
13
- :bar_chart: Powered by [UnicodePlot](https://github.com/red-data-tools/unicode_plot.rb)
1
+ <div align="center">
2
+ <img src="logo.svg">
3
+ <hr>
4
+ <img alt="Build Status" src="https://github.com/red-data-tools/YouPlot/workflows/test/badge.svg">
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
+ <a href="https://rubydoc.info/gems/youplot/"><img alt="Docs Stable" src="https://img.shields.io/badge/docs-stable-blue.svg"></a>
8
+ <a href="LICENSE.txt"><img alt="The MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
9
+
10
+ YouPlot is a command line tool that draws plots on the terminal.
11
+
12
+ :bar_chart: Powered by [UnicodePlot](https://github.com/red-data-tools/unicode_plot.rb)
13
+ </div>
14
14
 
15
15
  ## Installation
16
16
 
@@ -20,8 +20,9 @@ gem install youplot
20
20
 
21
21
  ## Quick Start
22
22
 
23
- * `cat data.tsv | uplot <command> [options]` or
24
- * `uplot <command> [options] <data.tsv>`
23
+ <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>
24
+
25
+ `uplot <command> [options] <data.tsv>`
25
26
 
26
27
  ### barplot
27
28
 
@@ -33,7 +34,7 @@ curl -sL https://git.io/ISLANDScsv \
33
34
  ```
34
35
 
35
36
  <p align="center">
36
- <img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
37
+ <img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
37
38
  </p>
38
39
 
39
40
  ### histogram
@@ -100,57 +101,41 @@ curl -sL https://git.io/IRIStsv \
100
101
 
101
102
  ### count
102
103
 
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.
104
-
105
- * https://www.gencodegenes.org/human/
106
-
107
104
  ```sh
108
105
  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
106
+ | grep -v '#' | grep 'gene' | cut -f1 \
107
+ | uplot count -t "The number of human gene annotations per chromosome" -c blue
111
108
  ```
112
109
 
113
110
  <p align="center">
114
111
  <img alt="count" src="https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png">
115
112
  </p>
116
113
 
114
+ In this example, YouPlot counts the number of chromosomes where genes are located.
115
+ * [GENCODE - Human Release](https://www.gencodegenes.org/human/)
116
+
117
117
  Note: `count` is not very fast because it runs in a Ruby script.
118
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.
119
119
 
120
120
  ```sh
121
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
122
+ | sort | uniq -c | sort -nrk1 \
123
+ | uplot bar --fmt yx -d ' ' -t "The number of human gene annotations per chromosome" -c blue
124
124
  ```
125
125
 
126
126
  ## Usage
127
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?
128
+ ### Commands
134
129
 
135
130
  `uplot` is the shortened form of `youplot`. You can use either.
136
131
 
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.
132
+ | Command | Description |
133
+ |------------------------------------------------|-----------------------------------|
134
+ | `cat data.tsv \| uplot <command> [options]` | Take input from stdin |
135
+ | `uplot <command> [options] data.tsv ...` | Take input from files |
136
+ | `pipeline1 \| uplot <command> -O \| pipeline2` | Outputs data from stdin to stdout |
147
137
 
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?
138
+ ### Subcommands
154
139
 
155
140
  The following sub-commands are available.
156
141
 
@@ -163,67 +148,87 @@ The following sub-commands are available.
163
148
  | scatter | s | draw a scatter plot |
164
149
  | density | d | draw a density plot |
165
150
  | boxplot | box | draw a horizontal boxplot |
151
+ | | | |
152
+ | count | c | draw a barplot based on the number of occurrences (slow) |
153
+ | | | |
154
+ | colors | color | show the list of available colors |
166
155
 
167
- See Quick Start for `count`.
156
+ ### Output the plot
168
157
 
169
- | command | short | how it works |
170
- |-----------|-------|----------------------------------------------------------|
171
- | count | c | draw a barplot based on the number of occurrences (slow) |
158
+ * `-o`
159
+ * By default, the plot is output to **standard error output**.
160
+ * If you want to output to standard input, Use hyphen ` -o -` or no argument `uplot s -o | `.
172
161
 
173
- ### What if the header line is included?
162
+ ### Output the input data
174
163
 
175
- If your input data contains a header line, you need to specify the `-H` option.
164
+ * `-O`
165
+ * By default, the input data is not shown anywhere.
166
+ * If you want to pass the input data directly to the standard output, Use hyphen `-O -` or no argument `uplot s -O |`.
167
+ * This is useful when passing data to a subsequent pipeline.
176
168
 
177
- ### How to specify the delimiter?
169
+ ### Header
178
170
 
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.
171
+ * `-H`
172
+ * If input data contains a header line, you need to specify the `-H` option.
180
173
 
181
- ### Is there a way to specify a column as the x-axis or y-axis?
174
+ ### Delimiter
182
175
 
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.
176
+ * `-d`
177
+ * You do not need to use `-d` option for tab-delimited text since the default value is tab.
178
+ * To specify a blank space, you can use `uplot bar -d ' ' data.txt`.
184
179
 
185
- ### How to plot real-time data?
180
+ ### Real-time data
186
181
 
187
- Experimental progressive mode is currently under development.
182
+ * `-p` `--progress`
183
+ * Experimental progressive mode is currently under development.
184
+ * `ruby -e 'loop{puts rand(100)}' | uplot line --progress`
188
185
 
189
- ```sh
190
- ruby -e 'loop{puts rand(100)}' | uplot line --progress
191
- ```
186
+ ### Show detailed options for subcommands
192
187
 
193
- ### How to view detailed command line options?
188
+ * `--help`
189
+ * The `--help` option will show more detailed options for each subcommand.
190
+ * `uplot hist --help`
194
191
 
195
- Use `--help` to print command-specific options.
192
+ ### Set columns as x-axis or y-axis
196
193
 
197
- `uplot hist --help`
194
+ * 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.
195
+ * 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.
198
196
 
199
- ```
200
- Usage: uplot histogram [options] <in.tsv>
197
+ * `--fmt`
198
+ * `--fmt xyy` `--fmt xyxy` `--fmt yx` options give you a few more choices. See `youplot <command> --help` for more details.
199
+ * The fmt option may be renamed in the future.
200
+ * The `-x` and `-y` options might be used to specify columns in the future.
201
201
 
202
- Options for histogram:
203
- --symbol VAL character to be used to plot the bars
204
- --closed VAL side of the intervals to be closed [left]
205
- -n, --nbins VAL approximate number of bins
202
+ * Use `awk '{print $2, $1}'` to swap columns. Use `paste` to concatenate series.
206
203
 
207
- Options:
208
- ...
209
- ```
204
+ ### Categorical data
210
205
 
211
- ### How to view the list of available colors?
206
+ * With GNU datamash, you can manage to handle categorized data.
207
+ * `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`
208
+ * This is not so easy...
212
209
 
213
- ```sh
214
- uplot colors
215
- ```
210
+ ### Time series
211
+
212
+ * Not yet supported.
213
+
214
+ ## Tools that are useful to use with YouPlot
215
+
216
+ * [csvtk](https://github.com/shenwei356/csvtk)
217
+ * [GNU datamash](https://www.gnu.org/software/datamash/)
218
+ * [awk](https://www.gnu.org/software/gawk/)
219
+ * [xsv](https://github.com/BurntSushi/xsv)
216
220
 
217
221
  ## Contributing
218
222
 
219
- YouPlot is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
223
+ YouPlot is a library under development, so even small improvements like typofix are welcome!
224
+ Please feel free to send us your pull requests.
220
225
 
221
- * [Report bugs](https://github.com/kojix2/youplot/issues)
222
- * Fix bugs and [submit pull requests](https://github.com/kojix2/youplot/pulls)
226
+ * [Report bugs](https://github.com/red-data-tools/YouPlot/issues)
227
+ * Fix bugs and [submit pull requests](https://github.com/red-data-tools/YouPlot/pulls)
223
228
  * Write, clarify, or fix documentation
224
229
  * English corrections by native speakers are welcome.
225
230
  * Suggest or add new features
226
-
231
+ * Make a donation
227
232
 
228
233
  ### Development
229
234
 
@@ -233,11 +238,11 @@ git clone https://github.com/your_name/YouPlot
233
238
  bundle install # Install the gem dependencies
234
239
  bundle exec rake test # Run the test
235
240
  bundle exec rake install # Installation from source code
241
+ bundle exec exe/uplot # Run youplot (Try out the edited code)
236
242
  ```
237
243
 
238
244
  ### Acknowledgements
239
245
 
240
- * [Red Data Tools](https://github.com/red-data-tools) - Technical support
241
246
  * [sampo grafiikka](https://jypg.net/sampo_grafiikka) - Project logo creation
242
247
  * [yutaas](https://github.com/yutaas) - English proofreading
243
248
 
@@ -6,18 +6,30 @@ module YouPlot
6
6
  module Processing
7
7
  module_function
8
8
 
9
- def count_values(arr, tally: true)
9
+ def count_values(arr, tally: true, reverse: false)
10
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 }
11
+ result = \
12
+ if tally && Enumerable.method_defined?(:tally)
13
+ arr.tally
14
+ else
15
+ # value_counts Enumerable::Statistics
16
+ arr.value_counts(dropna: false)
17
+ end
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 = a[0] <=> b[0] if r.zero?
25
+ r
17
26
  end
18
- .sort { |a, b| a[1] <=> b[1] }
19
- .reverse
20
- .transpose
27
+
28
+ # --reverse option
29
+ result.reverse! if reverse
30
+
31
+ # prepare for barplot
32
+ result.transpose
21
33
  end
22
34
  end
23
35
  end
@@ -1,22 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # UnicodePlot - Plot your data by Unicode characters
4
+ # https://github.com/red-data-tools/unicode_plot.rb
5
+
3
6
  require_relative 'processing'
4
7
  require 'unicode_plot'
5
8
 
9
+ # If the line color is specified as a number, the program will display an error
10
+ # message to the user and exit. Remove this patch when UnicodePlot is improved.
11
+
12
+ module UnicodePlot
13
+ class << self
14
+ alias lineplot_original lineplot
15
+ def lineplot(*args, **kw)
16
+ if kw[:color].is_a? Numeric
17
+ warn <<~EOS
18
+ YouPlot: Line colors cannot be specified by numerical values.
19
+
20
+ For more information, please see the following issue.
21
+ https://github.com/red-data-tools/unicode_plot.rb/issues/34
22
+ EOS
23
+ YouPlot.run_as_executable ? exit(1) : raise(Error)
24
+ end
25
+ lineplot_original(*args, **kw)
26
+ end
27
+ end
28
+ end
29
+
6
30
  module YouPlot
7
31
  # plotting functions.
8
32
  module Backends
9
- module UnicodePlotBackend
33
+ module UnicodePlot
10
34
  class Error < StandardError; end
11
35
 
12
36
  module_function
13
37
 
14
- def barplot(data, params, fmt = nil, count: false)
38
+ def barplot(data, params, fmt = nil, count: false, reverse: false)
15
39
  headers = data.headers
16
40
  series = data.series
17
41
  # `uplot count`
18
42
  if count
19
- series = Processing.count_values(series[0])
43
+ series = Processing.count_values(series[0], reverse: reverse)
20
44
  params.title = headers[0] if headers
21
45
  end
22
46
  if series.size == 1
@@ -39,7 +63,7 @@ module YouPlot
39
63
  labels = series[x_col]
40
64
  values = series[y_col].map(&:to_f)
41
65
  end
42
- UnicodePlot.barplot(labels, values, **params.to_hc)
66
+ ::UnicodePlot.barplot(labels, values, **params.to_hc)
43
67
  end
44
68
 
45
69
  def histogram(data, params)
@@ -47,7 +71,7 @@ module YouPlot
47
71
  series = data.series
48
72
  params.title ||= data.headers[0] if headers
49
73
  values = series[0].map(&:to_f)
50
- UnicodePlot.histogram(values, **params.to_hc)
74
+ ::UnicodePlot.histogram(values, **params.to_hc)
51
75
  end
52
76
 
53
77
  def line(data, params, fmt = nil)
@@ -57,7 +81,7 @@ module YouPlot
57
81
  # If there is only one series, it is assumed to be sequential data.
58
82
  params.ylabel ||= headers[0] if headers
59
83
  y = series[0].map(&:to_f)
60
- UnicodePlot.lineplot(y, **params.to_hc)
84
+ ::UnicodePlot.lineplot(y, **params.to_hc)
61
85
  else
62
86
  # If there are 2 or more series...
63
87
  if fmt == 'yx'
@@ -75,7 +99,7 @@ module YouPlot
75
99
  end
76
100
  x = series[x_col].map(&:to_f)
77
101
  y = series[y_col].map(&:to_f)
78
- UnicodePlot.lineplot(x, y, **params.to_hc)
102
+ ::UnicodePlot.lineplot(x, y, **params.to_hc)
79
103
  end
80
104
  end
81
105
 
@@ -94,27 +118,26 @@ module YouPlot
94
118
  end
95
119
  params.xlim ||= series[0].flatten.minmax # why need?
96
120
  params.ylim ||= series[1..-1].flatten.minmax # why need?
97
- plot = UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
121
+ plot = ::UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
98
122
  2.upto(series.size - 1) do |i|
99
- UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
123
+ ::UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
100
124
  end
101
125
  plot
102
126
  end
103
127
 
104
128
  def plot_xyxy(data, method1, params)
105
129
  headers = data.headers
106
- series = data.series
130
+ series2 = data.series
131
+ .map { |s| s.map(&:to_f) }
132
+ .each_slice(2).to_a
107
133
  method2 = get_method2(method1)
108
- series.map! { |s| s.map(&:to_f) }
109
- series2 = series.each_slice(2).to_a
110
- series = nil
111
134
  params.name ||= headers[0] if headers
112
135
  params.xlim ||= series2.map(&:first).flatten.minmax # why need?
113
136
  params.ylim ||= series2.map(&:last).flatten.minmax # why need?
114
137
  x1, y1 = series2.shift
115
- plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
138
+ plot = ::UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
116
139
  series2.each_with_index do |(xi, yi), i|
117
- UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
140
+ ::UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
118
141
  end
119
142
  plot
120
143
  end
@@ -152,13 +175,13 @@ module YouPlot
152
175
  series = data.series
153
176
  headers ||= (1..series.size).map(&:to_s)
154
177
  series.map! { |s| s.map(&:to_f) }
155
- UnicodePlot.boxplot(headers, series, **params.to_hc)
178
+ ::UnicodePlot.boxplot(headers, series, **params.to_hc)
156
179
  end
157
180
 
158
181
  def colors(color_names = false)
159
182
  # FIXME
160
183
  s = String.new
161
- UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
184
+ ::UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
162
185
  s << v
163
186
  s << k.to_s
164
187
  unless color_names
@@ -179,7 +202,7 @@ module YouPlot
179
202
  series = data.series
180
203
  if series.size == 1
181
204
  warn <<~EOS
182
- youplot: There is only one series of input data. Please check the delimiter.
205
+ YouPlot: There is only one series of input data. Please check the delimiter.
183
206
 
184
207
  Headers: \e[35m#{data.headers.inspect}\e[0m
185
208
  The first item is: \e[35m\"#{series[0][0]}\"\e[0m
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'dsv'
4
- require_relative 'command/parser'
4
+ require_relative 'parser'
5
5
 
6
6
  # FIXME
7
- require_relative 'backends/unicode_plot_backend'
7
+ require_relative 'backends/unicode_plot'
8
8
 
9
9
  module YouPlot
10
10
  Data = Struct.new(:headers, :series)
@@ -19,7 +19,7 @@ module YouPlot
19
19
  @command = nil
20
20
  @params = nil
21
21
  @options = nil
22
- @backend = YouPlot::Backends::UnicodePlotBackend
22
+ @backend = YouPlot::Backends::UnicodePlot
23
23
  end
24
24
 
25
25
  def run_as_executable
@@ -33,21 +33,34 @@ module YouPlot
33
33
  @options ||= parser.options
34
34
  @params ||= parser.params
35
35
 
36
+ # color command
36
37
  if %i[colors color colours colour].include? @command
37
38
  plot = create_plot
38
39
  output_plot(plot)
39
- elsif options[:progressive]
40
+ return
41
+ end
42
+
43
+ # progressive mode
44
+ if options[:progressive]
40
45
  stop = false
41
46
  Signal.trap(:INT) { stop = true }
42
- options[:output].print "\e[?25l" # make cursor invisible
47
+
48
+ # make cursor invisible
49
+ options[:output].print "\e[?25l"
50
+
51
+ # mainloop
43
52
  while (input = Kernel.gets)
44
53
  n = main_progressive(input)
45
54
  break if stop
46
55
 
47
56
  options[:output].print "\e[#{n}F"
48
57
  end
58
+
49
59
  options[:output].print "\e[0J"
50
- options[:output].print "\e[?25h" # make cursor visible
60
+ # make cursor visible
61
+ options[:output].print "\e[?25h"
62
+
63
+ # normal mode
51
64
  else
52
65
  # Sometimes the input file does not end with a newline code.
53
66
  while (input = Kernel.gets(nil))
@@ -59,23 +72,32 @@ module YouPlot
59
72
  private
60
73
 
61
74
  def main(input)
75
+ # Outputs input data to a file or stdout.
62
76
  output_data(input)
63
77
 
64
- @data = read_dsv(input)
78
+ @data = parse_dsv(input)
65
79
 
80
+ # Debug mode, show parsed results
66
81
  pp @data if options[:debug]
67
82
 
83
+ # When run as a program instead of a library
68
84
  if YouPlot.run_as_executable?
69
85
  begin
70
86
  plot = create_plot
71
87
  rescue ArgumentError => e
88
+ # Show only one line of error.
72
89
  warn e.backtrace[0]
90
+ # Show error message in purple
73
91
  warn "\e[35m#{e}\e[0m"
92
+ # Explicitly terminated with exit code: 1
74
93
  exit 1
75
94
  end
95
+
96
+ # When running YouPlot as a library (e.g. for testing)
76
97
  else
77
98
  plot = create_plot
78
99
  end
100
+
79
101
  output_plot(plot)
80
102
  end
81
103
 
@@ -95,15 +117,28 @@ module YouPlot
95
117
  @raw_data << input
96
118
 
97
119
  # FIXME
98
- @data = read_dsv(@raw_data)
120
+ @data = parse_dsv(@raw_data)
99
121
 
100
122
  plot = create_plot
101
123
  output_plot_progressive(plot)
102
124
  end
103
125
 
104
- def read_dsv(input)
105
- input = input.dup.force_encoding(options[:encoding]).encode('utf-8') if options[:encoding]
106
- DSV.parse(input, options[:delimiter], options[:headers], options[:transpose])
126
+ def parse_dsv(input)
127
+ # If encoding is specified, convert to UTF-8
128
+ if options[:encoding]
129
+ input.force_encoding(options[:encoding])
130
+ .encode!('utf-8')
131
+ end
132
+
133
+ begin
134
+ data = DSV.parse(input, options[:delimiter], options[:headers], options[:transpose])
135
+ rescue CSV::MalformedCSVError => e
136
+ warn 'Failed to parse the text. '
137
+ warn 'Please try to set the correct character encoding with --encoding option.'
138
+ raise e
139
+ end
140
+
141
+ data
107
142
  end
108
143
 
109
144
  def create_plot
@@ -111,7 +146,7 @@ module YouPlot
111
146
  when :bar, :barplot
112
147
  @backend.barplot(data, params, options[:fmt])
113
148
  when :count, :c
114
- @backend.barplot(data, params, count: true)
149
+ @backend.barplot(data, params, count: true, reverse: options[:reverse])
115
150
  when :hist, :histogram
116
151
  @backend.histogram(data, params)
117
152
  when :line, :lineplot
@@ -134,7 +169,7 @@ module YouPlot
134
169
  def output_data(input)
135
170
  # Pass the input to subsequent pipelines
136
171
  case options[:pass]
137
- when IO
172
+ when IO, StringIO
138
173
  options[:pass].print(input)
139
174
  else
140
175
  if options[:pass]
@@ -147,9 +182,9 @@ module YouPlot
147
182
 
148
183
  def output_plot(plot)
149
184
  case options[:output]
150
- when IO
185
+ when IO, StringIO
151
186
  plot.render(options[:output])
152
- else
187
+ when String, Tempfile
153
188
  File.open(options[:output], 'w') do |f|
154
189
  plot.render(f)
155
190
  end
@@ -158,7 +193,7 @@ module YouPlot
158
193
 
159
194
  def output_plot_progressive(plot)
160
195
  case options[:output]
161
- when IO
196
+ when IO, StringIO
162
197
  # RefactorMe
163
198
  out = StringIO.new(String.new)
164
199
  def out.tty?