reports_kit 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.travis.yml +20 -0
- data/README.md +17 -19
- data/app/assets/javascripts/reports_kit/lib/_init.js +2 -1
- data/app/assets/javascripts/reports_kit/lib/chart.js +25 -16
- data/app/assets/javascripts/reports_kit/lib/report.js +42 -25
- data/app/assets/javascripts/reports_kit/lib/table.js +37 -2
- data/app/assets/stylesheets/reports_kit/reports.css.sass +3 -0
- data/docs/dimensions.md +26 -34
- data/docs/display_options.md +12 -15
- data/docs/filters.md +54 -63
- data/docs/measures.md +3 -4
- data/lib/reports_kit.rb +12 -10
- data/lib/reports_kit/base_controller.rb +1 -2
- data/lib/reports_kit/configuration.rb +19 -4
- data/lib/reports_kit/entity.rb +3 -0
- data/lib/reports_kit/helper.rb +17 -21
- data/lib/reports_kit/model_configuration.rb +1 -1
- data/lib/reports_kit/report_builder.rb +11 -11
- data/lib/reports_kit/reports/{abstract_measure.rb → abstract_series.rb} +1 -1
- data/lib/reports_kit/reports/{composite_measure.rb → composite_series.rb} +12 -8
- data/lib/reports_kit/reports/data/add_table_aggregations.rb +105 -0
- data/lib/reports_kit/reports/data/{composite_aggregation.rb → aggregate_composite.rb} +28 -27
- data/lib/reports_kit/reports/data/{one_dimension.rb → aggregate_one_dimension.rb} +9 -7
- data/lib/reports_kit/reports/data/{two_dimensions.rb → aggregate_two_dimensions.rb} +9 -8
- data/lib/reports_kit/reports/data/chart_options.rb +6 -11
- data/lib/reports_kit/reports/data/format_one_dimension.rb +56 -36
- data/lib/reports_kit/reports/data/format_table.rb +65 -0
- data/lib/reports_kit/reports/data/format_two_dimensions.rb +10 -8
- data/lib/reports_kit/reports/data/generate.rb +51 -28
- data/lib/reports_kit/reports/data/generate_for_properties.rb +52 -30
- data/lib/reports_kit/reports/data/populate_one_dimension.rb +30 -12
- data/lib/reports_kit/reports/data/populate_two_dimensions.rb +31 -31
- data/lib/reports_kit/reports/data/utils.rb +28 -24
- data/lib/reports_kit/reports/dimension.rb +4 -0
- data/lib/reports_kit/reports/{dimension_with_measure.rb → dimension_with_series.rb} +8 -9
- data/lib/reports_kit/reports/filter.rb +4 -0
- data/lib/reports_kit/reports/filter_types/base.rb +4 -3
- data/lib/reports_kit/reports/filter_types/boolean.rb +4 -4
- data/lib/reports_kit/reports/filter_types/datetime.rb +13 -3
- data/lib/reports_kit/reports/filter_types/number.rb +5 -5
- data/lib/reports_kit/reports/{filter_with_measure.rb → filter_with_series.rb} +7 -7
- data/lib/reports_kit/reports/generate_autocomplete_results.rb +2 -2
- data/lib/reports_kit/reports/inferrable_configuration.rb +6 -6
- data/lib/reports_kit/reports/{measure.rb → series.rb} +28 -15
- data/lib/reports_kit/reports_controller.rb +25 -5
- data/lib/reports_kit/value.rb +3 -0
- data/lib/reports_kit/version.rb +1 -1
- data/spec/fixtures/generate_inputs.yml +116 -63
- data/spec/fixtures/generate_outputs.yml +64 -0
- data/spec/reports_kit/report_builder_spec.rb +10 -12
- data/spec/reports_kit/reports/data/generate_spec.rb +559 -140
- data/spec/reports_kit/reports/{dimension_with_measure_spec.rb → dimension_with_series_spec.rb} +5 -7
- data/spec/reports_kit/reports/{filter_with_measure_spec.rb → filter_with_series_spec.rb} +3 -3
- data/spec/spec_helper.rb +5 -5
- data/spec/support/config.rb +31 -1
- data/spec/support/helpers.rb +6 -2
- metadata +17 -14
- data/lib/reports_kit/reports/data/entity.rb +0 -7
- data/lib/reports_kit/reports/data/value.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50df5df0e40d9cd127c03bacec3905c401be05ab
|
4
|
+
data.tar.gz: 071d750fe875bcdaa4308fde9e6bf280b18c5d3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6fbfb97c8e5f30a23d1260c73046e5f1e19941b0cdaad796ae490c8ebcbf73eeacc3eb3cfc1cd974f80e58b7c31e56d7366e3311e6af9146da055a64c410f25
|
7
|
+
data.tar.gz: 57c6cdba6764b876efbe81d85f98285c5945b85f0571d8fa715806f2210b94b317698b06a957171ef78ea15fc23d2c21e904eb6f2f250e9036270f5217d26fd7
|
data/.rubocop.yml
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
cache: bundler
|
2
|
+
|
3
|
+
language: ruby
|
4
|
+
|
5
|
+
services:
|
6
|
+
- mysql
|
7
|
+
- postgresql
|
8
|
+
|
9
|
+
rvm:
|
10
|
+
- '2.2.7'
|
11
|
+
- '2.3.4'
|
12
|
+
- '2.4.1'
|
13
|
+
|
14
|
+
before_install: gem update bundler
|
15
|
+
before_script:
|
16
|
+
- psql -c 'CREATE DATABASE reports_kit_test;' -U postgres
|
17
|
+
- mysql -e 'CREATE DATABASE IF NOT EXISTS reports_kit_test;'
|
18
|
+
- bundle exec appraisal install
|
19
|
+
|
20
|
+
script: bundle exec appraisal rspec
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
ReportsKit
|
2
2
|
=====
|
3
|
+
[](https://travis-ci.org/tombenner/reports_kit)
|
4
|
+
|
3
5
|
ReportsKit lets you easily create beautiful charts with customizable, interactive filters.
|
4
6
|
|
5
7
|
For interactive examples, see [reportskit.co](https://www.reportskit.co/).
|
@@ -63,35 +65,27 @@ end
|
|
63
65
|
Quick Start
|
64
66
|
-----------
|
65
67
|
|
66
|
-
After installation, you can create your first chart with a single line
|
67
|
-
|
68
|
-
In any view, create a chart that shows the number of records of a model (e.g. `user`) created over time:
|
69
|
-
|
70
|
-
`app/views/users/index.html.haml`
|
71
|
-
```haml
|
72
|
-
= render_report measure: { key: 'user', dimensions: ['created_at'] }
|
73
|
-
```
|
74
|
-
|
75
|
-
You're done! `render_report` will render the following chart:
|
76
|
-
|
77
|
-
[<img src="docs/images/users_by_created_at.png?raw=true" width="500" />](docs/images/users_by_created_at.png?raw=true)
|
68
|
+
After installation, you can create your first chart with just a YAML file and a single line in any view.
|
78
69
|
|
79
|
-
|
70
|
+
Configure the chart in the YAML file:
|
80
71
|
|
81
72
|
`config/reports_kit/reports/my_users.yml`
|
82
73
|
```yaml
|
83
|
-
measure:
|
84
|
-
|
85
|
-
|
86
|
-
- created_at
|
74
|
+
measure: user
|
75
|
+
dimensions:
|
76
|
+
- created_at
|
87
77
|
```
|
88
78
|
|
79
|
+
Then pass that filename to `render_report` in a view:
|
80
|
+
|
89
81
|
`app/views/users/index.html.haml`
|
90
82
|
```haml
|
91
83
|
= render_report 'my_users'
|
92
84
|
```
|
93
85
|
|
94
|
-
|
86
|
+
You're done! `render_report` will render the following chart:
|
87
|
+
|
88
|
+
[<img src="docs/images/users_by_created_at.png?raw=true" width="500" />](docs/images/users_by_created_at.png?raw=true)
|
95
89
|
|
96
90
|
### Form Controls
|
97
91
|
|
@@ -109,7 +103,11 @@ Many other form controls are available; see [Filters](docs/filters.md) for more.
|
|
109
103
|
|
110
104
|
### How It Works
|
111
105
|
|
112
|
-
In the Quick Start chart, `
|
106
|
+
In the Quick Start chart, `measure: user` tells ReportsKit to count the number of `User` records, and `dimensions: ['created_at']` tells it to group by the week of the `created_at` column. Since `created_at` is a `datetime` column, ReportsKit knows that it should group the counts by week (the granularity is configurable), sort them chronologically, and add in zeros for any missing weeks.
|
107
|
+
|
108
|
+
ReportsKit infers sane defaults from your ActiveRecord model configurations. If there was a `belongs_to :company` association on `User` and you used `dimensions: ['company']`, then ReportsKit would count users grouped by the `company_id` column and show company names on the x-axis.
|
109
|
+
|
110
|
+
If you need more customization (e.g. custom filters, custom dimensions, custom aggregation functions, custom orders, aggregations of aggregations, etc), ReportsKit is very flexible and powerful and supports all of these with a simple syntax. It lets you use SQL, too.
|
113
111
|
|
114
112
|
To learn how to use more of ReportsKit's features, check out the following resources:
|
115
113
|
|
@@ -3,6 +3,7 @@ window.ReportsKit = {};
|
|
3
3
|
$(document).ready(function() {
|
4
4
|
$('.reports_kit_report').each(function(index, el) {
|
5
5
|
var el = $(el)
|
6
|
-
|
6
|
+
var reportClass = el.data('report-class');
|
7
|
+
new ReportsKit[reportClass]().render({ 'el': el });
|
7
8
|
});
|
8
9
|
});
|
@@ -6,7 +6,8 @@ ReportsKit.Chart = (function(options) {
|
|
6
6
|
self.report = options.report;
|
7
7
|
self.el = self.report.el;
|
8
8
|
|
9
|
-
self.
|
9
|
+
self.defaultEmptyStateText = 'No data was found';
|
10
|
+
self.emptyStateEl = $('<div>' + self.defaultEmptyStateText + '</div>').appendTo(self.report.visualizationEl).hide();
|
10
11
|
self.loadingIndicatorEl = $('<div class="loading_indicator"></div>').appendTo(self.report.visualizationEl).hide();
|
11
12
|
self.canvas = $('<canvas />').appendTo(self.report.visualizationEl);
|
12
13
|
};
|
@@ -15,19 +16,32 @@ ReportsKit.Chart = (function(options) {
|
|
15
16
|
var path = self.el.data('path');
|
16
17
|
var separator = path.indexOf('?') === -1 ? '?' : '&';
|
17
18
|
path += separator + 'properties=' + encodeURIComponent(JSON.stringify(self.report.properties()));
|
18
|
-
self.loadingIndicatorEl.fadeIn(
|
19
|
+
self.loadingIndicatorEl.fadeIn(1000);
|
20
|
+
if (self.canvas.is(':visible')) {
|
21
|
+
self.canvas.fadeTo(300, 0.1);
|
22
|
+
}
|
19
23
|
$.getJSON(path, function(response) {
|
20
24
|
var data = response.data;
|
21
25
|
var chartData = data.chart_data;
|
26
|
+
var isEmptyState = chartData.datasets.length === 0 ||
|
27
|
+
(chartData.datasets.length === 1 && chartData.datasets[0].data.length === 0);
|
28
|
+
var emptyStateText = (data.report_options && data.report_options.empty_state_text) || self.defaultEmptyStateText;
|
22
29
|
var options = chartData.options;
|
23
|
-
options = self.addAdditionalOptions(options,
|
30
|
+
options = self.addAdditionalOptions(options, data.report_options);
|
31
|
+
|
32
|
+
self.loadingIndicatorEl.stop(true, true).hide();
|
33
|
+
self.emptyStateEl.html(emptyStateText).toggle(isEmptyState);
|
34
|
+
if (isEmptyState) {
|
35
|
+
self.canvas.hide();
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
self.canvas.show().fadeTo(300, 1);
|
24
39
|
|
25
40
|
var args = {
|
26
41
|
type: data.type,
|
27
42
|
data: chartData,
|
28
43
|
options: options
|
29
44
|
};
|
30
|
-
self.loadingIndicatorEl.stop(true, true).hide();
|
31
45
|
|
32
46
|
if (self.chart) {
|
33
47
|
self.chart.data.datasets = chartData.datasets;
|
@@ -36,24 +50,19 @@ ReportsKit.Chart = (function(options) {
|
|
36
50
|
} else {
|
37
51
|
self.chart = new Chart(self.canvas, args);
|
38
52
|
}
|
39
|
-
self.noResultsEl.toggle(self.chart.data.labels.length === 0);
|
40
53
|
});
|
41
54
|
};
|
42
55
|
|
43
|
-
self.addAdditionalOptions = function(options,
|
56
|
+
self.addAdditionalOptions = function(options, reportOptions) {
|
44
57
|
var additionalOptions = {};
|
45
|
-
var maxItems =
|
58
|
+
var maxItems = reportOptions && reportOptions.legend && reportOptions.legend.max_items;
|
46
59
|
if (maxItems) {
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}
|
53
|
-
}
|
54
|
-
}
|
60
|
+
options.legend = options.legend || {};
|
61
|
+
options.legend.labels = options.legend.labels || {};
|
62
|
+
options.legend.labels.filter = options.legend.labels.filter || function(item) {
|
63
|
+
var index = (typeof item.datasetIndex === 'undefined') ? item.index : item.datasetIndex;
|
64
|
+
return index < maxItems;
|
55
65
|
};
|
56
|
-
options = $.extend(true, options, additionalOptions);
|
57
66
|
}
|
58
67
|
return options;
|
59
68
|
};
|
@@ -1,8 +1,7 @@
|
|
1
|
-
ReportsKit.Report = (function(
|
1
|
+
ReportsKit.Report = (function() {
|
2
2
|
var self = this;
|
3
3
|
|
4
|
-
self.
|
5
|
-
self.options = options;
|
4
|
+
self.render = function(options) {
|
6
5
|
self.el = options.el;
|
7
6
|
self.visualizationEl = self.el.find('.reports_kit_visualization');
|
8
7
|
|
@@ -11,33 +10,25 @@ ReportsKit.Report = (function(options) {
|
|
11
10
|
|
12
11
|
self.initializeElements();
|
13
12
|
self.initializeEvents();
|
13
|
+
self.initializeVisualization();
|
14
|
+
self.renderVisualization();
|
15
|
+
};
|
14
16
|
|
17
|
+
self.initializeVisualization = function() {
|
15
18
|
if (self.defaultProperties.format == 'table') {
|
16
19
|
self.visualization = new ReportsKit.Table({ report: self });
|
17
20
|
} else {
|
18
21
|
self.visualization = new ReportsKit.Chart({ report: self });
|
19
22
|
}
|
20
|
-
self.render();
|
21
23
|
};
|
22
24
|
|
23
25
|
self.initializeElements = function() {
|
24
26
|
self.exportButtons = self.el.find('[data-role=reports_kit_export_button]');
|
25
|
-
self.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
'Today': [moment(), moment()],
|
31
|
-
'Last 7 Days': [moment().subtract(7, 'days'), moment()],
|
32
|
-
'Last 30 Days': [moment().subtract(30, 'days'), moment()],
|
33
|
-
'Last 2 Months': [moment().subtract(2, 'months'), moment()],
|
34
|
-
'Last 3 Months': [moment().subtract(3, 'months'), moment()],
|
35
|
-
'Last 4 Months': [moment().subtract(4, 'months'), moment()],
|
36
|
-
'Last 6 Months': [moment().subtract(6, 'months'), moment()],
|
37
|
-
'Last 12 Months': [moment().subtract(12, 'months'), moment()],
|
38
|
-
'Year To Date': [moment().startOf('year'), moment()]
|
39
|
-
}
|
40
|
-
});
|
27
|
+
self.initializeAutocompletes();
|
28
|
+
self.initializeDateRangePickers();
|
29
|
+
};
|
30
|
+
|
31
|
+
self.initializeAutocompletes = function() {
|
41
32
|
self.form.find('.select2').each(function(index, el) {
|
42
33
|
el = $(el);
|
43
34
|
var path = el.data('path');
|
@@ -67,12 +58,40 @@ ReportsKit.Report = (function(options) {
|
|
67
58
|
});
|
68
59
|
};
|
69
60
|
|
61
|
+
self.initializeDateRangePickers = function() {
|
62
|
+
self.form.find('.date_range_picker').daterangepicker({
|
63
|
+
opens: 'left',
|
64
|
+
drops: 'down',
|
65
|
+
showDropdowns: false,
|
66
|
+
showWeekNumbers: false,
|
67
|
+
timePicker: false,
|
68
|
+
buttonClasses: ['btn', 'btn-sm'],
|
69
|
+
applyClass: 'btn-primary btn-daterange-submit',
|
70
|
+
cancelClass: 'btn-default',
|
71
|
+
maxDate: moment(),
|
72
|
+
locale: {
|
73
|
+
format: 'MMM D, YYYY'
|
74
|
+
},
|
75
|
+
ranges: {
|
76
|
+
'Today': [moment(), moment()],
|
77
|
+
'Last 7 Days': [moment().subtract(7, 'days'), moment()],
|
78
|
+
'Last 30 Days': [moment().subtract(30, 'days'), moment()],
|
79
|
+
'Last 2 Months': [moment().subtract(2, 'months'), moment()],
|
80
|
+
'Last 3 Months': [moment().subtract(3, 'months'), moment()],
|
81
|
+
'Last 4 Months': [moment().subtract(4, 'months'), moment()],
|
82
|
+
'Last 6 Months': [moment().subtract(6, 'months'), moment()],
|
83
|
+
'Last 12 Months': [moment().subtract(12, 'months'), moment()],
|
84
|
+
'Year To Date': [moment().startOf('year'), moment()]
|
85
|
+
}
|
86
|
+
});
|
87
|
+
};
|
88
|
+
|
70
89
|
self.initializeEvents = function() {
|
71
90
|
self.form.find('select,input').on('change', function() {
|
72
|
-
self.
|
91
|
+
self.renderVisualization();
|
73
92
|
})
|
74
93
|
self.form.on('submit', function() {
|
75
|
-
self.
|
94
|
+
self.renderVisualization();
|
76
95
|
return false;
|
77
96
|
})
|
78
97
|
self.exportButtons.on('click', self.onClickExportButton);
|
@@ -110,11 +129,9 @@ ReportsKit.Report = (function(options) {
|
|
110
129
|
return false;
|
111
130
|
};
|
112
131
|
|
113
|
-
self.
|
132
|
+
self.renderVisualization = function() {
|
114
133
|
self.visualization.render();
|
115
134
|
};
|
116
135
|
|
117
|
-
self.initialize(options);
|
118
|
-
|
119
136
|
return self;
|
120
137
|
});
|
@@ -6,6 +6,8 @@ ReportsKit.Table = (function(options) {
|
|
6
6
|
self.report = options.report;
|
7
7
|
self.el = self.report.el;
|
8
8
|
|
9
|
+
self.defaultEmptyStateText = 'No data was found';
|
10
|
+
self.emptyStateEl = $('<div>' + self.defaultEmptyStateText + '</div>').appendTo(self.report.visualizationEl).hide();
|
9
11
|
self.loadingIndicatorEl = $('<div class="loading_indicator"></div>').appendTo(self.report.visualizationEl).hide();
|
10
12
|
self.table = $('<table />', { 'class': 'table table-striped table-hover' }).appendTo(self.report.visualizationEl);
|
11
13
|
};
|
@@ -14,19 +16,37 @@ ReportsKit.Table = (function(options) {
|
|
14
16
|
var path = self.el.data('path');
|
15
17
|
var separator = path.indexOf('?') === -1 ? '?' : '&';
|
16
18
|
path += separator + 'properties=' + encodeURIComponent(JSON.stringify(self.report.properties()));
|
17
|
-
self.loadingIndicatorEl.fadeIn(
|
19
|
+
self.loadingIndicatorEl.fadeIn(1000);
|
20
|
+
if (self.table.is(':visible')) {
|
21
|
+
self.table.fadeTo(300, 0.1);
|
22
|
+
}
|
18
23
|
$.getJSON(path, function(response) {
|
19
24
|
var data = response.data;
|
20
25
|
var tableData = data.table_data;
|
26
|
+
var reportOptions = data.report_options || {};
|
27
|
+
// If the data only includes column headers, then it we have an empty state.
|
28
|
+
var isEmptyState = tableData.length <= 1;
|
29
|
+
var emptyStateText = reportOptions.empty_state_text || self.defaultEmptyStateText;
|
30
|
+
self.emptyStateEl.html(emptyStateText);
|
21
31
|
|
22
32
|
self.loadingIndicatorEl.stop(true, true).hide();
|
33
|
+
self.emptyStateEl.toggle(isEmptyState);
|
34
|
+
if (isEmptyState) {
|
35
|
+
self.table.hide();
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
self.table.show().fadeTo(300, 1);
|
23
39
|
|
40
|
+
var rowAggregationsCount = self.rowAggregationsCount(reportOptions);
|
41
|
+
var rowAggregationsStartIndex = rowAggregationsCount ? (tableData.length - rowAggregationsCount) : null;
|
24
42
|
var html = '';
|
25
43
|
for(var i = 0; i < tableData.length; i++) {
|
26
44
|
if (i == 0) {
|
27
45
|
html += '<thead><tr>';
|
28
46
|
} else if (i == 1) {
|
29
47
|
html += '<tbody><tr>';
|
48
|
+
} else if (rowAggregationsCount && i == rowAggregationsStartIndex) {
|
49
|
+
html += '<tfoot><tr>';
|
30
50
|
} else {
|
31
51
|
html += '<tr>';
|
32
52
|
}
|
@@ -35,12 +55,14 @@ ReportsKit.Table = (function(options) {
|
|
35
55
|
if (i == 0 || j == 0) {
|
36
56
|
html += '<th>' + (tableData[i][j] || '') + '</th>';
|
37
57
|
} else {
|
38
|
-
html += '<td>' + tableData[i][j] + '</td>';
|
58
|
+
html += '<td>' + ((tableData[i][j] === null) ? '' : tableData[i][j]) + '</td>';
|
39
59
|
}
|
40
60
|
}
|
41
61
|
|
42
62
|
if (i == 0) {
|
43
63
|
html += '</tr></thead>';
|
64
|
+
} else if (i == tableData.length && rowAggregationsCount) {
|
65
|
+
html += '</tfoot></tbody>';
|
44
66
|
} else if (i == tableData.length) {
|
45
67
|
html += '</tr></tbody>';
|
46
68
|
} else {
|
@@ -52,6 +74,19 @@ ReportsKit.Table = (function(options) {
|
|
52
74
|
});
|
53
75
|
};
|
54
76
|
|
77
|
+
self.rowAggregationsCount = function(reportOptions) {
|
78
|
+
if (!reportOptions.aggregations) {
|
79
|
+
return 0;
|
80
|
+
};
|
81
|
+
var rowAggregationsCount = 0;
|
82
|
+
for(var i = 0; i < reportOptions.aggregations.length; i++) {
|
83
|
+
if (reportOptions.aggregations[i].from === 'columns') {
|
84
|
+
rowAggregationsCount += 1;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return rowAggregationsCount;
|
88
|
+
};
|
89
|
+
|
55
90
|
self.initialize(options);
|
56
91
|
|
57
92
|
return self;
|
@@ -7,6 +7,9 @@
|
|
7
7
|
width: 180px
|
8
8
|
.loading_indicator
|
9
9
|
position: absolute
|
10
|
+
margin: 5px auto
|
11
|
+
left: 0
|
12
|
+
right: 0
|
10
13
|
padding: 22px
|
11
14
|
background: url(data:image/gif;base64,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) no-repeat center
|
12
15
|
|
data/docs/dimensions.md
CHANGED
@@ -15,71 +15,64 @@ end
|
|
15
15
|
You can then use `dimensions: ['carrier']` to count the number of Flights per Carrier:
|
16
16
|
|
17
17
|
```yaml
|
18
|
-
measure:
|
19
|
-
|
20
|
-
|
21
|
-
- carrier
|
18
|
+
measure: flight
|
19
|
+
dimensions:
|
20
|
+
- carrier
|
22
21
|
```
|
23
22
|
[<img src="images/flights_by_carrier.png?raw=true" width="500" />](images/flights_by_carrier.png?raw=true)
|
24
23
|
|
25
24
|
You can also use two dimensions:
|
26
25
|
|
27
26
|
```yaml
|
28
|
-
measure:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- flight_at
|
27
|
+
measure: flight
|
28
|
+
dimensions:
|
29
|
+
- carrier
|
30
|
+
- flight_at
|
33
31
|
```
|
34
32
|
[<img src="images/flights_by_carrier_and_flight_at.png?raw=true" width="500" />](images/flights_by_carrier_and_flight_at.png?raw=true)
|
35
33
|
|
36
34
|
Dimensions can be configured using a string (`carrier`):
|
37
35
|
|
38
36
|
```yaml
|
39
|
-
measure:
|
40
|
-
|
41
|
-
|
42
|
-
- carrier
|
37
|
+
measure: flight
|
38
|
+
dimensions:
|
39
|
+
- carrier
|
43
40
|
```
|
44
41
|
|
45
42
|
Or, if you need to use options, you can configure them using a hash:
|
46
43
|
|
47
44
|
```yaml
|
48
|
-
measure:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
limit: 5
|
45
|
+
measure: flight
|
46
|
+
dimensions:
|
47
|
+
- key: carrier
|
48
|
+
limit: 5
|
53
49
|
```
|
54
50
|
#### Types
|
55
51
|
|
56
52
|
##### Association
|
57
53
|
|
58
54
|
```yaml
|
59
|
-
measure:
|
60
|
-
|
61
|
-
|
62
|
-
- carrier
|
55
|
+
measure: flight
|
56
|
+
dimensions:
|
57
|
+
- carrier
|
63
58
|
```
|
64
59
|
[<img src="images/flights_by_carrier.png?raw=true" width="500" />](images/flights_by_carrier.png?raw=true)
|
65
60
|
|
66
61
|
##### Datetime Column
|
67
62
|
|
68
63
|
```yaml
|
69
|
-
measure:
|
70
|
-
|
71
|
-
|
72
|
-
- flight_at
|
64
|
+
measure: flight
|
65
|
+
dimensions:
|
66
|
+
- flight_at
|
73
67
|
```
|
74
68
|
[<img src="images/flights_by_flight_at.png?raw=true" width="500" />](images/flights_by_flight_at.png?raw=true)
|
75
69
|
|
76
70
|
##### Integer Column
|
77
71
|
|
78
72
|
```yaml
|
79
|
-
measure:
|
80
|
-
|
81
|
-
|
82
|
-
- delay
|
73
|
+
measure: flight
|
74
|
+
dimensions:
|
75
|
+
- delay
|
83
76
|
```
|
84
77
|
[<img src="images/flights_by_delay.png?raw=true" width="500" />](images/flights_by_delay.png?raw=true)
|
85
78
|
|
@@ -100,10 +93,9 @@ end
|
|
100
93
|
We can then use the `hours_delayed` dimension:
|
101
94
|
|
102
95
|
```yaml
|
103
|
-
measure:
|
104
|
-
|
105
|
-
|
106
|
-
- hours_delayed
|
96
|
+
measure: flight
|
97
|
+
dimensions:
|
98
|
+
- hours_delayed
|
107
99
|
```
|
108
100
|
[<img src="images/flights_by_hours_delayed.png?raw=true" width="500" />](images/flights_by_hours_delayed.png?raw=true)
|
109
101
|
|