rails-data-explorer 0.0.1 → 0.1.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 (52) hide show
  1. data/CHANGELOG.md +5 -1
  2. data/README.md +11 -0
  3. data/Rakefile +62 -0
  4. data/doc/how_to/release.md +23 -0
  5. data/doc/how_to/trouble_when_packaging_assets.md +8 -0
  6. data/lib/rails-data-explorer-no-rails.rb +42 -0
  7. data/lib/rails-data-explorer.rb +5 -9
  8. data/lib/rails-data-explorer/chart/box_plot.rb +5 -1
  9. data/lib/rails-data-explorer/chart/box_plot_group.rb +22 -5
  10. data/lib/rails-data-explorer/chart/contingency_table.rb +45 -10
  11. data/lib/rails-data-explorer/chart/histogram_categorical.rb +104 -3
  12. data/lib/rails-data-explorer/chart/histogram_quantitative.rb +99 -2
  13. data/lib/rails-data-explorer/chart/histogram_temporal.rb +10 -55
  14. data/lib/rails-data-explorer/chart/parallel_coordinates.rb +4 -0
  15. data/lib/rails-data-explorer/chart/parallel_set.rb +4 -0
  16. data/lib/rails-data-explorer/chart/pie_chart.rb +89 -8
  17. data/lib/rails-data-explorer/chart/scatterplot.rb +110 -8
  18. data/lib/rails-data-explorer/chart/stacked_bar_chart_categorical_percent.rb +133 -14
  19. data/lib/rails-data-explorer/data_series.rb +37 -2
  20. data/lib/rails-data-explorer/data_type/categorical.rb +72 -2
  21. data/lib/rails-data-explorer/data_type/quantitative.rb +41 -12
  22. data/lib/rails-data-explorer/data_type/quantitative/temporal.rb +3 -2
  23. data/lib/rails-data-explorer/exploration.rb +5 -1
  24. data/lib/rails-data-explorer/utils/data_binner.rb +31 -0
  25. data/lib/rails-data-explorer/utils/data_quantizer.rb +66 -0
  26. data/lib/rails_data_explorer.rb +133 -0
  27. data/rails-data-explorer.gemspec +4 -4
  28. data/spec/helper.rb +7 -0
  29. data/spec/helper_no_rails.rb +10 -0
  30. data/spec/rails-data-explorer/data_series_spec.rb +45 -0
  31. data/spec/rails-data-explorer/data_type/categorical_spec.rb +34 -0
  32. data/spec/rails-data-explorer/exploration_spec.rb +55 -0
  33. data/spec/rails-data-explorer/utils/data_binner_spec.rb +29 -0
  34. data/spec/rails-data-explorer/utils/data_quantizer_spec.rb +71 -0
  35. data/vendor/assets/javascripts/packaged/rails-data-explorer.min.js +1 -0
  36. data/vendor/assets/javascripts/rails-data-explorer.js +6 -5
  37. data/vendor/assets/javascripts/{d3.boxplot.js → sources/d3.boxplot.js} +10 -3
  38. data/vendor/assets/javascripts/{d3.parcoords.js → sources/d3.parcoords.js} +1 -1
  39. data/vendor/assets/javascripts/{d3.parsets.js → sources/d3.parsets.js} +3 -3
  40. data/vendor/assets/javascripts/{d3.v3.js → sources/d3.v3.js} +0 -0
  41. data/vendor/assets/javascripts/{nv.d3.js → sources/nv.d3.js} +0 -0
  42. data/vendor/assets/javascripts/sources/vega.js +7040 -0
  43. data/vendor/assets/stylesheets/packaged/rails-data-explorer.min.css +9 -0
  44. data/vendor/assets/stylesheets/rails-data-explorer.css +7 -7
  45. data/vendor/assets/stylesheets/{bootstrap-theme.css → sources/bootstrap-theme.css} +0 -0
  46. data/vendor/assets/stylesheets/{bootstrap.css → sources/bootstrap.css} +0 -0
  47. data/vendor/assets/stylesheets/{d3.boxplot.css → sources/d3.boxplot.css} +0 -0
  48. data/vendor/assets/stylesheets/{d3.parcoords.css → sources/d3.parcoords.css} +0 -0
  49. data/vendor/assets/stylesheets/{d3.parsets.css → sources/d3.parsets.css} +0 -0
  50. data/vendor/assets/stylesheets/{nv.d3.css → sources/nv.d3.css} +0 -0
  51. data/vendor/assets/stylesheets/{rde-default-style.css → sources/rde-default-style.css} +0 -0
  52. metadata +65 -28
@@ -1,3 +1,7 @@
1
- ## 0.0.1
1
+ ## 0.1.0
2
+
3
+ * Is now being used in a production app, however no documentation yet.
4
+
5
+ ### 0.0.1
2
6
 
3
7
  * Initial release
data/README.md CHANGED
@@ -7,6 +7,10 @@ data in your app using charts and statistics.
7
7
  Make sure to go to the thorough [documentation](http://rails-data-explorer.clearcove.ca)
8
8
  to find out more!
9
9
 
10
+ ## IMPORTANT NOTE
11
+
12
+ This gem is under active development and will see significant changes until it's
13
+ officially released.
10
14
 
11
15
  ### Installation
12
16
 
@@ -32,6 +36,13 @@ or with bundler in your Gemfile:
32
36
  * Chart -
33
37
 
34
38
 
39
+ ### Dependencies
40
+
41
+ * ActionView >= 3.0
42
+ * ActiveSupport >= 3.0
43
+ * Asset pipeline (for batteries included, otherwise you'll have to pull in a number of assets manually)
44
+ * jQuery??
45
+
35
46
  ### Resources
36
47
 
37
48
  * [Documentation](http://rails-data-explorer.clearcove.ca)
data/Rakefile CHANGED
@@ -16,3 +16,65 @@ Rake::TestTask.new do |t|
16
16
  end
17
17
 
18
18
  task :default => ['test']
19
+
20
+ require 'yui/compressor'
21
+
22
+ namespace :rde do
23
+
24
+ def minify_js(output_file_name, file_list)
25
+ uncompressed_source = ''
26
+ file_list.each do |file|
27
+ uncompressed_source << File.read(file)
28
+ end
29
+ compressor = YUI::JavaScriptCompressor.new
30
+ compressed_output = compressor.compress(uncompressed_source)
31
+ File.write(output_file_name, compressed_output)
32
+ end
33
+
34
+ def minify_css(output_file_name, file_list)
35
+ uncompressed_source = ''
36
+ file_list.each do |file|
37
+ uncompressed_source << File.read(file)
38
+ end
39
+ compressor = YUI::CssCompressor.new
40
+ compressed_output = compressor.compress(uncompressed_source)
41
+ File.write(output_file_name, compressed_output)
42
+ end
43
+
44
+ desc "minify"
45
+ task :minify => [:minify_js, :minify_css]
46
+
47
+ desc "minify javascript"
48
+ task :minify_js do
49
+ base_path = File.expand_path("../vendor/assets/javascripts", __FILE__)
50
+ minify_js(
51
+ File.join(base_path, 'packaged/rails-data-explorer.min.js'),
52
+ [
53
+ File.join(base_path, 'sources/d3.v3.js'),
54
+ # File.join(base_path, 'sources/nv.d3.js'),
55
+ File.join(base_path, 'sources/d3.boxplot.js'),
56
+ File.join(base_path, 'sources/d3.parcoords.js'),
57
+ File.join(base_path, 'sources/d3.parsets.js'),
58
+ File.join(base_path, 'sources/vega.js'),
59
+ ]
60
+ )
61
+ end
62
+
63
+ desc "minify css"
64
+ task :minify_css do
65
+ base_path = File.expand_path("../vendor/assets/stylesheets", __FILE__)
66
+ minify_css(
67
+ File.join(base_path, 'packaged/rails-data-explorer.min.css'),
68
+ [
69
+ File.join(base_path, 'sources/bootstrap-theme.css'),
70
+ File.join(base_path, 'sources/bootstrap.css'),
71
+ File.join(base_path, 'sources/d3.boxplot.css'),
72
+ File.join(base_path, 'sources/d3.parcoords.css'),
73
+ File.join(base_path, 'sources/d3.parsets.css'),
74
+ # File.join(base_path, 'sources/nv.d3.css'),
75
+ File.join(base_path, 'sources/rde-default-style.css'),
76
+ ]
77
+ )
78
+ end
79
+
80
+ end
@@ -0,0 +1,23 @@
1
+ Workflow to Maintain This Gem
2
+ =============================
3
+
4
+ I use the gem-release gem
5
+
6
+ For more info see: https://github.com/svenfuchs/gem-release#usage
7
+
8
+ Steps for an update
9
+ -------------------
10
+
11
+ 1. Update code and commit it.
12
+ 2. Add entry to CHANGELOG and commit it:
13
+ * h1 for major release (1.0.0)
14
+ * h2 for minor release (0.1.0)
15
+ * h3 for patch release (0.0.1)
16
+ 3. Update version in .gemspec and commit
17
+ 4. Release it.
18
+ * `gem release`
19
+ 5. Create a git tag and push to origin.
20
+ `gem tag`
21
+
22
+
23
+ http://prioritized.net/blog/gemify-assets-for-rails/
@@ -0,0 +1,8 @@
1
+ Trouble when packaging assets
2
+ =============================
3
+
4
+ I had syntax and dot errors when packaging the JS assets. Turns out that the
5
+ JS libraries used reserved words as method accessors. Here is an example how I
6
+ fixed it (`in`) is the reserved word:
7
+
8
+ `c.in` => `c["in"]`
@@ -0,0 +1,42 @@
1
+ # Require this file for fast testing outside of rails. Don't use this for normal
2
+ # usage.
3
+ require 'action_view'
4
+ require 'active_support/all' # TODO: once the dust settles, only require the modules we need
5
+ require 'color'
6
+ require 'descriptive-statistics'
7
+ require 'distribution'
8
+ require 'interpolate'
9
+
10
+ # require 'rails-data-explorer/engine'
11
+
12
+ require 'rails_data_explorer'
13
+ require 'rails-data-explorer/chart'
14
+ require 'rails-data-explorer/data_series'
15
+ require 'rails-data-explorer/data_set'
16
+ require 'rails-data-explorer/data_type'
17
+ require 'rails-data-explorer/exploration'
18
+ require 'rails-data-explorer/statistics/rng_category'
19
+ require 'rails-data-explorer/statistics/rng_gaussian'
20
+ require 'rails-data-explorer/statistics/rng_power_law'
21
+ require 'rails-data-explorer/utils/color_scale'
22
+ require 'rails-data-explorer/utils/data_binner'
23
+ require 'rails-data-explorer/utils/data_quantizer'
24
+ require 'rails-data-explorer/utils/value_formatter'
25
+
26
+ require 'rails-data-explorer/chart/box_plot'
27
+ require 'rails-data-explorer/chart/box_plot_group'
28
+ require 'rails-data-explorer/chart/contingency_table'
29
+ require 'rails-data-explorer/chart/descriptive_statistics_table'
30
+ require 'rails-data-explorer/chart/histogram_categorical'
31
+ require 'rails-data-explorer/chart/histogram_quantitative'
32
+ require 'rails-data-explorer/chart/histogram_temporal'
33
+ require 'rails-data-explorer/chart/parallel_coordinates'
34
+ require 'rails-data-explorer/chart/parallel_set'
35
+ require 'rails-data-explorer/chart/pie_chart'
36
+ require 'rails-data-explorer/chart/scatterplot'
37
+ require 'rails-data-explorer/chart/stacked_bar_chart_categorical_percent'
38
+ require 'rails-data-explorer/data_type/categorical'
39
+ require 'rails-data-explorer/data_type/quantitative'
40
+ require 'rails-data-explorer/data_type/quantitative/decimal'
41
+ require 'rails-data-explorer/data_type/quantitative/integer'
42
+ require 'rails-data-explorer/data_type/quantitative/temporal'
@@ -1,3 +1,5 @@
1
+ require 'action_view'
2
+ require 'active_support/all' # TODO: once the dust settles, only require the modules we need
1
3
  require 'color'
2
4
  require 'descriptive-statistics'
3
5
  require 'distribution'
@@ -5,6 +7,7 @@ require 'interpolate'
5
7
 
6
8
  require 'rails-data-explorer/engine'
7
9
 
10
+ require 'rails_data_explorer'
8
11
  require 'rails-data-explorer/chart'
9
12
  require 'rails-data-explorer/data_series'
10
13
  require 'rails-data-explorer/data_set'
@@ -14,6 +17,8 @@ require 'rails-data-explorer/statistics/rng_category'
14
17
  require 'rails-data-explorer/statistics/rng_gaussian'
15
18
  require 'rails-data-explorer/statistics/rng_power_law'
16
19
  require 'rails-data-explorer/utils/color_scale'
20
+ require 'rails-data-explorer/utils/data_binner'
21
+ require 'rails-data-explorer/utils/data_quantizer'
17
22
  require 'rails-data-explorer/utils/value_formatter'
18
23
 
19
24
  require 'rails-data-explorer/chart/box_plot'
@@ -33,12 +38,3 @@ require 'rails-data-explorer/data_type/quantitative'
33
38
  require 'rails-data-explorer/data_type/quantitative/decimal'
34
39
  require 'rails-data-explorer/data_type/quantitative/integer'
35
40
  require 'rails-data-explorer/data_type/quantitative/temporal'
36
-
37
- class RailsDataExplorer
38
-
39
- # Convenience method to instantiate new Exploration
40
- def self.new(*args)
41
- RailsDataExplorer::Exploration.new(*args)
42
- end
43
-
44
- end
@@ -11,12 +11,14 @@ class RailsDataExplorer
11
11
 
12
12
  def compute_chart_attrs
13
13
  x_ds = @data_set.data_series.first
14
+ return false if x_ds.nil?
15
+
14
16
  {
15
17
  values: [x_ds.values],
16
18
  min: x_ds.min_val,
17
19
  max: x_ds.max_val,
18
20
  base_width: 120,
19
- base_height: 1334,
21
+ base_height: 800,
20
22
  axis_tick_format: x_ds.axis_tick_format,
21
23
  }
22
24
  end
@@ -24,6 +26,8 @@ class RailsDataExplorer
24
26
  def render
25
27
  return '' unless render?
26
28
  ca = compute_chart_attrs
29
+ return '' unless ca
30
+
27
31
  %(
28
32
  <div id="#{ dom_id }" class="rde-chart rde-box-plot">
29
33
  <svg class="box" style="height: #{ ca[:base_width] }px;"></svg>
@@ -9,6 +9,9 @@ class RailsDataExplorer
9
9
  class Chart
10
10
  class BoxPlotGroup < Chart
11
11
 
12
+ # TODO: imitate this:
13
+ # http://www.stata.com/support/faqs/graphics/gph/graphdocs/horizontal-box-plot-of-variable-by-values-of-categorical-variable/
14
+
12
15
  def initialize(_data_set, options = {})
13
16
  @data_set = _data_set
14
17
  @options = {}.merge(options)
@@ -24,7 +27,6 @@ class RailsDataExplorer
24
27
 
25
28
  x_ds = x_candidates.first
26
29
  y_ds = (y_candidates - [x_ds]).first
27
-
28
30
  return false if x_ds.nil? || y_ds.nil?
29
31
 
30
32
  min = x_ds.min_val # get global min
@@ -36,16 +38,20 @@ class RailsDataExplorer
36
38
  }
37
39
 
38
40
  y_ds.values.each_with_index { |y_val, idx|
41
+ next if (y_val.nil? || Float::NAN == y_val)
39
42
  values_hash[y_val] << x_ds.values[idx]
40
43
  }
41
44
 
42
45
  {
43
46
  values: values_hash.values,
47
+ category_labels: values_hash.keys,
44
48
  min: min,
45
49
  max: max,
46
50
  base_width: 120,
47
- base_height: 1334,
51
+ base_height: 800,
48
52
  axis_tick_format: x_ds.axis_tick_format,
53
+ num_box_plots: y_ds.uniq_vals_count,
54
+ axis_scale: DataSeries.new('_', [min, max]).axis_scale
49
55
  }
50
56
  end
51
57
 
@@ -53,10 +59,20 @@ class RailsDataExplorer
53
59
  return '' unless render?
54
60
  ca = compute_chart_attrs
55
61
  return '' unless ca
62
+
63
+ svg_trs = ca[:category_labels].map { |cat_label|
64
+ %(
65
+ <tr>
66
+ <td style="vertical-align: middle;">#{ cat_label }</td>
67
+ <td style="vertical-align: middle; width: 100%">
68
+ <svg class="box" style="height: #{ ca[:base_width] }px;"></svg>
69
+ </td>
70
+ </tr>
71
+ )
72
+ }.join.html_safe
56
73
  %(
57
- <div id="#{ dom_id }" class="rde-chart rde-box-plot">
58
- <svg class="box" style="height: #{ ca[:base_width] }px;"></svg>
59
- <svg class="box" style="height: #{ ca[:base_width] }px;"></svg>
74
+ <div id="#{ dom_id }" class="rde-chart rde-box-plot-group">
75
+ <table>#{ svg_trs }</table>
60
76
 
61
77
  <script type="text/javascript">
62
78
  (function() {
@@ -78,6 +94,7 @@ class RailsDataExplorer
78
94
  var data = #{ ca[:values].to_json };
79
95
 
80
96
  chart.domain([min, max]);
97
+ chart.scale(#{ ca[:axis_scale] });
81
98
 
82
99
  var svg = d3.select("##{ dom_id }").selectAll("svg")
83
100
  .data(data)
@@ -5,6 +5,8 @@
5
5
  # * http://www.quora.com/What-is-the-most-intuitive-explanation-for-the-chi-square-test
6
6
  # * http://people.revoledu.com/kardi/tutorial/Questionnaire/Chi-Square%20IndependentTest.html
7
7
  # * http://stattrek.com/chi-square-test/independence.aspx?Tutorial=AP
8
+
9
+ # Contingency table and chi squared test is a good tool for interpreting A/B tests.
8
10
  class RailsDataExplorer
9
11
  class Chart
10
12
  class ContingencyTable < Chart
@@ -24,16 +26,23 @@ class RailsDataExplorer
24
26
 
25
27
  x_ds = x_candidates.first
26
28
  y_ds = (y_candidates - [x_ds]).first
29
+ return false if x_ds.nil? || y_ds.nil?
27
30
 
28
31
  # Compute @observed_vals, @expected_vals, etc.
29
32
  compute_contingency_and_chi_squared!(x_ds, y_ds)
30
33
 
31
- x_sorted_keys = x_ds.uniq_vals.sort { |a,b|
32
- @observed_vals[b][:_sum] <=> @observed_vals[a][:_sum]
33
- }
34
- y_sorted_keys = y_ds.uniq_vals.sort { |a,b|
35
- @observed_vals[:_sum][b] <=> @observed_vals[:_sum][a]
36
- }
34
+ x_sorted_keys = x_ds.uniq_vals.sort(
35
+ &x_ds.label_sorter(
36
+ nil,
37
+ lambda { |a,b| @observed_vals[b][:_sum] <=> @observed_vals[a][:_sum] }
38
+ )
39
+ )
40
+ y_sorted_keys = y_ds.uniq_vals.sort(
41
+ &y_ds.label_sorter(
42
+ nil,
43
+ lambda { |a,b| @observed_vals[:_sum][b] <=> @observed_vals[:_sum][a] }
44
+ )
45
+ )
37
46
 
38
47
  ca = case @data_set.dimensions_count
39
48
  when 2
@@ -97,6 +106,8 @@ class RailsDataExplorer
97
106
  def render
98
107
  return '' unless render?
99
108
  ca = compute_chart_attrs
109
+ return '' unless ca
110
+
100
111
  content_tag(:div, :class => 'rde-chart rde-contingency-table', :id => dom_id) do
101
112
  content_tag(:h3, "Contingency Table", :class => 'rde-chart-title') +
102
113
  render_html_table(ca)
@@ -176,11 +187,35 @@ class RailsDataExplorer
176
187
  # Set significance_level
177
188
  @significance_level = 0.05
178
189
  # Compute conclusion
179
- @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 )
180
- @conclusion << if @p_value <= @significance_level
181
- "#{ x_ds.name } and #{ y_ds.name } are dependent variables (p_value: #{ number_with_precision(@p_value) })"
190
+ all_observed_vals = []
191
+ x_ds.uniq_vals.each { |x_val|
192
+ y_ds.uniq_vals.each { |y_val|
193
+ all_observed_vals << @observed_vals[x_val][y_val]
194
+ }
195
+ }
196
+ observed_vals_less_than_five = all_observed_vals.find_all { |e| e < 5 }
197
+ ratio_of_observed_vals_below_five = observed_vals_less_than_five.length / all_observed_vals.length.to_f
198
+
199
+ if ratio_of_observed_vals_below_five > 0.2
200
+ @conclusion = [
201
+ "We did not run the ",
202
+ %(<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) } ",
204
+ "of observed values in the contingency table are below 5 (cutoff is 20%)."
205
+ ].join
206
+ elsif([x_ds, y_ds].any? { |e| e.uniq_vals.length < 2 })
207
+ @conclusion = [
208
+ "We did not run the ",
209
+ %(<a href="http://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test#Test_of_independence">Pearson chi squared test of independence</a> ),
210
+ "since there are not enough observed values in the contingency table."
211
+ ].join
182
212
  else
183
- "#{ x_ds.name } and #{ y_ds.name } are independent variables (p_value: #{ number_with_precision(@p_value) })"
213
+ @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
+ @conclusion << if @p_value <= @significance_level
215
+ %("#{ x_ds.name }" and "#{ y_ds.name }" are dependent variables (p_value: #{ number_with_precision(@p_value) }))
216
+ else
217
+ %("#{ x_ds.name }" and "#{ y_ds.name }" are independent variables (p_value: #{ number_with_precision(@p_value) }))
218
+ end
184
219
  end
185
220
  @conclusion = @conclusion.html_safe
186
221
  end
@@ -9,12 +9,21 @@ class RailsDataExplorer
9
9
 
10
10
  def compute_chart_attrs
11
11
  x_ds = @data_set.data_series.first
12
+ return false if x_ds.nil?
13
+
12
14
  # compute histogram
13
15
  h = x_ds.values.inject(Hash.new(0)) { |m,e| m[e] += 1; m }
14
16
  {
15
- values: h.map { |k,v| { x: k, y: v } }.sort { |a,b| b[:y] <=> a[:y] },
17
+ values: h.map { |k,v|
18
+ { x: k, y: v }
19
+ }.sort(
20
+ &x_ds.label_sorter(
21
+ :x,
22
+ lambda { |a,b| b[:y] <=> a[:y] }
23
+ )
24
+ ),
16
25
  x_axis_label: x_ds.name,
17
- x_axis_tick_format: "",
26
+ x_axis_tick_format: "d3.format('r')",
18
27
  y_axis_label: 'Frequency',
19
28
  y_axis_tick_format: "d3.format('r')",
20
29
  }
@@ -23,8 +32,88 @@ class RailsDataExplorer
23
32
  def render
24
33
  return '' unless render?
25
34
  ca = compute_chart_attrs
35
+ return '' unless ca
36
+ render_vega(ca)
37
+ end
38
+
39
+ def render_vega(ca)
26
40
  %(
27
- <div class="rde-chart rde-histogram">
41
+ <div class="rde-chart rde-histogram-categorical">
42
+ <h3 class="rde-chart-title">Histogram</h3>
43
+ <div id="#{ dom_id }"></div>
44
+ <script type="text/javascript">
45
+ (function() {
46
+ var spec = {
47
+ "width": 800,
48
+ "height": 200,
49
+ "padding": {"top": 10, "left": 70, "bottom": 50, "right": 10},
50
+ "data": [
51
+ {
52
+ "name": "table",
53
+ "values": #{ ca[:values].to_json }
54
+ }
55
+ ],
56
+ "scales": [
57
+ {
58
+ "name": "x",
59
+ "type": "ordinal",
60
+ "range": "width",
61
+ "domain": {"data": "table", "field": "data.x"}
62
+ },
63
+ {
64
+ "name": "y",
65
+ "range": "height",
66
+ "nice": true,
67
+ "domain": {"data": "table", "field": "data.y"}
68
+ }
69
+ ],
70
+ "axes": [
71
+ {
72
+ "type": "x",
73
+ "scale": "x",
74
+ "title": "#{ ca[:x_axis_label] }",
75
+ "format": #{ ca[:x_axis_tick_format] },
76
+ },
77
+ {
78
+ "type": "y",
79
+ "scale": "y",
80
+ "title": "#{ ca[:y_axis_label] }",
81
+ "titleOffset": 60,
82
+ "format": #{ ca[:y_axis_tick_format] },
83
+ }
84
+ ],
85
+ "marks": [
86
+ {
87
+ "type": "rect",
88
+ "from": {"data": "table"},
89
+ "properties": {
90
+ "enter": {
91
+ "x": {"scale": "x", "field": "data.x"},
92
+ "width": {"scale": "x", "band": true, "offset": -1},
93
+ "y": {"scale": "y", "field": "data.y"},
94
+ "y2": {"scale": "y", "value": 0}
95
+ },
96
+ "update": {
97
+ "fill": {"value": "#1F77B4"}
98
+ },
99
+ }
100
+ }
101
+ ]
102
+ };
103
+
104
+ vg.parse.spec(spec, function(chart) {
105
+ var view = chart({ el:"##{ dom_id }" }).update();
106
+ });
107
+
108
+ })();
109
+ </script>
110
+ </div>
111
+ )
112
+ end
113
+
114
+ def render_nvd3(ca)
115
+ %(
116
+ <div class="rde-chart rde-histogram-categorical">
28
117
  <h3 class="rde-chart-title">Histogram</h3>
29
118
  <div id="#{ dom_id }", style="height: 200px;">
30
119
  <svg></svg>
@@ -52,6 +141,12 @@ class RailsDataExplorer
52
141
  .tickFormat(#{ ca[:y_axis_tick_format] })
53
142
  ;
54
143
 
144
+ chart.tooltipContent(
145
+ function(key, x, y, e, graph) {
146
+ return '<p>' + x + '</p>' + '<p>' + y + '</p>'
147
+ }
148
+ );
149
+
55
150
  d3.select('##{ dom_id } svg')
56
151
  .datum(data)
57
152
  .transition().duration(100)
@@ -68,6 +163,12 @@ class RailsDataExplorer
68
163
  )
69
164
  end
70
165
 
166
+ # Render HistogramCategorical only if there is a fairly small number of
167
+ # distinct values.
168
+ def render?
169
+ !@data_set.data_series.first.has_many_uniq_vals?
170
+ end
171
+
71
172
  end
72
173
  end
73
174
  end