Gabriele Ferri

info@gabrieleferri.it :: mobile: +39 346 8642134

home » laboratorio » Label nel grafico radar delle pChart

:: Label nel grafico radar delle pChart

Uno dei grafici con un utilizzo più particolare e mirato è il grafico di tipo "radar"; quando capita di doverlo utilizzare per particolari applicazioni php, ci si trova sempre di fronte ad un dilemma: o scriverselo da zero utilizzando le librerie GD oppure andare alla ricerca di librerie (preferibilmente a costo zero) che ti possano fare il grafico radar.
Dopo il sostanziale fallimento del package Pear Image_Graph, la mia ricerca si è fermata (almeno per ora) quando ho scoperto le librerie pChart.

Ho scelto pChart perché innanzi tutto sono facilmente configurabili e permettono di fare grafici eleganti, grazie alle varie personalizzazioni nella configurazione.

Le label del radar prima dell'intervento

Le label proposte nella documentazione relativa agli esempi di base, si limitano a segnare il livelli del grafico senza definire i valori dei vertici del radar disegnato.
La documentazione offre il metodo writeValues per scrivere i valori per cui, dopo aver disegnato il radar, aggiungo la seguente parte di codice all'esempio mostrasto nel tutorial: $Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",8); $Test->writeValues($DataSet->GetData(),$DataSet->GetDataDescription(),array("Serie1", "Serie2"),20,$MaxVal); Il risultato è il seguente:

grafico radar con le label raggruppate tutte in fondo a sinistra

Per i grafici radar non vengono gestite le posizioni delle label nei vertici per cui è necessario ridefinire quantomeno il metodo writeValues nella classe pChart.class

Estensione della classe pChart

Ho chiamato l'estensione della classe pChart, LabelRadarpChart ridefinendo i metodi drawRadarAxis e writeValues.
Al metodo drawRadarAxis ho aggiunto il passaggio di un altro parametro che ho chiamato $writeValues e che mi serve per gestire la scrittura o meno dei valori dei livelli della ragnatela, questo perché l'eventuale scrittura dei valori sui vertici potrebbe produrre un grafico illeggibile. Le modifiche sostanziali sono: function drawadarAxis($Data,$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1,$writeValues=TRUE) { [....] if($writeValues){ for ( $t=1; $t<=$MaxValue; $t++) { $TRadius = ( $Radius / $MaxValue ) * $t; $Angle = -90 + 360 / $Points; $X1 = $XCenter; $Y1 = $YCenter - $TRadius; $X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; $Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; $XPos = floor(($X2-$X1)/2) + $X1; $YPos = floor(($Y2-$Y1)/2) + $Y1; $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t); $X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2; $Y = $YPos + $this->FontSize; $this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240); $this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220); imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t); } } }

Il metodo writeValues è stato ridefinito prevedendo la gestione di $BorderOffset, così com'è previsto nel metodo drawadarAxis, e di $MaxValue nel caso in cui si voglia definire in modo autonomo il valore massimo di rappresentazione del radar.
Da notare anche il settaggio del parametro $C_SetTextColor, se vero, scrive i valori delle label con lo stesso colore dell'area che viene rappresentata; i valori risultano poco leggibili ed è per questo che preferisco non utilizzare tale settaggio. Tuttavia se si pensa di voler impostare un colore specifico per ogni serie rappresentata, sarà opportuno ripensare al parametro come un array e non più una variabile booleana.
Il metodo risulta così definito:
function writeValues($Data,$DataDescription,$Series,$BorderOffset=10,$MaxValue=-1,$C_SetTextColor=FALSE) { /* Validate the Data and DataDescription array */ $this->validateDataDescription("writeValues",$DataDescription); $this->validateData("writeValues",$Data); $Points = count($Data); $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; $XCenter = ( ( $this->GArea_X2 - $this->GArea_X1 ) / 2 ) + $this->GArea_X1; $YCenter = ( ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 ) + $this->GArea_Y1; if ( !is_array($Series) ) { $Series = array($Series); } /* Search for the max value */ if ( $MaxValue == -1 ) { foreach ( $DataDescription["Values"] as $Key2 => $ColName ) { foreach ( $Data as $Key => $Values ) { if ( isset($Data[$Key][$ColName])) if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; } } } } foreach($Series as $Key => $Serie) { $ID = 0; foreach ( $DataDescription["Description"] as $keyI => $ValueI ) { if ( $keyI == $Serie ) { $ColorID = $ID; }; $ID++; } $Angle = -90; $XLast = -1; foreach ( $Data as $Key => $Values ) { if ( isset($Data[$Key][$Serie]) && is_numeric($Data[$Key][$Serie])) { $Value = $Data[$Key][$Serie]; $Strength = ( $Radius / $MaxValue ) * $Value; $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter; $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter; $Angle = $Angle + (360/$Points); $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Value); $Width = $Positions[2] - $Positions[6]; $Height = $Positions[3] - $Positions[7]; $XOffset = $XPos - ($Width/2); $YOffset = $YPos + ($Height/2); if ($C_SetTextColor) $C_TextColor =$this->AllocateColor($this->Picture,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); imagettftext($this->Picture,$this->FontSize,0,$XOffset,$YOffset,$C_TextColor,$this->FontName,$Value); } $XPos = $XPos + $this->DivisionWidth; } } }

Come si utilizza la nuova estensione

La classe estesa LabelRadarpChart è pronta per essere utilizzata tenendo presente che ora sarà necessario includere nello script php la nostra classe e si dovrà istanziare la classe estesa:
include_once(LIBS_PATH."/pChart/LabelRadarpChart.class"); [...] $Test = new LabelRadarpChart(500,333); [...] $Test->drawRadarAxis($DataSet->GetData(),$DataSet->GetDataDescription(),TRUE,20,120,120,120,230,230,230,$MaxVal,FALSE);

Il risultato è il seguente:

grafico radar con le label posizionate correttamente ai vertici