rails-data-explorer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +18 -0
  4. data/doc/how_to/release.md +2 -5
  5. data/lib/rails-data-explorer-no-rails.rb +1 -0
  6. data/lib/rails-data-explorer.rb +5 -0
  7. data/lib/rails-data-explorer/chart.rb +11 -11
  8. data/lib/rails-data-explorer/chart/box_plot_group.rb +10 -3
  9. data/lib/rails-data-explorer/chart/contingency_table.rb +58 -45
  10. data/lib/rails-data-explorer/chart/descriptive_statistics_table.rb +2 -2
  11. data/lib/rails-data-explorer/chart/histogram_categorical.rb +10 -4
  12. data/lib/rails-data-explorer/chart/histogram_quantitative.rb +12 -5
  13. data/lib/rails-data-explorer/chart/histogram_temporal.rb +6 -0
  14. data/lib/rails-data-explorer/chart/parallel_coordinates.rb +4 -4
  15. data/lib/rails-data-explorer/chart/parallel_set.rb +3 -3
  16. data/lib/rails-data-explorer/chart/stacked_bar_chart_categorical_percent.rb +3 -3
  17. data/lib/rails-data-explorer/constants.rb +5 -0
  18. data/lib/rails-data-explorer/data_series.rb +20 -14
  19. data/lib/rails-data-explorer/data_set.rb +4 -0
  20. data/lib/rails-data-explorer/data_type/categorical.rb +84 -72
  21. data/lib/rails-data-explorer/data_type/quantitative.rb +46 -48
  22. data/lib/rails-data-explorer/data_type/quantitative/temporal.rb +23 -17
  23. data/lib/rails-data-explorer/exploration.rb +20 -4
  24. data/lib/rails-data-explorer/statistics/rng_category.rb +1 -1
  25. data/lib/rails-data-explorer/utils/data_binner.rb +20 -10
  26. data/lib/rails-data-explorer/utils/data_quantizer.rb +6 -6
  27. data/lib/rails-data-explorer/utils/rde_table.rb +62 -0
  28. data/lib/rails_data_explorer.rb +35 -20
  29. data/rails-data-explorer.gemspec +1 -1
  30. data/spec/rails-data-explorer/exploration_spec.rb +4 -4
  31. data/spec/rails-data-explorer/utils/data_binner_spec.rb +3 -3
  32. metadata +30 -50
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 111102a24d7fb013d746b9a0dba6df3f7a881c1d
4
+ data.tar.gz: a2a99dd6d1b00c8f62143c725fdb7eb0bd6bb404
5
+ SHA512:
6
+ metadata.gz: 75fd9d7a12c1e32bc06fad41a4e662165aed8909290bf5c7fd17270a9d4e7dd23d780c5611bf42bd835d0052648cf17e3aa6a07f70e0b899bcf58772b7a9ea3c
7
+ data.tar.gz: c5c5236cb2fbcb441be1a4a449b405f02ec06741880bedeeb1cd5e9bdcb74fbdc774da84baaccf2a12b932ebbc1b272405f4bdec51203333e6f3d5d49285642c
@@ -1,3 +1,13 @@
1
+ ## 0.2.0
2
+
3
+ * Improvements to charts.
4
+ * Sort labels for categorical data.
5
+ * Improved table of contents at top of page.
6
+ * Improved presentation of contingency table.
7
+ * Avoid division by zero when given a data series with all '0' values.
8
+ * Improved performance of table rendering.
9
+ * Added `#number_of_values` for integration with Filterrific gem.
10
+
1
11
  ## 0.1.0
2
12
 
3
13
  * Is now being used in a production app, however no documentation yet.
data/README.md CHANGED
@@ -36,6 +36,24 @@ or with bundler in your Gemfile:
36
36
  * Chart -
37
37
 
38
38
 
39
+ ### Ways to shoot yourself in the foot
40
+
41
+ * Loading too many DB rows at once: Remember that you are loading ActiveRecord
42
+ objects, and they can use a lot of ram. It's a cartesian product of number of
43
+ rows times columns per record. As a rule of thumb, for a medium sized model with
44
+ 30 columns, you can load up to 10,000 rows.
45
+ * Using expensive operations in the :data_method option for a given data series.
46
+ As a rule of thumb, it should be ok to run simple methods that don't require
47
+ DB access. Examples: `#.to_s`, `if` and `case`, and math operations.
48
+ * Declaring too many charts: The charts rendered are the sum of the following:
49
+ * univariate: one or more charts for each data series
50
+ * bivariate: the cartesian product of all data series in a bivariate group
51
+ * multivariate: one or more charts for each multivariate group
52
+ I have tested it with 70 charts on a single page. More are probably ok, I
53
+ just haven't tested it.
54
+ * Drowning in detail. rde makes it easy to generate a large number of charts.
55
+ Make sure you don't miss the important data in the noise.
56
+
39
57
  ### Dependencies
40
58
 
41
59
  * ActionView >= 3.0
@@ -1,12 +1,10 @@
1
- Workflow to Maintain This Gem
2
- =============================
1
+ # Workflow to Maintain This Gem
3
2
 
4
3
  I use the gem-release gem
5
4
 
6
5
  For more info see: https://github.com/svenfuchs/gem-release#usage
7
6
 
8
- Steps for an update
9
- -------------------
7
+ ## Steps for an update
10
8
 
11
9
  1. Update code and commit it.
12
10
  2. Add entry to CHANGELOG and commit it:
@@ -19,5 +17,4 @@ Steps for an update
19
17
  5. Create a git tag and push to origin.
20
18
  `gem tag`
21
19
 
22
-
23
20
  http://prioritized.net/blog/gemify-assets-for-rails/
@@ -11,6 +11,7 @@ require 'interpolate'
11
11
 
12
12
  require 'rails_data_explorer'
13
13
  require 'rails-data-explorer/chart'
14
+ require 'rails-data-explorer/constants'
14
15
  require 'rails-data-explorer/data_series'
15
16
  require 'rails-data-explorer/data_set'
16
17
  require 'rails-data-explorer/data_type'
@@ -1,3 +1,5 @@
1
+
2
+
1
3
  require 'action_view'
2
4
  require 'active_support/all' # TODO: once the dust settles, only require the modules we need
3
5
  require 'color'
@@ -9,6 +11,7 @@ require 'rails-data-explorer/engine'
9
11
 
10
12
  require 'rails_data_explorer'
11
13
  require 'rails-data-explorer/chart'
14
+ require 'rails-data-explorer/constants'
12
15
  require 'rails-data-explorer/data_series'
13
16
  require 'rails-data-explorer/data_set'
14
17
  require 'rails-data-explorer/data_type'
@@ -19,6 +22,7 @@ require 'rails-data-explorer/statistics/rng_power_law'
19
22
  require 'rails-data-explorer/utils/color_scale'
20
23
  require 'rails-data-explorer/utils/data_binner'
21
24
  require 'rails-data-explorer/utils/data_quantizer'
25
+ require 'rails-data-explorer/utils/rde_table'
22
26
  require 'rails-data-explorer/utils/value_formatter'
23
27
 
24
28
  require 'rails-data-explorer/chart/box_plot'
@@ -33,6 +37,7 @@ require 'rails-data-explorer/chart/parallel_set'
33
37
  require 'rails-data-explorer/chart/pie_chart'
34
38
  require 'rails-data-explorer/chart/scatterplot'
35
39
  require 'rails-data-explorer/chart/stacked_bar_chart_categorical_percent'
40
+ require 'rails-data-explorer/chart/stacked_histogram_temporal'
36
41
  require 'rails-data-explorer/data_type/categorical'
37
42
  require 'rails-data-explorer/data_type/quantitative'
38
43
  require 'rails-data-explorer/data_type/quantitative/decimal'
@@ -19,27 +19,27 @@ class RailsDataExplorer
19
19
  protected
20
20
 
21
21
  # Renders an HTML table
22
- # @param[OpenStruct, Struct] table_struct
23
- def render_html_table(table_struct)
24
- content_tag(:table, :class => 'table rde-table') do
25
- table_struct.rows.map { |row|
26
- content_tag(row.tag, :class => row.css_class) do
22
+ # @param rde_table [RdeTable]
23
+ def render_html_table(rde_table)
24
+ content_tag(:table, class: 'table rde-table') do
25
+ rde_table.rows.map { |row|
26
+ content_tag(row.tag, class: row.css_class) do
27
27
  row.cells.map { |cell|
28
28
  if cell.ruby_formatter
29
29
  content_tag(
30
30
  cell.tag,
31
31
  instance_exec(cell.value, &cell.ruby_formatter),
32
- :class => cell.css_class,
33
- :title => cell.title,
34
- :style => cell.style,
32
+ class: cell.css_class,
33
+ title: cell.title,
34
+ style: cell.style,
35
35
  )
36
36
  else
37
37
  content_tag(
38
38
  cell.tag,
39
39
  cell.value,
40
- :class => cell.css_class,
41
- :title => cell.title,
42
- :style => cell.style,
40
+ class: cell.css_class,
41
+ title: cell.title,
42
+ style: cell.style,
43
43
  )
44
44
  end
45
45
  }.join.html_safe
@@ -41,17 +41,24 @@ class RailsDataExplorer
41
41
  next if (y_val.nil? || Float::NAN == y_val)
42
42
  values_hash[y_val] << x_ds.values[idx]
43
43
  }
44
+ y_sorted_keys = y_ds.uniq_vals.sort(
45
+ &y_ds.label_sorter(
46
+ nil,
47
+ lambda { |a,b| a <=> b }
48
+ )
49
+ )
50
+ sorted_values = y_sorted_keys.map { |y_val| values_hash[y_val] }
44
51
 
45
52
  {
46
- values: values_hash.values,
47
- category_labels: values_hash.keys,
53
+ values: sorted_values,
54
+ category_labels: y_sorted_keys,
48
55
  min: min,
49
56
  max: max,
50
57
  base_width: 120,
51
58
  base_height: 800,
52
59
  axis_tick_format: x_ds.axis_tick_format,
53
60
  num_box_plots: y_ds.uniq_vals_count,
54
- axis_scale: DataSeries.new('_', [min, max]).axis_scale
61
+ axis_scale: DataSeries.new('_', [min, max]).axis_scale(:d3)
55
62
  }
56
63
  end
57
64
 
@@ -46,54 +46,61 @@ class RailsDataExplorer
46
46
 
47
47
  ca = case @data_set.dimensions_count
48
48
  when 2
49
- # Table
50
- OpenStruct.new(
49
+ Utils::RdeTable.new(
51
50
  # Top header row
52
- :rows => [
53
- OpenStruct.new(
54
- :css_class => 'rde-column_header',
55
- :tag => :tr,
56
- :cells => [
57
- OpenStruct.new(:tag => :th, :value => '')
58
- ] +
59
- x_sorted_keys.map { |x_val|
60
- OpenStruct.new(:tag => :th, :value => x_val)
61
- } +
62
- [OpenStruct.new(:tag => :th, :value => 'Totals')]
51
+ [
52
+ Utils::RdeTableRow.new(
53
+ :tr,
54
+ [Utils::RdeTableCell.new(:th, '')] +
55
+ x_sorted_keys.map { |x_val| Utils::RdeTableCell.new(:th, x_val) } +
56
+ [Utils::RdeTableCell.new(:th, 'Totals')],
57
+ css_class: 'rde-column_header'
63
58
  )
64
59
  ] +
65
60
  # Data rows
66
61
  y_sorted_keys.map { |y_val|
67
- OpenStruct.new(
68
- :css_class => 'rde-data_row',
69
- :tag => :tr,
70
- :cells => [
71
- OpenStruct.new(:tag => :th, :value => y_val, :css_class => 'rde-row_header')
62
+ Utils::RdeTableRow.new(
63
+ :tr,
64
+ [
65
+ Utils::RdeTableCell.new(:th, y_val, css_class: 'rde-row_header')
72
66
  ] +
73
67
  x_sorted_keys.map { |x_val|
74
- OpenStruct.new(
75
- :tag => :td,
76
- :value => @observed_vals[x_val][y_val],
77
- :css_class => 'rde-numerical',
78
- :title => "Expected value: #{ number_with_precision(@expected_vals[x_val][y_val]) }",
79
- :style => "color: #{ @delta_attrs[x_val][y_val][:color] };",
68
+ Utils::RdeTableCell.new(
69
+ :td,
70
+ @observed_vals[x_val][y_val],
71
+ css_class: 'rde-numerical',
72
+ title: [
73
+ "Expected value: #{ number_with_precision(@expected_vals[x_val][y_val], precision: 3, significant: true) }",
74
+ "Percentage of row: #{ number_to_percentage(@delta_attrs[x_val][y_val][:percentage_of_row], precision: 3, significant: true) }",
75
+ "Percentage of col: #{ number_to_percentage(@delta_attrs[x_val][y_val][:percentage_of_col], precision: 3, significant: true) }",
76
+ ].join("\n"),
77
+ style: "color: #{ @delta_attrs[x_val][y_val][:color] };",
80
78
  )
81
79
  } +
82
- [OpenStruct.new(:tag => :th, :value => @observed_vals[:_sum][y_val])]
80
+ [
81
+ Utils::RdeTableCell.new(
82
+ :th,
83
+ @observed_vals[:_sum][y_val],
84
+ title: "Percentage of col: #{ number_to_percentage(@delta_attrs[:_sum][y_val][:percentage_of_col], precision: 3, significant: true) }"
85
+ )
86
+ ],
87
+ css_class: 'rde-data_row'
83
88
  )
84
89
  } +
85
90
  # Footer row
86
91
  [
87
- OpenStruct.new(
88
- :css_class => 'rde-column_header',
89
- :tag => :tr,
90
- :cells => [
91
- OpenStruct.new(:tag => :th, :value => 'Totals', :css_class => 'rde-row_header')
92
- ] +
92
+ Utils::RdeTableRow.new(
93
+ :tr,
94
+ [Utils::RdeTableCell.new(:th, 'Totals', css_class: 'rde-row_header')] +
93
95
  x_sorted_keys.map { |x_val|
94
- OpenStruct.new(:tag => :th, :value => @observed_vals[x_val][:_sum])
96
+ Utils::RdeTableCell.new(
97
+ :th,
98
+ @observed_vals[x_val][:_sum],
99
+ title: "Percentage of row: #{ number_to_percentage(@delta_attrs[x_val][:_sum][:percentage_of_row], precision: 3, significant: true) }"
100
+ )
95
101
  } +
96
- [OpenStruct.new(:tag => :th, :value => @observed_vals[:_sum][:_sum])]
102
+ [Utils::RdeTableCell.new(:th, @observed_vals[:_sum][:_sum])],
103
+ css_class: 'rde-column_header'
97
104
  )
98
105
  ]
99
106
  )
@@ -108,8 +115,8 @@ class RailsDataExplorer
108
115
  ca = compute_chart_attrs
109
116
  return '' unless ca
110
117
 
111
- content_tag(:div, :class => 'rde-chart rde-contingency-table', :id => dom_id) do
112
- content_tag(:h3, "Contingency Table", :class => 'rde-chart-title') +
118
+ content_tag(:div, class: 'rde-chart rde-contingency-table', id: dom_id) do
119
+ content_tag(:h3, "Contingency Table", class: 'rde-chart-title') +
113
120
  render_html_table(ca)
114
121
  end +
115
122
  content_tag(:p, @conclusion)
@@ -127,7 +134,7 @@ class RailsDataExplorer
127
134
  # @param[DataSeries] y_ds
128
135
  def compute_contingency_and_chi_squared!(x_ds, y_ds)
129
136
  # Compute the observed values table
130
- @observed_vals = { :_sum => { :_sum => 0 } }
137
+ @observed_vals = { _sum: { _sum: 0 } }
131
138
  x_ds.uniq_vals.each { |x_val|
132
139
  @observed_vals[x_val] = {}
133
140
  @observed_vals[x_val][:_sum] = 0
@@ -166,18 +173,24 @@ class RailsDataExplorer
166
173
  }
167
174
  }
168
175
  # Compute deltas
169
- @delta_attrs = {}
176
+ @delta_attrs = { _sum: {} }
170
177
  color_scale = RailsDataExplorer::Utils::ColorScale.new
171
178
  x_ds.uniq_vals.each { |x_val|
172
- @delta_attrs[x_val] = {}
179
+ @delta_attrs[x_val] = { _sum: {} }
180
+ @delta_attrs[x_val][:_sum][:percentage_of_row] = (@observed_vals[x_val][:_sum] / @observed_vals[:_sum][:_sum].to_f) * 100
173
181
  y_ds.uniq_vals.each { |y_val|
174
182
  delta = @observed_vals[x_val][y_val] - @expected_vals[x_val][y_val]
175
183
  delta_factor = delta / @expected_vals[x_val][y_val].to_f
176
184
  @delta_attrs[x_val][y_val] = {
177
- :expected => @expected_vals[x_val][y_val],
178
- :color => color_scale.compute(delta_factor),
179
- :delta => delta,
180
- :delta_factor => delta_factor,
185
+ :expected @expected_vals[x_val][y_val],
186
+ color: color_scale.compute(delta_factor),
187
+ delta: delta,
188
+ delta_factor: delta_factor,
189
+ percentage_of_row: (@observed_vals[x_val][y_val] / @observed_vals[:_sum][y_val].to_f) * 100,
190
+ percentage_of_col: (@observed_vals[x_val][y_val] / @observed_vals[x_val][:_sum].to_f) * 100,
191
+ }
192
+ @delta_attrs[:_sum][y_val] ||= {
193
+ percentage_of_col: (@observed_vals[:_sum][y_val] / @observed_vals[:_sum][:_sum].to_f) * 100
181
194
  }
182
195
  }
183
196
  }
@@ -200,7 +213,7 @@ class RailsDataExplorer
200
213
  @conclusion = [
201
214
  "We did not run the ",
202
215
  %(<a href="http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test#Test_of_independence">Pearson chi squared test of independence</a> ),
203
- "since #{ number_to_percentage(ratio_of_observed_vals_below_five * 100, :precision => 0) } ",
216
+ "since #{ number_to_percentage(ratio_of_observed_vals_below_five * 100, precision: 0) } ",
204
217
  "of observed values in the contingency table are below 5 (cutoff is 20%)."
205
218
  ].join
206
219
  elsif([x_ds, y_ds].any? { |e| e.uniq_vals.length < 2 })
@@ -212,9 +225,9 @@ class RailsDataExplorer
212
225
  else
213
226
  @conclusion = %(<a href="http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test#Test_of_independence">Pearson chi squared test of independence</a> suggests that )
214
227
  @conclusion << if @p_value <= @significance_level
215
- %("#{ x_ds.name }" and "#{ y_ds.name }" are dependent variables (p_value: #{ number_with_precision(@p_value) }))
228
+ %("#{ x_ds.name }" and "#{ y_ds.name }" are dependent variables (p_value of #{ number_with_precision(@p_value) } <= #{ number_with_precision(@significance_level )}))
216
229
  else
217
- %("#{ x_ds.name }" and "#{ y_ds.name }" are independent variables (p_value: #{ number_with_precision(@p_value) }))
230
+ %("#{ x_ds.name }" and "#{ y_ds.name }" are independent variables (p_value of #{ number_with_precision(@p_value) } > #{ number_with_precision(@significance_level )}))
218
231
  end
219
232
  end
220
233
  @conclusion = @conclusion.html_safe
@@ -9,9 +9,9 @@ class RailsDataExplorer
9
9
 
10
10
  def render
11
11
  return '' unless render?
12
- content_tag(:div, :id => dom_id, :class => 'rde-chart rde-descriptive-statistics-table') do
12
+ content_tag(:div, id: dom_id, class: 'rde-chart rde-descriptive-statistics-table') do
13
13
  @data_set.data_series.map { |data_series|
14
- content_tag(:h3, "Descriptive Statistics", :class => 'rde-chart-title') +
14
+ content_tag(:h3, "Descriptive Statistics", class: 'rde-chart-title') +
15
15
  render_html_table(data_series.descriptive_statistics_table)
16
16
  }.join.html_safe
17
17
  end
@@ -13,6 +13,9 @@ class RailsDataExplorer
13
13
 
14
14
  # compute histogram
15
15
  h = x_ds.values.inject(Hash.new(0)) { |m,e| m[e] += 1; m }
16
+ histogram_values_ds = DataSeries.new('_', h.values)
17
+ y_scale_type = histogram_values_ds.axis_scale(:vega)
18
+ bar_y2_val = 'log' == y_scale_type ? histogram_values_ds.min_val / 10.0 : 0
16
19
  {
17
20
  values: h.map { |k,v|
18
21
  { x: k, y: v }
@@ -25,7 +28,10 @@ class RailsDataExplorer
25
28
  x_axis_label: x_ds.name,
26
29
  x_axis_tick_format: "d3.format('r')",
27
30
  y_axis_label: 'Frequency',
28
- y_axis_tick_format: "d3.format('r')",
31
+ y_axis_tick_format: "d3.format(',g')", #histogram_values_ds.axis_tick_format,
32
+ y_scale_type: y_scale_type,
33
+ y_scale_domain: [bar_y2_val, histogram_values_ds.max_val],
34
+ bar_y2_val: bar_y2_val,
29
35
  }
30
36
  end
31
37
 
@@ -62,9 +68,9 @@ class RailsDataExplorer
62
68
  },
63
69
  {
64
70
  "name": "y",
71
+ "type": "#{ ca[:y_scale_type] }",
65
72
  "range": "height",
66
- "nice": true,
67
- "domain": {"data": "table", "field": "data.y"}
73
+ "domain": #{ ca[:y_scale_domain].to_json },
68
74
  }
69
75
  ],
70
76
  "axes": [
@@ -91,7 +97,7 @@ class RailsDataExplorer
91
97
  "x": {"scale": "x", "field": "data.x"},
92
98
  "width": {"scale": "x", "band": true, "offset": -1},
93
99
  "y": {"scale": "y", "field": "data.y"},
94
- "y2": {"scale": "y", "value": 0}
100
+ "y2": {"scale": "y", "value": #{ ca[:bar_y2_val] }},
95
101
  },
96
102
  "update": {
97
103
  "fill": {"value": "#1F77B4"}
@@ -12,11 +12,14 @@ class RailsDataExplorer
12
12
  return false if x_ds.nil?
13
13
 
14
14
  # compute histogram
15
- quantizer = Utils::DataQuantizer.new(x_ds, :max_number_of_bins => 100)
15
+ quantizer = Utils::DataQuantizer.new(x_ds, max_number_of_bins: 100)
16
16
  quantized_values = quantizer.values
17
17
  number_of_bars = quantizer.number_of_bins
18
18
  width = 800
19
19
  h = quantized_values.inject(Hash.new(0)) { |m,e| m[e] += 1; m }
20
+ histogram_values_ds = DataSeries.new('_', h.values)
21
+ y_scale_type = histogram_values_ds.axis_scale(:vega)
22
+ bar_y2_val = 'log' == y_scale_type ? histogram_values_ds.min_val / 10.0 : 0
20
23
  {
21
24
  values: h.map { |k,v| { x: k, y: v } },
22
25
  width: width,
@@ -27,6 +30,9 @@ class RailsDataExplorer
27
30
  bar_width: (width / number_of_bars.to_f) - 3,
28
31
  y_axis_label: 'Frequency',
29
32
  y_axis_tick_format: "d3.format('r')",
33
+ y_scale_type: y_scale_type,
34
+ y_scale_domain: [bar_y2_val, histogram_values_ds.max_val],
35
+ bar_y2_val: bar_y2_val,
30
36
  }
31
37
  end
32
38
 
@@ -51,7 +57,7 @@ class RailsDataExplorer
51
57
  "data": [
52
58
  {
53
59
  "name": "table",
54
- "values": #{ ca[:values].to_json }
60
+ "values": #{ ca[:values].to_json },
55
61
  }
56
62
  ],
57
63
  "scales": [
@@ -61,12 +67,13 @@ class RailsDataExplorer
61
67
  "range": "width",
62
68
  "zero": false,
63
69
  "nice": #{ ca[:x_scale_nice] },
64
- "domain": {"data": "table", "field": "data.x"}
70
+ "domain": {"data": "table", "field": "data.x"},
65
71
  },
66
72
  {
67
73
  "name": "y",
74
+ "type": "#{ ca[:y_scale_type] }",
68
75
  "range": "height",
69
- "domain": {"data": "table", "field": "data.y"}
76
+ "domain": #{ ca[:y_scale_domain].to_json },
70
77
  }
71
78
  ],
72
79
  "axes": [
@@ -93,7 +100,7 @@ class RailsDataExplorer
93
100
  "x": {"scale": "x", "field": "data.x"},
94
101
  "width": { "value": #{ ca[:bar_width] } },
95
102
  "y": {"scale": "y", "field": "data.y"},
96
- "y2": {"scale": "y", "value": 0},
103
+ "y2": {"scale": "y", "value": #{ ca[:bar_y2_val] }},
97
104
  },
98
105
  "update": {
99
106
  "fill": {"value": "#1F77B4"}