Salve a tutti. In questo articolo vedremo come calcolare e rappresentare in maniera automatica la media e la deviazione standard, la moda e la mediana di un diagramma a barre. Per fare ciò utilizzeremo la libreria jqPlot.
Per prima cosa partiamo da una sequenza di dati da rappresentare. Generalmente questi dati provengono da una sorgente esterna e non sono definiti all’interno della pagina Web. Spesso sono il risultato di una query effettuata su un database, o dalla lettura di un file esterno come un file .txt,.csv o dalla acquisizione diretta proveniente da uno strumento, da una stazione di rilevamento o più generalmente da un sensore. Per semplicità in questo esempio utilizzeremo direttamente una sequenza di dati già definita all’interno di un array che chiameremo data.
var data = [15.2,13.0,11.7,12.9,16.9,22.7,26.0,22.7, 29.7,31.7,21.3,16.7,11.4,6.6,2.7,-5.0,-7.3,-11.3];
Nelle situazioni più reali dovremo implementare noi la funzione, o utilizzando funzioni appartenenti ad altre librerie, che ci permettono di leggere i dati da fonti esterne, farne un parsing in modo da selezionare solo il dato che ci interessa e convertirlo nel formato corretto (spesso da stringa a numerico).
Se siete interessati ad approfondire l’argomento, all’interno del libro Beginning JavaScript Charts vengono presentate varie metodologie di acquisizione dati, dall’estrazione di dati da una tabella di un database (tramite PHP), alla lettura e parsing dei dati contenuti in un file esterno. Viene inoltre spiegato dettagliatamente il formato JSON, e grazie a numerosi esempi viene mostrato come sia pratico utilizzarlo in queste occasioni.
Inoltre sono presenti vari capitoli che riguardano i diagrammi a barre con tantissimi esempi che illustrano varie modalità di visualizzazione: orizzontali, verticali, stacked (a pila), e a gruppo, ecc.
Ma tornando all’esempio di questo articolo, scriviamo una pagina Web con integrate all’interno le funzioni JavaScript che richiamano la libreria jqPlot in modo da poter rappresentare un diagramma a barre come quello in Fig.2.
<html>
<head>
<title>Statistics on a bar chart</title>
<!--[if lt IE 9]><script type="text/javascript" src="../src/excanvas.js"></script> <![endif]-->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.js"></script>
<link href="http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.min.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisTickRenderer.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.barRenderer.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.pointLabels.min.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisLabelRenderer.min.js">
</script><script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasOverlay.js"></script>
<script type="text/javascript" src="arrays.js"></script>
<script class="code" type="text/javascript"> $(document).ready(function(){
var data = [15.2,13.0,11.7,12.9,16.9,22.7,26.0,22.7,
29.7,31.7,21.3,16.7,11.4,6.6,2.7,-5.0,-7.3,-11.3];
var options= {
title: 'Statistics on a Bar Charts',
seriesColors: ['darkgreen'],
series:[{
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barMargin: 5,
fillToZero: true
},
pointLabels: {
show: true,
formatString: '%.1f',
seriesLabelIndex:1,
hideZeros:false
}
}],
axes: {
xaxis: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
renderer: $.jqplot.CategoryAxisRenderer,
label: 'Sample #'
},
yaxis: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
padMin: 0,
pad: 1.1,
label: 'Temperatures (°C)',
rendererOptions: { forceTickAt0: true}
}
},
negativeSeriesColors:['darkred'],
grid:{
background: '#f8f8f8'
}
};
$.jqplot('graph', [data], options ); });
</head>
<body>
<div id="graph" style="height: 400px; width: 700px;"></div>
</body>
</html>
E questo è il diagramma a barre che si ottiene:
Adesso a questo diagramma a barre vogliamo rappresentare mediante delle linee tratteggiate:
- la media
- la mediana
- la moda
Inoltre rappresenteremo la deviazione standard come un’area ombreggiata centrata sulla media ed infine vedremo come aggiungere l’andamento della media calcolata punto dopo punto attraverso un grafico lineare sovrapponendolo al nostro diagramma a barre.
Prima di passare alla parte grafica sarà necessario implementare tutta una serie di funzioni che effettuino i calcoli statistici sugli elementi contenuti all’interno di un array. A tale scopo scriveremo una libreria arrays.js, contenente le varie funzioni che utilizzeremo nella pagina web. Tale funzioni vanno ad estendere le funzionalità dell’oggetto Array in JavaScript.
Array.prototype.average=function(){
var sum=0;
var j=0;
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
}
}
if(j===0){
return 0;
}else{
return sum/j;
}
}
Array.prototype.stddev=function(){
var n = 0;
var sum = 0.0;
var sum_sq = 0.0;
for(var i=0;i<this.length;i++){
n++;
sum += this[i];
sum_sq += this[i]*this[i];
}
return Math.sqrt( (sum_sq /n) - Math.pow(sum /n, 2));
}
Array.prototype.median=function(){
var median = 0,
sorted = [],
numsLen = this.length;
sorted = this.slice();
sorted.sort();
if (numsLen % 2 === 0) {
median = (sorted[numsLen / 2 - 1] + sorted[numsLen / 2]) / 2;
} else {
median = sorted[(numsLen - 1) / 2];
}
return median;
}
Array.prototype.mode=function(){
//it returns an array. If modal it has only 1 element
// if multimodal it has n elements
var modes = [],
count = [],
i,
number,
maxIndex = 0;
for (i = 0; i < this.length; i += 1) {
number = this[i];
count[number] = (count[number] || 0) + 1;
if (count[number] > maxIndex) {
maxIndex = count[number];
}
}
for (i in count)
if (count.hasOwnProperty(i)){
if (count[i] === maxIndex) {
modes.push(Number(i));
}
}
return modes;
}
Array.prototype.average_t=function(){
var sum=0;
var j=0;
var average_t = [];
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
average_t[i] = sum/j
}
}
if(j===0){
return 0;
}else{
return average_t;
}
}
Una volta scritta la libreria, la dobbiamo includere nella nostra pagina Web. Aggiungiamo quindi
<script type="text/javascript" src="arrays.js"></script>
e facciamo alcune aggiunte al codice JavaScript.
$(document).ready(function(){
var data = [15.2,13.0,11.7,12.9,16.9,22.7,26.0,22.7,29.7,
31.7,21.3,16.7,11.4,6.6,2.7,-5.0,-7.3,-11.3];
var line = data.average_t();
var options= {
title: 'Statistics on a Bar Chart',
seriesColors: ['darkgreen','orange'],
series:[{
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barMargin: 5,
fillToZero: true
},
pointLabels: {
show: true,
formatString: '%.1f',
seriesLabelIndex:1,
hideZeros:false
}
}],
axes: {
xaxis: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
renderer: $.jqplot.CategoryAxisRenderer,
label: 'Sample #'
},
yaxis: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
padMin: 0,
pad: 1.1,
label: 'Temperatures (°C)',
rendererOptions: { forceTickAt0: true}
}
},
negativeSeriesColors:['darkred'],
grid:{ background: '#f8f8f8' },
canvasOverlay: {
show: true,
objects: [
{dashedHorizontalLine: {
name: 'average',
y: data.average(),
lineWidth: 3,
color: 'black',
shadow: false
}},
{dashedHorizontalLine: {
name: 'mode',
y: data.mode()[0],
lineWidth: 3,
color: 'darkred',
shadow: false
}},
{dashedHorizontalLine: {
name: 'median',
y: data.median(),
lineWidth: 3,
color: 'blue',
shadow: false
}}
]
}
};
$.jqplot('graph', [data,line], options );
});
Quindi adesso nel diagramma a barre compariranno tre nuove linee tratteggiate (ved Fig.3): la mediana in blu, la media in nero e la moda in rosso. Inoltre l’andamento lineare in giallo che si sovrappone alle varie barre è la media calcolata per ciascuna barra n utilizzando tutti i campioni da 1 a n (alla fine questa linea tende alla linea tratteggiata nera, cioè la media calcolata su tutti i valori).
Infine possiamo anche visualizzare la deviazione standard della media come un’area opaca (in grigio) centrata sulla linea della media. Aggiungiamo le seguenti righe di codice all’interno di canvasOverlay
{rectangle: {
name: 'stddev',
ymin: data.average()-data.stddev(),
ymax: data.average()+data.stddev(),
color: 'rgba(150,150,150,0.3)',
shadow: false
}}
e disabilitando la visualizzazione della mediana e della modo, otteniamo il seguente grafico: