sábado, diciembre 17, 2011

Graficar con JFreeChart

Tomado de: Crear gráficas con series con JFreeChart.


0. Índice de contenidos.


1. Introducción

Como vimos en otro tutorial es muy sencillo exportar datos a una hoja de cálculo mediante Apache POI. Sin embargo, las hojas de cálculo no son la única solución para la exportación de datos. En determinados casos puede ser muy interesante plasmar toda esa información en una gráfica.
En este tutorial vamos a ver cómo generar gráficas con series de datos con ayuda de la librería JFreeChart. Para ello vamos a aprovechar los datos del ejemplo que utilizamos en el tutorial anteriormente mencionado.

2. Entorno.

El tutorial está escrito usando el siguiente entorno:
  • Hardware: Portátil MacBook Pro 15' (2.2 Ghz Intel Core I7, 4GB DDR3).
  • Sistema Operativo: Mac OS Snow Leopard 10.6.7
  • Entorno de desarrollo: Eclipse 3.7 Indigo.
  • JFreeChart 1.0.13.

3. Diseñando la gráfica.

Como hemos dicho anteriormente, nos vamos a basar en datos de pilotos que dan vueltas de entrenamiento a un circuito para generar este ejemplo. Las características que tendrá nuestra gráfica serán las siguientes:
  • Cada serie (de tiempos por vuelta de un piloto) se representará de forma lineal.
  • El eje Y de la gráfica mostrará los tiempos en segundos en un rango de 120 a 135. El número de segundos del eje se visualizará de dos en dos (120, 122, 124...).
  • El eje X de la gráfica mostrará el número de vueltas, de la vuelta 1 a la vuelta 5.
  • Cada punto de la gráfica debe de mostrarse con un círculo (evidentemente los círculos serán unidos por la línea que representará la serie).
  • Los colores de las series deben ser distintos, así como las líneas de la gráfica que hacen de guía (líneas discontinuas que salen en el fondo de la gráfica).
  • En el pie de la gráfica debe figurar una leyenda con los nombres de los pilotos.

4. Construyendo la gráfica.

Pues bien, aquí tenemos la clase que nos generará la gráfica:
01import java.awt.Color;
02import java.io.File;
03import org.jfree.chart.ChartFactory;
04import org.jfree.chart.ChartUtilities;
05import org.jfree.chart.JFreeChart;
06import org.jfree.chart.axis.NumberAxis;
07import org.jfree.chart.axis.NumberTickUnit;
08import org.jfree.chart.plot.PlotOrientation;
09import org.jfree.chart.plot.XYPlot;
10import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
11import org.jfree.data.xy.XYSeries;
12import org.jfree.data.xy.XYSeriesCollection;
13
14public class PruebaJFreeChart {
15
16    private static Color COLOR_SERIE_1 = new Color(255, 128, 64);
17
18    private static Color COLOR_SERIE_2 = new Color(28, 84, 140);
19
20    private static Color COLOR_RECUADROS_GRAFICA = new Color(31, 87, 4);
21
22    private static Color COLOR_FONDO_GRAFICA = Color.white;
23
24    public JFreeChart crearGrafica(XYSeriesCollection dataset) {
25
26        final JFreeChart chart = ChartFactory.createXYLineChart("Tiempos de entrenamientos", "Vuelta", "Tiempo (segundos)",
27                dataset,
28                PlotOrientation.VERTICAL,
29                true, // uso de leyenda
30                false, // uso de tooltips 
31                false // uso de urls
32                );
33        // color de fondo de la gráfica
34        chart.setBackgroundPaint(COLOR_FONDO_GRAFICA);
35
36        final XYPlot plot = (XYPlot) chart.getPlot();
37        configurarPlot(plot);
38
39        final NumberAxis domainAxis = (NumberAxis)plot.getDomainAxis();
40        configurarDomainAxis(domainAxis);
41         
42        final NumberAxis rangeAxis = (NumberAxis)plot.getRangeAxis();
43        configurarRangeAxis(rangeAxis);
44
45        final XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer)plot.getRenderer();
46        configurarRendered(renderer);
47
48        return chart;
49    }
50     
51    // configuramos el contenido del gráfico (damos un color a las líneas que sirven de guía)
52    private void configurarPlot (XYPlot plot) {
53        plot.setDomainGridlinePaint(COLOR_RECUADROS_GRAFICA);
54        plot.setRangeGridlinePaint(COLOR_RECUADROS_GRAFICA);
55    }
56     
57    // configuramos el eje X de la gráfica (se muestran números enteros y de uno en uno)
58    private void configurarDomainAxis (NumberAxis domainAxis) {
59        domainAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
60        domainAxis.setTickUnit(new NumberTickUnit(1));
61    }
62     
63    // configuramos el eje y de la gráfica (números enteros de dos en dos y rango entre 120 y 135)
64    private void configurarRangeAxis (NumberAxis rangeAxis) {
65        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
66        rangeAxis.setTickUnit(new NumberTickUnit(2));
67        rangeAxis.setRange(120, 135);
68    }
69     
70    // configuramos las líneas de las series (añadimos un círculo en los puntos y asignamos el color de cada serie)
71    private void configurarRendered (XYLineAndShapeRenderer renderer) {
72        renderer.setSeriesShapesVisible(0, true);
73        renderer.setSeriesShapesVisible(1, true);
74        renderer.setSeriesPaint(0, COLOR_SERIE_1);
75        renderer.setSeriesPaint(1, COLOR_SERIE_2);
76    }
77     
78}
Bien, como vemos el método ChartFactory.createXYLineChart nos creará una gráfica de series representadas por líneas.
El método configurarPlot se ocupa de establecer el color de las líneas de fondo de la gráfica que hacen de guía. Son las líneas discontinuas verticales y horizontales que aparecen en el fondo de la gráfica.
El método configurarDomainAxis actua sobre el eje X, el eje del número de vueltas, y hace que se muestren números enteros y de uno en uno.
El método configurarRangeAxis actua sobre el eje Y, el de los tiempos, y hace que se muestren los tiempos comprendidos en el rango de 120 a 135 pero mostrando un número si, un número no.
El método configurarRndered hace que en cada punto (relación tiempo - vuelta de una serie) se muestre un círculo y que cada serie sea de un color.

5. Ejecutando el ejemplo.

Por último, nos queda cargar los datos de los pilotos (usaremos los del otro tutorial) y generar la gráfica en un fichero.
01public static final int ANCHO_GRAFICA = 400;
02
03public static final int ALTO_GRAFICA = 300;
04
05public static void main(String args[]) {
06
07    final XYSeries serie1 = new XYSeries("Fernando Alonso");
08    serie1.add(1, 131.78);
09    serie1.add(2, 129.95);
10    serie1.add(3, 128.16);
11    serie1.add(4, 125.91);
12    serie1.add(5, 130.44);
13     
14    final XYSeries serie2 = new XYSeries("Jaime Alguersuari");
15    serie2.add(1, 133.16);
16    serie2.add(2, 132.32);
17    serie2.add(3, 129.86);
18    serie2.add(4, 128.02);
19    serie2.add(5, 132.45);
20     
21    final XYSeriesCollection collection = new XYSeriesCollection();
22    collection.addSeries(serie1);
23    collection.addSeries(serie2);
24     
25    try {
26        final PruebaJFreeChart prueba = new PruebaJFreeChart();
27        final JFreeChart grafica = prueba.crearGrafica(collection);
28        ChartUtilities.saveChartAsPNG(new File("tiempos-entrenamientos.png"), grafica, ANCHO_GRAFICA, ALTO_GRAFICA);
29    } catch (Exception e) {
30        e.printStackTrace();
31    }
32
33}
Observemos que añadimos los tiempos de cada piloto en una serie llamada XYSeries. A esta serie únicamente le indicamos el nombre, que se corresponderá con el nombre del piloto, y el tiempo por vuelta. Ej: en la serie 1 hemos indicado que en la vuelta 1 el tiempo fue de 131.78 segundos, en la vuelta 2 fue de 129.95, etc...
Añadimos las gráficas a un dataset de tipo XYSeriesCollection y se lo pasamos al método crearGrafica.
Por último, con el método saveChartAsPNG de la clase ChartUtilities generamos una imagen en formato png, con el alto y ancho que queramos y que que dará como resultado una imagen llamada tiempos-entrenamiento.png. La gráfica resultante es la siguiente:

6. Referencias.


7. Conclusiones.

En este tutorial hemos visto lo sencillo que es generar gráficas de series lineales con ayuda de la librería JFreeChart.
Nótese que esta librería es capaz de generar una gran cantidad de tipos de gráficas que pueden verse en la demo de su página web.

No hay comentarios: