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.
- data/CHANGELOG.md +5 -1
- data/README.md +11 -0
- data/Rakefile +62 -0
- data/doc/how_to/release.md +23 -0
- data/doc/how_to/trouble_when_packaging_assets.md +8 -0
- data/lib/rails-data-explorer-no-rails.rb +42 -0
- data/lib/rails-data-explorer.rb +5 -9
- data/lib/rails-data-explorer/chart/box_plot.rb +5 -1
- data/lib/rails-data-explorer/chart/box_plot_group.rb +22 -5
- data/lib/rails-data-explorer/chart/contingency_table.rb +45 -10
- data/lib/rails-data-explorer/chart/histogram_categorical.rb +104 -3
- data/lib/rails-data-explorer/chart/histogram_quantitative.rb +99 -2
- data/lib/rails-data-explorer/chart/histogram_temporal.rb +10 -55
- data/lib/rails-data-explorer/chart/parallel_coordinates.rb +4 -0
- data/lib/rails-data-explorer/chart/parallel_set.rb +4 -0
- data/lib/rails-data-explorer/chart/pie_chart.rb +89 -8
- data/lib/rails-data-explorer/chart/scatterplot.rb +110 -8
- data/lib/rails-data-explorer/chart/stacked_bar_chart_categorical_percent.rb +133 -14
- data/lib/rails-data-explorer/data_series.rb +37 -2
- data/lib/rails-data-explorer/data_type/categorical.rb +72 -2
- data/lib/rails-data-explorer/data_type/quantitative.rb +41 -12
- data/lib/rails-data-explorer/data_type/quantitative/temporal.rb +3 -2
- data/lib/rails-data-explorer/exploration.rb +5 -1
- data/lib/rails-data-explorer/utils/data_binner.rb +31 -0
- data/lib/rails-data-explorer/utils/data_quantizer.rb +66 -0
- data/lib/rails_data_explorer.rb +133 -0
- data/rails-data-explorer.gemspec +4 -4
- data/spec/helper.rb +7 -0
- data/spec/helper_no_rails.rb +10 -0
- data/spec/rails-data-explorer/data_series_spec.rb +45 -0
- data/spec/rails-data-explorer/data_type/categorical_spec.rb +34 -0
- data/spec/rails-data-explorer/exploration_spec.rb +55 -0
- data/spec/rails-data-explorer/utils/data_binner_spec.rb +29 -0
- data/spec/rails-data-explorer/utils/data_quantizer_spec.rb +71 -0
- data/vendor/assets/javascripts/packaged/rails-data-explorer.min.js +1 -0
- data/vendor/assets/javascripts/rails-data-explorer.js +6 -5
- data/vendor/assets/javascripts/{d3.boxplot.js → sources/d3.boxplot.js} +10 -3
- data/vendor/assets/javascripts/{d3.parcoords.js → sources/d3.parcoords.js} +1 -1
- data/vendor/assets/javascripts/{d3.parsets.js → sources/d3.parsets.js} +3 -3
- data/vendor/assets/javascripts/{d3.v3.js → sources/d3.v3.js} +0 -0
- data/vendor/assets/javascripts/{nv.d3.js → sources/nv.d3.js} +0 -0
- data/vendor/assets/javascripts/sources/vega.js +7040 -0
- data/vendor/assets/stylesheets/packaged/rails-data-explorer.min.css +9 -0
- data/vendor/assets/stylesheets/rails-data-explorer.css +7 -7
- data/vendor/assets/stylesheets/{bootstrap-theme.css → sources/bootstrap-theme.css} +0 -0
- data/vendor/assets/stylesheets/{bootstrap.css → sources/bootstrap.css} +0 -0
- data/vendor/assets/stylesheets/{d3.boxplot.css → sources/d3.boxplot.css} +0 -0
- data/vendor/assets/stylesheets/{d3.parcoords.css → sources/d3.parcoords.css} +0 -0
- data/vendor/assets/stylesheets/{d3.parsets.css → sources/d3.parsets.css} +0 -0
- data/vendor/assets/stylesheets/{nv.d3.css → sources/nv.d3.css} +0 -0
- data/vendor/assets/stylesheets/{rde-default-style.css → sources/rde-default-style.css} +0 -0
- metadata +65 -28
data/CHANGELOG.md
CHANGED
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'
|
data/lib/rails-data-explorer.rb
CHANGED
@@ -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:
|
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:
|
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
|
-
<
|
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
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
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|
|
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
|