geoptima 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/bin/csv_chart CHANGED
@@ -5,15 +5,22 @@ $: << 'lib'
5
5
  $: << '../lib'
6
6
 
7
7
  require 'geoptima/chart'
8
+ require 'geoptima/version'
8
9
  require 'geoptima/options'
9
10
  require 'fileutils'
10
11
 
12
+ Geoptima::assert_version("0.0.9")
13
+
11
14
  $export_dir = '.'
15
+ $diversity = 40.0
12
16
 
13
17
  $files = Geoptima::Options.process_args do |option|
14
18
  option.m {$merge_all = true}
19
+ option.a {$create_all = true}
15
20
  option.D {$export_dir = ARGV.shift}
16
21
  option.N {$merged_name = ARGV.shift}
22
+ option.S {$specfile = ARGV.shift}
23
+ option.P {$diversity = ARGV.shift.to_f}
17
24
  end
18
25
 
19
26
  FileUtils.mkdir_p $export_dir
@@ -21,12 +28,15 @@ FileUtils.mkdir_p $export_dir
21
28
  $help = true unless($files.length>0)
22
29
  if $help
23
30
  puts <<EOHELP
24
- Usage: csv_chart <-dhm> <-N name> <-D dir> files...
31
+ Usage: csv_chart <-dham> <-S specfile> <-N name> <-D dir> files...
25
32
  -d debug mode #{cw $debug}
26
33
  -h print this help #{cw $help}
34
+ -a automatically create charts for all properties #{cw $create_all}
27
35
  -m merge all files into single stats #{cw $merge_all}
28
36
  -N use specified name for merged dataset: #{$merged_name}
29
37
  -D export charts to specified directory: #{$export_dir}
38
+ -S use chart specification in specified file: #{$specfile}
39
+ -P diversity threshold in percentage for automatic reports: #{$diversity}
30
40
  Files to import: #{$files.join(', ')}
31
41
  EOHELP
32
42
  exit
@@ -42,8 +52,16 @@ class Stats
42
52
  @data = fields.map{|h| []}
43
53
  @numerical = fields.map{|h| true}
44
54
  end
55
+ def add_header(h)
56
+ @headers << h
57
+ @stats << {}
58
+ @data << []
59
+ @numerical << true
60
+ @headers.length - 1
61
+ end
45
62
  def add(field,index)
46
- if field =~ /\w/
63
+ puts "\tAdding field '#{field}' at index #{index}" if($debug)
64
+ if field && field =~ /\w/
47
65
  @numerical[index] &&= is_number?(field)
48
66
  puts "\tField[#{index}]: #{field}" if($debug)
49
67
  stats = @stats[index]
@@ -69,7 +87,7 @@ class Stats
69
87
  100.0 * @stats[index].length.to_f / @data[index].length.to_f
70
88
  end
71
89
  def diverse?(index)
72
- @stats[index].length>500 || diversity(index) > 40.0
90
+ @stats[index].length>500 || diversity(index) > $diversity
73
91
  end
74
92
  def numerical?(index)
75
93
  @numerical[index]
@@ -78,6 +96,139 @@ end
78
96
 
79
97
  $stats = {}
80
98
 
99
+ module Geoptima
100
+ class StatSpec
101
+ attr_reader :header, :index, :indices, :fields, :options, :proc
102
+ def initialize(header,*fields,&block)
103
+ @header = header
104
+ @fields = fields
105
+ @proc = block
106
+ if @fields[-1].is_a?(Hash)
107
+ @options = @fields.pop
108
+ else
109
+ @options = {}
110
+ end
111
+ puts "Created StatSpec: #{self}"
112
+ end
113
+ def mk_range(val)
114
+ if val =~ /\w/
115
+ div = options[:div].to_i
116
+ div = 1 if(div<1)
117
+ min = val.to_i/div * div
118
+ "#{min}..#{min+div}"
119
+ else
120
+ val
121
+ end
122
+ end
123
+ def map(values)
124
+ if @indices
125
+ puts "StatSpec[#{self}]: #{options.inspect}" if($debug)
126
+ vals = @indices.map{|i| values[i]}
127
+ if options[:div]
128
+ vals.map!{|v| mk_range(v)}
129
+ end
130
+ puts "StatSpec[#{self}]: #{vals.inspect}" if($debug)
131
+ val = proc.call(*vals)
132
+ puts "StatSpec[#{self}]: #{vals.inspect} --> #{val.inspect}" if($debug)
133
+ val
134
+ end
135
+ end
136
+ def prepare_indices(stats)
137
+ if stats.headers.index(header)
138
+ puts "Header '#{header}' already exists, cannot create #{self}"
139
+ else
140
+ @index = stats.add_header(header)
141
+ @indices = @fields.map{|h| stats.headers.index(h) || stats.headers.index(h.downcase) }
142
+ puts "#{self}: Header[#{@index}], Indices[#{@indices.join(',')}]" if($debug)
143
+ if @indices.compact.length < @fields.length
144
+ puts "Unable to find some headers for #{self}, ignoring stats"
145
+ @indices = nil
146
+ end
147
+ end
148
+ end
149
+ def to_s
150
+ "#{header}[#{index}]<-#{fields.inspect}(#{indices && indices.join(',')})"
151
+ end
152
+ end
153
+ class ChartSpec
154
+ attr_reader :chart_type, :header, :options
155
+ def initialize(chart_type,header,options={})
156
+ @header = header
157
+ @chart_type = chart_type
158
+ @options = options
159
+ end
160
+ def process(stats)
161
+ puts "Charting #{header} using stats.headers: #{stats.headers}"
162
+ index = stats.headers.index(header)
163
+ index ||= stats.headers.index(header.downcase)
164
+ unless index
165
+ puts "Cannot find statistics for '#{header}' - ignoring chart"
166
+ return
167
+ end
168
+ puts "Charting #{header} at index #{index} and options #{options.inspect}"
169
+ puts "Charting #{header} with diversity #{stats.diversity(index)}"
170
+ hist = stats.stats[index]
171
+ title = options[:title]
172
+ if options[:top]
173
+ keys = hist.keys.sort{|a,b| hist[b] <=> hist[a]}[0..(options[:top].to_i)]
174
+ title ||= "#{header} Top #{options[:top]}"
175
+ else
176
+ keys = hist.keys.sort{|a,b| a.to_i <=> b.to_i}
177
+ end
178
+ values = keys.map{|k| hist[k]}
179
+ title ||= "#{header} Distribution"
180
+ options.merge!( :title => title, :width => 1024 )
181
+ legend = $merge_all ? "ALL" : stats.name
182
+ g = Geoptima::Chart.send "draw_#{chart_type}_chart", stats.name, keys, values, options
183
+ g.write("#{$export_dir}/Chart_#{stats.name}_#{header}_distribution.png")
184
+ end
185
+ def to_s
186
+ "#{chart_type.upcase}-#{header}"
187
+ end
188
+ end
189
+ class StatsSpecs
190
+ attr_reader :chart_specs, :stat_specs
191
+ def initialize(specfile)
192
+ @chart_specs = []
193
+ @stat_specs = []
194
+ instance_eval(File.open(specfile).read)
195
+ end
196
+ def category_chart(header,options={})
197
+ chart(:category, header, options)
198
+ end
199
+ def histogram_chart(header,options={})
200
+ chart(:histogram, header, options)
201
+ end
202
+ def line_chart(header,options={})
203
+ chart(:line, header, options)
204
+ end
205
+ def chart(chart_type,header,options={})
206
+ @chart_specs << ChartSpec.new(chart_type,header,options)
207
+ end
208
+ def stats(header,*fields,&block)
209
+ @stat_specs << StatSpec.new(header,*fields,&block)
210
+ end
211
+ def add_stats(stats)
212
+ stat_specs.each do |stat_spec|
213
+ stat_spec.prepare_indices(stats)
214
+ end
215
+ end
216
+ def add_fields(stats,fields)
217
+ $specs.stat_specs.each do |stat_spec|
218
+ stats.add(
219
+ stat_spec.map(fields),
220
+ stat_spec.index
221
+ )
222
+ end
223
+ end
224
+ def to_s
225
+ "Charts[#{chart_specs.length}]: #{@chart_specs.join(', ')}"
226
+ end
227
+ end
228
+ end
229
+
230
+ $specfile && $specs = Geoptima::StatsSpecs.new($specfile)
231
+
81
232
  $files.each do |file|
82
233
  lines = 0
83
234
  filename = File.basename(file)
@@ -92,15 +243,22 @@ $files.each do |file|
92
243
  fields.each_with_index do |field,index|
93
244
  $stats[file].add(field,index)
94
245
  end
246
+ $specs && $specs.add_fields($stats[file],fields)
95
247
  elsif($merge_all && $stats.length>0)
96
248
  file = $stats.values[0].file
97
249
  else
98
250
  $stats[file] = Stats.new(filename,name,fields)
251
+ $specs && $specs.add_stats($stats[file])
99
252
  end
100
253
  end
101
254
  end
102
255
 
103
256
  $stats.each do |file,stats|
257
+ if $specs
258
+ $specs.chart_specs.each do |chart_spec|
259
+ chart_spec.process(stats)
260
+ end
261
+ else
104
262
  stats.headers.each_with_index do |header,index|
105
263
  puts "Charting #{header} with diversity #{stats.diversity(index)}"
106
264
  case header
@@ -136,7 +294,7 @@ $stats.each do |file,stats|
136
294
 
137
295
  else
138
296
  if stats.diverse?(index)
139
- puts "Ingnoring high diversity field #{header}"
297
+ puts "Ignoring high diversity field #{header}"
140
298
  else
141
299
  puts "Charting field: #{header} with length #{stats.length(index)} and diversity #{stats.diversity(index)}"
142
300
  hist = stats.stats[index]
@@ -156,5 +314,6 @@ $stats.each do |file,stats|
156
314
  end
157
315
  end
158
316
  end
317
+ end
159
318
  end
160
319
 
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.0.8")
10
+ Geoptima::assert_version("0.0.9")
11
11
 
12
12
  $debug=false
13
13
 
@@ -5,15 +5,22 @@ $: << 'lib'
5
5
  $: << '../lib'
6
6
 
7
7
  require 'geoptima/chart'
8
+ require 'geoptima/version'
8
9
  require 'geoptima/options'
9
10
  require 'fileutils'
10
11
 
12
+ Geoptima::assert_version("0.0.9")
13
+
11
14
  $export_dir = '.'
15
+ $diversity = 40.0
12
16
 
13
17
  $files = Geoptima::Options.process_args do |option|
14
18
  option.m {$merge_all = true}
19
+ option.a {$create_all = true}
15
20
  option.D {$export_dir = ARGV.shift}
16
21
  option.N {$merged_name = ARGV.shift}
22
+ option.S {$specfile = ARGV.shift}
23
+ option.P {$diversity = ARGV.shift.to_f}
17
24
  end
18
25
 
19
26
  FileUtils.mkdir_p $export_dir
@@ -21,12 +28,15 @@ FileUtils.mkdir_p $export_dir
21
28
  $help = true unless($files.length>0)
22
29
  if $help
23
30
  puts <<EOHELP
24
- Usage: csv_chart <-dhm> <-N name> <-D dir> files...
31
+ Usage: csv_chart <-dham> <-S specfile> <-N name> <-D dir> files...
25
32
  -d debug mode #{cw $debug}
26
33
  -h print this help #{cw $help}
34
+ -a automatically create charts for all properties #{cw $create_all}
27
35
  -m merge all files into single stats #{cw $merge_all}
28
36
  -N use specified name for merged dataset: #{$merged_name}
29
37
  -D export charts to specified directory: #{$export_dir}
38
+ -S use chart specification in specified file: #{$specfile}
39
+ -P diversity threshold in percentage for automatic reports: #{$diversity}
30
40
  Files to import: #{$files.join(', ')}
31
41
  EOHELP
32
42
  exit
@@ -42,8 +52,16 @@ class Stats
42
52
  @data = fields.map{|h| []}
43
53
  @numerical = fields.map{|h| true}
44
54
  end
55
+ def add_header(h)
56
+ @headers << h
57
+ @stats << {}
58
+ @data << []
59
+ @numerical << true
60
+ @headers.length - 1
61
+ end
45
62
  def add(field,index)
46
- if field =~ /\w/
63
+ puts "\tAdding field '#{field}' at index #{index}" if($debug)
64
+ if field && field =~ /\w/
47
65
  @numerical[index] &&= is_number?(field)
48
66
  puts "\tField[#{index}]: #{field}" if($debug)
49
67
  stats = @stats[index]
@@ -69,7 +87,7 @@ class Stats
69
87
  100.0 * @stats[index].length.to_f / @data[index].length.to_f
70
88
  end
71
89
  def diverse?(index)
72
- @stats[index].length>500 || diversity(index) > 40.0
90
+ @stats[index].length>500 || diversity(index) > $diversity
73
91
  end
74
92
  def numerical?(index)
75
93
  @numerical[index]
@@ -78,6 +96,139 @@ end
78
96
 
79
97
  $stats = {}
80
98
 
99
+ module Geoptima
100
+ class StatSpec
101
+ attr_reader :header, :index, :indices, :fields, :options, :proc
102
+ def initialize(header,*fields,&block)
103
+ @header = header
104
+ @fields = fields
105
+ @proc = block
106
+ if @fields[-1].is_a?(Hash)
107
+ @options = @fields.pop
108
+ else
109
+ @options = {}
110
+ end
111
+ puts "Created StatSpec: #{self}"
112
+ end
113
+ def mk_range(val)
114
+ if val =~ /\w/
115
+ div = options[:div].to_i
116
+ div = 1 if(div<1)
117
+ min = val.to_i/div * div
118
+ "#{min}..#{min+div}"
119
+ else
120
+ val
121
+ end
122
+ end
123
+ def map(values)
124
+ if @indices
125
+ puts "StatSpec[#{self}]: #{options.inspect}" if($debug)
126
+ vals = @indices.map{|i| values[i]}
127
+ if options[:div]
128
+ vals.map!{|v| mk_range(v)}
129
+ end
130
+ puts "StatSpec[#{self}]: #{vals.inspect}" if($debug)
131
+ val = proc.call(*vals)
132
+ puts "StatSpec[#{self}]: #{vals.inspect} --> #{val.inspect}" if($debug)
133
+ val
134
+ end
135
+ end
136
+ def prepare_indices(stats)
137
+ if stats.headers.index(header)
138
+ puts "Header '#{header}' already exists, cannot create #{self}"
139
+ else
140
+ @index = stats.add_header(header)
141
+ @indices = @fields.map{|h| stats.headers.index(h) || stats.headers.index(h.downcase) }
142
+ puts "#{self}: Header[#{@index}], Indices[#{@indices.join(',')}]" if($debug)
143
+ if @indices.compact.length < @fields.length
144
+ puts "Unable to find some headers for #{self}, ignoring stats"
145
+ @indices = nil
146
+ end
147
+ end
148
+ end
149
+ def to_s
150
+ "#{header}[#{index}]<-#{fields.inspect}(#{indices && indices.join(',')})"
151
+ end
152
+ end
153
+ class ChartSpec
154
+ attr_reader :chart_type, :header, :options
155
+ def initialize(chart_type,header,options={})
156
+ @header = header
157
+ @chart_type = chart_type
158
+ @options = options
159
+ end
160
+ def process(stats)
161
+ puts "Charting #{header} using stats.headers: #{stats.headers}"
162
+ index = stats.headers.index(header)
163
+ index ||= stats.headers.index(header.downcase)
164
+ unless index
165
+ puts "Cannot find statistics for '#{header}' - ignoring chart"
166
+ return
167
+ end
168
+ puts "Charting #{header} at index #{index} and options #{options.inspect}"
169
+ puts "Charting #{header} with diversity #{stats.diversity(index)}"
170
+ hist = stats.stats[index]
171
+ title = options[:title]
172
+ if options[:top]
173
+ keys = hist.keys.sort{|a,b| hist[b] <=> hist[a]}[0..(options[:top].to_i)]
174
+ title ||= "#{header} Top #{options[:top]}"
175
+ else
176
+ keys = hist.keys.sort{|a,b| a.to_i <=> b.to_i}
177
+ end
178
+ values = keys.map{|k| hist[k]}
179
+ title ||= "#{header} Distribution"
180
+ options.merge!( :title => title, :width => 1024 )
181
+ legend = $merge_all ? "ALL" : stats.name
182
+ g = Geoptima::Chart.send "draw_#{chart_type}_chart", stats.name, keys, values, options
183
+ g.write("#{$export_dir}/Chart_#{stats.name}_#{header}_distribution.png")
184
+ end
185
+ def to_s
186
+ "#{chart_type.upcase}-#{header}"
187
+ end
188
+ end
189
+ class StatsSpecs
190
+ attr_reader :chart_specs, :stat_specs
191
+ def initialize(specfile)
192
+ @chart_specs = []
193
+ @stat_specs = []
194
+ instance_eval(File.open(specfile).read)
195
+ end
196
+ def category_chart(header,options={})
197
+ chart(:category, header, options)
198
+ end
199
+ def histogram_chart(header,options={})
200
+ chart(:histogram, header, options)
201
+ end
202
+ def line_chart(header,options={})
203
+ chart(:line, header, options)
204
+ end
205
+ def chart(chart_type,header,options={})
206
+ @chart_specs << ChartSpec.new(chart_type,header,options)
207
+ end
208
+ def stats(header,*fields,&block)
209
+ @stat_specs << StatSpec.new(header,*fields,&block)
210
+ end
211
+ def add_stats(stats)
212
+ stat_specs.each do |stat_spec|
213
+ stat_spec.prepare_indices(stats)
214
+ end
215
+ end
216
+ def add_fields(stats,fields)
217
+ $specs.stat_specs.each do |stat_spec|
218
+ stats.add(
219
+ stat_spec.map(fields),
220
+ stat_spec.index
221
+ )
222
+ end
223
+ end
224
+ def to_s
225
+ "Charts[#{chart_specs.length}]: #{@chart_specs.join(', ')}"
226
+ end
227
+ end
228
+ end
229
+
230
+ $specfile && $specs = Geoptima::StatsSpecs.new($specfile)
231
+
81
232
  $files.each do |file|
82
233
  lines = 0
83
234
  filename = File.basename(file)
@@ -92,15 +243,22 @@ $files.each do |file|
92
243
  fields.each_with_index do |field,index|
93
244
  $stats[file].add(field,index)
94
245
  end
246
+ $specs && $specs.add_fields($stats[file],fields)
95
247
  elsif($merge_all && $stats.length>0)
96
248
  file = $stats.values[0].file
97
249
  else
98
250
  $stats[file] = Stats.new(filename,name,fields)
251
+ $specs && $specs.add_stats($stats[file])
99
252
  end
100
253
  end
101
254
  end
102
255
 
103
256
  $stats.each do |file,stats|
257
+ if $specs
258
+ $specs.chart_specs.each do |chart_spec|
259
+ chart_spec.process(stats)
260
+ end
261
+ else
104
262
  stats.headers.each_with_index do |header,index|
105
263
  puts "Charting #{header} with diversity #{stats.diversity(index)}"
106
264
  case header
@@ -136,7 +294,7 @@ $stats.each do |file,stats|
136
294
 
137
295
  else
138
296
  if stats.diverse?(index)
139
- puts "Ingnoring high diversity field #{header}"
297
+ puts "Ignoring high diversity field #{header}"
140
298
  else
141
299
  puts "Charting field: #{header} with length #{stats.length(index)} and diversity #{stats.diversity(index)}"
142
300
  hist = stats.stats[index]
@@ -156,5 +314,6 @@ $stats.each do |file,stats|
156
314
  end
157
315
  end
158
316
  end
317
+ end
159
318
  end
160
319
 
@@ -7,7 +7,7 @@ $: << '../lib'
7
7
  require 'date'
8
8
  require 'geoptima'
9
9
 
10
- Geoptima::assert_version("0.0.8")
10
+ Geoptima::assert_version("0.0.9")
11
11
 
12
12
  $debug=false
13
13
 
@@ -47,7 +47,8 @@ module Geoptima
47
47
  end
48
48
  def self.draw_histogram_chart(legend,keys,values,options={})
49
49
  puts "Creating a chart with legend #{legend} for #{keys.length} keys and #{values.length} values"
50
- g = make_chart(:bar, options)
50
+ chart_type = options[:side] ? :side_bar : :bar
51
+ g = make_chart(chart_type, options)
51
52
  g.data(legend, values)
52
53
  g.minimum_value = 0
53
54
  g.labels = keys.inject({}){|a,v| a[a.length] = v;a}
@@ -91,6 +92,8 @@ module Geoptima
91
92
  @chart.hide_lines = !options[:show_lines]
92
93
  when 'bar'
93
94
  @chart = Gruff::Bar.new(options[:width])
95
+ when 'side_bar'
96
+ @chart = Gruff::SideBar.new(options[:width])
94
97
  else
95
98
  raise "Unsupported chart type: #{chart_type}"
96
99
  end
@@ -45,6 +45,7 @@ module Geoptima
45
45
 
46
46
  def self.process_args(debug=nil)
47
47
  options = Options.new(debug)
48
+ options.add('v') {$print_version = true}
48
49
  options.add('d') {$debug = true}
49
50
  options.add('h') {$help = true}
50
51
  puts "Processing options: #{options}" if(debug)
@@ -58,6 +59,7 @@ module Geoptima
58
59
  options.args << arg
59
60
  end
60
61
  end
62
+ puts "Geoptima Gem Version: #{Geoptima::VERSION}" if($print_version)
61
63
  options.args
62
64
  end
63
65
 
@@ -1,6 +1,6 @@
1
1
  module Geoptima
2
2
 
3
- VERSION = "0.0.8"
3
+ VERSION = "0.0.9"
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: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 8
10
- version: 0.0.8
9
+ - 9
10
+ version: 0.0.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Craig Taverner
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-19 00:00:00 +01:00
19
- default_executable:
18
+ date: 2012-03-21 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: multi_json
@@ -91,7 +90,6 @@ files:
91
90
  - CONTRIBUTORS
92
91
  - Gemfile
93
92
  - geoptima.gemspec
94
- has_rdoc: true
95
93
  homepage: http://github.com/craigtaverner/geoptima.rb
96
94
  licenses: []
97
95
 
@@ -129,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
127
  requirements: []
130
128
 
131
129
  rubyforge_project: geoptima
132
- rubygems_version: 1.6.2
130
+ rubygems_version: 1.7.2
133
131
  signing_key:
134
132
  specification_version: 3
135
133
  summary: Ruby access to Geoptima JSON files