Skip to content

Commit 68deacb

Browse files
committed
Add 7-day moving averages to download graph. Plus UI tweaks.
The non-stacked scattered chart as a basis reflects the download numbers correctly. The stacked area chart before was a bit midleading. Both approaches are a bit "noisy", so I added a 7-day moving average line for each version number. This gives a higher-level overview and also makes it easy to see when new versions overtake older ones in usage. The colors were chosen to be colorblindness-friendly as well as having a hot-cold metaphor.
1 parent 474e926 commit 68deacb

File tree

1 file changed

+61
-3
lines changed

1 file changed

+61
-3
lines changed

app/components/download-graph.js

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,64 @@ export default Ember.Component.extend({
7979
});
8080
fmt.format(myData, 0);
8181

82-
var chart = new window.google.visualization.AreaChart(this.get('element'));
83-
chart.draw(myData, {
82+
// use a DataView to calculate an x-day moving average
83+
var days = 7;
84+
var view = new google.visualization.DataView(myData);
85+
var moving_avg_func_for_col = function(col) {
86+
return function(dt, row) {
87+
// For the last rows (the *first* days, remember, the dataset is
88+
// backwards), we cannot calculate the avg. of previous days.
89+
if (row >= dt.getNumberOfRows() - days) {
90+
return null;
91+
}
92+
93+
var total = 0;
94+
for (var i = days; i > 0; i--) {
95+
total += dt.getValue(row + i, col);
96+
}
97+
var avg = total / days;
98+
return {
99+
v: avg,
100+
f: avg.toFixed(2)
101+
};
102+
};
103+
};
104+
105+
var columns = [0]; // 0 = datetime
106+
var seriesOption = {};
107+
// Colors by http://colorbrewer2.org/#type=diverging&scheme=RdBu&n=10
108+
var colors = ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#92c5de',
109+
'#4393c3', '#2166ac', '#053061'];
110+
var [headers, ] = data;
111+
// Walk over the headers/colums in reverse order, as the newest version
112+
// is at the end, but in the UI we want it at the top of the chart legend.
113+
_.forEach(_.range(headers.length - 1, 0, -1), (dataCol, i) => {
114+
columns.push(dataCol); // add the column itself
115+
columns.push({ // add a 'calculated' column, the moving average
116+
type: 'number',
117+
label: `${headers[dataCol]} ${days}-day avg.`,
118+
calc: moving_avg_func_for_col(dataCol)
119+
});
120+
// Note: while the columns start with index 1 (because 0 is the time
121+
// axis), the series configuration starts with index 0.
122+
seriesOption[i * 2] = {
123+
type: 'scatter',
124+
color: colors[i % colors.length],
125+
pointSize: 3,
126+
pointShape: 'square'
127+
};
128+
seriesOption[i * 2 + 1] = {
129+
type: 'line',
130+
color: colors[i % colors.length],
131+
lineWidth: 2,
132+
curveType: 'function',
133+
visibleInLegend: false
134+
};
135+
});
136+
view.setColumns(columns);
137+
138+
var chart = new window.google.visualization.ComboChart(this.get('element'));
139+
chart.draw(view, {
84140
chartArea: { 'left': 85, 'width': '77%', 'height': '80%' },
85141
hAxis: {
86142
minorGridlines: { count: 8 },
@@ -89,8 +145,10 @@ export default Ember.Component.extend({
89145
minorGridlines: { count: 5 },
90146
viewWindow: { min: 0, },
91147
},
92-
isStacked: true,
148+
isStacked: false,
93149
focusTarget: 'category',
150+
seriesType: 'scatter',
151+
series: seriesOption
94152
});
95153
},
96154
});

0 commit comments

Comments
 (0)