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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/README.md +18 -0
- data/doc/how_to/release.md +2 -5
- data/lib/rails-data-explorer-no-rails.rb +1 -0
- data/lib/rails-data-explorer.rb +5 -0
- data/lib/rails-data-explorer/chart.rb +11 -11
- data/lib/rails-data-explorer/chart/box_plot_group.rb +10 -3
- data/lib/rails-data-explorer/chart/contingency_table.rb +58 -45
- data/lib/rails-data-explorer/chart/descriptive_statistics_table.rb +2 -2
- data/lib/rails-data-explorer/chart/histogram_categorical.rb +10 -4
- data/lib/rails-data-explorer/chart/histogram_quantitative.rb +12 -5
- data/lib/rails-data-explorer/chart/histogram_temporal.rb +6 -0
- data/lib/rails-data-explorer/chart/parallel_coordinates.rb +4 -4
- data/lib/rails-data-explorer/chart/parallel_set.rb +3 -3
- data/lib/rails-data-explorer/chart/stacked_bar_chart_categorical_percent.rb +3 -3
- data/lib/rails-data-explorer/constants.rb +5 -0
- data/lib/rails-data-explorer/data_series.rb +20 -14
- data/lib/rails-data-explorer/data_set.rb +4 -0
- data/lib/rails-data-explorer/data_type/categorical.rb +84 -72
- data/lib/rails-data-explorer/data_type/quantitative.rb +46 -48
- data/lib/rails-data-explorer/data_type/quantitative/temporal.rb +23 -17
- data/lib/rails-data-explorer/exploration.rb +20 -4
- data/lib/rails-data-explorer/statistics/rng_category.rb +1 -1
- data/lib/rails-data-explorer/utils/data_binner.rb +20 -10
- data/lib/rails-data-explorer/utils/data_quantizer.rb +6 -6
- data/lib/rails-data-explorer/utils/rde_table.rb +62 -0
- data/lib/rails_data_explorer.rb +35 -20
- data/rails-data-explorer.gemspec +1 -1
- data/spec/rails-data-explorer/exploration_spec.rb +4 -4
- data/spec/rails-data-explorer/utils/data_binner_spec.rb +3 -3
- metadata +30 -50
checksums.yaml
ADDED
@@ -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
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/doc/how_to/release.md
CHANGED
@@ -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'
|
data/lib/rails-data-explorer.rb
CHANGED
@@ -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[
|
23
|
-
def render_html_table(
|
24
|
-
content_tag(:table, :
|
25
|
-
|
26
|
-
content_tag(row.tag, :
|
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
|
-
:
|
33
|
-
:
|
34
|
-
:
|
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
|
-
:
|
41
|
-
:
|
42
|
-
:
|
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:
|
47
|
-
category_labels:
|
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
|
-
|
50
|
-
OpenStruct.new(
|
49
|
+
Utils::RdeTable.new(
|
51
50
|
# Top header row
|
52
|
-
|
53
|
-
|
54
|
-
:
|
55
|
-
:
|
56
|
-
:
|
57
|
-
|
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
|
-
|
68
|
-
:
|
69
|
-
|
70
|
-
|
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
|
-
|
75
|
-
:
|
76
|
-
|
77
|
-
:
|
78
|
-
|
79
|
-
|
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
|
-
[
|
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
|
-
|
88
|
-
:
|
89
|
-
:
|
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
|
-
|
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
|
-
[
|
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, :
|
112
|
-
content_tag(:h3, "Contingency Table", :
|
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 = { :
|
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
|
178
|
-
:
|
179
|
-
:
|
180
|
-
:
|
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, :
|
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
|
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
|
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, :
|
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", :
|
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('
|
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
|
-
"
|
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":
|
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, :
|
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": {
|
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":
|
103
|
+
"y2": {"scale": "y", "value": #{ ca[:bar_y2_val] }},
|
97
104
|
},
|
98
105
|
"update": {
|
99
106
|
"fill": {"value": "#1F77B4"}
|