gruff 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ /.idea/
2
+ /pkg/
3
+ .DS_Store
4
+ /test/output
5
+ .bundle
6
+ .yardoc
data/.rvmrc ADDED
@@ -0,0 +1,5 @@
1
+ if [[ -n "$rvm_environments_path" && -s "$rvm_environments_path/ree-1.8.7-2010.02@gruff" ]] ; then
2
+ . "$rvm_environments_path/ree-1.8.7-2010.02@gruff"
3
+ else
4
+ rvm --create use "ree-1.8.7-2010.02@gruff"
5
+ fi
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.8.7"
4
+ - "1.9.3"
5
+ - jruby-18mode # JRuby in 1.8 mode
6
+ - jruby-19mode # JRuby in 1.9 mode
7
+ - rbx-18mode
8
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gruff.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+
9
+ platform :ruby do
10
+ gem 'rmagick'
11
+ end
12
+
13
+ platform :jruby do
14
+ gem 'rmagick4j'
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gruff (0.3.7)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (0.9.2.2)
10
+ rmagick4j (0.3.7)
11
+
12
+ PLATFORMS
13
+ java
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ gruff!
18
+ rake
19
+ rmagick
20
+ rmagick4j
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Uwe Kubosch
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # Gruff Graphs
2
+
3
+ A library for making beautiful graphs.
4
+
5
+ ## WARNING
6
+
7
+ This is beta-quality software. It works well according to our tests,
8
+ but the API may change and other features will be added.
9
+ We are working to make Gruff production quality software.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'gruff'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install gruff
24
+
25
+ ## Usage
26
+
27
+ See the test suite in test/line_test.rb for examples.
28
+
29
+ ## Samples
30
+
31
+ http://nubyonrails.com/pages/gruff
32
+
33
+ ## Documentation
34
+
35
+ http://gruff.rubyforge.org
36
+
37
+ ## Contributing
38
+
39
+ == Source
40
+
41
+ The source for this project is now kept at GitHub:
42
+
43
+ http://github.com/topfunky/gruff/tree/master
44
+
45
+ 1. Fork it
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create new Pull Request
data/README.txt CHANGED
@@ -1,3 +1,6 @@
1
+ == MAIN FIX
2
+ Zero Division Problem
3
+
1
4
  == Gruff Graphs
2
5
 
3
6
  A library for making beautiful graphs.
data/Rakefile CHANGED
@@ -1,55 +1,38 @@
1
- require 'rubygems'
2
- require 'hoe'
1
+ require "rubygems"
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ require 'rake/clean'
3
6
  $:.unshift(File.dirname(__FILE__) + "/lib")
4
- require 'gruff'
5
7
 
6
- Hoe.new('Gruff', Gruff::VERSION) do |p|
7
- p.name = "gruff"
8
- p.author = "Geoffrey Grosenbach"
9
- p.description = "Beautiful graphs for one or multiple datasets. Can be used on websites or in documents."
10
- p.email = 'boss@topfunky.com'
11
- p.summary = "Beautiful graphs for one or multiple datasets."
12
- p.url = "http://nubyonrails.com/pages/gruff"
13
- p.clean_globs = ['test/output/*.png']
14
- p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
15
- p.remote_rdoc_dir = '' # Release to root
16
- end
8
+ CLEAN << ['pkg', 'test/output/*']
17
9
 
18
- desc "Simple require on packaged files to make sure they are all there"
19
- task :verify => :package do
20
- # An error message will be displayed if files are missing
21
- if system %(ruby -e "require 'pkg/gruff-#{Gruff::VERSION}/lib/gruff'")
22
- puts "\nThe library files are present"
23
- end
24
- raise "\n*** Gruff::Base::DEBUG must be set to false for releases ***\n\n" if Gruff::Base::DEBUG
25
- end
10
+ desc "Run tests"
11
+ task :default => :test
26
12
 
27
- task :release => :verify
13
+ Rake::TestTask.new do |t|
14
+ t.libs << 'test'
15
+ end
28
16
 
29
17
  namespace :test do
30
-
31
18
  desc "Run mini tests"
32
19
  task :mini => :clean do
33
20
  Dir['test/test_mini*'].each do |file|
34
21
  system "ruby #{file}"
35
22
  end
36
-
37
23
  end
38
-
39
24
  end
40
25
 
41
26
  ##
42
27
  # Catch unmatched tasks and run them as a unit test.
43
- #
44
28
  # Makes it possible to do
45
29
  #
46
30
  # rake pie
47
31
  #
48
32
  # To run the +test/test_pie+ and +test/test_mini_pie+ files.
49
-
50
- rule '' do |t|
51
- # Rake::Task["clean"].invoke
52
- Dir["test/test_*#{t.name}*.rb"].each do |filename|
53
- system "ruby #{filename}"
54
- end
55
- end
33
+ #rule '' do |t|
34
+ # # Rake::Task["clean"].invoke
35
+ # Dir["test/test_*#{t.name}*.rb"].each do |filename|
36
+ # system "ruby #{filename}"
37
+ # end
38
+ #end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gruff/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gruff}
8
+ s.version = Gruff::VERSION
9
+
10
+ # s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ['Geoffrey Grosenbach', 'Uwe Kubosch']
12
+ # s.date = Date.today.to_s
13
+ s.description = %q{Beautiful graphs for one or multiple datasets. Can be used on websites or in documents.}
14
+ s.email = %q{boss@topfunky.com}
15
+ # s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
16
+ # s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.txt", "Rakefile", "assets/bubble.png", "assets/city_scene/background/0000.png", "assets/city_scene/background/0600.png", "assets/city_scene/background/2000.png", "assets/city_scene/clouds/cloudy.png", "assets/city_scene/clouds/partly_cloudy.png", "assets/city_scene/clouds/stormy.png", "assets/city_scene/grass/default.png", "assets/city_scene/haze/true.png", "assets/city_scene/number_sample/1.png", "assets/city_scene/number_sample/2.png", "assets/city_scene/number_sample/default.png", "assets/city_scene/sky/0000.png", "assets/city_scene/sky/0200.png", "assets/city_scene/sky/0400.png", "assets/city_scene/sky/0600.png", "assets/city_scene/sky/0800.png", "assets/city_scene/sky/1000.png", "assets/city_scene/sky/1200.png", "assets/city_scene/sky/1400.png", "assets/city_scene/sky/1500.png", "assets/city_scene/sky/1700.png", "assets/city_scene/sky/2000.png", "assets/pc306715.jpg", "assets/plastik/blue.png", "assets/plastik/green.png", "assets/plastik/red.png", "init.rb", "lib/gruff.rb", "lib/gruff/accumulator_bar.rb", "lib/gruff/area.rb", "lib/gruff/bar.rb", "lib/gruff/bar_conversion.rb", "lib/gruff/base.rb", "lib/gruff/bullet.rb", "lib/gruff/deprecated.rb", "lib/gruff/dot.rb", "lib/gruff/line.rb", "lib/gruff/mini/bar.rb", "lib/gruff/mini/legend.rb", "lib/gruff/mini/pie.rb", "lib/gruff/mini/side_bar.rb", "lib/gruff/net.rb", "lib/gruff/photo_bar.rb", "lib/gruff/pie.rb", "lib/gruff/scene.rb", "lib/gruff/side_bar.rb", "lib/gruff/side_stacked_bar.rb", "lib/gruff/spider.rb", "lib/gruff/stacked_area.rb", "lib/gruff/stacked_bar.rb", "lib/gruff/stacked_mixin.rb", "rails_generators/gruff/gruff_generator.rb", "rails_generators/gruff/templates/controller.rb", "rails_generators/gruff/templates/functional_test.rb", "test/gruff_test_case.rb", "test/test_accumulator_bar.rb", "test/test_area.rb", "test/test_bar.rb", "test/test_base.rb", "test/test_bullet.rb", "test/test_dot.rb", "test/test_legend.rb", "test/test_line.rb", "test/test_mini_bar.rb", "test/test_mini_pie.rb", "test/test_mini_side_bar.rb", "test/test_net.rb", "test/test_photo.rb", "test/test_pie.rb", "test/test_scene.rb", "test/test_side_bar.rb", "test/test_sidestacked_bar.rb", "test/test_spider.rb", "test/test_stacked_area.rb", "test/test_stacked_bar.rb"]
17
+ s.files = `git ls-files`.split($/)
18
+ # s.has_rdoc = true
19
+ s.homepage = %q{http://nubyonrails.com/pages/gruff}
20
+ # s.rdoc_options = ["--main", "README.txt"]
21
+ s.require_paths = ["lib"]
22
+ # s.rubyforge_project = %q{gruff}
23
+ # s.rubygems_version = %q{1.3.1}
24
+ s.summary = %q{Beautiful graphs for one or multiple datasets.}
25
+ # s.test_files = ["test/test_accumulator_bar.rb", "test/test_area.rb", "test/test_bar.rb", "test/test_base.rb", "test/test_bullet.rb", "test/test_dot.rb", "test/test_legend.rb", "test/test_line.rb", "test/test_mini_bar.rb", "test/test_mini_pie.rb", "test/test_mini_side_bar.rb", "test/test_net.rb", "test/test_photo.rb", "test/test_pie.rb", "test/test_scene.rb", "test/test_side_bar.rb", "test/test_sidestacked_bar.rb", "test/test_spider.rb", "test/test_stacked_area.rb", "test/test_stacked_bar.rb"]
26
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
27
+
28
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
29
+
30
+ # s.specification_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
31
+ # s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
32
+ # s.add_dependency(%q<rmagick>, [">= 2.12.2"])
33
+ end
@@ -1,3 +1,5 @@
1
+ require "gruff/version"
2
+
1
3
  # Extra full path added to fix loading errors on some installations.
2
4
 
3
5
  %w(
@@ -9,6 +11,7 @@
9
11
  pie
10
12
  spider
11
13
  net
14
+ scatter
12
15
  stacked_area
13
16
  stacked_bar
14
17
  side_stacked_bar
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'RMagick'
3
+ require 'bigdecimal'
3
4
 
4
5
  require File.dirname(__FILE__) + '/deprecated'
5
6
 
@@ -18,10 +19,6 @@ require File.dirname(__FILE__) + '/deprecated'
18
19
  # See Gruff::Base#theme= for setting themes.
19
20
 
20
21
  module Gruff
21
-
22
- # This is the version of Gruff you are using.
23
- VERSION = '0.3.6'
24
-
25
22
  class Base
26
23
 
27
24
  include Magick
@@ -34,6 +31,7 @@ module Gruff
34
31
  DATA_LABEL_INDEX = 0
35
32
  DATA_VALUES_INDEX = 1
36
33
  DATA_COLOR_INDEX = 2
34
+ DATA_VALUES_X_INDEX = 3
37
35
 
38
36
  # Space around text elements. Mostly used for vertical spacing
39
37
  LEGEND_MARGIN = TITLE_MARGIN = 20.0
@@ -41,7 +39,7 @@ module Gruff
41
39
  DEFAULT_MARGIN = 20.0
42
40
 
43
41
  DEFAULT_TARGET_WIDTH = 800
44
-
42
+
45
43
  THOUSAND_SEPARATOR = ','
46
44
 
47
45
  # Blank space above the graph
@@ -55,10 +53,10 @@ module Gruff
55
53
 
56
54
  # Blank space to the left of the graph
57
55
  attr_accessor :left_margin
58
-
56
+
59
57
  # Blank space below the title
60
58
  attr_accessor :title_margin
61
-
59
+
62
60
  # Blank space below the legend
63
61
  attr_accessor :legend_margin
64
62
 
@@ -223,7 +221,7 @@ module Gruff
223
221
  @marker_font_size = 21.0
224
222
  @legend_font_size = 20.0
225
223
  @title_font_size = 36.0
226
-
224
+
227
225
  @top_margin = @bottom_margin = @left_margin = @right_margin = DEFAULT_MARGIN
228
226
  @legend_margin = LEGEND_MARGIN
229
227
  @title_margin = TITLE_MARGIN
@@ -698,7 +696,8 @@ module Gruff
698
696
  @d = @d.fill(@marker_color)
699
697
  @d = @d.line(@graph_left, y, @graph_right, y)
700
698
 
701
- marker_label = index * @increment + @minimum_value.to_f
699
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) +
700
+ BigDecimal(@minimum_value.to_s)
702
701
 
703
702
  unless @hide_line_numbers
704
703
  @d.fill = @font_color
@@ -977,9 +976,10 @@ module Gruff
977
976
  data_point
978
977
  end
979
978
 
980
- def significant(inc) # :nodoc:
981
- return 1.0 if inc == 0 # Keep from going into infinite loop
982
- factor = 1.0
979
+ def significant(i) # :nodoc:
980
+ return 1.0 if i == 0 # Keep from going into infinite loop
981
+ inc = BigDecimal(i.to_s)
982
+ factor = BigDecimal('1.0')
983
983
  while (inc < 10)
984
984
  inc *= 10
985
985
  factor /= 10
@@ -1063,7 +1063,7 @@ module Gruff
1063
1063
  # Return a formatted string representing a number value that should be
1064
1064
  # printed as a label.
1065
1065
  def label(value)
1066
- label = if (@spread.to_f % @marker_count.to_f == 0) || !@y_axis_increment.nil?
1066
+ label = if (@spread.to_f % (@marker_count.to_f==0 ? 1 : @marker_count.to_f) == 0) || !@y_axis_increment.nil?
1067
1067
  value.to_i.to_s
1068
1068
  elsif @spread > 10.0
1069
1069
  sprintf("%0i", value)
@@ -1072,7 +1072,7 @@ module Gruff
1072
1072
  else
1073
1073
  value.to_s
1074
1074
  end
1075
-
1075
+
1076
1076
  parts = label.split('.')
1077
1077
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{THOUSAND_SEPARATOR}")
1078
1078
  parts.join('.')
@@ -1085,6 +1085,7 @@ module Gruff
1085
1085
  # handle.
1086
1086
  def calculate_caps_height(font_size)
1087
1087
  @d.pointsize = font_size
1088
+ @d.font = @font if @font
1088
1089
  @d.get_type_metrics(@base_image, 'X').height
1089
1090
  end
1090
1091
 
@@ -1093,7 +1094,9 @@ module Gruff
1093
1094
  # Not scaled since it deals with dimensions that the regular
1094
1095
  # scaling will handle.
1095
1096
  def calculate_width(font_size, text)
1097
+ return 0 if text.nil?
1096
1098
  @d.pointsize = font_size
1099
+ @d.font = @font if @font
1097
1100
  @d.get_type_metrics(@base_image, text.to_s).width
1098
1101
  end
1099
1102
 
@@ -16,7 +16,7 @@ class Gruff::Line < Gruff::Base
16
16
 
17
17
  # Draw a dashed line at the given value
18
18
  attr_accessor :baseline_value
19
-
19
+
20
20
  # Color of the baseline
21
21
  attr_accessor :baseline_color
22
22
 
@@ -26,6 +26,10 @@ class Gruff::Line < Gruff::Base
26
26
 
27
27
  # Hide parts of the graph to fit more datapoints, or for a different appearance.
28
28
  attr_accessor :hide_dots, :hide_lines
29
+
30
+ #accessors for support of xy data
31
+ attr_accessor :minimum_x_value
32
+ attr_accessor :maximum_x_value
29
33
 
30
34
  # Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
31
35
  #
@@ -34,7 +38,7 @@ class Gruff::Line < Gruff::Base
34
38
  # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
35
39
  #
36
40
  # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
37
- #
41
+ #
38
42
  # The preferred way is to call hide_dots or hide_lines instead.
39
43
  def initialize(*args)
40
44
  raise ArgumentError, "Wrong number of arguments" if args.length > 2
@@ -43,20 +47,95 @@ class Gruff::Line < Gruff::Base
43
47
  else
44
48
  super args.shift
45
49
  end
46
-
50
+
47
51
  @hide_dots = @hide_lines = false
48
52
  @baseline_color = 'red'
49
53
  @baseline_value = nil
54
+ @maximum_x_value = nil
55
+ @minimum_x_value = nil
56
+ end
57
+
58
+ # This method allows one to plot a dataset with both X and Y data.
59
+ #
60
+ # Parameters are as follows:
61
+ # name: string, the title of the dataset
62
+ # x_data_points: an array containing the x data points for the graph
63
+ # y_data_points: an array containing the y data points for the graph
64
+ # color: hex number indicating the line color as an RGB triplet
65
+ #
66
+ # Notes:
67
+ # -if (x_data_points.length != y_data_points.length) an error is
68
+ # returned.
69
+ # -if the color argument is nil, the next color from the default theme will
70
+ # be used.
71
+ # -if you want to use a preset theme, you must set it before calling
72
+ # dataxy().
73
+ #
74
+ # Example:
75
+ # g = Gruff::Line.new
76
+ # g.title = "X/Y Dataset"
77
+ # g.dataxy("Apples", [1,3,4,5,6,10], [1, 2, 3, 4, 4, 3])
78
+ # g.dataxy("Bapples", [1,3,4,5,7,9], [1, 1, 2, 2, 3, 3])
79
+ # #you can still use the old data method too if you want:
80
+ # g.data("Capples", [1, 1, 2, 2, 3, 3])
81
+ # #labels will be drawn at the x locations of the 1st dataset that you
82
+ # #passed in. In this example the lables are drawn at x locations 1,4,6
83
+ # g.labels = {0 => '2003', 2 => '2004', 4 => '2005'} #labels
84
+
85
+ def dataxy(name, x_data_points=[], y_data_points=[], color=nil)
86
+ raise ArgumentError, "x_data_points is nil!" if x_data_points.length == 0
87
+
88
+ if x_data_points.all?{|p| p.size == 2}
89
+ x_data_points, y_data_points = x_data_points.map{|p| p[0]}, x_data_points.map{|p| p[1]}
90
+ end
91
+
92
+ raise ArgumentError, "x_data_points.length != y_data_points.length!" if x_data_points.length != y_data_points.length
93
+
94
+ #call the existing data routine for the y data.
95
+ self.data(name, y_data_points, color)
96
+
97
+ x_data_points = Array(x_data_points) # make sure it's an array
98
+ #append the x data to the last entry that was just added in the @data member
99
+ lastElem = @data.length()-1
100
+ @data[lastElem][DATA_VALUES_X_INDEX] = x_data_points
101
+
102
+ # Update the global min/max values for the x data
103
+ x_data_points.each_with_index do |x_data_point, index|
104
+ next if x_data_point.nil?
105
+
106
+ # Setup max/min so spread starts at the low end of the data points
107
+ if @maximum_x_value.nil? && @minimum_x_value.nil?
108
+ @maximum_x_value = @minimum_x_value = x_data_point
109
+ end
110
+
111
+ @maximum_x_value = (x_data_point > @maximum_x_value) ?
112
+ x_data_point : @maximum_x_value
113
+ @minimum_x_value = (x_data_point < @minimum_x_value) ?
114
+ x_data_point : @minimum_x_value
115
+ end
116
+
50
117
  end
51
118
 
52
119
  def draw
53
120
  super
54
121
 
55
122
  return unless @has_data
56
-
57
- # Check to see if more than one datapoint was given. NaN can result otherwise.
123
+
124
+ # Check to see if more than one datapoint was given. NaN can result otherwise.
58
125
  @x_increment = (@column_count > 1) ? (@graph_width / (@column_count - 1).to_f) : @graph_width
59
126
 
127
+ #normalize the x data if it is specified
128
+ @data.each_with_index do |data_row, index|
129
+ norm_x_data_points = []
130
+ if (data_row[DATA_VALUES_X_INDEX] != nil)
131
+ data_row[DATA_VALUES_X_INDEX].each do |x_data_point|
132
+ norm_x_data_points << ( (x_data_point.to_f - @minimum_x_value.to_f ) /
133
+ (@maximum_x_value.to_f - @minimum_x_value.to_f) )
134
+ end
135
+ @norm_data[index] << norm_x_data_points
136
+ end
137
+ end
138
+
60
139
  if (defined?(@norm_baseline)) then
61
140
  level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
62
141
  @d = @d.push
@@ -68,15 +147,22 @@ class Gruff::Line < Gruff::Base
68
147
  @d = @d.pop
69
148
  end
70
149
 
71
- @norm_data.each do |data_row|
150
+ @norm_data.each_with_index do |data_row, dr_index|
72
151
  prev_x = prev_y = nil
73
152
 
74
153
  @one_point = contains_one_point_only?(data_row)
75
154
 
76
155
  data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
77
- new_x = @graph_left + (@x_increment * index)
78
156
  next if data_point.nil?
79
157
 
158
+ x_data = data_row[DATA_VALUES_X_INDEX]
159
+ if (x_data == nil)
160
+ #use the old method: equally spaced points along the x-axis
161
+ new_x = @graph_left + (@x_increment * index)
162
+ else
163
+ new_x = getXCoord(x_data[index], @graph_width, @graph_left)
164
+ end
165
+
80
166
  draw_label(new_x, index)
81
167
 
82
168
  new_y = @graph_top + (@graph_height - data_point * @graph_height)
@@ -92,7 +178,7 @@ class Gruff::Line < Gruff::Base
92
178
  circle_radius = dot_radius ||
93
179
  clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
94
180
 
95
- if !@hide_lines and !prev_x.nil? and !prev_y.nil? then
181
+ if !@hide_lines and !prev_x.nil? and !prev_y.nil? then
96
182
  @d = @d.line(prev_x, prev_y, new_x, new_y)
97
183
  elsif @one_point
98
184
  # Show a circle if there's just one_point
@@ -114,6 +200,14 @@ class Gruff::Line < Gruff::Base
114
200
  super
115
201
  @norm_baseline = (@baseline_value.to_f / @maximum_value.to_f) if @baseline_value
116
202
  end
203
+
204
+ def sort_norm_data
205
+ super unless @data.any?{|d| d[DATA_VALUES_X_INDEX]}
206
+ end
207
+
208
+ def getXCoord(x_data_point, width, offset)
209
+ return(x_data_point * width + offset)
210
+ end
117
211
 
118
212
  def contains_one_point_only?(data_row)
119
213
  # Spin through data to determine if there is just one_value present.
@@ -123,10 +217,9 @@ class Gruff::Line < Gruff::Base
123
217
  if one_point
124
218
  # more than one point, bail
125
219
  return false
126
- else
127
- # there is at least one data point
128
- return true
129
220
  end
221
+ # there is at least one data point
222
+ one_point = true
130
223
  end
131
224
  end
132
225
  return one_point