rails-data-explorer 0.1.0 → 0.2.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.
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"}