geoptima 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -11,7 +11,7 @@ For more information on Geoptima refer to:
11
11
 
12
12
  The current version includes the core geoptima.rb library as well as a few command-line apps for using the library. We have not yet documented the library, but some of the command-line scripts are described below.
13
13
 
14
- == show_geoptima
14
+ ==== show_geoptima
15
15
 
16
16
  This script imports the JSON files on the command-line and then:
17
17
  * Prints out basic information about each file (subscriber information, start date and number of events)
@@ -38,15 +38,15 @@ Which event types to include and various other options are available using the c
38
38
 
39
39
  Currently the script also locates events that are close enough in time to GPS events. We hope to improve this with interpolation in the near future to be more compatible with the results from the commercial solutions. This time-window is also used for some of the extended header information, like LAC and CI, and effectively duplicates those fields from their own events to others. Take this into account when doing statistics on the results. It is better to use the original values, not the duplicates, if you want reliable statistics.
40
40
 
41
- == csv_stats
41
+ ==== csv_stats
42
42
 
43
43
  This script reads any CSV file and outputs histograms of the values for each column. These can be manually imported into a spreadsheet or charting program for further analysis or charting.
44
44
 
45
- == csv_charts
45
+ ==== csv_charts
46
46
 
47
47
  This script also performs statistics on CSV files but is much more powerful, including automatic output of charts based on columns of data, as well as a configurable system for adding new columns by modifying or merging other columns, as designing specific charts for output.
48
48
 
49
- Usage: csv_chart <-dhamt> <-S specfile> <-N name> <-D dir> <-T range> <-P diversity> files...
49
+ Usage: csv_chart <-dhamt> <-S specfile> <-N name> <-D dir> <-T range> <-P diversity> files...
50
50
  -d debug mode
51
51
  -h print this help (true)
52
52
  -a automatically create charts for all properties (true)
@@ -109,6 +109,14 @@ This example uses some fancy Ruby code to replace cryptic HTTP URL codes with no
109
109
 
110
110
  This one copies the 'runningApp.appName' column to the 'Apps' column, but only if the 'runningApps.state' column is set to 'STARTED'.
111
111
 
112
+ === Charts
113
+
114
+ The charts described above can also be seen as examples in the Gallery wiki page at https://github.com/craigtaverner/geoptima.rb/wiki/Gallery.
115
+
116
+ One example included here is a distribution of call status over time.
117
+
118
+ https://github.com/craigtaverner/geoptima.rb/blob/master/images/Chart_All_Call%20Status_category_distribution.png?raw=true
119
+
112
120
  === Installation
113
121
 
114
122
  Two options:
@@ -125,6 +133,12 @@ This should produce a file called 357841036600753.csv containing a CSV version o
125
133
 
126
134
  The examples directory also contains a number of sample *.spec files for the csv_chart command.
127
135
 
136
+ ==== Installing on Windows
137
+
138
+ For windows use the RubyInstaller at http://rubyinstaller.org/
139
+
140
+ To get chart support working you will probably need to install the DevKit as described on https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
141
+
128
142
  === Contributing
129
143
 
130
144
  Have you found a bug, need help or have a patch ?
data/bin/csv_chart CHANGED
@@ -10,11 +10,12 @@ require 'geoptima/options'
10
10
  require 'fileutils'
11
11
  require 'geoptima/daterange'
12
12
 
13
- Geoptima::assert_version("0.1.1")
13
+ Geoptima::assert_version("0.1.2")
14
14
  Geoptima::Chart.available? || puts("No charting libraries available") || exit(-1)
15
15
 
16
16
  $export_dir = '.'
17
17
  $diversity = 40.0
18
+ $chart_width = 1024
18
19
 
19
20
  $files = Geoptima::Options.process_args do |option|
20
21
  option.m {$merge_all = true}
@@ -24,15 +25,15 @@ $files = Geoptima::Options.process_args do |option|
24
25
  option.N {$merged_name = ARGV.shift}
25
26
  option.S {$specfile = ARGV.shift}
26
27
  option.P {$diversity = ARGV.shift.to_f}
28
+ option.W {$chart_width = ARGV.shift.to_i}
27
29
  option.T do
28
- $time_range = Geoptima::DateRange.new(*(ARGV.shift.split(/[\,]+/).map do |t|
29
- DateTime.parse t
30
- end))
30
+ $time_range = Geoptima::DateRange.from ARGV.shift
31
31
  end
32
32
  end
33
33
 
34
34
  FileUtils.mkdir_p $export_dir
35
35
 
36
+ $chart_width=100 if($chart_width.to_i < 100)
36
37
  $create_all = true unless($specfile)
37
38
  $merge_all = true if($time_split)
38
39
  $help = true unless($files.length>0)
@@ -49,6 +50,7 @@ Usage: csv_chart <-dhamt> <-S specfile> <-N name> <-D dir> <-T range> <-P divers
49
50
  -S use chart specification in specified file: #{$specfile}
50
51
  -P diversity threshold in percentage for automatic reports: #{$diversity}
51
52
  -T set time-range filter: #{$time_range}
53
+ -W set default chart-width: #{$chart_width}
52
54
  Files to import: #{$files.join(', ')}
53
55
  EOHELP
54
56
  exit
@@ -63,8 +65,7 @@ class Stats
63
65
  @numerical = true
64
66
  end
65
67
  def add(field)
66
- puts "\tAdding field '#{field}' for property #{name}" if($debug)
67
- if field && field =~ /\w/
68
+ unless field.nil? || field == ''
68
69
  @numerical &&= is_number?(field)
69
70
  stats[field] ||= 0
70
71
  stats[field] += 1
@@ -129,12 +130,12 @@ class StatsManager
129
130
  end
130
131
  def add_all(fields,headers)
131
132
  fields.each_with_index do |field,index|
132
- add(field,headers[index])
133
+ add(field,headers[index],index)
133
134
  end
134
135
  $specs && $specs.add_fields(self,fields)
135
136
  end
136
- def add(field,header)
137
- puts "\tAdding field '#{field}' for property #{header}" if($debug)
137
+ def add(field,header,index)
138
+ puts "\tAdding field[#{index}] '#{field}' for property #{header}" if($debug)
138
139
  add_header(header) unless(@stats[header])
139
140
  @stats[header].add(field)
140
141
  end
@@ -148,10 +149,11 @@ end
148
149
 
149
150
  module Geoptima
150
151
  class StatSpec
151
- attr_reader :header, :index, :indices, :fields, :options, :proc, :groups
152
+ attr_reader :header, :event, :index, :indices, :fields, :options, :proc, :groups
152
153
  def initialize(header,*fields,&block)
153
154
  @header = header
154
155
  @fields = fields
156
+ @event = @fields[0].split(/\./)[0]
155
157
  @proc = block
156
158
  @groups = {}
157
159
  if @fields[-1].is_a?(Hash)
@@ -182,20 +184,42 @@ module Geoptima
182
184
  key = @group.call(time)
183
185
  ghead = "#{header} #{key}"
184
186
  @groups[key] = ghead
185
- stats_manager.add(map(fields),ghead)
187
+ stats_manager.add(map(fields),ghead,nil)
186
188
  end
187
189
  rescue ArgumentError
188
190
  puts "Error: Unable to process time field[#{time}]: #{$!}"
189
191
  end
190
192
  end
191
- stats_manager.add(map(fields),header)
193
+ stats_manager.add(map(fields),header,index)
192
194
  end
193
- def mk_range(val)
194
- if val =~ /\w/
195
- div = options[:div].to_i
196
- div = 1 if(div<1)
195
+ def div
196
+ unless @div
197
+ @div = options[:div].to_i
198
+ @div = 1 if(@div<1)
199
+ end
200
+ @div
201
+ end
202
+ def cats
203
+ @cats ||= (options[:categories] || []).map{|c| c.to_i}
204
+ end
205
+ def mk_div_range(val)
206
+ unless val.nil? || val == ''
197
207
  min = val.to_i/div * div
198
- "#{min}..#{min+div}"
208
+ (div == 1) ? min : "#{min}..#{min+div}"
209
+ else
210
+ val
211
+ end
212
+ end
213
+ def mk_cat_range(val)
214
+ if val.to_s =~ /\w/
215
+ val = val.to_i
216
+ puts "\t\tSearching for value[#{val}] in categories #{cats.inspect}" if($debug)
217
+ min = cats[0]
218
+ cats.each do |c|
219
+ max = c
220
+ return "#{min}..#{max}" if(min<=val && max>val)
221
+ min = c
222
+ end
199
223
  else
200
224
  val
201
225
  end
@@ -204,12 +228,22 @@ module Geoptima
204
228
  if @indices
205
229
  puts "StatSpec[#{self}]: #{options.inspect}" if($debug)
206
230
  vals = @indices.map{|i| values[i]}
231
+ puts "\tVALUES: #{vals.inspect}" if($debug)
232
+ (options[:filter] || {}).each do |field,expected|
233
+ puts "\t\tChecking if field #{field} is #{expected}" if($debug)
234
+ puts "\t\tLooking for #{field} or #{event}.#{field} in #{@fields.inspect}" if($debug)
235
+ hi = @fields.index(field.to_s) || @fields.index("#{event}.#{field}")
236
+ puts "\t\t#{field} -> #{hi} -> #{hi && vals[hi]}" if($debug)
237
+ return nil unless(hi && vals[hi] && (expected === vals[hi].downcase || vals[hi].downcase === expected.to_s.downcase))
238
+ end
239
+ val = proc.nil? ? vals[0] : proc.call(*vals)
240
+ puts "\tBLOCK MAP: #{vals.inspect} --> #{val.inspect}" if($debug)
207
241
  if options[:div]
208
- vals.map!{|v| mk_range(v)}
242
+ val = mk_div_range(val)
243
+ elsif options[:categories]
244
+ val = mk_cat_range(val)
209
245
  end
210
- puts "StatSpec[#{self}]: #{vals.inspect}" if($debug)
211
- val = proc && proc.call(*vals) || vals[0]
212
- puts "StatSpec[#{self}]: #{vals.inspect} --> #{val.inspect}" if($debug)
246
+ puts "\tDIV/CAT MAP: #{vals.inspect} --> #{val.inspect}" if($debug)
213
247
  val
214
248
  end
215
249
  end
@@ -260,15 +294,19 @@ module Geoptima
260
294
  if grouped_stats.length > 0
261
295
  title = options[:title]
262
296
  title ||= "#{header} Distribution"
263
- options.merge!( :title => title, :width => 1024 )
297
+ options.merge!( :title => title, :width => $chart_width )
264
298
  value_map = {}
265
299
  groups = grouped_stats.keys.sort
266
300
  groups.each_with_index do |name,index|
267
301
  gs = grouped_stats[name]
268
- hist = gs.stats
269
- hist.keys.each do |k|
270
- value_map[k] ||= [].fill(0,0...groups.length)
271
- value_map[k][index] = hist[k]
302
+ if gs
303
+ hist = gs.stats
304
+ hist.keys.each do |k|
305
+ value_map[k] ||= [].fill(0,0...groups.length)
306
+ value_map[k][index] = hist[k]
307
+ end
308
+ else
309
+ puts "No grouped stats found for #{name}"
272
310
  end
273
311
  end
274
312
  legends = value_map.keys.sort
@@ -284,7 +322,7 @@ module Geoptima
284
322
  end
285
323
  values = keys.map{|k| hist[k]}
286
324
  title ||= "#{header} Distribution"
287
- options.merge!( :title => title, :width => 1024 )
325
+ options.merge!( :title => title, :width => $chart_width )
288
326
  g = Geoptima::Chart.send "draw_#{chart_type}_chart", stats_manager.name, keys, values, options
289
327
  end
290
328
  g.write("#{$export_dir}/Chart_#{stats_manager.name}_#{header}_#{chart_type}_distribution.png")
@@ -321,7 +359,9 @@ module Geoptima
321
359
  end
322
360
  end
323
361
  def add_fields(stats_manager,fields)
362
+ puts "Adding fields to #{stat_specs.length} StatSpec's" if($debug)
324
363
  stat_specs.each do |stat_spec|
364
+ puts "Adding fields to StatSpec: #{stat_spec}" if($debug)
325
365
  stat_spec.add(stats_manager,fields)
326
366
  end
327
367
  end
data/bin/csv_merge ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # useful if being run inside a source code checkout
4
+ $: << 'lib'
5
+ $: << '../lib'
6
+
7
+ require 'geoptima/version'
8
+ require 'geoptima/options'
9
+ require 'fileutils'
10
+ require 'geoptima/daterange'
11
+
12
+ Geoptima::assert_version("0.1.2")
13
+
14
+ $export_dir = '.'
15
+ $export_name = 'merged.csv'
16
+
17
+ $files = Geoptima::Options.process_args do |option|
18
+ option.t {$time_split = true}
19
+ option.D {$export_dir = ARGV.shift}
20
+ option.N {$export_name = ARGV.shift}
21
+ option.T do
22
+ $time_range = Geoptima::DateRange.new(*(ARGV.shift.split(/[\,]+/).map do |t|
23
+ DateTime.parse t
24
+ end))
25
+ end
26
+ end
27
+
28
+ FileUtils.mkdir_p $export_dir
29
+
30
+ $help = true unless($files.length>0)
31
+ if $help
32
+ puts <<EOHELP
33
+ Usage: csv_chart <-dht> <-N name> <-D dir> <-T range> files...
34
+ -d debug mode #{cw $debug}
35
+ -h print this help #{cw $help}
36
+ -t merge and split by time (days) #{cw $time_split}
37
+ -N use specified name for merged dataset: #{$merged_name}
38
+ -D export to specified directory: #{$export_dir}
39
+ -T set time-range filter: #{$time_range}
40
+ Files to import: #{$files.join(', ')}
41
+ EOHELP
42
+ exit
43
+ end
44
+
45
+ class CSVData
46
+ attr_reader :headers
47
+ def initialize(headers)
48
+ end
49
+ end
50
+
51
+ $files.each do |file|
52
+ lines = 0
53
+ headers = nil
54
+ filename = File.basename(file)
55
+ (names = filename.split(/[_\.]/)).pop
56
+ name = $merge_all ? ($merged_name || 'All') : names.join('_')
57
+ $stats_managers[name] ||= StatsManager.new(name)
58
+ puts "About to read file #{file}"
59
+ File.open(file).each do |line|
60
+ lines += 1
61
+ fields=line.chomp.split(/\t/)
62
+ if headers
63
+ puts "Processing line: #{line}" if($debug)
64
+ $stats_managers[name].add_all(fields,headers)
65
+ else
66
+ headers = fields
67
+ if headers.length<2
68
+ puts "Too few headers, rejecting #{file}"
69
+ break
70
+ end
71
+ $stats_managers[name].set_headers(headers)
72
+ end
73
+ end
74
+ end
75
+
data/bin/show_geoptima CHANGED
@@ -7,7 +7,7 @@ $: << '../lib'
7
7
  require 'date'
8
8
  require 'geoptima'
9
9
 
10
- Geoptima::assert_version("0.1.1")
10
+ Geoptima::assert_version("0.1.2")
11
11
 
12
12
  $debug=false
13
13
 
@@ -10,11 +10,12 @@ require 'geoptima/options'
10
10
  require 'fileutils'
11
11
  require 'geoptima/daterange'
12
12
 
13
- Geoptima::assert_version("0.1.1")
13
+ Geoptima::assert_version("0.1.2")
14
14
  Geoptima::Chart.available? || puts("No charting libraries available") || exit(-1)
15
15
 
16
16
  $export_dir = '.'
17
17
  $diversity = 40.0
18
+ $chart_width = 1024
18
19
 
19
20
  $files = Geoptima::Options.process_args do |option|
20
21
  option.m {$merge_all = true}
@@ -24,15 +25,15 @@ $files = Geoptima::Options.process_args do |option|
24
25
  option.N {$merged_name = ARGV.shift}
25
26
  option.S {$specfile = ARGV.shift}
26
27
  option.P {$diversity = ARGV.shift.to_f}
28
+ option.W {$chart_width = ARGV.shift.to_i}
27
29
  option.T do
28
- $time_range = Geoptima::DateRange.new(*(ARGV.shift.split(/[\,]+/).map do |t|
29
- DateTime.parse t
30
- end))
30
+ $time_range = Geoptima::DateRange.from ARGV.shift
31
31
  end
32
32
  end
33
33
 
34
34
  FileUtils.mkdir_p $export_dir
35
35
 
36
+ $chart_width=100 if($chart_width.to_i < 100)
36
37
  $create_all = true unless($specfile)
37
38
  $merge_all = true if($time_split)
38
39
  $help = true unless($files.length>0)
@@ -49,6 +50,7 @@ Usage: csv_chart <-dhamt> <-S specfile> <-N name> <-D dir> <-T range> <-P divers
49
50
  -S use chart specification in specified file: #{$specfile}
50
51
  -P diversity threshold in percentage for automatic reports: #{$diversity}
51
52
  -T set time-range filter: #{$time_range}
53
+ -W set default chart-width: #{$chart_width}
52
54
  Files to import: #{$files.join(', ')}
53
55
  EOHELP
54
56
  exit
@@ -63,8 +65,7 @@ class Stats
63
65
  @numerical = true
64
66
  end
65
67
  def add(field)
66
- puts "\tAdding field '#{field}' for property #{name}" if($debug)
67
- if field && field =~ /\w/
68
+ unless field.nil? || field == ''
68
69
  @numerical &&= is_number?(field)
69
70
  stats[field] ||= 0
70
71
  stats[field] += 1
@@ -129,12 +130,12 @@ class StatsManager
129
130
  end
130
131
  def add_all(fields,headers)
131
132
  fields.each_with_index do |field,index|
132
- add(field,headers[index])
133
+ add(field,headers[index],index)
133
134
  end
134
135
  $specs && $specs.add_fields(self,fields)
135
136
  end
136
- def add(field,header)
137
- puts "\tAdding field '#{field}' for property #{header}" if($debug)
137
+ def add(field,header,index)
138
+ puts "\tAdding field[#{index}] '#{field}' for property #{header}" if($debug)
138
139
  add_header(header) unless(@stats[header])
139
140
  @stats[header].add(field)
140
141
  end
@@ -148,10 +149,11 @@ end
148
149
 
149
150
  module Geoptima
150
151
  class StatSpec
151
- attr_reader :header, :index, :indices, :fields, :options, :proc, :groups
152
+ attr_reader :header, :event, :index, :indices, :fields, :options, :proc, :groups
152
153
  def initialize(header,*fields,&block)
153
154
  @header = header
154
155
  @fields = fields
156
+ @event = @fields[0].split(/\./)[0]
155
157
  @proc = block
156
158
  @groups = {}
157
159
  if @fields[-1].is_a?(Hash)
@@ -182,20 +184,42 @@ module Geoptima
182
184
  key = @group.call(time)
183
185
  ghead = "#{header} #{key}"
184
186
  @groups[key] = ghead
185
- stats_manager.add(map(fields),ghead)
187
+ stats_manager.add(map(fields),ghead,nil)
186
188
  end
187
189
  rescue ArgumentError
188
190
  puts "Error: Unable to process time field[#{time}]: #{$!}"
189
191
  end
190
192
  end
191
- stats_manager.add(map(fields),header)
193
+ stats_manager.add(map(fields),header,index)
192
194
  end
193
- def mk_range(val)
194
- if val =~ /\w/
195
- div = options[:div].to_i
196
- div = 1 if(div<1)
195
+ def div
196
+ unless @div
197
+ @div = options[:div].to_i
198
+ @div = 1 if(@div<1)
199
+ end
200
+ @div
201
+ end
202
+ def cats
203
+ @cats ||= (options[:categories] || []).map{|c| c.to_i}
204
+ end
205
+ def mk_div_range(val)
206
+ unless val.nil? || val == ''
197
207
  min = val.to_i/div * div
198
- "#{min}..#{min+div}"
208
+ (div == 1) ? min : "#{min}..#{min+div}"
209
+ else
210
+ val
211
+ end
212
+ end
213
+ def mk_cat_range(val)
214
+ if val.to_s =~ /\w/
215
+ val = val.to_i
216
+ puts "\t\tSearching for value[#{val}] in categories #{cats.inspect}" if($debug)
217
+ min = cats[0]
218
+ cats.each do |c|
219
+ max = c
220
+ return "#{min}..#{max}" if(min<=val && max>val)
221
+ min = c
222
+ end
199
223
  else
200
224
  val
201
225
  end
@@ -204,12 +228,22 @@ module Geoptima
204
228
  if @indices
205
229
  puts "StatSpec[#{self}]: #{options.inspect}" if($debug)
206
230
  vals = @indices.map{|i| values[i]}
231
+ puts "\tVALUES: #{vals.inspect}" if($debug)
232
+ (options[:filter] || {}).each do |field,expected|
233
+ puts "\t\tChecking if field #{field} is #{expected}" if($debug)
234
+ puts "\t\tLooking for #{field} or #{event}.#{field} in #{@fields.inspect}" if($debug)
235
+ hi = @fields.index(field.to_s) || @fields.index("#{event}.#{field}")
236
+ puts "\t\t#{field} -> #{hi} -> #{hi && vals[hi]}" if($debug)
237
+ return nil unless(hi && vals[hi] && (expected === vals[hi].downcase || vals[hi].downcase === expected.to_s.downcase))
238
+ end
239
+ val = proc.nil? ? vals[0] : proc.call(*vals)
240
+ puts "\tBLOCK MAP: #{vals.inspect} --> #{val.inspect}" if($debug)
207
241
  if options[:div]
208
- vals.map!{|v| mk_range(v)}
242
+ val = mk_div_range(val)
243
+ elsif options[:categories]
244
+ val = mk_cat_range(val)
209
245
  end
210
- puts "StatSpec[#{self}]: #{vals.inspect}" if($debug)
211
- val = proc && proc.call(*vals) || vals[0]
212
- puts "StatSpec[#{self}]: #{vals.inspect} --> #{val.inspect}" if($debug)
246
+ puts "\tDIV/CAT MAP: #{vals.inspect} --> #{val.inspect}" if($debug)
213
247
  val
214
248
  end
215
249
  end
@@ -260,15 +294,19 @@ module Geoptima
260
294
  if grouped_stats.length > 0
261
295
  title = options[:title]
262
296
  title ||= "#{header} Distribution"
263
- options.merge!( :title => title, :width => 1024 )
297
+ options.merge!( :title => title, :width => $chart_width )
264
298
  value_map = {}
265
299
  groups = grouped_stats.keys.sort
266
300
  groups.each_with_index do |name,index|
267
301
  gs = grouped_stats[name]
268
- hist = gs.stats
269
- hist.keys.each do |k|
270
- value_map[k] ||= [].fill(0,0...groups.length)
271
- value_map[k][index] = hist[k]
302
+ if gs
303
+ hist = gs.stats
304
+ hist.keys.each do |k|
305
+ value_map[k] ||= [].fill(0,0...groups.length)
306
+ value_map[k][index] = hist[k]
307
+ end
308
+ else
309
+ puts "No grouped stats found for #{name}"
272
310
  end
273
311
  end
274
312
  legends = value_map.keys.sort
@@ -284,7 +322,7 @@ module Geoptima
284
322
  end
285
323
  values = keys.map{|k| hist[k]}
286
324
  title ||= "#{header} Distribution"
287
- options.merge!( :title => title, :width => 1024 )
325
+ options.merge!( :title => title, :width => $chart_width )
288
326
  g = Geoptima::Chart.send "draw_#{chart_type}_chart", stats_manager.name, keys, values, options
289
327
  end
290
328
  g.write("#{$export_dir}/Chart_#{stats_manager.name}_#{header}_#{chart_type}_distribution.png")
@@ -321,7 +359,9 @@ module Geoptima
321
359
  end
322
360
  end
323
361
  def add_fields(stats_manager,fields)
362
+ puts "Adding fields to #{stat_specs.length} StatSpec's" if($debug)
324
363
  stat_specs.each do |stat_spec|
364
+ puts "Adding fields to StatSpec: #{stat_spec}" if($debug)
325
365
  stat_spec.add(stats_manager,fields)
326
366
  end
327
367
  end
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # useful if being run inside a source code checkout
4
+ $: << 'lib'
5
+ $: << '../lib'
6
+
7
+ require 'geoptima/version'
8
+ require 'geoptima/options'
9
+ require 'fileutils'
10
+ require 'geoptima/daterange'
11
+
12
+ Geoptima::assert_version("0.1.2")
13
+
14
+ $export_dir = '.'
15
+ $export_name = 'merged.csv'
16
+
17
+ $files = Geoptima::Options.process_args do |option|
18
+ option.t {$time_split = true}
19
+ option.D {$export_dir = ARGV.shift}
20
+ option.N {$export_name = ARGV.shift}
21
+ option.T do
22
+ $time_range = Geoptima::DateRange.new(*(ARGV.shift.split(/[\,]+/).map do |t|
23
+ DateTime.parse t
24
+ end))
25
+ end
26
+ end
27
+
28
+ FileUtils.mkdir_p $export_dir
29
+
30
+ $help = true unless($files.length>0)
31
+ if $help
32
+ puts <<EOHELP
33
+ Usage: csv_chart <-dht> <-N name> <-D dir> <-T range> files...
34
+ -d debug mode #{cw $debug}
35
+ -h print this help #{cw $help}
36
+ -t merge and split by time (days) #{cw $time_split}
37
+ -N use specified name for merged dataset: #{$merged_name}
38
+ -D export to specified directory: #{$export_dir}
39
+ -T set time-range filter: #{$time_range}
40
+ Files to import: #{$files.join(', ')}
41
+ EOHELP
42
+ exit
43
+ end
44
+
45
+ class CSVData
46
+ attr_reader :headers
47
+ def initialize(headers)
48
+ end
49
+ end
50
+
51
+ $files.each do |file|
52
+ lines = 0
53
+ headers = nil
54
+ filename = File.basename(file)
55
+ (names = filename.split(/[_\.]/)).pop
56
+ name = $merge_all ? ($merged_name || 'All') : names.join('_')
57
+ $stats_managers[name] ||= StatsManager.new(name)
58
+ puts "About to read file #{file}"
59
+ File.open(file).each do |line|
60
+ lines += 1
61
+ fields=line.chomp.split(/\t/)
62
+ if headers
63
+ puts "Processing line: #{line}" if($debug)
64
+ $stats_managers[name].add_all(fields,headers)
65
+ else
66
+ headers = fields
67
+ if headers.length<2
68
+ puts "Too few headers, rejecting #{file}"
69
+ break
70
+ end
71
+ $stats_managers[name].set_headers(headers)
72
+ end
73
+ end
74
+ end
75
+
@@ -7,7 +7,7 @@ $: << '../lib'
7
7
  require 'date'
8
8
  require 'geoptima'
9
9
 
10
- Geoptima::assert_version("0.1.1")
10
+ Geoptima::assert_version("0.1.2")
11
11
 
12
12
  $debug=false
13
13
 
@@ -45,7 +45,7 @@ module Geoptima
45
45
  def self.draw_line_chart(legend,keys,values,options={})
46
46
  g = make_chart(:line,{:show_points => false}.merge(options))
47
47
  g.data(legend, values)
48
- g.labels= {0=>keys[0], (keys.length-1)=>keys[-1]}
48
+ g.labels= {0=>keys[0].to_s, (keys.length-1)=>keys[-1].to_s}
49
49
  options[:maximum_value] && g.maximum_value = options[:maximum_value].to_i
50
50
  options[:minimum_value] && g.minimum_value = options[:minimum_value].to_i
51
51
  options[:filename] && g.write(options[:filename])
@@ -57,7 +57,15 @@ module Geoptima
57
57
  g = make_chart(chart_type, options)
58
58
  g.data(legend, values)
59
59
  g.minimum_value = 0
60
- g.labels = keys.inject({}){|a,v| a[a.length] = v;a}
60
+ mod = 1
61
+ unless options[:side]
62
+ while(keys.length/mod > 10) do
63
+ mod+=1
64
+ end
65
+ end
66
+ labels = {}
67
+ keys.each_with_index{|v,i| labels[i] = v.to_s if(i%mod == 0)}
68
+ g.labels = labels
61
69
  options[:filename] && g.write(options[:filename])
62
70
  g
63
71
  end
@@ -69,7 +77,7 @@ module Geoptima
69
77
  g.data(legend, values[legend])
70
78
  end
71
79
  g.minimum_value = 0
72
- g.labels = keys.inject({}){|a,v| a[a.length] = v;a}
80
+ g.labels = keys.inject({}){|a,v| a[a.length] = v.to_s;a}
73
81
  options[:filename] && g.write(options[:filename])
74
82
  g
75
83
  end
@@ -19,10 +19,10 @@ end
19
19
  module Geoptima
20
20
  class DateRange
21
21
  attr_reader :min, :max, :range
22
- def initialize(min,max)
22
+ def initialize(min,max=nil)
23
23
  @min = min
24
- @max = max
25
- @range = Range.new(min,max)
24
+ @max = max || (min + 1.0)
25
+ @range = Range.new(@min,@max)
26
26
  end
27
27
  if ENV['RUBY_VERSION'] =~ /1\.8/
28
28
  puts "Defining Range.include? to wrap for 1.8"
@@ -35,6 +35,57 @@ module Geoptima
35
35
  (time >= min) && (time <= @max)
36
36
  end
37
37
  end
38
+ def to_s
39
+ @range.to_s
40
+ end
41
+ def self.from(spec)
42
+ if spec =~ /\.\./
43
+ puts "New time range spec: #{spec}" if($debug)
44
+ DateRanges.new(spec)
45
+ elsif spec.split(/\,/).length > 2
46
+ puts "New days array: #{spec}" if($debug)
47
+ DaysRange.new(spec)
48
+ else
49
+ puts "Classic time range: #{spec}" if($debug)
50
+ DateRange.new(*spec.split(/\,/).map{|t| DateTime.parse(t)})
51
+ end
52
+ end
53
+ def self.test
54
+ [
55
+ '2012-03-15,2012-03-16',
56
+ '2012-03-15..2012-03-16',
57
+ '2012-03-15..2012-03-20',
58
+ '2012-03-15..2012-03-16,2012-03-20..2012.03.21',
59
+ '2012-03-15..2012-03-16,2012-03-20',
60
+ '2012-03-15,2012-03-16,2012-03-20'
61
+ ].each do |test|
62
+ puts "Testing: #{test}"
63
+ puts "\t#{Geoptima::DateRange.from(test)}"
64
+ end
65
+ end
66
+ end
67
+ class DateRanges
68
+ def initialize(spec)
69
+ @ranges = spec.split(/\,/).map do |range|
70
+ minmax = range.split(/\.\./).map{|t| DateTime.parse t}
71
+ DateRange.new(*minmax)
72
+ end
73
+ end
74
+ def include?(time)
75
+ @ranges.each{|r| return true if(r.include?(time))}
76
+ return false
77
+ end
78
+ def to_s
79
+ @ranges.join(',')
80
+ end
81
+ end
82
+ class DaysRange < DateRanges
83
+ def initialize(spec)
84
+ @ranges = spec.split(/\,/).map do |day|
85
+ min = DateTime.parse(DateTime.parse(day).strftime("%Y-%m-%d"))
86
+ DateRange.new(min)
87
+ end
88
+ end
38
89
  end
39
90
  end
40
91
 
@@ -1,6 +1,6 @@
1
1
  module Geoptima
2
2
 
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
 
5
5
  def self.version_as_int(ver)
6
6
  base = 1
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geoptima
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Craig Taverner
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-23 00:00:00 Z
18
+ date: 2012-03-26 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: multi_json
@@ -74,6 +74,7 @@ files:
74
74
  - bin/csv_chart
75
75
  - bin/geoptima_file_time
76
76
  - bin/csv_stats
77
+ - bin/csv_merge
77
78
  - lib/geoptima/version.rb
78
79
  - lib/geoptima/data.rb
79
80
  - lib/geoptima/chart.rb
@@ -85,6 +86,7 @@ files:
85
86
  - examples/csv_chart.rb
86
87
  - examples/geoptima_file_time.rb
87
88
  - examples/csv_stats.rb
89
+ - examples/csv_merge.rb
88
90
  - examples/sample_geoptima.json
89
91
  - README.rdoc
90
92
  - CHANGELOG