info@gabrieleferri.it :: mobile: +39 346 8642134
home » laboratorio » Creare un grafico a barre orizzontali con pChart
La libreria pChart mette a disposizione una serie di metodi per creare un istogramma e gestire le funzionalità essenziali come ad esempio la media, le serie multiple, il valore massimo e minimo in ordinata e così via.
Purtroppo in questa libreria, non è stata prevista la possibilità di creare un istogramma orizzontale.
Ho deciso di scrivere questo articolo da quando sono stato informato che la mia estensione è stata inserita, integrata e corretta in Goolge Code e segnalata in alcune piattaforme di software collaborativo come Chamilo.
L'estensione che presento, si integra alla libreria esistente e permette di creare un grafico a barre orizzonatli utilizzando la stessa logica di pChart.
Realizzare un grafico a barre verticali con pChart è molto semplice; partendo dalla documentazione e dagli esempi di base, utilizzando i metodi già messi a disposizione è possibile fare grafici di questo tipo:
La necessità di realizzare un istogramma orizzontale può sorgere per diversi motivi: ci potrebbero essere molte barre da visualizzare e alcuni layout non permettono di generare grafici lunghi (come questo sito) con la conseguenza che il grafico potrebbe diventare illeggibile. Come in questo caso, anche le label con i testi molto lunghi potrebbero essere un problema.
La realizzazione di un istogramma orizzontale potrebbe risolvere buona parte dei nostri problemi, ma la libreria pChart non è in grado di disegnarla.
Da una prima analisi, si nota che non è opportuno effettuare l'override dei metodi principali che realizzano l'istogramma veritcale per cui ho proceduto a creare nuovi metodi che tengano conto delle necessità
che possono sorgere nella realizzazione di un grafico a barre orizzontali.
I metodi creati sono:
Il metodo che invece è stato ridefinito è drawTreshold solitamente utilizzato per segnare la media dei valori rappresentati dalle seire di barre.
A questo metodo sono stati aggiunti tre parametri ($Angle, $LabelMarginX, $LabelMarginY) che servono per disporre meglio il relativo valore.
Grazie anche al contributo di Julio Montoya che ha apportato alcune modifiche al mio codice originale, il metodo risulta così definito:
function drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnBottom=FALSE,$TickWidth=4,$FreeText=NULL,$Angle=0,$LabelMarginX=0,$LabelMarginY=0)
{
if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
$C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B);
$X = $this->GArea_X1 + ($Value - $this->VMin) * $this->DivisionRatio;
if ( $X <= $this->GArea_X1 || $X >= $this->GArea_X2 )
return(-1);
if ( $TickWidth == 0 )
$this->drawLine($X,$this->GArea_Y1,$X,$this->GArea_Y2,$R,$G,$B);
else
$this->drawDottedLine($X,$this->GArea_Y1,$X,$this->GArea_Y2,$TickWidth,$R,$G,$B);
if ( $ShowLabel )
{
if ( $FreeText == NULL ) { $Label = $Value; }
else { $Label = $FreeText; }
$Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Label);
$TextWidth = abs($Position[2])-abs($Position[0]);
$TextLeft = abs($Position[3])-abs($Position[1]);
if ( $ShowOnBottom )
imagettftext($this->Picture,$this->FontSize,$Angle,$X+$LabelMarginX,$this->GArea_Y2+$LabelMarginY,$C_TextColor,$this->FontName,$Label);
else
imagettftext($this->Picture,$this->FontSize,$Angle,$X+$LabelMarginX,$this->GArea_Y1-$TextWidth+$LabelMarginY,$C_TextColor,$this->FontName,$Label);
}
}
La classe estesa HorizontalBar è pronta per essere utilizzata tenendo presente che ora sarà necessario includere nello script php la nuova classe e si dovrà istanziare la classe estesa.
Bisognerà inoltre ricordarsi di utilizzare i nuovi metodi specifici descritti sopra, per disegnare l'istogramma orizzontale:
<?php
define("LIBS_PATH",'your pChart direcotry');
// Standard inclusions
include_once(LIBS_PATH."/pChart/pData.class");
include_once(LIBS_PATH."/pChart/pChart.class");
include_once(LIBS_PATH."/pChart/HorizontalBar.class");
// Dataset definition
$DataSet = new pData;
$DataSet->AddPoint(array("Label 1","Label 2
con testo lungo","Label 3","Label 4","Label 5","Label 6","Label 7"),"Label");
$DataSet->SetAbsciseLabelSerie("Label");
$serie1 = array(1,4,3,2,1,3,2);
$serie2 = array(3,3,2,1,3.73,2,1);
$serie3 = array(4,1,2,1,4.5,2,3);
$serie4 = array(3,1.5,4,2,4.7,3,4);
$average = round(array_sum($serie1)/count($serie1), 2);
$DataSet->AddPoint($serie1,"Serie1");
$DataSet->AddSerie("Serie1");
$DataSet->SetSerieName("1a serie","Serie1");
$DataSet->AddPoint($serie2,"Serie2");
$DataSet->AddSerie("Serie2");
$DataSet->SetSerieName("2a serie","Serie2");
$DataSet->AddPoint($serie3,"Serie3");
$DataSet->AddSerie("Serie3");
$DataSet->SetSerieName("3a serie","Serie3");
$DataSet->AddPoint($serie4,"Serie4");
$DataSet->AddSerie("Serie4");
$DataSet->SetSerieName("4a serie","Serie4");
$average = round(($average + round(array_sum($serie2)/count($serie2), 2) + round(array_sum($serie3)/count($serie3), 2) + round(array_sum($serie4)/count($serie4), 2))/4, 2);
// Initialise the graph
$Test = new HorizontalBar(500,700);
$Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",8);
$Test->setGraphArea(120,60,450,650);
$Test->setFixedScale(0,5,5,0,0,0);
$Test->drawFilledRoundedRectangle(7,7,493,693,5,240,240,240);
$Test->drawRoundedRectangle(5,5,495,695,5,230,230,230);
$Test->drawGraphArea(255,255,255,TRUE);
$Test->drawHorScale($DataSet->GetData(),$DataSet->GetDataDescription(),SCALE_NORMAL,150,150,150,TRUE,0,2,TRUE);
$Test->drawHorGrid(10,TRUE,230,230,230,50);
// Draw the 0 line
$Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",6);
$Test->drawTreshold($average,143,55,72,TRUE,FALSE,2,null,90,3,-3);
// Draw the bar graph
$Test->drawHorBarGraph($DataSet->GetData(),$DataSet->GetDataDescription(),FALSE);
// Finish the graph
$Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",8);
$Test->drawLegend(15,15,$DataSet->GetDataDescription(),255,255,255);
$Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",10);
$Test->drawTitle(170,27,"Confronto evoluzione",50,50,50,-1);
$Test->Stroke();
?>
Il risultato è il seguente: