technical_graph 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/DOCUMENTATION.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Options Hash
4
4
 
5
+ options[:drawer_class] = :rasem (default) or :rmagick
6
+
5
7
  Default ranges:
6
8
 
7
9
  options[:x_min]
@@ -38,6 +40,13 @@ Labels has truncate string to define precision. Default it is "%.2f".
38
40
 
39
41
  options[:truncate_string] = "%.2f"
40
42
 
43
+ Draw axis labels, and labels for zero axis
44
+
45
+ options[:axis_value_and_param_labels] = true
46
+ options[:axis_zero_labels] = true
47
+
48
+
49
+
41
50
  Graph image size:
42
51
 
43
52
  options[:width]
@@ -49,13 +58,13 @@ Possible #RRGGBB or color names (ex. 'white').
49
58
 
50
59
  options[:background_color] - background color of image
51
60
  options[:background_hatch_color] - background hatch color
52
- options[:axis_color] - color of axis
61
+ options[:axis_color] - color of axis, default #000000
53
62
 
54
63
  Anti-aliasing:
55
64
 
56
- options[:axis_antialias] - use anti-aliasing for axis, default false
57
- options[:layers_antialias] - use anti-aliasing for data layers, default false, can be override using layer option
58
- options[:font_antialias] - use anti-aliasing for all fonts, default false
65
+ options[:antialias] - draw axis using antialias
66
+ # options[:layers_antialias] - use anti-aliasing for data layers, default false, can be override using layer option
67
+ # options[:font_antialias] - use anti-aliasing for all fonts, default false
59
68
 
60
69
  Font size:
61
70
 
@@ -91,3 +100,4 @@ Layer options Hash
91
100
  layer_options[:noise_removal] - enable removal of noises/peaks, default false
92
101
  layer_options[:noise_removal_level] - tolerance level, higher - less points will be removes, default 3
93
102
  layer_options[:noise_removal_window_size] - how many near values check for determining what is noise, default 10
103
+ layer_options[:perform_parameter_uniq] - it takes some time and rarely usable, so it is turned off by default
@@ -359,9 +359,76 @@ file_name = 'samples/readme/08b_truncate_string.png'
359
359
  !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/08b_truncate_string.png((08b) displaying float numbers)!
360
360
 
361
361
 
362
+
363
+
364
+
365
+
366
+ h2. Graph image size
367
+
368
+ p. It would be very silly if this library had hard coded image size. You can change it using options[:width] and options[:height].
369
+
370
+ <pre>
371
+ <code>
372
+ @simple_data_array = [
373
+ { :x => 0, :y => 0 },
374
+ { :x => 1, :y => 1 },
375
+ { :x => 2, :y => 2 },
376
+ { :x => 3, :y => 2 },
377
+ { :x => 4, :y => 1 },
378
+ { :x => 5, :y => 0 },
379
+ ]
380
+
381
+ @tg = TechnicalGraph.new(
382
+ {
383
+ :width => 600,
384
+ :height => 300
385
+ })
386
+ @tg.add_layer(@simple_data_array)
387
+ @tg.render
388
+ file_name = 'samples/readme/09_image_size.png'
389
+ @tg.image_drawer.save_to_file(file_name)
390
+ </code>
391
+ </pre>
392
+
393
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/09_image_size.png((09) image size)!
394
+
395
+
396
+
397
+ h2. Colours
398
+
399
+ p. If you think you have better artistic taste feel free to change colours used in graph :)
400
+
401
+ <pre>
402
+ <code>
403
+ @simple_data_array = [
404
+ { :x => 0, :y => 0 },
405
+ { :x => 1, :y => 1 },
406
+ { :x => 2, :y => 2 },
407
+ { :x => 3, :y => 2 },
408
+ { :x => 4, :y => 1 },
409
+ { :x => 5, :y => 0 },
410
+ ]
411
+
412
+ @tg = TechnicalGraph.new(
413
+ {
414
+ :width => 600,
415
+ :height => 300
416
+ })
417
+ @tg.add_layer(@simple_data_array, @layer_params)
418
+ @tg.render
419
+ file_name = 'samples/readme/09_image_size.png'
420
+ @tg.image_drawer.save_to_file(file_name)
421
+ </code>
422
+ </pre>
423
+
424
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/09_image_size.png((09) image size)!
425
+
426
+
427
+
428
+
429
+
362
430
  h2. TODO
363
431
 
364
- # Graph image size
365
432
  # Graph colors: background, hatch (option to turn it off?), axis
366
433
  # Anti-aliasing: image size comparison, layer antialiases
367
434
  # Font sizes
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem 'rmagick'
4
+ gem 'rasem'
4
5
 
5
6
  # Add dependencies to develop your gem here.
6
7
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -8,6 +8,7 @@ GEM
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  rake (0.9.2)
11
+ rasem (0.6.1)
11
12
  rcov (0.9.10)
12
13
  rmagick (2.13.1)
13
14
  rspec (2.6.0)
@@ -26,6 +27,7 @@ PLATFORMS
26
27
  DEPENDENCIES
27
28
  bundler (~> 1.0.0)
28
29
  jeweler
30
+ rasem
29
31
  rcov
30
32
  rmagick
31
33
  rspec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.4.0
@@ -11,4 +11,29 @@ class Array
11
11
  def float_mean
12
12
  float_sum / size
13
13
  end
14
+
15
+ # Create partial array and fill with border values if needed
16
+ def clone_partial_w_fill(_from, _to)
17
+ part_array = Array.new
18
+ # border = false
19
+
20
+ (_from.._to).each do |current_i|
21
+ # outside ranges
22
+ if current_i < 0
23
+ part_array << self.first
24
+ # border = true
25
+ next
26
+ end
27
+
28
+ if self.size <= current_i
29
+ part_array << self.last
30
+ # border = true
31
+ next
32
+ end
33
+
34
+ part_array << self[current_i]
35
+ end
36
+
37
+ return part_array
38
+ end
14
39
  end
@@ -10,7 +10,23 @@ require 'technical_graph/data_layer_processor'
10
10
 
11
11
  class DataLayer
12
12
 
13
- def initialize(d = [], options = { })
13
+ # Use global logger for technical_graph or create new
14
+ def logger
15
+ return @logger if not @logger.nil?
16
+
17
+ if not @technical_graph.nil?
18
+ @logger = @technical_graph.logger
19
+ else
20
+ @logger = Logger.new(STDOUT)
21
+ end
22
+
23
+ @logger
24
+ end
25
+
26
+ def initialize(d = [], options = { }, technical_graph = nil)
27
+ # used for accessing logger
28
+ @technical_graph = technical_graph
29
+
14
30
  @data_params = options
15
31
 
16
32
  @data_params[:color] ||= GraphColorLibrary.instance.get_color
@@ -42,10 +58,14 @@ class DataLayer
42
58
  if data_array.kind_of? Array
43
59
  # append as DataPoint
44
60
  # convert to DataPoints, which has more specialized methods
61
+
62
+ t = Time.now
45
63
  data_array.each do |d|
46
64
  @data << DataPoint.new(d)
47
65
  end
48
-
66
+ logger.debug "appending data, size #{data_array.size}"
67
+ logger.debug " TIME COST #{Time.now - t}"
68
+
49
69
  # sort, clean bad records
50
70
  process_data_internal
51
71
 
@@ -72,8 +92,11 @@ class DataLayer
72
92
 
73
93
  # Run external processor (smoothing, ...)
74
94
  def process!
95
+ t = Time.now
75
96
  @processed_data = @data.clone
76
97
  @processed_data = @processor.process
98
+ logger.debug "processed data using external processor"
99
+ logger.debug " TIME COST #{Time.now - t}"
77
100
  end
78
101
 
79
102
  # Additional parameters
@@ -84,10 +107,6 @@ class DataLayer
84
107
  return @data_params[:color]
85
108
  end
86
109
 
87
- def antialias
88
- return @data_params[:antialias]
89
- end
90
-
91
110
  def label
92
111
  return @data_params[:label]
93
112
  end
@@ -116,6 +135,10 @@ class DataLayer
116
135
  return @data_params[:simple_smoother_x]
117
136
  end
118
137
 
138
+ def perform_parameter_uniq
139
+ return @data_params[:perform_parameter_uniq] == true
140
+ end
141
+
119
142
  # Clear data
120
143
  def clear_data
121
144
  @data = Array.new
@@ -123,12 +146,24 @@ class DataLayer
123
146
 
124
147
  # Clean and process data used for drawing current data layer
125
148
  def process_data_internal
149
+ t = Time.now
150
+
126
151
  # delete duplicates
127
- @data = @data.inject([]) { |result, d| result << d unless result.select { |r| r.x == d.x }.size > 0; result }
152
+ if perform_parameter_uniq
153
+ @data = @data.inject([]) { |result, d| result << d unless result.select { |r| r.x == d.x }.size > 0; result }
154
+ end
155
+
156
+ logger.debug "internal processor - deleting duplicates"
157
+ logger.debug " TIME COST #{Time.now - t}"
158
+ t = Time.now
128
159
 
129
160
  @data.delete_if { |d| d.x.nil? or d.y.nil? }
130
161
  @data.sort! { |d, e| d.x <=> e.x }
131
162
 
163
+ logger.debug "internal processor - deleting nils and sorting"
164
+ logger.debug " TIME COST #{Time.now - t}"
165
+ t = Time.now
166
+
132
167
  # default X values, if data is not empty
133
168
  if @data.size > 0
134
169
  @data_params[:x_min] = @data.first.x || @options[:default_x_min]
@@ -139,6 +174,9 @@ class DataLayer
139
174
  @data_params[:y_min] = y_sort.first.y || @options[:default_y_min]
140
175
  @data_params[:y_max] = y_sort.last.y || @options[:@default_y_max]
141
176
  end
177
+
178
+ logger.debug "internal processor - setting min and max"
179
+ logger.debug " TIME COST #{Time.now - t}"
142
180
  end
143
181
 
144
182
  def x_min
@@ -9,6 +9,10 @@ class DataLayerProcessor
9
9
  include DataLayerProcessorSimpleSmoother
10
10
  include DataLayerProcessorNoiseRemoval
11
11
 
12
+ def logger
13
+ @data_layer.logger
14
+ end
15
+
12
16
  def initialize(data_layer)
13
17
  @data_layer = data_layer
14
18
  simple_smoother_initialize(data_params)
@@ -33,7 +37,6 @@ class DataLayerProcessor
33
37
  simple_smoother_initialize(data_params)
34
38
  noise_removal_initialize(data_params)
35
39
 
36
- # TODO add in options array to choose order of these methods
37
40
  noise_removal_process
38
41
  simple_smoother_process
39
42
 
@@ -23,7 +23,7 @@ module DataLayerProcessorNoiseRemoval
23
23
 
24
24
  @noises_removed_count = 0
25
25
 
26
- puts "Noise removal started"
26
+ logger.debug "Noise removal started"
27
27
 
28
28
  (0...data.size).each do |i|
29
29
  if not noise?(i)
@@ -33,7 +33,8 @@ module DataLayerProcessorNoiseRemoval
33
33
  end
34
34
  end
35
35
 
36
- puts "Noise removal completed, removed #{@noises_removed_count}, time #{Time.now - t}"
36
+ logger.debug "Noise removal completed, removed #{@noises_removed_count}"
37
+ logger.debug " TIME COST #{Time.now - t}"
37
38
 
38
39
  @data = new_data
39
40
  return new_data
@@ -52,27 +53,7 @@ module DataLayerProcessorNoiseRemoval
52
53
  i_from = noise_removal_window_from(i)
53
54
  i_to = noise_removal_window_to(i)
54
55
 
55
- # create partial array, TODO move it somewhere else
56
- part_array = Array.new
57
- border = false
58
-
59
- (i_from..i_to).each do |current_i|
60
- # outside ranges
61
- if current_i < 0
62
- part_array << data.first
63
- border = true
64
- next
65
- end
66
-
67
- if data.size <= current_i
68
- part_array << data.last
69
- border = true
70
- next
71
- end
72
-
73
- part_array << data[current_i]
74
-
75
- end
56
+ part_array = data.clone_partial_w_fill(i_from, i_to)
76
57
  y_mean = part_array.collect { |p| p.y }.float_mean
77
58
 
78
59
  # another algorithm
@@ -72,7 +72,8 @@ module DataLayerProcessorSimpleSmoother
72
72
 
73
73
  # pre-processing, distance
74
74
  if simple_smoother_x == true
75
- puts "X axis distance smoothing enabled"
75
+ logger.debug "X axis distance smoothing enabled"
76
+ t = Time.now
76
77
 
77
78
  (0...old_data.size).each do |i|
78
79
  new_data << DataPoint.xy(old_data[i].x, process_part(old_data, i, false))
@@ -80,15 +81,20 @@ module DataLayerProcessorSimpleSmoother
80
81
 
81
82
  old_data = new_data
82
83
  new_data = Array.new
84
+
85
+ logger.debug "X axis distance smoothing completed"
86
+ logger.debug " TIME COST #{Time.now - t}"
83
87
  end
84
88
 
85
- puts "Y axis distance smoothing"
89
+ logger.debug "Y axis distance smoothing"
90
+ t = Time.now
86
91
 
87
92
  (0...old_data.size).each do |i|
88
93
  new_data << DataPoint.xy(old_data[i].x, process_part(old_data, i))
89
94
  end
90
95
 
91
- puts "Smoothing completed, simple_smoother_level #{simple_smoother_level}, data size #{old_data.size}, time #{Time.now - t}"
96
+ logger.debug "Y axis Smoothing completed, simple_smoother_level #{simple_smoother_level}, data size #{old_data.size}"
97
+ logger.debug " TIME COST #{Time.now - t}"
92
98
 
93
99
  @data = new_data
94
100
  return new_data