gruff 0.3.6 → 0.3.7

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.
@@ -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