Páginas

domingo, 19 de diciembre de 2010

Creacion de Graficos en documentos PDF con FPDF y JGRAPH

Para esta nueva entrada realizaremos reportes estadísticos mediante gráficos de torta, utilizando la librería FPDF y JGRAPH.

Materiales necesarios:
-Librería FPDF descargar
-Librería JGRAPG, descargar

Muchas veces al momento de estar realizando nuestros sistemas necesitamos reportes estadísticos en los mismo, mayormente lo que se necesita es un documento con los datos en formato PDF, es ahí donde utilizamos la librería FPDF, esta es una librería formada por una clase cuyos métodos nos ayudan a generar los documentos PDF, para mayor información en su sitio oficial http://www.fpdf.org/. Pero esta librería por sí sola no nos permite generar gráficos estadísticos es ahí donde entra la participación de la librería JGRAP, la cual es una librería que nos permite generar gráficos estadísticos escrita en PHP, para mas información de JGRAPH su sitio oficial es http://jpgraph.net/ .
Pero como trabajar estas librerías juntas??
En esta ocasión realizaremos una clase llamada reporte que extiende de FPDF y dentro de sus métodos utilizaremos uno para generar los gráficos mediante JGRAPH. Vamos a la acción.
Como Se indico lo primero que haremos es crear una clase que extiende FPDF esto para poder acceder a los métodos de esta librería y así crear nuestro documento PDF
class Reporte extends FPDF
{
     public function __construct($orientation='P', $unit='mm', $format='A4')
  {
   parent::__construct($orientation, $unit, $format);
 } 
}
Si nos fijamos el constructor de nuestra clase sobrescribe al constructor de la clase FPDF, de manera que cuando instanciamos nuestra clase si le damos algún parámetro el mismo pasara también a la clase padre.

Luego crearemos un método para generar los gráficos, en este articulo solo trabajaremos con los gráficos de tarta, si es necesario otro tendríamos que hacer algunas modificaciones a nuestro método.
public function gaficoPDF($datos = array(),$nombreGrafico = NULL,$ubicacionTamamo = array(),$titulo = NULL)
 { 
  //construccion de los arrays de los ejes x e y
  if(!is_array($datos) || !is_array($ubicacionTamamo)){
   echo "los datos del grafico y la ubicacion deben de ser arreglos";
  }
  elseif($nombreGrafico == NULL){
   echo "debe indicar el nombre del grafico a crear";
  }
  else{ 
   #obtenemos los datos del grafico  
   foreach ($datos as $key => $value){
    $data[] = $value[0];
    $nombres[] = $key; 
    $color[] = $value[1];
   } 
   $x = $ubicacionTamamo[0];
   $y = $ubicacionTamamo[1]; 
   $ancho = $ubicacionTamamo[2];  
   $altura = $ubicacionTamamo[3];  
   #Creamos un grafico vacio
   $graph = new PieGraph(600,400);
   #indicamos titulo del grafico si lo indicamos como parametro
   if(!empty($titulo)){
    $graph->title->Set($titulo);
   }   
   //Creamos el plot de tipo tarta
   $p1 = new PiePlot3D($data);
   $p1->SetSliceColors($color);
   #indicamos la leyenda para cada porcion de la tarta
   $p1->SetLegends($nombres);
   //Añadirmos el plot al grafico
   $graph->Add($p1);
   //mostramos el grafico en pantalla
   $graph->Stroke("$nombreGrafico.png"); 
   $this->Image("$nombreGrafico.png",$x,$y,$ancho,$altura);  
  } 
 }
Si se fijan dentro de los paramtros de nuestro método tenemos:
$datos: Es un arreglo asociativo con los datos que se desean graficar, para nuestro ejemplo es la cantidad de alumnos aprobados y reprobados de un salón de clase. El arreglo que contendrá los datos debe de tener la siguiente estructura.
Array(‘nombredeldato’=>array(valor,colorEnTarta));
Cada uno de los valores tendrá que ser mediante este formato para obtener el grafico en la manera deseada.
$nombreGrafico: Es el nombre que llevara la imagen del grafico que se creara, el método “gaficoPDF” lo que hace es crear una imagen por medio de la librería JGRAPH y luego llamar a la misma desde FPDF para obtener así el grafico dentro del documento PDF, entonces este parámetro será el nombre con que se guardara nuestra imagen del grafico en nuestro servidor.

$ubicacionTamaño: Este parámetro es un arreglo donde indicaremos el lugar y el tamaño dentro de la página que deseemos que se encuentre nuestro grafico, el formato es el siguiente
array(posicionx,posicionY,ancho,alto);

$titulo: Es la única variable que será opcional, esto por motivado a que muchas veces colocamos el titulo desde FPDF y no es necesario colocárselo al grafico, pero si en algún momento es necesario solo con indicar este parámetro el titulo del grafico sera colocado en nuestra imagen por medio de JGRAPH.
Ahora que conocemos los parámetros que debemos indicarle a nuestro método solo nos queda instanciar la clase y llamar al metodo gaficoPDF de la misma para obtener un documento PDF con un grafico estadístico.
$pdf=new Reporte();//creamos el documento pdf
$pdf->AddPage();//agregamos la pagina
$pdf->SetFont("Arial","B",16);//establecemos propiedades del texto tipo de letra, negrita, tamaño
//$pdf->Cell(40,10,'hola mundo',1);
$pdf->Cell(0,5,"GRAFICO REALIZADO CON FPDF Y JGRAPH",0,0,'C');
$pdf->gaficoPDF(array('aprobados'=>array(1,'red'),'reprobados'=>array(1,'blue')),'Grafico',array(20,40,100,50),'grafico');
$pdf->Output();
Sencillamente en este código instanciamos la clase Reportes y llamamos a varios de los métodos de la librería FPDF para crear el documento PDF y mediante el método creado en este tutorial creamos un grafico de tarta.
Les dejo el código completo del artículo:
/*
clase para reportes 
autor Carlos Belisario
*/

require_once("fpdf/fpdf.php");
require_once('jpgraph/inc/jpgraph.php');
require_once('jpgraph/inc/jpgraph_pie.php');
require_once ("jpgraph/inc/jpgraph_pie3d.php");
class Reporte extends FPDF
{
     public function __construct($orientation='P', $unit='mm', $format='A4')
  {
   parent::__construct($orientation, $unit, $format);
 } 
public function gaficoPDF($datos = array(),$nombreGrafico = NULL,$ubicacionTamamo = array(),$titulo = NULL)
 { 
  //construccion de los arrays de los ejes x e y
  if(!is_array($datos) || !is_array($ubicacionTamamo)){
   echo "los datos del grafico y la ubicacion deben de ser arreglos";
  }
  elseif($nombreGrafico == NULL){
   echo "debe indicar el nombre del grafico a crear";
  }
  else{ 
   #obtenemos los datos del grafico  
   foreach ($datos as $key => $value){
    $data[] = $value[0];
    $nombres[] = $key; 
    $color[] = $value[1];
   } 
   $x = $ubicacionTamamo[0];
   $y = $ubicacionTamamo[1]; 
   $ancho = $ubicacionTamamo[2];  
   $altura = $ubicacionTamamo[3];  
   #Creamos un grafico vacio
   $graph = new PieGraph(600,400);
   #indicamos titulo del grafico si lo indicamos como parametro
   if(!empty($titulo)){
    $graph->title->Set($titulo);
   }   
   //Creamos el plot de tipo tarta
   $p1 = new PiePlot3D($data);
   $p1->SetSliceColors($color);
   #indicamos la leyenda para cada porcion de la tarta
   $p1->SetLegends($nombres);
   //Añadirmos el plot al grafico
   $graph->Add($p1);
   //mostramos el grafico en pantalla
   $graph->Stroke("$nombreGrafico.png"); 
   $this->Image("$nombreGrafico.png",$x,$y,$ancho,$altura);  
  } 
 } 
}
$pdf=new Reporte();//creamos el documento pdf
$pdf->AddPage();//agregamos la pagina
$pdf->SetFont("Arial","B",16);//establecemos propiedades del texto tipo de letra, negrita, tamaño
//$pdf->Cell(40,10,'hola mundo',1);
$pdf->Cell(0,5,"GRAFICO REALIZADO CON FPDF Y JGRAPH",0,0,'C');
$pdf->gaficoPDF(array('aprobados'=>array(1,'red'),'reprobados'=>array(1,'blue')),'Grafico',array(20,40,100,50),'grafico');
$pdf->Output(); 

el resultado seria el siguiente:
Grafica con FPDF y JGRAPH

Espero que le sea de utilidad a alguien cualquier correccion o sugerencia no duden es hacerla saludos

41 comentarios:

  1. Interesante post este de graficos pero si se necesitara otro tipo de graficos como se haria??

    ResponderEliminar
    Respuestas
    1. Importas las librerias que si de BAR o LINE.. y le modificas..

      Eliminar
  2. Pues la libreria JGRAPH tiene para crear ese tipo de graficos en el link que deje para la descarga hay como realizar cada uno, en el articulo coloque el de tarta porque es el que mas he utilizado y por eso hice un metodo directamente para el, pero este metodo pudiera mejorarse creando metodos privados con los tipos de graficos y llamandolo desde nuestro metodo grafico por medio de un parametro, a lo mejor sea un buen tema para otra entrada saludos

    ResponderEliminar
  3. Hola, se ve muy bueno e interesante el codigo, pues te digo que lo he probado pero me aparece la pantalla en blanco, ¿podiras darme el codigo en un archivo plano? pues depronto el que esta escrito aqui debe tener algun error. Gracias

    ResponderEliminar
  4. Estimado.

    Lo probe y funciona bien. salvo que da un error con la variable $altura.

    ResponderEliminar
  5. Gracias por el reporte, si había un error de dedo en el tuto, había declarado $alttura en la línea 35 en vez de colocar $altura, corregido, saludos

    ResponderEliminar
  6. en la linea 39 creo que hay un empty sobrando.
    Excelente articulo.
    Gracias

    ResponderEliminar
    Respuestas
    1. gracias por el reporte, pero ese problema es del highlight del blog, que esta repitiendo si le das a la opción de ver código este error no aparece, y así debe de hacerse para poderlo copiar, de todas maneras voy a ver si subo esto a github para que sea mas fácil de utilizar, saludos

      Eliminar
  7. lo prometido es deuda https://github.com/carlosbelisario/reportes_estadisticos_pdf, para que se descargue mas fácil los archivos, de hecho hice algunas modificaciones, cree un wrapper para crear cualquier gráfico no solo el pie, solo hay que indicar cual es el gráfico de JPGraph y crearle el método para generarlo, cree los dos que más he utilizado, pronto le agrego el gráfico de barras, saludos

    ResponderEliminar
    Respuestas
    1. me descarge tu ejercicio pero tiene problemas con nombre de archivos en el require_once y tambien sale un mensaje diciendo 'Fatal error: Exception thrown without a stack frame in Unknown on line 0' salu2

      Eliminar
  8. buenas, el error es mio por no indicar cual es el grafico de prueba que se necesita, e hice algunos cambios, ya acomode para que salga en el PDF y también si quieres ver el grafico directo en el navegador puedes verlos en el archivo graph/grahpTest.php, saludos y gracias por indicar el error en los ejemplos, saludos cualquier cosa me lo indicas

    ResponderEliminar
  9. hola gracias por el aporte!!! Pero yo tengo un problema me funciona perfectamente tu ejemplo el detalle esta en que al generar mi reporte dejo un boton al dar click me genera el pdf y crea la imagen en mi directorio, al cerrar el pdf, y volver a dar click en el boton ya no me funciona porq dice que no puede ser eliminada la imagen a lafata de permisos, entons tengo que eliminarla directamente del directorio y funciona denuevo, entons veo que funciona para ejecutarse solo una vez, ahi mi problema, como hacer que de manera automatica elimine esa imagen si existe y volver a crearla?
    espero me ayuden gracias

    ResponderEliminar
  10. Buenas el problema es de lo permisos que tienes sobre la carpeta que estas creando la imagen, de hecho yo tengo las clases expuestas acá implementadas en un sistema que tengo en producción y no me ha generado problemas, las carpetas de las imágenes normalmente son públicas, en el método Stroke de la clase JPGraph tu puedes indicarle la ruta especifica donde quieres que quede la imagen ejemplo
    Stroke("../images/$nameGraph.png");
    si sigue el problema me comentas a ver si indagamos un poco más en el tema, pero en teoría no debería de darte problema en carpetas públicas, saludos

    ResponderEliminar
  11. Saludos !!! aun sigo con el problema..
    En efecto cambie la ruta en el metodo stroke y funciona bien, pero aun asi a la nueva carpeta creada incluso la comparti le di permisos de control total y nada, me manda el mismo mensaje de que no tengo permisos para eliminar,,, mi sistema esta en un Windows Xp Sp3 y pues acaso sera que tengo que crear mi carpeta en la raiz c:?? o alguna otra idea de como cambiar esos permisos?
    De antemano gracias por la atencion presta!! buena tarde

    ResponderEliminar
    Respuestas
    1. Buenas gracias por tu comentario, la solución que creo que es la viable y la acabo de anexar al código que esta en github, es darle permisos a la imagen una vez creada (gracias por el dato), esto lo vas a hacer


      $graph->Stroke("../$nameGraph.png");
      chmod($nameGraph . ".png", 0777);


      saludos

      Eliminar
  12. Buen dia !!

    Solucione mi problema pero tuve que primero eliminar la imagen con: unlink("$nombreGrafico.png");
    $graph->Stroke("$nombreGrafico.png");

    ya que dandole los permisos con chmod seguia con el mismo error.

    Aun así agradesco la atención!! Muchas GRACIAS

    ResponderEliminar
  13. Emanuelle.. podrias decirme como fue q se soluciono.. porfavor.. a mi me sige dando ese erroor...

    ResponderEliminar
  14. ¿cual es el error que te esta dando? el mismo de permisos? si te fijas Emanuelle elimina el gráfico anterior cada vez que va a crear un gráfico nuevo, haciendo esto

    //línea para eliminar el gráfico anterior
    unlink("$nombreGrafico.png");
    $graph->Stroke("$nombreGrafico.png");

    Antes de la creación de la imagen, yo le asigne todos los permisos a la imagen y también me la creaba sin problemas, a mi ambas me funcionan pero trabajo con linux, a lo mejor con windows el asignar los permisos no es tan factible y por eso es que el eliminarla como Emmanuel es la mejor solución, saludos

    ResponderEliminar
  15. De los mejores ejemplos que encontré buscando. Sin embargo, no se como hacerlo para que salgan varios gráficos por documento pdf, ¿es posible? si lo es, no tengo la menos idea como sería..

    ResponderEliminar
  16. Claro que es posible lo que tienes es que llamar al método que crea el gráfico la cantidad de veces que necesites, pasando los parámetros de datos, saludos

    ResponderEliminar
  17. me gustaría saber como utilizar mas tipos de gráficos si alguien me puede ayudar lo agradecería

    ResponderEliminar
  18. Yo había hecho un wrapper para crear los gráficos, en el link del github que deje arriba se encuentra el código, sin embargo es simplemente sacarle el provecho a la librería jpgraph y a los gráficos que esta ofrece

    ResponderEliminar
  19. Disculpa tengo que llamarlo mediante algún botón o algo? porque ejecuto el archivo php en mi servidor y no realiza nada, gracias...

    ResponderEliminar
    Respuestas
    1. Algún error?? porque en teoría el código que deje al hacerlo en un archivo debe de funcionar

      Eliminar
  20. Tengo un problema al enviar mi gráfica al pdf me muestra un error que es el 150009 illegal Pie Plot, espero puedas ayudarme gracias

    ResponderEliminar
    Respuestas
    1. el objeto que estas pasando no es correcto según la documentación, verifica que estes pasando bien los datos y nos comentas ya que el código que se dejo funciona correctamente, saludos

      Eliminar
  21. Hola Carlos, mira estoy realizando tu ejemplo, pero al momento de de generar el grafico, practicamente me sale el grafico pero no en el pdf que quiero que salga.

    La grafica dibuja pero en html, que puede ser.

    Saludos,
    David

    ResponderEliminar
  22. Soy la persona que no le genera el grafico al momento de comentar la linea

    $pdf->gaficoPDF(array('aprobados'=>array(1,'red'),'reprobados'=>array(1,'blue')),'Grafico',array(20,40,100,50),'grafico');

    ahi me genera el pdf, claro al comentarlo solo me genera el pdf con el titulo, favor ayudame

    ResponderEliminar
  23. En la carpeta donde tienes el script te genera alguna imagen con el gráfico y el mismo nombre del gráfico??

    ResponderEliminar
  24. Gracias Carlos por contestarme, segun veo son los permisos estoy sobre fedora, le di permisos 777 como root, apache y no me sale el siguiente error, te pongo el error que me sale... david.php es el archivo donde lo escribi a tu ejemplo.

    Warning: unlink(graficoPrecision.png): Permission denied in /var/www/html/labcalidadpro/site/tcpdf/examples/david.php on line 46

    Warning: fopen(graficoPrecision.png): failed to open stream: Permission denied in /var/www/html/labcalidadpro/site/jpgraph/src/gd_image.inc.php on line 2136

    Warning: flock() expects parameter 1 to be resource, boolean given in /var/www/html/labcalidadpro/site/jpgraph/src/gd_image.inc.php on line 2137

    Warning: flock() expects parameter 1 to be resource, boolean given in /var/www/html/labcalidadpro/site/jpgraph/src/gd_image.inc.php on line 2142
    JpGraph Error: 25111 Can't delete cached image graficoPrecision.png. Permission problem?

    ResponderEliminar
  25. Amigo muchas gracias por la pista que me diste, era permisos,ahora funciona de maravilla, el problema era del contexto de selinux (por ahi lo lei, no estoy seguro, pero funciono), ejecute lo siguiente:

    sudo chcon -R -t httpd_sys_content_rw_t /var/www/html/


    Saludos,
    David

    Por cierto muy buen articulo

    ResponderEliminar
    Respuestas
    1. Excelente que hayas logrado resolver el problema, porque hice varias pruebas y me estaba funcionando correctamente y no encontraba que pudiera estarte pasando, en fin excelente que te haya resultado, saludos

      Eliminar
  26. Muchas Gracias, parte de este código me ayudó a solucionar tema IMAGEN en PDF (librería FPDF) trayéndolo desde ($imagen) con archivo comenzado con LETRA Ej P001.jpg
    GRACIAS. / clamisch@hotmail.es

    ResponderEliminar
  27. Hola Disculpa, presento un problema no hace nada el codigo :(, la pantalla queda en blanco que puede ser?

    ResponderEliminar
    Respuestas
    1. activa el error_reporting o ve los logs de apache para ver si te da un error en la sintaxis

      Eliminar
  28. que tal si tuviera que tomar los datos desde base de datos me podrias un topic o idea gracias

    ResponderEliminar
    Respuestas
    1. arma el array con el formato que necesita el método de la clase y debería de funcionar, aunque actualmente no se si hubo algún cambio con el FPDF o el jpGraph

      Eliminar
  29. Hola, excelente tu aporte, decidí llevarlo más allá y la intención es que la generación sea dinamica, es decir me genere el grafico sin yo saber el numero de partes que tendra lo trabajo con un ciclo cuando es hasta dos partes esta bien, pero, cuando son mas de dos se rompe y me dice que es ilegal y que la suma de todo el data es cero y pues en realidad ya no se que hacer te agradezco me ayudes!!

    ResponderEliminar
    Respuestas
    1. muestras como lo estas creando a ver que puede estar pasando, saludos

      Eliminar
  30. Según entiendo, debo borrar la imagen antes de crear la siguiente. ¿Puedo borrarla al momento de cerrar la página que la llamó? De ser así... ¿Cómo lo hago?

    ResponderEliminar
  31. Excelente, muchas gracias, de verdad que me has ayudado como no tienes idea :)

    ResponderEliminar