<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/array.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -3,6 +3,8 @@ $:.unshift(File.dirname(__FILE__)) unless
 
 require 'cgi'
 
+require 'array'
+
 require 'google_chart/axis'
 require 'google_chart/bar_style'
 require 'google_chart/color'</diff>
      <filename>lib/google_chart.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,5 @@
+require 'matrix'
+
 module GoogleChart
   class BarChart &lt; AbstractChart
     include Axis
@@ -10,7 +12,7 @@ module GoogleChart
     include Title
     
     @@orientations = {:horizontal =&gt; 'h', :vertical =&gt; 'v'}
-    @@groupings    = {:grouped    =&gt; 'g', :stacked  =&gt; 's'}
+    @@groupings    = {:group =&gt; 'g', :stack =&gt; 's', :overlap =&gt; 's'}
     
     attr_writer :orientation, :grouping
     
@@ -18,14 +20,38 @@ module GoogleChart
       self.orientation = arg ? :horizontal : :vertical
     end
     
-    def grouped=(arg)
-      self.grouping = arg ? :grouped : :stacked
-    end
-    
     def chart_type
-      @grouping    ||= :stacked
+      @grouping    ||= :group
       @orientation ||= :vertical
       &quot;cht=b#{@@orientations[@orientation]}#{@@groupings[@grouping]}&quot;
     end
+    
+    private
+    def reduce(data)
+      if @grouping == :overlap
+        # FIXME: This is really ugly!
+        (data.size - 1).downto(1) do |i|
+          data[i].size.times do |j|
+            data[i][j] -= data[0...i].map {|set|
+              set[j].nil? || set[j] &lt; 0 ? 0 : set[j]
+            }.sum
+          end
+        end
+        data
+      else
+        super
+      end
+    end
+    
+    def set_scale
+      if @grouping == :stack
+        if @scale.nil? &amp;&amp; !@data.nil?
+          min = [0, @data.map {|set| set.compact.min }.compact.min].max
+          max = Matrix[*@data].column_vectors.map {|v| v.to_a.compact.sum }.max
+          @scale = min..max
+        end
+      end
+      super
+    end
   end
 end</diff>
      <filename>lib/google_chart/bar_chart.rb</filename>
    </modified>
    <modified>
      <diff>@@ -19,7 +19,8 @@ module GoogleChart
     end
     
     def data
-      'chd=' + send(:&quot;#{encoding}_encode&quot;, @data) if @data
+      set_scale
+      'chd=' + send(:&quot;#{encoding}_encode&quot;, reduce(@data)) if @data
     end
     
     private
@@ -27,17 +28,22 @@ module GoogleChart
       @encoding ||= :simple
     end
     
-    def scale
-      if @scale.nil?
-        min = [0, @data.map {|set| set.compact.min }.compact.min].min
+    def set_scale
+      if @scale.nil? &amp;&amp; !@data.nil?
+        min = @data.map {|set| set.compact.min }.compact.min
+        min = 0 if min &gt; 0
         max = @data.map {|set| set.compact.max }.compact.max
         @scale = min..max
       end
       @scale
     end
     
+    def reduce(data)
+      data
+    end
+    
     def normalize(set, encoding_max)
-      min, max = scale.first, scale.last
+      min, max = @scale.first, @scale.last
       if min != max
         set.map {|e| (e.to_f - min) / (max - min) * encoding_max if e }
       else
@@ -52,7 +58,7 @@ module GoogleChart
           when e.nil? then '_'
           when e &lt;= 0 then @@simple[0]
           when e &gt;= @@simple.size then @@simple[-1]
-          else @@simple[e.round]
+          else @@simple[e.floor]
           end
         }.join
       }.join(',')
@@ -65,7 +71,7 @@ module GoogleChart
           when e.nil? then '__'
           when e &lt;= 0 then @@extended[0]
           when e &gt;= @@extended.size then @@extended[-1]
-          else @@extended[e.round]
+          else @@extended[e.floor]
           end
         }.join
       }.join(',')</diff>
      <filename>lib/google_chart/data.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,19 +2,94 @@ require File.dirname(__FILE__) + '/../test_helper'
 
 class TestBarChart &lt; Test::Unit::TestCase
   should 'have a default chart type' do
-    assert_match(/\bcht=bvs\b/, GoogleChart::BarChart.new.to_url)
+    assert_match(/\bcht=bvg\b/, GoogleChart::BarChart.new.to_url)
   end
   
   should 'support horizontal orientation' do
-    assert_match(/\bcht=bhs\b/, GoogleChart::BarChart.new(:horizontal =&gt; true).to_url)
+    assert_match(/\bcht=bhg\b/, GoogleChart::BarChart.new(:horizontal =&gt; true).to_url)
   end
   
-  should 'support grouped grouping' do
-    assert_match(/\bcht=bvg\b/, GoogleChart::BarChart.new(:grouped =&gt; true).to_url)
+  should 'support grouping' do
+    assert_match(/\bcht=bvg\b/, GoogleChart::BarChart.new(:grouping =&gt; :group).to_url)
   end
   
-  should 'support horizontal orientation and grouped grouping' do
-    assert_match(/\bcht=bhg\b/, GoogleChart::BarChart.new(:horizontal =&gt; true, :grouped =&gt; true).to_url)
+  should 'support stacking' do
+    assert_match(/\bcht=bvs\b/, GoogleChart::BarChart.new(:grouping =&gt; :stack).to_url)
+  end
+  
+  should 'support overlapping as alias for stacking' do
+    assert_match(/\bcht=bvs\b/, GoogleChart::BarChart.new(:grouping =&gt; :overlap).to_url)
+  end
+  
+  should 'support horizontal orientation with grouping' do
+    assert_match(/\bcht=bhg\b/, GoogleChart::BarChart.new(:horizontal =&gt; true, :grouping =&gt; :group).to_url)
+  end
+  
+  should 'support horizontal orientation with stacking' do
+    assert_match(/\bcht=bhs\b/, GoogleChart::BarChart.new(:horizontal =&gt; true, :grouping =&gt; :stack).to_url)
+  end
+  
+  should 'support horizontal orientation with overlapping' do
+    assert_match(/\bcht=bhs\b/, GoogleChart::BarChart.new(:horizontal =&gt; true, :grouping =&gt; :overlap).to_url)
+  end
+  
+  context 'data reduction and scaling' do
+    context 'with one data set' do
+      setup { @chart = GoogleChart::BarChart.new(:data =&gt; [0,2,3]) }
+      
+      should 'scale normally for grouping' do
+        @chart.grouping = :group
+        assert_match(/\bchd=s:Ao9\b/, @chart.to_url)
+      end
+      
+      should 'scale normally for stacking' do
+        @chart.grouping = :stack
+        assert_match(/\bchd=s:Ao9\b/, @chart.to_url)
+      end
+      
+      should 'scale normally for overlapping' do
+        @chart.grouping = :overlap
+        assert_match(/\bchd=s:Ao9\b/, @chart.to_url)
+      end
+    end
+    
+    context 'with two data sets' do
+      setup { @chart = GoogleChart::BarChart.new(:data =&gt; [[0,2,3], [0,4,6]]) }
+      
+      should 'scale normally for grouping' do
+        @chart.grouping = :group
+        assert_match(/\bchd=s:AUe,Ao9\b/, @chart.to_url)
+      end
+      
+      should 'scale based on column sums for stacking' do
+        @chart.grouping = :stack
+        assert_match(/\bchd=s:ANU,Abo\b/, @chart.to_url)
+      end
+      
+      should 'scale based on reduced data for overlapping' do
+        @chart.grouping = :overlap
+        assert_match(/\bchd=s:AUe,AUe\b/, @chart.to_url)
+      end
+    end
+    
+    context 'with three data sets' do
+      setup { @chart = GoogleChart::BarChart.new(:data =&gt; [[0,2,3], [0,4,6], [0,6,9]]) }
+      
+      should 'scale normally for grouping' do
+        @chart.grouping = :group
+        assert_match(/\bchd=s:ANU,Abo,Ao9\b/, @chart.to_url)
+      end
+      
+      should 'scale based on column sums for stacking' do
+        @chart.grouping = :stack
+        assert_match(/\bchd=s:AGK,ANU,AUe\b/, @chart.to_url)
+      end
+      
+      should 'scale based on reduced data for overlapping' do
+        @chart.grouping = :overlap
+        assert_match(/\bchd=s:ANU,ANU,AAA\b/, @chart.to_url)
+      end
+    end
   end
   
   should 'include Axis module' do</diff>
      <filename>test/google_chart/test_bar_chart.rb</filename>
    </modified>
    <modified>
      <diff>@@ -21,26 +21,38 @@ class TestData &lt; Test::Unit::TestCase
     assert_nothing_raised(ArgumentError) { @klass.new(:data =&gt; [[nil, nil], [nil, 1]]) }
   end
   
-  should 'be able to auto-scale datasets with nils' do
+  should 'auto-scale between 0 and maximum value among all data sets' do
+    assert_match(/\bchd=s:67,89\b/, @klass.new(:data =&gt; [[58, 59], [60, 61]]).to_url)
+  end
+  
+  should 'be able to auto-scale data sets with nils' do
     assert_match(/\bchd=s:A_9\b/, @klass.new(:data =&gt; [0, nil, 100]).to_url)
   end
   
-  should 'be able to auto-scale datasets with an empty dataset' do
+  should 'be able to auto-scale data sets with one empty set' do
     assert_match(/\bchd=s:__,A9\b/, @klass.new(:data =&gt; [[nil, nil], [0, 100]]).to_url)
   end
   
+  should 'encode data with high-pass filter when auto-scaling' do
+    assert_match(/\bchd=s:AAB89\b/, @klass.new(:data =&gt; [-1, 0, 1, 60, 61]).to_url)
+  end
+  
+  should 'encode data with band-pass filter when manual-scaling' do
+    assert_match(/\bchd=s:AB899\b/, @klass.new(:data =&gt; [-5, -1, 99, 100, 102], :scale =&gt; -3..100).to_url)
+  end
+  
   context 'simple encoding' do
     setup { @chart = @klass.new(:encoding =&gt; :simple) }
     
     should 'encode dataset with auto-scaling' do
       @chart.data = [0, 15, 10]
-      assert_match(/\bchd=s:A9p\b/, @chart.to_url)
+      assert_match(/\bchd=s:A9o\b/, @chart.to_url)
     end
     
     should 'encode dataset with manual scaling' do
       @chart.data = [0, 15, 10]
       @chart.scale = 0..20
-      assert_match(/\bchd=s:Auf\b/, @chart.to_url)
+      assert_match(/\bchd=s:Ate\b/, @chart.to_url)
     end
     
     should 'encode multiple datasets' do
@@ -50,27 +62,11 @@ class TestData &lt; Test::Unit::TestCase
     end
     
     should 'encode floating point data' do
-      @chart.data = [49.5, 33.4]
+      @chart.data = [50.5, 33.4]
       @chart.scale = 0..61
       assert_match(/\bchd=s:yh\b/, @chart.to_url)
     end
     
-    should 'encode all zeros with &quot;A&quot;' do
-      @chart.data = [0, 0, 0]
-      assert_match(/\bchd=s:AAA\b/, @chart.to_url)
-    end
-    
-    should 'encode unchanging non-zero data with max encoding value' do
-      @chart.data = [1, 1, 1]
-      assert_match(/\bchd=s:999\b/, @chart.to_url)
-    end
-    
-    should 'encode out-of-bounds data' do
-      @chart.data = [62, 61, 60, 1, 0, -1]
-      @chart.scale = 0..61
-      assert_match(/\bchd=s:998BAA/, @chart.to_url)
-    end
-    
     should 'encode missing data' do
       @chart.data = [50, nil, 33]
       @chart.scale = 0..61
@@ -87,9 +83,9 @@ class TestData &lt; Test::Unit::TestCase
     end
     
     should 'encode dataset with manual scaling' do
-      @chart.data = [0, 15, 10]
+      @chart.data = [15, 10, 0]
       @chart.scale = 0..20
-      assert_match(/\bchd=e:AAv\.gA\b/, @chart.to_url)
+      assert_match(/\bchd=e:v\.f\.AA\b/, @chart.to_url)
     end
     
     should 'encode multiple datasets' do
@@ -99,27 +95,11 @@ class TestData &lt; Test::Unit::TestCase
     end
     
     should 'encode floating point data' do
-      @chart.data = [2281.49, 3232.50]
+      @chart.data = [2281.49, 3233.50]
       @chart.scale = 0..4095
       assert_match(/\bchd=e:jpyh\b/, @chart.to_url)
     end
     
-    should 'encode all zeros with &quot;AA&quot;' do
-      @chart.data = [0, 0, 0]
-      assert_match(/\bchd=e:AAAAAA\b/, @chart.to_url)
-    end
-    
-    should 'encode unchanging non-zero data with max encoding value' do
-      @chart.data = [1, 1, 1]
-      assert_match(/\bchd=e:\.{6}/, @chart.to_url)
-    end
-    
-    should 'encode out-of-bounds data' do
-      @chart.data = [4096, 4095, 4094, 1, 0, -1]
-      @chart.scale = 0..4095
-      assert_match(/\bchd=e:\.\.\.\.\.-ABAAAA\b/, @chart.to_url)
-    end
-    
     should 'encode missing data' do
       @chart.data = [2281, nil, 3233]
       @chart.scale = 0..4095
@@ -153,22 +133,6 @@ class TestData &lt; Test::Unit::TestCase
       assert_match(/\bchd=t:6,14,5.2\b/, @chart.to_url)
     end
     
-    should 'encode all zeros with &quot;0&quot;' do
-      @chart.data = [0, 0, 0]
-      assert_match(/\bchd=t:0,0,0\b/, @chart.to_url)
-    end
-    
-    should 'encode unchanging non-zero data with max encoding value' do
-      @chart.data = [1, 1, 1]
-      assert_match(/\bchd=t:100,100,100\b/, @chart.to_url)
-    end
-    
-    should 'encode out-of-bounds data' do
-      @chart.data = [101, 100, 99, 1, 0, -1]
-      @chart.scale = 0..100
-      assert_match(/\bchd=t:100,100,99,1,0,0\b/, @chart.to_url)
-    end
-    
     should 'encode missing data' do
       @chart.data = [6, nil, 14]
       @chart.scale = 0..100</diff>
      <filename>test/google_chart/test_data.rb</filename>
    </modified>
    <modified>
      <diff>@@ -62,7 +62,7 @@ class TestGoogleChart &lt; Test::Unit::TestCase
       end
       
       should 'include chart type parameter' do
-        assert_match(/\bcht=bvs\b/, @url)
+        assert_match(/\bcht=bvg\b/, @url)
       end
       
       should 'include chart size parameter' do
@@ -88,7 +88,7 @@ class TestGoogleChart &lt; Test::Unit::TestCase
       end
       
       should 'include chart type parameter' do
-        assert_match(/\bcht=bvs\b/, @url)
+        assert_match(/\bcht=bvg\b/, @url)
       end
       
       should 'include chart size parameter' do</diff>
      <filename>test/test_google_chart.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>9d15bfd333fd0e33f6057e5d592a98f5b093f916</id>
    </parent>
  </parents>
  <author>
    <name>John Parker</name>
    <email>jparker@urgetopunt.com</email>
  </author>
  <url>http://github.com/jparker/ruby-googlechart/commit/a4c1c276fd575943bfc86671cec29f522a836a26</url>
  <id>a4c1c276fd575943bfc86671cec29f522a836a26</id>
  <committed-date>2008-11-23T02:22:37-08:00</committed-date>
  <authored-date>2008-11-23T02:22:37-08:00</authored-date>
  <message>Redesigned handling of bar grouping.

- Bar grouping can be grouped, stacked or overlapping
- Data scaling for bar charts now accounts for grouping</message>
  <tree>edccb14fd6e243049018aec1c92231439527d2b0</tree>
  <committer>
    <name>John Parker</name>
    <email>jparker@urgetopunt.com</email>
  </committer>
</commit>
