youplot 0.3.2 → 0.4.1

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: ff7e21952a560421314ae80fc894a8c1321d27ad985f50d2cdc53f8b3306a5ba
4
- data.tar.gz: 5229cb0a38b73477ab91570dd0d04bf646c66d511fb6d5c8a12c09d64a08d1cf
3
+ metadata.gz: 6db41d30d7f51a3209bd6c17e805c7dd6bcaf68db325ffb2d23b95850837d8d4
4
+ data.tar.gz: 1580e5501a9b635cc871c9d572549e4d33cc46e265ffe7befcd0a9d51285673a
5
5
  SHA512:
6
- metadata.gz: d8d28d4118af6be5d7b115a3341e2bc066821718d0367286c2dbb2d49f364ac241af1d75f8c0466f91761e7a1c1ccdab4693010f41389c2703a25a3b9b83c8a2
7
- data.tar.gz: ccc0b88ff329b9f002cb089f07ddfd9e3be8eed1a63a6c609df018efb1b25f3a92ff640ae22413e3271d051799cc009a090d8af1662b408282941e190da7f75b
6
+ metadata.gz: 4a60bbfd3edf64151c20a23bb3e13b7f528e7a313030d8e1134bb5cac7918aff2cc604fca301c2a86c3f8e8a8a6b411bb0e28fbb15b179ff4528559ded890cc7
7
+ data.tar.gz: b76603426970dc8d7c019bb394374d9c1e851a216a0d6607f5adcd9532649a25a6fd56113bce037d92a3eb66fdcab533f58391d8db93aa5091020c15c0043b16
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
- ![Logo](https://user-images.githubusercontent.com/5798442/102004318-ec89d280-3d52-11eb-8608-d890b42593f1.png)
1
+ <p align="center">
2
+ <img src="logo.svg" width="60%" height="60%" />
3
+ </p>
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)
7
9
  [![DOI](https://zenodo.org/badge/283230219.svg)](https://zenodo.org/badge/latestdoi/283230219)
8
10
 
@@ -18,7 +20,8 @@ gem install youplot
18
20
 
19
21
  ## Quick Start
20
22
 
21
- `cat data.tsv | uplot <command> [options]`
23
+ * `cat data.tsv | uplot <command> [options]` or
24
+ * `uplot <command> [options] <data.tsv>`
22
25
 
23
26
  ### barplot
24
27
 
@@ -29,7 +32,9 @@ curl -sL https://git.io/ISLANDScsv \
29
32
  | uplot bar -d, -t "Areas of the World's Major Landmasses"
30
33
  ```
31
34
 
32
- ![barplot](https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png)
35
+ <p align="center">
36
+ <img alt="barplot" src="https://user-images.githubusercontent.com/5798442/101999903-d36a2d00-3d24-11eb-9361-b89116f44122.png">
37
+ </p>
33
38
 
34
39
  ### histogram
35
40
 
@@ -40,7 +45,10 @@ echo -e "from numpy import random;" \
40
45
  | python \
41
46
  | uplot hist --nbins 20
42
47
  ```
43
- ![histogram](https://user-images.githubusercontent.com/5798442/101999820-21cafc00-3d24-11eb-86db-e410d19b07df.png)
48
+
49
+ <p align="center">
50
+ <img alt="histogram" src="https://user-images.githubusercontent.com/5798442/101999820-21cafc00-3d24-11eb-86db-e410d19b07df.png">
51
+ </p>
44
52
 
45
53
  ### lineplot
46
54
 
@@ -50,7 +58,9 @@ curl -sL https://git.io/AirPassengers \
50
58
  | uplot line -d, -w 50 -h 15 -t AirPassengers --xlim 1950,1960 --ylim 0,600
51
59
  ```
52
60
 
53
- ![lineplot](https://user-images.githubusercontent.com/5798442/101999825-24c5ec80-3d24-11eb-99f4-c642e8d221bc.png)
61
+ <p align="center">
62
+ <img alt="lineplot" src="https://user-images.githubusercontent.com/5798442/101999825-24c5ec80-3d24-11eb-99f4-c642e8d221bc.png">
63
+ </p>
54
64
 
55
65
  ### scatter
56
66
 
@@ -60,7 +70,9 @@ curl -sL https://git.io/IRIStsv \
60
70
  | uplot scatter -H -t IRIS
61
71
  ```
62
72
 
63
- ![scatter](https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png)
73
+ <p align="center">
74
+ <img alt="scatter" src="https://user-images.githubusercontent.com/5798442/101999827-27284680-3d24-11eb-9903-551857eaa69c.png">
75
+ </p>
64
76
 
65
77
  ### density
66
78
 
@@ -70,7 +82,9 @@ curl -sL https://git.io/IRIStsv \
70
82
  | uplot density -H -t IRIS
71
83
  ```
72
84
 
73
- ![density](https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png)
85
+ <p align="center">
86
+ <img alt="density" src="https://user-images.githubusercontent.com/5798442/101999828-2abbcd80-3d24-11eb-902c-2f44266fa6ae.png">
87
+ </p>
74
88
 
75
89
  ### boxplot
76
90
 
@@ -80,28 +94,32 @@ curl -sL https://git.io/IRIStsv \
80
94
  | uplot boxplot -H -t IRIS
81
95
  ```
82
96
 
83
- ![boxplot](https://user-images.githubusercontent.com/5798442/101999830-2e4f5480-3d24-11eb-8891-728c18bf5b35.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>
84
100
 
85
101
  ### count
86
102
 
87
- In this example, YouPlot counts the number of chromosomes where the gene is located from the human gene annotation file and create a bar chart. The human gene annotation file can be downloaded from the following website.
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.
88
104
 
89
105
  * https://www.gencodegenes.org/human/
90
106
 
91
107
  ```sh
92
108
  cat gencode.v35.annotation.gff3 \
93
- | grep -v '#' | grep 'gene' | cut -f1 | \
94
- uplot count -t "The number of human gene annotations per chromosome" -c blue
109
+ | grep -v '#' | grep 'gene' | cut -f1 \
110
+ | uplot count -t "The number of human gene annotations per chromosome" -c blue
95
111
  ```
96
112
 
97
- ![count](https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png)
113
+ <p align="center">
114
+ <img alt="count" src="https://user-images.githubusercontent.com/5798442/101999832-30b1ae80-3d24-11eb-96fe-e5000bed1f5c.png">
115
+ </p>
98
116
 
99
117
  Note: `count` is not very fast because it runs in a Ruby script.
100
- This is fine if the data is small, that is, in most cases. However, if you want to visualize huge data, it is faster to use a combination of common Unix commands as shown below.
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.
101
119
 
102
120
  ```sh
103
121
  cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
104
- |sort | uniq -c | sort -nrk2 | awk '{print $2,$1}' \
122
+ | sort | uniq -c | sort -nrk2 | awk '{print $2,$1}' \
105
123
  | uplot bar -d ' ' -t "The number of human gene annotations per chromosome" -c blue
106
124
  ```
107
125
 
@@ -109,32 +127,33 @@ cat gencode.v35.annotation.gff3 | grep -v '#' | grep 'gene' | cut -f1 \
109
127
 
110
128
  ### Why YouPlot?
111
129
 
112
- Wouldn't it be a bit of pain to have to run R, Python, Julia, gnuplot or whatever REPL just to check your data?
113
- YouPlot is a command line tool for this purpose. With YouPlot, you can continue working without leaving your terminal and shell.
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.
114
132
 
115
- ### how to use YouPlot?
133
+ ### How to use YouPlot?
116
134
 
117
135
  `uplot` is the shortened form of `youplot`. You can use either.
118
136
 
119
- | | |
120
- |-----------------------------------|------------------------------------------------|
121
- | Reads data from standard input | `cat data.tsv \| uplot <command> [options]` |
122
- | Reads data from files | `uplot <command> [options] data.tsv ...` |
123
- | Outputs data from stdin to stdout | `pipeline1 \| uplot <command> -O \| pipeline2` |
137
+ | Command | Description |
138
+ |------------------------------------------------|-----------------------------------|
139
+ | `cat data.tsv \| uplot <command> [options]` | Take input from stdin |
140
+ | `uplot <command> [options] data.tsv ...` | Take input from files |
141
+ | `pipeline1 \| uplot <command> -O \| pipeline2` | Outputs data from stdin to stdout |
124
142
 
125
143
  ### Where to output the plot?
126
144
 
127
- By default, the plot is output to *standard error output*.
145
+ By default, the plot is output to *standard error output*.
128
146
  The output file or stream for the plot can be specified with the `-o` option.
129
147
 
130
148
  ### Where to output the input data?
131
149
 
132
- By default, the input data is not output anywhere.
133
- 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.
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.
152
+ This is useful when passing data to a subsequent pipeline.
134
153
 
135
154
  ### What types of plots are available?
136
155
 
137
- The following sub-commands are available
156
+ The following sub-commands are available.
138
157
 
139
158
  | command | short | how it works |
140
159
  |-----------|-------|----------------------------------------|
@@ -150,9 +169,39 @@ See Quick Start for `count`.
150
169
 
151
170
  | command | short | how it works |
152
171
  |-----------|-------|----------------------------------------------------------|
153
- | count | c | draw a baplot based on the number of occurrences (slow) |
172
+ | count | c | draw a barplot based on the number of occurrences (slow) |
173
+
174
+ ### What if the header line is included?
175
+
176
+ If your input data contains a header line, you need to specify the `-H` option.
177
+
178
+ ### How to specify the delimiter?
179
+
180
+ Use the `-d` option. To specify a blank space, you can use `uplot bar -d ' ' data.txt`.
181
+ You do not need to use `-d` option for tab-delimited text since the default value is tab.
182
+
183
+ ### Is there a way to specify a column as the x-axis or y-axis?
184
+
185
+ Not yet.
186
+ YouPlot treats the first column as the X axis and the second column as the Y axis.
187
+ 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.
188
+ 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.
189
+
190
+ * `--fmt xyy` `--fmt xyxy` `--fmt yx` options give you a few more choices.
191
+ See `youplot <command> --help` for more details.
192
+
193
+ * Use `awk '{print $2, $1}'` to swap lines.
194
+ * Use `paste` to concatenate series.
154
195
 
155
- ### How to view detailed command line options
196
+ ### How to plot real-time data?
197
+
198
+ Experimental progressive mode is currently under development.
199
+
200
+ ```sh
201
+ ruby -e 'loop{puts rand(100)}' | uplot line --progress
202
+ ```
203
+
204
+ ### How to view detailed command line options?
156
205
 
157
206
  Use `--help` to print command-specific options.
158
207
 
@@ -163,7 +212,7 @@ Usage: uplot histogram [options] <in.tsv>
163
212
 
164
213
  Options for histogram:
165
214
  --symbol VAL character to be used to plot the bars
166
- --closed VAL
215
+ --closed VAL side of the intervals to be closed [left]
167
216
  -n, --nbins VAL approximate number of bins
168
217
 
169
218
  Options:
@@ -178,22 +227,32 @@ uplot colors
178
227
 
179
228
  ## Contributing
180
229
 
230
+ YouPlot is a library under development, so even small improvements like typofix are welcome!
231
+ Please feel free to send us your pull requests.
232
+
181
233
  * [Report bugs](https://github.com/kojix2/youplot/issues)
182
234
  * Fix bugs and [submit pull requests](https://github.com/kojix2/youplot/pulls)
183
235
  * Write, clarify, or fix documentation
236
+ * English corrections by native speakers are welcome.
184
237
  * Suggest or add new features
185
-
238
+ * Make a donation
186
239
 
187
240
  ### Development
188
241
 
189
242
  ```sh
190
- git clone https://github.com/your_name/GR.rb # Clone the Git repo
191
- cd GR.rb
243
+ # fork the main repository by clicking the Fork button.
244
+ git clone https://github.com/your_name/YouPlot
192
245
  bundle install # Install the gem dependencies
193
246
  bundle exec rake test # Run the test
194
247
  bundle exec rake install # Installation from source code
195
248
  ```
196
249
 
250
+ ### Acknowledgements
251
+
252
+ * [Red Data Tools](https://github.com/red-data-tools) - Technical support
253
+ * [sampo grafiikka](https://jypg.net/sampo_grafiikka) - Project logo creation
254
+ * [yutaas](https://github.com/yutaas) - English proofreading
255
+
197
256
  ## License
198
257
 
199
258
  [MIT License](https://opensource.org/licenses/MIT).
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
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'unicode_plot'
4
- require 'youplot/version'
5
- require 'youplot/dsv_reader'
6
- require 'youplot/command'
3
+ require_relative 'youplot/version'
4
+ require_relative 'youplot/dsv'
5
+ require_relative 'youplot/parameters'
6
+ require_relative '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
@@ -6,18 +6,30 @@ module YouPlot
6
6
  module Processing
7
7
  module_function
8
8
 
9
- def count_values(arr)
9
+ def count_values(arr, tally: true, reverse: false)
10
10
  # tally was added in Ruby 2.7
11
- if 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,20 +1,25 @@
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
 
6
9
  module YouPlot
7
10
  # plotting functions.
8
11
  module Backends
9
- module UnicodePlotBackend
12
+ module UnicodePlot
13
+ class Error < StandardError; end
14
+
10
15
  module_function
11
16
 
12
- def barplot(data, params, fmt = nil, count: false)
17
+ def barplot(data, params, fmt = nil, count: false, reverse: false)
13
18
  headers = data.headers
14
19
  series = data.series
15
20
  # `uplot count`
16
21
  if count
17
- series = Processing.count_values(series[0])
22
+ series = Processing.count_values(series[0], reverse: reverse)
18
23
  params.title = headers[0] if headers
19
24
  end
20
25
  if series.size == 1
@@ -37,7 +42,7 @@ module YouPlot
37
42
  labels = series[x_col]
38
43
  values = series[y_col].map(&:to_f)
39
44
  end
40
- UnicodePlot.barplot(labels, values, **params.to_hc)
45
+ ::UnicodePlot.barplot(labels, values, **params.to_hc)
41
46
  end
42
47
 
43
48
  def histogram(data, params)
@@ -45,7 +50,7 @@ module YouPlot
45
50
  series = data.series
46
51
  params.title ||= data.headers[0] if headers
47
52
  values = series[0].map(&:to_f)
48
- UnicodePlot.histogram(values, **params.to_hc)
53
+ ::UnicodePlot.histogram(values, **params.to_hc)
49
54
  end
50
55
 
51
56
  def line(data, params, fmt = nil)
@@ -55,7 +60,7 @@ module YouPlot
55
60
  # If there is only one series, it is assumed to be sequential data.
56
61
  params.ylabel ||= headers[0] if headers
57
62
  y = series[0].map(&:to_f)
58
- UnicodePlot.lineplot(y, **params.to_hc)
63
+ ::UnicodePlot.lineplot(y, **params.to_hc)
59
64
  else
60
65
  # If there are 2 or more series...
61
66
  if fmt == 'yx'
@@ -73,7 +78,7 @@ module YouPlot
73
78
  end
74
79
  x = series[x_col].map(&:to_f)
75
80
  y = series[y_col].map(&:to_f)
76
- UnicodePlot.lineplot(x, y, **params.to_hc)
81
+ ::UnicodePlot.lineplot(x, y, **params.to_hc)
77
82
  end
78
83
  end
79
84
 
@@ -90,10 +95,11 @@ module YouPlot
90
95
  params.name ||= headers[1]
91
96
  params.xlabel ||= headers[0]
92
97
  end
98
+ params.xlim ||= series[0].flatten.minmax # why need?
93
99
  params.ylim ||= series[1..-1].flatten.minmax # why need?
94
- plot = UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
100
+ plot = ::UnicodePlot.public_send(method1, series[0], series[1], **params.to_hc)
95
101
  2.upto(series.size - 1) do |i|
96
- UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
102
+ ::UnicodePlot.public_send(method2, plot, series[0], series[i], name: headers&.[](i))
97
103
  end
98
104
  plot
99
105
  end
@@ -103,14 +109,15 @@ module YouPlot
103
109
  series = data.series
104
110
  method2 = get_method2(method1)
105
111
  series.map! { |s| s.map(&:to_f) }
106
- series = series.each_slice(2).to_a
112
+ series2 = series.each_slice(2).to_a
113
+ series = nil
107
114
  params.name ||= headers[0] if headers
108
- params.xlim = series.map(&:first).flatten.minmax # why need?
109
- params.ylim = series.map(&:last).flatten.minmax # why need?
110
- x1, y1 = series.shift
111
- plot = UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
112
- series.each_with_index do |(xi, yi), i|
113
- UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
115
+ params.xlim ||= series2.map(&:first).flatten.minmax # why need?
116
+ params.ylim ||= series2.map(&:last).flatten.minmax # why need?
117
+ x1, y1 = series2.shift
118
+ plot = ::UnicodePlot.public_send(method1, x1, y1, **params.to_hc)
119
+ series2.each_with_index do |(xi, yi), i|
120
+ ::UnicodePlot.public_send(method2, plot, xi, yi, name: headers&.[]((i + 1) * 2))
114
121
  end
115
122
  plot
116
123
  end
@@ -148,13 +155,13 @@ module YouPlot
148
155
  series = data.series
149
156
  headers ||= (1..series.size).map(&:to_s)
150
157
  series.map! { |s| s.map(&:to_f) }
151
- UnicodePlot.boxplot(headers, series, **params.to_hc)
158
+ ::UnicodePlot.boxplot(headers, series, **params.to_hc)
152
159
  end
153
160
 
154
161
  def colors(color_names = false)
155
162
  # FIXME
156
163
  s = String.new
157
- UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
164
+ ::UnicodePlot::StyledPrinter::TEXT_COLORS.each do |k, v|
158
165
  s << v
159
166
  s << k.to_s
160
167
  unless color_names
@@ -174,19 +181,25 @@ module YouPlot
174
181
  def check_series_size(data, fmt)
175
182
  series = data.series
176
183
  if series.size == 1
177
- warn 'youplot: There is only one series of input data. Please check the delimiter.'
178
- warn ''
179
- warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
180
- warn " The first item is: \e[35m\"#{series[0][0]}\"\e[0m"
181
- warn " The last item is : \e[35m\"#{series[0][-1]}\"\e[0m"
182
- exit 1
184
+ warn <<~EOS
185
+ youplot: There is only one series of input data. Please check the delimiter.
186
+
187
+ Headers: \e[35m#{data.headers.inspect}\e[0m
188
+ The first item is: \e[35m\"#{series[0][0]}\"\e[0m
189
+ The last item is : \e[35m\"#{series[0][-1]}\"\e[0m
190
+ EOS
191
+ # NOTE: Error messages cannot be colored.
192
+ YouPlot.run_as_executable ? exit(1) : raise(Error)
183
193
  end
184
194
  if fmt == 'xyxy' && series.size.odd?
185
- warn 'YouPlot: In the xyxy format, the number of series must be even.'
186
- warn ''
187
- warn " Number of series: \e[35m#{series.size}\e[0m"
188
- warn " Headers: \e[35m#{data.headers.inspect}\e[0m"
189
- exit 1
195
+ warn <<~EOS
196
+ YouPlot: In the xyxy format, the number of series must be even.
197
+
198
+ Number of series: \e[35m#{series.size}\e[0m
199
+ Headers: \e[35m#{data.headers.inspect}\e[0m
200
+ EOS
201
+ # NOTE: Error messages cannot be colored.
202
+ YouPlot.run_as_executable ? exit(1) : raise(Error)
190
203
  end
191
204
  end
192
205
  end