technical_graph 0.3.2 → 0.4.0

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/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