technical_graph 0.5.1 → 0.6.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/Gemfile CHANGED
@@ -1,11 +1,32 @@
1
+ # hack for loading gems if they were are available to add
2
+ # some optional features
3
+ def gem_available?(name)
4
+ Gem::Specification.find_by_name(name)
5
+ rescue Gem::LoadError
6
+ false
7
+ rescue
8
+ Gem.available?(name)
9
+ end
10
+
11
+
1
12
  source "http://rubygems.org"
2
13
 
14
+ # SVG
3
15
  gem 'rasem'
4
16
 
5
- # optional gem
6
- if Gem.source_index.find_name('rmagick').size > 0
7
- gem 'rmagick'
8
- end
17
+ # PNG
18
+ gem 'chunky_png'
19
+ gem 'rmagick' if gem_available? 'rmagick'
20
+ gem 'oily_png' if gem_available? 'oily_png'
21
+
22
+ # optional gem - creating graphs using ImageMagic
23
+ #if Gem.source_index.find_name('rmagick').size > 0
24
+ # gem 'rmagick'
25
+ #end
26
+ # optional gem - chunky_png C addon
27
+ #if Gem.source_index.find_name('oily_png').size > 0
28
+ # gem 'oily_png'
29
+ #end
9
30
 
10
31
  # Add dependencies to develop your gem here.
11
32
  # Include everything needed to run rake, tests, features, etc.
@@ -15,5 +36,5 @@ group :development do
15
36
  gem "bundler", "~> 1.0.0"
16
37
  gem "rspec"
17
38
  gem "jeweler" #, "~> 1.6.4"
18
- gem "rcov", ">= 0"
39
+ gem "simplecov", ">= 0"
19
40
  end
data/Gemfile.lock CHANGED
@@ -1,36 +1,52 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ chunky_png (1.2.5)
4
5
  diff-lcs (1.1.3)
5
6
  git (1.2.5)
6
- jeweler (1.6.4)
7
+ jeweler (1.8.3)
7
8
  bundler (~> 1.0)
8
9
  git (>= 1.2.5)
9
10
  rake
10
- json (1.6.1)
11
+ rdoc
12
+ json (1.7.3)
13
+ multi_json (1.3.5)
14
+ oily_png (1.0.2)
15
+ chunky_png (~> 1.2.1)
11
16
  rake (0.9.2.2)
12
17
  rasem (0.6.1)
13
- rcov (0.9.11)
14
- rdoc (3.11)
18
+ rdoc (3.12)
15
19
  json (~> 1.4)
16
- rspec (2.7.0)
17
- rspec-core (~> 2.7.0)
18
- rspec-expectations (~> 2.7.0)
19
- rspec-mocks (~> 2.7.0)
20
- rspec-core (2.7.1)
21
- rspec-expectations (2.7.0)
22
- diff-lcs (~> 1.1.2)
23
- rspec-mocks (2.7.0)
24
- shoulda (2.11.3)
20
+ rmagick (2.13.1)
21
+ rspec (2.10.0)
22
+ rspec-core (~> 2.10.0)
23
+ rspec-expectations (~> 2.10.0)
24
+ rspec-mocks (~> 2.10.0)
25
+ rspec-core (2.10.1)
26
+ rspec-expectations (2.10.0)
27
+ diff-lcs (~> 1.1.3)
28
+ rspec-mocks (2.10.1)
29
+ shoulda (3.0.1)
30
+ shoulda-context (~> 1.0.0)
31
+ shoulda-matchers (~> 1.0.0)
32
+ shoulda-context (1.0.0)
33
+ shoulda-matchers (1.0.0)
34
+ simplecov (0.6.4)
35
+ multi_json (~> 1.0)
36
+ simplecov-html (~> 0.5.3)
37
+ simplecov-html (0.5.3)
25
38
 
26
39
  PLATFORMS
27
40
  ruby
28
41
 
29
42
  DEPENDENCIES
30
43
  bundler (~> 1.0.0)
44
+ chunky_png
31
45
  jeweler
46
+ oily_png
32
47
  rasem
33
- rcov
34
48
  rdoc
49
+ rmagick
35
50
  rspec
36
51
  shoulda
52
+ simplecov
data/README.md CHANGED
@@ -3,83 +3,113 @@ technical_graph
3
3
 
4
4
  Purpose of this gem is to create neat, meaningful, linear graphs for large amount of data.
5
5
 
6
- If you want to:
7
-
8
- * create big graphs using large amount of data,
9
- * do it offline,
6
+ When you want to:
7
+ * create big graph using large amount of data,
8
+ * do it offline and speed is not the most important factor,
10
9
  * minimize needed code,
11
10
  * use only linear graph,
12
- * speed is not essential,
13
11
  * RMagick / ImageMagick is ok for you,
14
12
  * tired of forgotten gems/libraries...
15
13
 
16
- then you should try this gem.
14
+ Then you should try this gem.
17
15
 
18
16
  I created it because there were not available and maintained gems for that I needed. Now I use it to create hourly
19
- temperature and wind graphs for vast period of time (months, years), visualize measurements for [HomeIO](https://github.com/akwiatkowski/HomeIO).
20
-
21
- If you want to create candy, ultra fast, web graphs it maybe not the best tool. If you want other graph types than linear it
22
- is definitely not the right tool for you. It is also not SVG ready yet, but it should be within a few months.
23
- You can find my competitors [here](https://www.ruby-toolbox.com/categories/graphing).
17
+ temperature and wind speed graphs for vast period of time (months, years), visualize measurements for [HomeIO](https://github.com/akwiatkowski/HomeIO).
24
18
 
19
+ If you want to create candy, ultra fast, web graphs it is maybe not the best tool. If you want other graph types than linear it
20
+ is definitely not the right tool for you. You can find my competitors [here](https://www.ruby-toolbox.com/categories/graphing).
25
21
 
26
22
  Future
27
23
  ------
28
24
 
29
- 1. Finish data processors: smoothing (nearly done), noise removal (50%), interpolation or curved graphs (planned).
30
- 2. Fix export to SVG.
31
- 3. Optimization, and if needed find or write something faster for creating SVGs.
32
-
25
+ 1. Curved graphs.
26
+ 2. Bug fixes, cleaning.
33
27
 
34
28
  Quick start
35
29
  -----------
36
30
 
37
- Check currents test when documentation is not enough :)
31
+ Check currents test if documentation is not enough :)
32
+
33
+ * Create 'the instance'
34
+
35
+ > tg = TechnicalGraph.new
36
+
37
+ or
38
+
39
+ > tg = TechnicalGraph.new( options )
40
+
41
+ where:
42
+
43
+ + options - Hash of parameters, all parameters are described [here](https://github.com/akwiatkowski/technical_graph/blob/master/DOCUMENTATION.textile).
44
+
45
+ * Add layer
46
+
47
+ > tg.add_layer(layer_data)
38
48
 
39
- 1. Create instance
49
+ or
40
50
 
41
- > tg = TechnicalGraph.new
51
+ > tg.add_layer(layer_data, layer_params)
42
52
 
43
- or
53
+ where:
44
54
 
45
- > tg = TechnicalGraph.new( options )
55
+ + layer_data - Array of Hashes, like [{:x => 0, :y => 0}, {:x => 1, :y => 1}, ...]
56
+ + layer_params - Hash of other parameters, all parameters are described [here](https://github.com/akwiatkowski/technical_graph/blob/master/DOCUMENTATION.textile).
46
57
 
47
- where:
58
+ * Save to file
48
59
 
49
- * options - Hash of parameters, all parameters are described below.
60
+ > tg.save_to_file('image.svg')
50
61
 
51
- 2. Add layer
62
+ or
52
63
 
53
- > tg.add_layer(layer_data)
64
+ > tg.save_to_file('image.svgz')
54
65
 
55
- or
66
+ or
56
67
 
57
- > tg.add_layer(layer_data, layer_params)
68
+ > tg.save_to_file('image.png')
69
+
70
+
71
+ or get binary version of output using
72
+
73
+ > tg.to_format(format) # where format is 'svg', 'svgz', 'png', ...
74
+
75
+
76
+ This is the new, easiest, better and nicer approach because technical_graph render graph
77
+ using appropriate drawer to file extension.
78
+
79
+
80
+ Some notes about formats and dependencies
81
+ -----------------------------------------
82
+
83
+ technical_graph uses [rasem](https://github.com/aseldawy/rasem) for SVG and it works wery well.
84
+ For PNG it uses [chunky_png](https://github.com/wvanbergen/chunky_png) with [oily_png](https://github.com/wvanbergen/oily_png)
85
+ if possible, but there is a lot of missing features. If you need PNG I recommend to install
86
+ good, old [rmagick](https://github.com/rmagick/rmagick).
87
+
88
+
89
+ An old way
90
+ -------------
58
91
 
59
- where:
92
+ Up to version 0.5.1 you had to render image before you could save it to file. It should work in current version too.
60
93
 
61
- * layer_data - Array of Hashes, like [{:x => 0, :y => 0}, {:x => 1, :y => 1}, ...]
62
- * layer_params - Hash of other parameters, all parameters are described later.
94
+ * Render graph
63
95
 
64
- 3. Render graph
96
+ > tg.render
65
97
 
66
- > tg.render
98
+ * Save to file
67
99
 
68
- 4. Save to file
100
+ > tg.image_drawer.save_to_file('image.png')
69
101
 
70
- > tg.image_drawer.save_to_file('image.png')
102
+ or get image binary content.
71
103
 
72
- or get image binary content.
104
+ > tg.image_drawer.to_format(format)
73
105
 
74
- > tg.image_drawer.to_format(format)
75
106
 
76
- where format is image format, ex. 'png', 'jpeg', ... Of course I prefer 'png'.
77
107
 
78
108
 
79
109
  Documentation
80
110
  -------------
81
111
 
82
- Documentation is moved [here](https://github.com/akwiatkowski/technical_graph/blob/master/DOCUMENTATION.textile)
112
+ Documentation was moved [here](https://github.com/akwiatkowski/technical_graph/blob/master/DOCUMENTATION.textile)
83
113
 
84
114
 
85
115
  Contributing to technical-graph
@@ -99,6 +129,5 @@ Contributing to technical-graph
99
129
  Copyright
100
130
  ---------
101
131
 
102
- Copyright (c) 2011 Aleksander Kwiatkowski. See LICENSE.txt for
103
- further details.
132
+ Copyright (c) 2011-2012 Aleksander Kwiatkowski. See LICENSE.txt for further details.
104
133
 
data/Rakefile CHANGED
@@ -41,29 +41,31 @@ desc "Clean and release"
41
41
  task :clean_and_release => [:clean, :release] do
42
42
  end
43
43
 
44
- require 'rake/testtask'
45
- Rake::TestTask.new(:test) do |test|
46
- test.libs << 'lib' << 'test'
47
- test.pattern = 'test/**/test_*.rb'
48
- test.verbose = true
44
+ require 'rspec/core'
45
+ require 'rspec/core/rake_task'
46
+ RSpec::Core::RakeTask.new(:spec) do |spec|
47
+ spec.pattern = FileList['spec/**/*_spec.rb']
49
48
  end
50
49
 
51
- require 'rcov/rcovtask'
52
- Rcov::RcovTask.new do |test|
53
- test.libs << 'test'
54
- test.pattern = 'test/**/test_*.rb'
55
- test.verbose = true
56
- test.rcov_opts << '--exclude "gems/*"'
50
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
51
+ spec.pattern = 'spec/**/*_spec.rb'
52
+ spec.rcov = true
57
53
  end
58
54
 
59
- task :default => :test
55
+ task :default => :spec
60
56
 
61
- require 'rdoc/task'
57
+ require 'rake/rdoctask'
62
58
  Rake::RDocTask.new do |rdoc|
63
59
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
64
60
 
65
61
  rdoc.rdoc_dir = 'rdoc'
66
- rdoc.title = "technical-graph #{version}"
62
+ rdoc.title = "gpx2exif #{version}"
67
63
  rdoc.rdoc_files.include('README*')
68
64
  rdoc.rdoc_files.include('lib/**/*.rb')
69
65
  end
66
+
67
+ desc "Run RSpec with code coverage"
68
+ task :coverage do
69
+ `rake spec COVERAGE=true`
70
+ #`open coverage/index.html`
71
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.1
1
+ 0.6.0
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'logger'
5
+ require 'technical_graph/gem'
5
6
  require 'technical_graph/data_layer'
6
7
  require 'technical_graph/graph_data_processor'
7
8
  require 'technical_graph/graph_image_drawer'
@@ -71,4 +72,48 @@ class TechnicalGraph
71
72
  # draw legend
72
73
  @image_drawer.render_data_legend
73
74
  end
75
+
76
+ # Render and save graph to a file
77
+ def save_to_file(filename)
78
+ ext = File.extname(filename).gsub(/^\./, '')
79
+ pre_render(ext)
80
+ @image_drawer.save_to_file(filename)
81
+ end
82
+
83
+ # Render and return graph string
84
+ def to_format(ext)
85
+ pre_render(ext)
86
+ @image_drawer.to_format(ext)
87
+ end
88
+
89
+ # You don't have to run this
90
+ def pre_render(ext)
91
+ case ext
92
+ when 'svg', 'svgz' then
93
+ @options[:drawer_class] = :rasem
94
+ render
95
+
96
+ when 'png' then
97
+ if gem_available?('rmagick')
98
+ # rmagick is at the moment the best solution
99
+ @options[:drawer_class] = :rmagick
100
+ else
101
+ @options[:drawer_class] = :chunky_png
102
+ end
103
+ render
104
+
105
+ when 'jpeg', 'jpg', 'bmp', 'gif' then
106
+ if rmagick_installed?
107
+ @options[:drawer_class] = :rmagick
108
+ render
109
+ else
110
+ raise Gem::LoadError
111
+ end
112
+
113
+ else
114
+ raise ArgumentError
115
+
116
+ end
117
+ end
118
+
74
119
  end
@@ -6,7 +6,7 @@ module DataLayerProcessorSimpleSmoother
6
6
  :rectangular => 'generate_vector_rectangular',
7
7
  :gauss => 'generate_vector_gauss'
8
8
  }
9
- DEFAULT_SIMPLE_SMOOTHER_STRATEGY = :rectangular
9
+ DEFAULT_SIMPLE_SMOOTHER_STRATEGY = :gauss
10
10
 
11
11
  MIN_SIMPLE_SMOOTHER_LEVEL = 1
12
12
  MAX_SIMPLE_SMOOTHER_LEVEL = 200
@@ -0,0 +1,12 @@
1
+ def gem_available?(name)
2
+ Gem::Specification.find_by_name(name)
3
+ rescue Gem::LoadError
4
+ false
5
+ rescue
6
+ Gem.available?(name)
7
+ end
8
+
9
+ # Check if rmagick is installed
10
+ def rmagick_installed?
11
+ gem_available?('rmagick')
12
+ end
@@ -6,6 +6,9 @@ class GraphAxis
6
6
 
7
7
  attr_reader :technical_graph
8
8
 
9
+ # some issues with float precision and rounding
10
+ SAFE_ENL_COEFF = 1.1
11
+
9
12
  # Accessor for options Hash
10
13
  def options
11
14
  @technical_graph.options
@@ -125,10 +128,10 @@ class GraphAxis
125
128
 
126
129
  # Enlarge image to maintain proper axis density
127
130
  def axis_distance_image_enlarge
128
- if options[:axis_density_enlarge_image]
131
+ if options[:axis_density_enlarge_image] or options[:x_axis_density_enlarge_image] or options[:y_axis_density_enlarge_image]
129
132
  t = Time.now
130
- x_axis_distance_image_enlarge
131
- y_axis_distance_image_enlarge
133
+ x_axis_distance_image_enlarge if options[:axis_density_enlarge_image] or options[:x_axis_density_enlarge_image]
134
+ y_axis_distance_image_enlarge if options[:axis_density_enlarge_image] or options[:y_axis_density_enlarge_image]
132
135
 
133
136
  logger.debug "axis enlarged"
134
137
  logger.debug " TIME COST #{Time.now - t}"
@@ -143,9 +146,9 @@ class GraphAxis
143
146
  return if a.size < 2
144
147
 
145
148
  ax = a[0]
146
- ax = image.calc_bitmap_y(ax).round
149
+ ax = image.calc_bitmap_x(ax).round
147
150
  bx = a[1]
148
- bx = image.calc_bitmap_y(bx).round
151
+ bx = image.calc_bitmap_x(bx).round
149
152
 
150
153
  axis_distance = (bx - ax).abs
151
154
 
@@ -153,7 +156,9 @@ class GraphAxis
153
156
  if axis_distance < options[:x_axis_min_distance]
154
157
  # enlarging image
155
158
  options[:old_width] = options[:width]
156
- options[:width] *= (options[:x_axis_min_distance] / axis_distance).ceil
159
+ options[:width] = options[:width].to_f * (options[:x_axis_min_distance].to_f / axis_distance.to_f)
160
+ options[:width] *= SAFE_ENL_COEFF
161
+ options[:width] = options[:width].ceil
157
162
  logger.debug "axis enlarged - width modified to #{options[:width]}"
158
163
  end
159
164
  end
@@ -176,7 +181,9 @@ class GraphAxis
176
181
  if axis_distance < options[:y_axis_min_distance]
177
182
  # enlarging image
178
183
  options[:old_height] = options[:height]
179
- options[:height] *= (options[:y_axis_min_distance] / axis_distance).ceil
184
+ options[:height] = options[:height].to_f * (options[:y_axis_min_distance].to_f / axis_distance.to_f)
185
+ options[:height] *= SAFE_ENL_COEFF
186
+ options[:height] = options[:height].ceil
180
187
  logger.debug "axis enlarged - height modified from #{options[:old_height]} to #{options[:height]}"
181
188
  end
182
189
  end