As the amount of data produced and made available on the web by social interactions and ecommerce grows larger and larger, structuring and visualizing these data in meaningful (and human-friendly) ways becomes increasingly crucial.
The amount of data generated grows exponentially every year, such that in late 2013 it was estimated that 90% of world's data had been generated over the previous two years; companies faces an arm-race to make sense of this flood of information, which can easily make the difference between understanding the market or going out of business.
While most companies easily cope with collecting data (from clicks, visits, purchases, applications' logs etc...), not all of them are able to transform the information into knowledge (or at least valuable indications). The result is that gathering terabytes of information is pointless if then we don't have efficient way to summarize and visualize it - in a few word, extracting meaning from the mere information.
In the last few years both IT giants like Google (with Google Analytics) and startups have turned their attention to this increasing demand for data-visualization tools. A new market segment has indeed thrived around this idea, with mainly two kind of products:
The alternative to such products would be, of course, in-house developments of such tools - but that's often too costly for start-ups or small companies.
Either if you need to develop charts on your own or if you are a company that offers in data-visualization as a service, you'll need to build your work upon a chart library - and hopefully a good one too.
Among the vast offer of libraries for data visualization, the first big distinction can be made between HTML5 libraries and SVG libraries.
SVG and HTML5 solutions, as you would expect, have some Pros and Cons; oversimplifying we could say that:
All things considered, since rarely you do need to insert more than a few hundreds shapes in a single chart (and if you do you might want to revisit your design), so far SVG has been the mainstream technology for data visualization.
Probably the most famous example of a chart library using this solution is ChartJs.
Another interesting library to manipulate shapes in the Canvas is FabricJs.
[
{
"name": "Morning",
"start_time": "6am",
"end_time": "12am",
"visitors": 22.7,
"unique_visitors": 42.0,
"clicks": 12.5,
"top_pages": [
{"page": "SomeSportSite.tv", "visitors": 23},
{"page": "SearchEngine.com", "visitors": 20},
...
]
},
{
"name": "Afternoon",
"start_time": "12am",
"end_time": "5pm",
"visitors": 30.3,
"unique_visitors": 19.5,
"clicks": 25.0,
"top_pages": [...]
}
...
]
<div id="day-chart" class="day-chart-div"></div>
var segmentChart = segments
.append('div')
.attr('class', 'day-part-chart')
.append('svg:svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
fields.forEach(function (fieldName, fieldIndex) {
segmentChart
.append('text')
.attr('x', rectMargin + fieldIndex * (rectMargin + rectWidth) + rectWidth * 0.5)
.attr('y', function (d) {
return rectTopMargin - 1 + rectHeight * (1 - scalePercent(d[fieldName]));
})
.attr('text-anchor', 'middle')
.text(function (d) {
return d[fieldName];
});
segmentChart
.append('rect')
.attr('class', 'day-part-main-bar')
.attr('x', rectMargin + fieldIndex * (rectMargin + rectWidth))
.attr('y', function (d) {
return rectTopMargin + rectHeight * (1 - scalePercent(d[fieldName]));
})
.attr('width', rectWidth + 'px')
.transition()
.attr('height', function (d) {
return rectHeight * scalePercent(d[fieldName]);
})
.duration(1000);
});
segmentChart
.append('line')
.attr('x1', 0)
.attr('x2', sectionWidth)
.attr('y1', rectTopMargin + rectHeight)
.attr('y2', rectTopMargin + rectHeight);
segmentLabels = segments
.append('div')
.attr('class', 'day-part-part-area');
segmentLabels
.append('span')
.attr('class', 'day-part-name')
.text(function (d, i) {
return d.name;
})
.append('br');
segmentLabels
.append('span')
.attr('class', 'day-part-time-window')
.text(function (d, i) {
return d.start_time + ' - ' + d.end_time;
});
segmentTable = segments
.append('div')
.attr('class', 'day-part-table-container');
segmentTableRows = segmentTable
.append('table')
.attr('class', 'day-part-table')
.selectAll('tr')
.data(function (d) {
return d.top_pages;
})
.enter()
.append('tr')
.attr('class', function (d) {
return d.selected ? 'day-part-table-selected' : '';
})
.on('click', function (d,i) {
updateSelection(d, i);
return false;
});
segmentTableRows
.append('td')
.text(function (d, i){
return (i+1) + '.';
});
segmentTableRows
.append('td')
.attr('class', function (d) {
return d.selected ? 'day-part-table-selected' : '';
})
.text(function (d, i){
return d.page;
});
segmentTableRows
.append('td')
.text(function (d, i){
return d[fields[tableField]] + '%';
});
var container = d3.select('#' + containerId),
segments = container.selectAll('div.day-part-section')
.data(json),
newSegments = segments
.enter()
.append('div')
.attr('class', 'day-part-section')
.style('width', sectionWidth + 'px')
.style('left', function (d, i) {
return (i * sectionWidth) + 'px';
})
.style('height', chartHeight + 'px');
var n = json.length,
fields = ['visitors', 'unique_visitors', 'clicks'],
fieldsNbr = fields.length,
ractive = new Ractive({
el: container_id,
template: ractiveTemplateId,
data: {
daypart: json,
title: title,
fields: fields,
tableField: 0,
rectWidth: chartWidth / n * 0.75 / fieldsNbr - 5,
svgHeight: chartAreaHeight,
svgWidth: chartWidth / n,
chartWidth: chartWidth,
chartHeight: chartHeight,
rectHeight: rectHeight,
sectionWidth: chartWidth / n,
rectMargin: (sectionWidth - rectWidth * fieldsNbr) / (1 + fieldsNbr),
rectTopMargin: DEFAULT_BAR_MARGIN,
scalePercent: function scalePercent(p) {
return p / 100;
}
}
});
return ractive;
function updateChart(newData) {
var n = json.length,
svgWidth = ractive.get('chartWidth') / n,
sectionWidth = svgWidth;
ractive.animate('svgWidth', svgWidth);
ractive.animate('sectionWidth', sectionWidth);
ractive.animate('daypart', newData);
}