youplot 0.3.5 → 0.4.3

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: 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?