nyaplot 0.1.6 → 0.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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