rails-data-explorer 0.0.1
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/.gitignore +10 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +52 -0
- data/Rakefile +18 -0
- data/lib/rails-data-explorer.rb +44 -0
- data/lib/rails-data-explorer/action_view_extension.rb +12 -0
- data/lib/rails-data-explorer/active_record_extension.rb +14 -0
- data/lib/rails-data-explorer/chart.rb +52 -0
- data/lib/rails-data-explorer/chart/box_plot.rb +79 -0
- data/lib/rails-data-explorer/chart/box_plot_group.rb +109 -0
- data/lib/rails-data-explorer/chart/contingency_table.rb +189 -0
- data/lib/rails-data-explorer/chart/descriptive_statistics_table.rb +22 -0
- data/lib/rails-data-explorer/chart/descriptive_statistics_table_group.rb +0 -0
- data/lib/rails-data-explorer/chart/histogram_categorical.rb +73 -0
- data/lib/rails-data-explorer/chart/histogram_quantitative.rb +73 -0
- data/lib/rails-data-explorer/chart/histogram_temporal.rb +78 -0
- data/lib/rails-data-explorer/chart/multi_dimensional_charts.rb +1 -0
- data/lib/rails-data-explorer/chart/parallel_coordinates.rb +89 -0
- data/lib/rails-data-explorer/chart/parallel_set.rb +65 -0
- data/lib/rails-data-explorer/chart/pie_chart.rb +67 -0
- data/lib/rails-data-explorer/chart/scatterplot.rb +120 -0
- data/lib/rails-data-explorer/chart/scatterplot_matrix.rb +1 -0
- data/lib/rails-data-explorer/chart/stacked_bar_chart_categorical_percent.rb +120 -0
- data/lib/rails-data-explorer/data_series.rb +115 -0
- data/lib/rails-data-explorer/data_set.rb +127 -0
- data/lib/rails-data-explorer/data_type.rb +34 -0
- data/lib/rails-data-explorer/data_type/categorical.rb +117 -0
- data/lib/rails-data-explorer/data_type/geo.rb +1 -0
- data/lib/rails-data-explorer/data_type/quantitative.rb +109 -0
- data/lib/rails-data-explorer/data_type/quantitative/decimal.rb +13 -0
- data/lib/rails-data-explorer/data_type/quantitative/integer.rb +13 -0
- data/lib/rails-data-explorer/data_type/quantitative/temporal.rb +62 -0
- data/lib/rails-data-explorer/engine.rb +24 -0
- data/lib/rails-data-explorer/exploration.rb +89 -0
- data/lib/rails-data-explorer/statistics/pearsons_chi_squared_independence_test.rb +75 -0
- data/lib/rails-data-explorer/statistics/rng_category.rb +37 -0
- data/lib/rails-data-explorer/statistics/rng_gaussian.rb +24 -0
- data/lib/rails-data-explorer/statistics/rng_power_law.rb +21 -0
- data/lib/rails-data-explorer/utils/color_scale.rb +33 -0
- data/lib/rails-data-explorer/utils/data_binner.rb +8 -0
- data/lib/rails-data-explorer/utils/data_encoder.rb +2 -0
- data/lib/rails-data-explorer/utils/data_quantizer.rb +2 -0
- data/lib/rails-data-explorer/utils/value_formatter.rb +41 -0
- data/rails-data-explorer.gemspec +30 -0
- data/vendor/assets/javascripts/d3.boxplot.js +302 -0
- data/vendor/assets/javascripts/d3.parcoords.js +585 -0
- data/vendor/assets/javascripts/d3.parsets.js +663 -0
- data/vendor/assets/javascripts/d3.v3.js +9294 -0
- data/vendor/assets/javascripts/nv.d3.js +14369 -0
- data/vendor/assets/javascripts/rails-data-explorer.js +19 -0
- data/vendor/assets/stylesheets/bootstrap-theme.css +346 -0
- data/vendor/assets/stylesheets/bootstrap.css +1727 -0
- data/vendor/assets/stylesheets/d3.boxplot.css +20 -0
- data/vendor/assets/stylesheets/d3.parcoords.css +34 -0
- data/vendor/assets/stylesheets/d3.parsets.css +34 -0
- data/vendor/assets/stylesheets/nv.d3.css +769 -0
- data/vendor/assets/stylesheets/rails-data-explorer.css +21 -0
- data/vendor/assets/stylesheets/rde-default-style.css +42 -0
- metadata +250 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
class RailsDataExplorer
|
2
|
+
class DataType
|
3
|
+
|
4
|
+
# @param[Hash, optional] constraints
|
5
|
+
# * :dimensions_count - how many data_series are there?
|
6
|
+
def available_chart_types(constraints={})
|
7
|
+
r = all_available_chart_types
|
8
|
+
if(c = constraints.delete(:dimensions_count))
|
9
|
+
r = r.find_all { |chart_type|
|
10
|
+
(
|
11
|
+
chart_type[:dimensions_count_min].nil? ||
|
12
|
+
(chart_type[:dimensions_count_min] <= c)
|
13
|
+
) && (
|
14
|
+
chart_type[:dimensions_count_max].nil? ||
|
15
|
+
(chart_type[:dimensions_count_max] >= c)
|
16
|
+
)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
if(c = constraints.delete(:chart_roles))
|
20
|
+
# c = { ChartClass => [:x, :y], ... }
|
21
|
+
r = r.find_all { |chart_type|
|
22
|
+
c[chart_type[:chart_class]].nil? ||
|
23
|
+
(c[chart_type[:chart_class]] & chart_type[:chart_roles]).any?
|
24
|
+
}
|
25
|
+
end
|
26
|
+
# check for any unhandled options
|
27
|
+
if constraints.any?
|
28
|
+
raise "Unhandled constraints: #{ constraints.inspect }"
|
29
|
+
end
|
30
|
+
r
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class RailsDataExplorer
|
2
|
+
class DataType
|
3
|
+
class Categorical < DataType
|
4
|
+
|
5
|
+
def all_available_chart_types
|
6
|
+
[
|
7
|
+
{
|
8
|
+
:chart_class => Chart::HistogramCategorical,
|
9
|
+
:chart_roles => [:x],
|
10
|
+
:dimensions_count_min => 1,
|
11
|
+
:dimensions_count_max => 1,
|
12
|
+
},
|
13
|
+
{
|
14
|
+
:chart_class => Chart::PieChart,
|
15
|
+
:chart_roles => [:any],
|
16
|
+
:dimensions_count_min => 1,
|
17
|
+
:dimensions_count_max => 1,
|
18
|
+
},
|
19
|
+
{
|
20
|
+
chart_class: Chart::BoxPlotGroup,
|
21
|
+
chart_roles: [:y],
|
22
|
+
dimensions_count_min: 2,
|
23
|
+
dimensions_count_max: 2,
|
24
|
+
},
|
25
|
+
{
|
26
|
+
chart_class: Chart::Scatterplot,
|
27
|
+
chart_roles: [:color],
|
28
|
+
dimensions_count_min: 3,
|
29
|
+
},
|
30
|
+
{
|
31
|
+
chart_class: Chart::ParallelCoordinates,
|
32
|
+
chart_roles: [:dimension],
|
33
|
+
dimensions_count_min: 3,
|
34
|
+
},
|
35
|
+
{
|
36
|
+
chart_class: Chart::StackedBarChartCategoricalPercent,
|
37
|
+
chart_roles: [:x, :y],
|
38
|
+
dimensions_count_min: 2,
|
39
|
+
dimensions_count_max: 2,
|
40
|
+
},
|
41
|
+
{
|
42
|
+
chart_class: Chart::ContingencyTable,
|
43
|
+
chart_roles: [:any],
|
44
|
+
dimensions_count_min: 2,
|
45
|
+
dimensions_count_max: 2,
|
46
|
+
},
|
47
|
+
{
|
48
|
+
chart_class: Chart::DescriptiveStatisticsTable,
|
49
|
+
chart_roles: [:any],
|
50
|
+
dimensions_count_min: 1,
|
51
|
+
dimensions_count_max: 1,
|
52
|
+
},
|
53
|
+
{
|
54
|
+
chart_class: Chart::ParallelSet,
|
55
|
+
chart_roles: [:dimension],
|
56
|
+
dimensions_count_min: 3,
|
57
|
+
},
|
58
|
+
].freeze
|
59
|
+
end
|
60
|
+
|
61
|
+
def descriptive_statistics(values)
|
62
|
+
frequencies = values.inject(Hash.new(0)) { |m,e| m[e] += 1; m }
|
63
|
+
total_count = values.length
|
64
|
+
ruby_formatters = {
|
65
|
+
:integer => Proc.new { |v| number_with_delimiter(v.round) },
|
66
|
+
:percent => Proc.new { |v| number_to_percentage(v, :precision => 3, :significant => true, :strip_insignificant_zeros => true, :delimiter => ',') },
|
67
|
+
}
|
68
|
+
r = frequencies.inject([]) { |m, (k,v)|
|
69
|
+
m << { :label => "#{ k.to_s }_count", :value => v, :ruby_formatter => ruby_formatters[:integer] }
|
70
|
+
m << { :label => "#{ k.to_s }_percent", :value => (v / total_count.to_f) * 100, :ruby_formatter => ruby_formatters[:percent] }
|
71
|
+
m
|
72
|
+
}.sort { |a,b| b[:value] <=> a[:value] }
|
73
|
+
r.insert(0, { :label => 'Total_count', :value => total_count, :ruby_formatter => ruby_formatters[:integer] })
|
74
|
+
r.insert(0, { :label => 'Total_percent', :value => 100, :ruby_formatter => ruby_formatters[:percent] })
|
75
|
+
r
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns an OpenStruct that describes a statistics table.
|
79
|
+
def descriptive_statistics_table(values)
|
80
|
+
desc_stats = descriptive_statistics(values)
|
81
|
+
labels = desc_stats.map { |e| e[:label].gsub(/_count|_percent/, '') }.uniq
|
82
|
+
table = OpenStruct.new(
|
83
|
+
:rows => []
|
84
|
+
)
|
85
|
+
table.rows << OpenStruct.new(
|
86
|
+
:css_class => 'rde-column_header',
|
87
|
+
:tag => :tr,
|
88
|
+
:cells => labels.map { |label|
|
89
|
+
OpenStruct.new(:value => label, :ruby_formatter => Proc.new { |e| e }, :tag => :th, :css_class => 'rde-cell-label')
|
90
|
+
}
|
91
|
+
)
|
92
|
+
table.rows << OpenStruct.new(
|
93
|
+
:css_class => 'rde-data_row',
|
94
|
+
:tag => :tr,
|
95
|
+
:cells => labels.map { |label|
|
96
|
+
stat = desc_stats.detect { |e| "#{ label }_count" == e[:label] }
|
97
|
+
OpenStruct.new(:value => stat[:value], :ruby_formatter => stat[:ruby_formatter], :tag => :td, :css_class => 'rde-cell-value')
|
98
|
+
}
|
99
|
+
)
|
100
|
+
table.rows << OpenStruct.new(
|
101
|
+
:css_class => 'rde-data_row',
|
102
|
+
:tag => :tr,
|
103
|
+
:cells => labels.map { |label|
|
104
|
+
stat = desc_stats.detect { |e| "#{ label }_percent" == e[:label] }
|
105
|
+
OpenStruct.new(:value => stat[:value], :ruby_formatter => stat[:ruby_formatter], :tag => :td, :css_class => 'rde-cell-value')
|
106
|
+
}
|
107
|
+
)
|
108
|
+
table
|
109
|
+
end
|
110
|
+
|
111
|
+
def axis_tick_format(values)
|
112
|
+
%(function(d) { return d })
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# For displaying data on maps.
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class RailsDataExplorer
|
2
|
+
class DataType
|
3
|
+
class Quantitative < DataType
|
4
|
+
|
5
|
+
# This is an abstract class. Use sub_classes
|
6
|
+
|
7
|
+
def all_available_chart_types
|
8
|
+
[
|
9
|
+
{
|
10
|
+
chart_class: Chart::BoxPlot,
|
11
|
+
chart_roles: [:y],
|
12
|
+
dimensions_count_min: 1,
|
13
|
+
dimensions_count_max: 1
|
14
|
+
},
|
15
|
+
{
|
16
|
+
chart_class: Chart::HistogramQuantitative,
|
17
|
+
chart_roles: [:x],
|
18
|
+
dimensions_count_min: 1,
|
19
|
+
dimensions_count_max: 1
|
20
|
+
},
|
21
|
+
{
|
22
|
+
chart_class: Chart::BoxPlotGroup,
|
23
|
+
chart_roles: [:x],
|
24
|
+
dimensions_count_min: 2,
|
25
|
+
dimensions_count_max: 2,
|
26
|
+
},
|
27
|
+
{
|
28
|
+
chart_class: Chart::Scatterplot,
|
29
|
+
chart_roles: [:x, :y, :size],
|
30
|
+
dimensions_count_min: 2
|
31
|
+
},
|
32
|
+
{
|
33
|
+
chart_class: Chart::DescriptiveStatisticsTable,
|
34
|
+
chart_roles: [:any],
|
35
|
+
dimensions_count_min: 1,
|
36
|
+
dimensions_count_max: 1
|
37
|
+
},
|
38
|
+
{
|
39
|
+
chart_class: Chart::ParallelCoordinates,
|
40
|
+
chart_roles: [:dimension],
|
41
|
+
dimensions_count_min: 3,
|
42
|
+
},
|
43
|
+
].freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
def descriptive_statistics(values)
|
47
|
+
stats = ::DescriptiveStatistics::Stats.new(values)
|
48
|
+
ruby_formatters = {
|
49
|
+
:integer => Proc.new { |v| number_with_delimiter(v.round) },
|
50
|
+
:decimal => Proc.new { |v| number_with_precision(v, :precision => 3, :significant => true, :strip_insignificant_zeros => true, :delimiter => ',') },
|
51
|
+
:pass_through => Proc.new { |v| v },
|
52
|
+
}
|
53
|
+
[
|
54
|
+
{ :label => 'Min', :value => stats.min, :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
55
|
+
{ :label => '1%ile', :value => stats.value_from_percentile(1), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
56
|
+
{ :label => '10%ile', :value => stats.value_from_percentile(10), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
57
|
+
{ :label => '25%ile', :value => stats.value_from_percentile(25), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
58
|
+
{ :label => 'Median', :value => stats.median, :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
59
|
+
{ :label => '75%ile', :value => stats.value_from_percentile(75), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
60
|
+
{ :label => '90%ile', :value => stats.value_from_percentile(90), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
61
|
+
{ :label => '99%ile', :value => stats.value_from_percentile(99), :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
62
|
+
{ :label => 'Max', :value => stats.max, :ruby_formatter => ruby_formatters[:decimal], :table_row => 1 },
|
63
|
+
{ :label => '', :value => '', :ruby_formatter => ruby_formatters[:pass_through], :table_row => 1 },
|
64
|
+
|
65
|
+
{ :label => 'Range', :value => stats.range, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
66
|
+
{ :label => 'Mean', :value => stats.mean, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
67
|
+
{ :label => 'Mode', :value => stats.mode, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
68
|
+
{ :label => 'Count', :value => values.length, :ruby_formatter => ruby_formatters[:integer], :table_row => 2 },
|
69
|
+
{ :label => 'Sum', :value => values.inject(0) { |m,e| m += e }, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
70
|
+
{ :label => 'Variance', :value => stats.variance, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
71
|
+
{ :label => 'Std. dev.', :value => stats.standard_deviation, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
72
|
+
{ :label => 'Rel. std. dev.', :value => stats.relative_standard_deviation, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
73
|
+
{ :label => 'Skewness', :value => stats.skewness, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
74
|
+
{ :label => 'Kurtosis', :value => stats.kurtosis, :ruby_formatter => ruby_formatters[:decimal], :table_row => 2 },
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns an OpenStruct that describes a statistics table.
|
79
|
+
def descriptive_statistics_table(values)
|
80
|
+
desc_stats = descriptive_statistics(values)
|
81
|
+
table = OpenStruct.new(
|
82
|
+
:rows => []
|
83
|
+
)
|
84
|
+
[1,2].each do |table_row|
|
85
|
+
table.rows << OpenStruct.new(
|
86
|
+
:css_class => 'rde-column_header',
|
87
|
+
:tag => :tr,
|
88
|
+
:cells => desc_stats.find_all { |e| table_row == e[:table_row] }.map { |stat|
|
89
|
+
OpenStruct.new(:value => stat[:label], :ruby_formatter => Proc.new { |e| e }, :tag => :th, :css_class => 'rde-cell-label')
|
90
|
+
}
|
91
|
+
)
|
92
|
+
table.rows << OpenStruct.new(
|
93
|
+
:css_class => 'rde-data_row',
|
94
|
+
:tag => :tr,
|
95
|
+
:cells => desc_stats.find_all { |e| table_row == e[:table_row] }.map { |stat|
|
96
|
+
OpenStruct.new(:value => stat[:value], :ruby_formatter => stat[:ruby_formatter], :tag => :td, :css_class => 'rde-cell-value')
|
97
|
+
}
|
98
|
+
)
|
99
|
+
end
|
100
|
+
table
|
101
|
+
end
|
102
|
+
|
103
|
+
def axis_tick_format(values)
|
104
|
+
raise "Implement me in sub_class"
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class RailsDataExplorer
|
2
|
+
class DataType
|
3
|
+
class Quantitative
|
4
|
+
class Temporal < Quantitative
|
5
|
+
|
6
|
+
def all_available_chart_types
|
7
|
+
[
|
8
|
+
{
|
9
|
+
:chart_class => Chart::HistogramTemporal,
|
10
|
+
:chart_roles => [:x],
|
11
|
+
:dimensions_count_min => 1,
|
12
|
+
:dimensions_count_max => 1
|
13
|
+
},
|
14
|
+
{
|
15
|
+
chart_class: Chart::DescriptiveStatisticsTable,
|
16
|
+
chart_roles: [:any],
|
17
|
+
dimensions_count_min: 1,
|
18
|
+
dimensions_count_max: 1
|
19
|
+
},
|
20
|
+
{
|
21
|
+
chart_class: Chart::ParallelCoordinates,
|
22
|
+
chart_roles: [:dimension],
|
23
|
+
dimensions_count_min: 3,
|
24
|
+
},
|
25
|
+
].freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
def descriptive_statistics(values)
|
29
|
+
ruby_formatter = Proc.new { |v| v.nil? ? '' : v.strftime('%a, %b %e, %Y, %l:%M:%S %p %Z') }
|
30
|
+
[
|
31
|
+
{ :label => 'Min', :value => values.min, :ruby_formatter => ruby_formatter },
|
32
|
+
{ :label => 'Max', :value => values.max, :ruby_formatter => ruby_formatter },
|
33
|
+
{ :label => 'Count', :value => values.length, :ruby_formatter => Proc.new { |e| number_with_delimiter(e) } },
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an OpenStruct that describes a statistics table.
|
38
|
+
def descriptive_statistics_table(values)
|
39
|
+
desc_stats = descriptive_statistics(values)
|
40
|
+
table = OpenStruct.new(
|
41
|
+
:rows => desc_stats.map { |stat|
|
42
|
+
OpenStruct.new(
|
43
|
+
:css_class => 'rde-row-values',
|
44
|
+
:tag => :tr,
|
45
|
+
:cells => [
|
46
|
+
OpenStruct.new(:value => stat[:label], :tag => :th, :css_class => 'rde-row_header'),
|
47
|
+
OpenStruct.new(:value => stat[:value], :ruby_formatter => stat[:ruby_formatter], :tag => :td, :css_class => 'rde-cell-value'),
|
48
|
+
]
|
49
|
+
)
|
50
|
+
}
|
51
|
+
)
|
52
|
+
table
|
53
|
+
end
|
54
|
+
|
55
|
+
def axis_tick_format(values)
|
56
|
+
%(function(d) { return d3.time.format('%x')(new Date(d)) })
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
class RailsDataExplorer
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
|
6
|
+
# It's an engine so that we can add javascript and image assets
|
7
|
+
# to the asset pipeline.
|
8
|
+
|
9
|
+
# initializer "rails-data-explorer.active_record_extension" do |app|
|
10
|
+
# require 'rails-data-explorer/active_record_extension'
|
11
|
+
# class ::ActiveRecord::Base
|
12
|
+
# extend RailsDataExplorer::ActiveRecordExtension::ClassMethods
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
|
16
|
+
# initializer "rails-data-explorer.action_view_extension" do |app|
|
17
|
+
# require 'rails-data-explorer/action_view_extension'
|
18
|
+
# class ::ActionView::Base
|
19
|
+
# include RailsDataExplorer::ActionViewExtension
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class RailsDataExplorer
|
2
|
+
class Exploration
|
3
|
+
|
4
|
+
attr_accessor :output_buffer # required for content_tag
|
5
|
+
include ActionView::Helpers::TagHelper
|
6
|
+
|
7
|
+
attr_accessor :charts, :data_set, :title
|
8
|
+
|
9
|
+
# Initializes a new visualization.
|
10
|
+
# @param[String] _title will be printed at top of visualization
|
11
|
+
# @param[Array] data_set_or_array can be a number of things:
|
12
|
+
# * Array<Scalar> - for single data series, uni-variate options are applied.
|
13
|
+
# * Array<Hash> - for multiple data series, bi/multi-variate options are applied.
|
14
|
+
# * DataSet - For finer grained control.
|
15
|
+
# @param[Array<Chart, String, Symbol>, optional] chart_specs
|
16
|
+
# The list of charts to include. Defaults to all applicable charts for the
|
17
|
+
# given data_set_or_array.
|
18
|
+
# Charts can be provided as Array of Strings, Symbols, or Chart classes
|
19
|
+
# (can be mixed).
|
20
|
+
def initialize(_title, data_set_or_array, chart_specs=nil)
|
21
|
+
@title = _title
|
22
|
+
@data_set = initialize_data_set(data_set_or_array)
|
23
|
+
@charts = initialize_charts(chart_specs)
|
24
|
+
end
|
25
|
+
|
26
|
+
def render
|
27
|
+
content_tag(:div, :class => 'rde-exploration panel panel-default', :id => dom_id) do
|
28
|
+
content_tag(:div, :class => 'panel-heading') do
|
29
|
+
content_tag(:h2, @title, :class => 'rde-exploration-title panel-title')
|
30
|
+
end +
|
31
|
+
content_tag(:div, :class => 'panel-body') do
|
32
|
+
@charts.map { |e| e.render }.join.html_safe
|
33
|
+
end
|
34
|
+
end.html_safe
|
35
|
+
end
|
36
|
+
|
37
|
+
def dom_id
|
38
|
+
"rde-exploration-#{ object_id }"
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect(indent=1, recursive=1000)
|
42
|
+
r = %(#<#{ self.class.to_s }\n)
|
43
|
+
r << [
|
44
|
+
"@title=#{ @title.inspect }",
|
45
|
+
].map { |e| "#{ ' ' * indent }#{ e }\n"}.join
|
46
|
+
if recursive > 0
|
47
|
+
r << %(#{ ' ' * indent }@data_set=)
|
48
|
+
r << data_set.inspect(indent + 1, recursive - 1)
|
49
|
+
end
|
50
|
+
r << %(#{ ' ' * (indent-1) }>\n)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def initialize_charts(chart_specs)
|
56
|
+
if chart_specs.present?
|
57
|
+
chart_specs.map { |chart_spec|
|
58
|
+
case chart_spec
|
59
|
+
when Chart
|
60
|
+
when String, Symbol
|
61
|
+
else
|
62
|
+
end
|
63
|
+
}
|
64
|
+
else
|
65
|
+
@data_set.available_chart_types.map { |e|
|
66
|
+
e.send(:new, @data_set)
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize_data_set(data_set_or_array)
|
72
|
+
case data_set_or_array
|
73
|
+
when Array
|
74
|
+
DataSet.new(data_set_or_array, @title)
|
75
|
+
when DataSet
|
76
|
+
# use as is
|
77
|
+
_data_set
|
78
|
+
else
|
79
|
+
raise(
|
80
|
+
ArgumentError.new(
|
81
|
+
"data_set_or_array must be an Array or a DataSet, " + \
|
82
|
+
"is #{ data_set_or_array.class.to_s }"
|
83
|
+
)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|