nyaplot 0.1.6 → 0.2.0.rc1

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.
data/lib/nyaplot/core.rb CHANGED
@@ -2,10 +2,7 @@ require 'erb'
2
2
 
3
3
  module Nyaplot
4
4
 
5
- @@dep_libraries = {
6
- d3:'https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min',
7
- downloadable: 'http://cdn.rawgit.com/domitry/d3-downloadable/master/d3-downloadable'
8
- }
5
+ @@dep_libraries = {d3:'http://d3js.org/d3.v3.min'}
9
6
  @@additional_libraries = {}
10
7
  @@extension_lists = []
11
8
 
@@ -39,11 +36,54 @@ module Nyaplot
39
36
  js
40
37
  end
41
38
 
39
+ def self.start_debug(port=9996)
40
+ require 'webrick'
41
+ path = File.expand_path("../../../nyaplotjs/release", __FILE__)
42
+ `ruby -e httpd #{path} -p #{port}`
43
+
44
+ js = self.generate_init_code
45
+ js.gsub!("http.+nyaplot.js", "http://localhost:" + port.to_s + "/nyaplot.js")
46
+ IRuby.display(IRuby.javascript(js))
47
+ end
48
+
42
49
  # Enable to show plots on IRuby notebook
43
50
  def self.init_iruby
44
51
  js = self.generate_init_code
45
52
  IRuby.display(IRuby.javascript(js))
46
53
  end
47
54
 
48
- init_iruby if defined? IRuby
55
+ # Create multi-column layout
56
+ # @example
57
+ # include Nyaplot
58
+ # p1 = Plot.add(:scatter, x1, y1)
59
+ # p2 = Plot.add(:line, x2, y2)
60
+ # columns(p1, p2).draw
61
+ #
62
+ def columns(*plots)
63
+ panes = plots.map{|p| p.pane}
64
+ plot = Plot.new
65
+ plot.pane = Pane.columns(*panes)
66
+ plot
67
+ end
68
+
69
+ # Create multi-row layout
70
+ # @example
71
+ # include Nyaplot
72
+ # p1 = Plot.add(:scatter, x1, y1)
73
+ # p2 = Plot.add(:line, x2, y2)
74
+ # p3 = Plot.add(:bar, x3, y3)
75
+ # rows(columns(p1, p2), p3).draw
76
+ #
77
+ def rows(*plots)
78
+ panes = plots.map{|p| p.pane}
79
+ plot = Plot.new
80
+ plot.pane = Pane.rows(*panes)
81
+ plot
82
+ end
83
+
84
+ if $DEBUG_NYAPLOT == true
85
+ start_debug
86
+ else
87
+ init_iruby if defined? IRuby
88
+ end
49
89
  end
data/lib/nyaplot/data.rb CHANGED
@@ -4,229 +4,277 @@ require 'json'
4
4
  require 'csv'
5
5
 
6
6
  module Nyaplot
7
+ begin
8
+ require "mikon"
9
+ rescue
10
+ end
7
11
 
8
- # Ruby DataFrame for plotting
9
- class DataFrame
10
- DEFAULT_OPTS = {
11
- :col_sep => ',',
12
- :headers => true,
13
- :converters => :numeric,
14
- :header_converters => :symbol
15
- }
16
-
17
- attr_reader :rows
18
-
19
- def initialize(source, name=SecureRandom.uuid())
20
- @name = name
21
- @rows = []
22
- case
23
- when source.is_a?(Array)
24
- # like [{a:10, b:10},{a:20,b:20}]
25
- @rows = source
26
- when source.is_a?(Hash)
27
- # like {a:[10,20], b:[10, 20]}
28
- keys = source.keys
29
- len = source[keys[0]].length
30
- (0..len-1).each do |i|
31
- hash = {}
32
- keys.each{|key| hash[key] = source[key][i]}
33
- @rows.push(hash)
12
+ if defined? Mikon
13
+ class DataFrame
14
+ include Nyaplot::Base
15
+ type :data
16
+ required_args :data
17
+
18
+ def initialize(*args)
19
+ super()
20
+ if args.length == 1 && args.first.is_a?(Mikon::DataFrame)
21
+ @df = args.first
22
+ else
23
+ @df = Mikon::DataFrame.new(*args)
34
24
  end
25
+ data(@df)
35
26
  end
36
27
 
37
- # transform String to Symbol as a key
38
- unless @rows.all? {|row| row.keys.all? {|el| el.is_a?(Symbol)}}
39
- @rows.map! do |row|
40
- row.inject({}) do |hash, (key, val)|
41
- hash[key.to_sym]=val
42
- hash
28
+ def select!(*args, &block)
29
+ @df = @df.select(*args, &block)
30
+ data(@df)
31
+ self
32
+ end
33
+
34
+ def to_html
35
+ @df.to_html
36
+ end
37
+
38
+ def method_missing(name, *args, &block)
39
+ if @df.respond_to? name
40
+ ret = @df.send(name, *args, &block)
41
+ if ret.is_a?(Mikon::DataFrame)
42
+ self.class.new(ret)
43
+ else
44
+ ret
43
45
  end
46
+ else
47
+ super
44
48
  end
45
49
  end
46
50
  end
51
+ else
52
+ # Ruby DataFrame for plotting
53
+ class DataFrame
54
+ include Nyaplot::Base
55
+ type :data
56
+ required_args :data
57
+
58
+ DEFAULT_OPTS = {
59
+ :col_sep => ',',
60
+ :headers => true,
61
+ :converters => :numeric,
62
+ :header_converters => :symbol
63
+ }
64
+
65
+ attr_reader :rows
66
+
67
+ def initialize(source)
68
+ super()
69
+ @rows = []
70
+ case
71
+ when source.is_a?(Array)
72
+ # like [{a:10, b:10},{a:20,b:20}]
73
+ @rows = source
74
+ when source.is_a?(Hash)
75
+ # like {a:[10,20], b:[10, 20]}
76
+ keys = source.keys
77
+ len = source[keys[0]].length
78
+ (0..len-1).each do |i|
79
+ hash = {}
80
+ keys.each{|key| hash[key] = source[key][i]}
81
+ @rows.push(hash)
82
+ end
83
+ end
47
84
 
48
- def self.from_csv(*args)
49
- path = args.shift
50
-
51
- opts = DEFAULT_OPTS
52
- if args.size > 0 && args.first.is_a?(Hash)
53
- opts = opts.merge(args.shift)
54
- else
55
- opts[:col_sep] = args.shift if args.size > 0
56
- opts[:headers] = args.shift if args.size > 0
85
+ # transform String to Symbol as a key
86
+ unless @rows.all? {|row| row.keys.all? {|el| el.is_a?(Symbol)}}
87
+ @rows.map! do |row|
88
+ row.inject({}) do |hash, (key, val)|
89
+ hash[key.to_sym]=val
90
+ hash
91
+ end
92
+ end
93
+ end
57
94
  end
58
95
 
59
- csv = CSV.open(path, "r", opts)
60
- yield csv if block_given?
96
+ def self.from_csv(*args)
97
+ path = args.shift
61
98
 
62
- rows = []
63
- csv.each do |row|
64
- hash = {}
65
- row.each_with_index do |el,i|
66
- next if el[0].nil? && el[1].nil?
67
- hash[el[0].to_sym] = el[1]
99
+ opts = DEFAULT_OPTS
100
+ if args.size > 0 && args.first.is_a?(Hash)
101
+ opts = opts.merge(args.shift)
102
+ else
103
+ opts[:col_sep] = args.shift if args.size > 0
104
+ opts[:headers] = args.shift if args.size > 0
68
105
  end
69
- rows << hash
70
- end
71
- self.new(rows)
72
- end
73
106
 
74
- # Filtering row out using recieved block
75
- # @example
76
- # new_df = df.filter{|row| row[:a] %2 == 0}
77
- def filter(&block)
78
- DataFrame.new(@rows.select(&block))
79
- end
107
+ csv = CSV.open(path, "r", opts)
108
+ yield csv if block_given?
80
109
 
81
- # destructive version of DataFrame#filter
82
- def filter!(&block)
83
- @rows.select!(&block)
84
- end
110
+ rows = []
111
+ csv.each do |row|
112
+ hash = {}
113
+ row.each_with_index do |el,i|
114
+ next if el[0].nil? && el[1].nil?
115
+ hash[el[0].to_sym] = el[1]
116
+ end
117
+ rows << hash
118
+ end
119
+ self.new(rows)
120
+ end
85
121
 
86
- # @return [String] the name of dataframe. If not specified when initializing, uuid v4 will be set.
87
- def name
88
- @name
89
- end
122
+ # Filtering row out using recieved block
123
+ # @example
124
+ # new_df = df.filter{|row| row[:a] %2 == 0}
125
+ def filter(&block)
126
+ DataFrame.new(@rows.select(&block))
127
+ end
90
128
 
91
- def insert_column(name, arr)
92
- name = name.is_a?(Symbol) ? name : name.to_sym
93
- arr.each_with_index{|val, i| @rows[i][name]=val}
94
- end
129
+ # destructive version of DataFrame#filter
130
+ def filter!(&block)
131
+ @rows.select!(&block)
132
+ end
95
133
 
96
- def delete_column(name)
97
- name = name.is_a?(Symbol) ? name : name.to_sym
98
- @rows.each do |row|
99
- row.delete(name)
134
+ # @return [String] the name of dataframe. If not specified when initializing, uuid v4 will be set.
135
+ def name
136
+ @uuid
100
137
  end
101
- end
102
138
 
103
- # Access column using its label
104
- def column(name)
105
- id = name.is_a?(Symbol) ? name : name.to_sym
106
- column = @rows.map{|row| row[id]}
107
- return Series.new(name, column)
108
- end
139
+ def insert_column(name, arr)
140
+ name = name.is_a?(Symbol) ? name : name.to_sym
141
+ arr.each_with_index{|val, i| @rows[i][name]=val}
142
+ end
109
143
 
110
- # Insert row using index
111
- # @param [Hash] row row to insert
112
- # @param [Numeric] index if not specified, the row will be inserted to the end
113
- def insert_row(row, index=@rows.length)
114
- @rows.insert(index, row)
115
- end
144
+ def delete_column(name)
145
+ name = name.is_a?(Symbol) ? name : name.to_sym
146
+ @rows.each do |row|
147
+ row.delete(name)
148
+ end
149
+ end
116
150
 
117
- def row(index)
118
- @rows[index]
119
- end
151
+ # Access column using its label
152
+ def column(name)
153
+ id = name.is_a?(Symbol) ? name : name.to_sym
154
+ column = @rows.map{|row| row[id]}
155
+ return Series.new(name, column)
156
+ end
120
157
 
121
- def to_json(*args)
122
- @rows.to_json
123
- end
158
+ # Insert row using index
159
+ # @param [Hash] row row to insert
160
+ # @param [Numeric] index if not specified, the row will be inserted to the end
161
+ def insert_row(row, index=@rows.length)
162
+ @rows.insert(index, row)
163
+ end
124
164
 
125
- def each_column(&block)
126
- self.column_labels.each do |label|
127
- block.call(column(label).to_a)
165
+ def row(index)
166
+ @rows[index]
128
167
  end
129
- end
130
168
 
131
- def each_row(&block)
132
- @rows.each do |row|
133
- block.call(row)
169
+ def before_to_json
170
+ data(@rows)
134
171
  end
135
- end
136
172
 
137
- def to_html(threshold = 15)
138
- html = '<table>'
173
+ def each_column(&block)
174
+ self.column_labels.each do |label|
175
+ block.call(column(label).to_a)
176
+ end
177
+ end
139
178
 
140
- unless @rows[0].nil?
141
- html += '<tr>'
142
- @rows[0].each {|key, val| html.concat('<th>' + key.to_s + '</th>')}
143
- html += '</tr>'
179
+ def each_row(&block)
180
+ @rows.each do |row|
181
+ block.call(row)
182
+ end
144
183
  end
145
184
 
146
- @rows.each_with_index do |row, i|
147
- next if i > threshold && i < @rows.length-1
148
- html += '<tr>'
149
- row.each{|key, val| html.concat('<td>' + val.to_s + '</td>')}
150
- html += '</tr>'
151
- if i == threshold
185
+ def to_html(threshold = 15)
186
+ html = '<table>'
187
+
188
+ unless @rows[0].nil?
152
189
  html += '<tr>'
153
- row.length.times {html.concat('<td>...</td>')}
190
+ @rows[0].each {|key, val| html.concat('<th>' + key.to_s + '</th>')}
154
191
  html += '</tr>'
155
192
  end
193
+
194
+ @rows.each_with_index do |row, i|
195
+ next if i > threshold && i < @rows.length-1
196
+ html += '<tr>'
197
+ row.each{|key, val| html.concat('<td>' + val.to_s + '</td>')}
198
+ html += '</tr>'
199
+ if i == threshold
200
+ html += '<tr>'
201
+ row.length.times {html.concat('<td>...</td>')}
202
+ html += '</tr>'
203
+ end
204
+ end
205
+ html += '</table>'
156
206
  end
157
- html += '</table>'
158
- end
159
207
 
160
- def to_s
161
- to_html
162
- end
208
+ def to_s
209
+ to_html
210
+ end
163
211
 
164
- # The alias method for DataFrame#column
165
- def [](name)
166
- return self.column(name)
167
- end
212
+ # The alias method for DataFrame#column
213
+ def [](name)
214
+ return self.column(name)
215
+ end
168
216
 
169
- def column_labels
170
- @rows[0].keys
171
- end
217
+ def column_labels
218
+ @rows[0].keys
219
+ end
172
220
 
173
- def method_missing(name, *args, &block)
174
- if md = name.match(/(.+)\=/)
175
- self.insert_column(name[/(.+)\=/].delete("="), args[0])
176
- return
177
- elsif column_labels.include?(name)
178
- return self.column(name)
179
- else
180
- super(name, *args, &block)
221
+ def method_missing(name, *args, &block)
222
+ if md = name.match(/(.+)\=/)
223
+ self.insert_column(name[/(.+)\=/].delete("="), args[0])
224
+ return
225
+ elsif column_labels.include?(name)
226
+ return self.column(name)
227
+ else
228
+ super(name, *args, &block)
229
+ end
181
230
  end
182
231
  end
183
- end
184
232
 
185
- class Series
186
- include Enumerable
187
- def each(&block)
188
- @arr.each(&block)
189
- end
233
+ class Series
234
+ include Enumerable
235
+ def each(&block)
236
+ @arr.each(&block)
237
+ end
190
238
 
191
- def initialize(label, arr)
192
- @arr = arr
193
- @label = label
194
- end
239
+ def initialize(label, arr)
240
+ @arr = arr
241
+ @label = label
242
+ end
195
243
 
196
- def to_html(threshold=15)
197
- html = '<table><tr><th>' + label.to_s + '</th></tr>>'
198
- @arr.each_with_index do |el,i|
199
- next if threshold < i && i < @arr.length-1
200
- content = i == threshold ? '...' : el.to_s
201
- html.concat('<tr><td>' + content + '</td></tr>')
244
+ def to_html(threshold=15)
245
+ html = '<table><tr><th>' + label.to_s + '</th></tr>>'
246
+ @arr.each_with_index do |el,i|
247
+ next if threshold < i && i < @arr.length-1
248
+ content = i == threshold ? '...' : el.to_s
249
+ html.concat('<tr><td>' + content + '</td></tr>')
250
+ end
251
+ html += '</table>'
202
252
  end
203
- html += '</table>'
204
- end
205
253
 
206
- def to_json(*args)
207
- @arr.to_json
208
- end
254
+ def to_json(*args)
255
+ @arr.to_json
256
+ end
209
257
 
210
- def to_a
211
- @arr
212
- end
258
+ def to_a
259
+ @arr
260
+ end
213
261
 
214
- def label
215
- @label
216
- end
262
+ def label
263
+ @label
264
+ end
217
265
 
218
- def method_missing(meth, *args, &block)
219
- if @arr.respond_to?(meth)
220
- @arr.send(meth, *args, &block)
221
- else
222
- super(meth, *args, &block)
266
+ def method_missing(meth, *args, &block)
267
+ if @arr.respond_to?(meth)
268
+ @arr.send(meth, *args, &block)
269
+ else
270
+ super(meth, *args, &block)
271
+ end
223
272
  end
224
- end
225
273
 
226
- def respond_to?(meth)
227
- return true if @arr.respond_to?(meth)
228
- super(meth)
274
+ def respond_to?(meth)
275
+ return true if @arr.respond_to?(meth)
276
+ super(meth)
277
+ end
229
278
  end
230
-
231
279
  end
232
280
  end