JFreeChart: una libreria Open Source per la generazione dinamica di grafici

I parte: introduzione al frameworkdi

Primo di due articoli sulla descrizione delle API di JFreeChart, una libreria Java Open Source che consente la generazione dinamica di grafici a partire da una fonte dati e di esportarli nei formati PNG e JPEG, anche da Servlet.

Introduzione

JFreeChart è una libreria Java Open Source (rilasciata sotto licenza LGPL) per la generazione dinamica di grafici a partire da una fonte dati. Può essere utilizzata sia in applicazioni Java standalone che web (quindi anche nelle Servlet e nelle JSP).

Caratteristiche principali della libreria

Tramite JFreeChart è possibile generare grafici di svariati tipi, quali grafici a torta, istogrammi, line chart, time series chart, scatter plot chart, Gantt, etc. Nelle figure 1, 2, 3 e 4 vengono mostrati quattro esempi dei diversi tipi realizzabili tramite JFreeChart.




Tra le caratteristiche principali di JFreeChart vale la pena di ricordare anche le seguenti:

  • grafici realizzabili in maniera sia bidimensionale che tridimensionale;
  • export diretto dei grafici nei formati immagine PNG (Portable Network Graphic) e JPEG (Joint Photografic Experts Group);
  • possibilità  di aggiungere tooltip ai grafici;
  • possibilità  di implementare uno zoom interattivo sui grafici;
  • gestione degli eventi del mouse sui grafici;
  • generazione di Image Map HTML;
  • export dei grafici in PDF tramite iText (http://www.lowagie.com/iText/);
  • export dei grafici in SVG tramite Batik (http://xmlgraphics.apache.org/batik/);
  • accesso ai dati provenienti da sorgenti di diversa natura (database, file, etc.) tramite interfacce dataset dedicate già  disponibili nella libreria.

La versione più recente di JFreeChart è la 1.0.1. Necessita della versione 1.3 o superiore del JDK. Ha bisogno anche di JCommon 1.0.0 (http://www.jfree.org/jcommon/index.php), un insieme di utility già  incluso comunque nell‘archivio scaricabile dal sito ufficiale di JFreeChart (http://www.jfree.org/jfreechart/index.php).
Nell‘implementazione di un‘applicazione Java che ha bisogno di generare dei grafici a runtime solo al momento in cui arrivano effettivamente i dati, utilizzare JFreeChart porta dei vantaggi rispetto al ricorso alle sole API Sun native. Innanzitutto si ha la possibilità  di esportare i grafici anche nel formato PNG, oltre che JPEG. Si ha poi la possibilità  di utilizzare le API allo stesso modo sia in una Servlet che in una qualsiasi altra classe Java. E soprattutto, si ha già  a disposizione un insieme di dataset e un insieme di API per la loro gestione che evitano di doverne implementare di nuovi.
JFreeChart è integrato anche in JasperReports per l‘inclusione di grafici nei report generati con quest‘ultima libreria.

A prescindere dal tipo, la generazione di un grafico tramite JFreeChart prevede sempre le seguenti azioni:

  • creazione e popolamento di un Dataset;
  • creazione di un oggetto di tipo JFreeChart tramite il corrispondente metodo della classe org.jfree.chart.ChartFactory;
  • impostazione degli attributi del diagramma tramite una delle classi plot del package org.jfree.chart.plot;
  • rendering del grafico tramite una delle classi del package org.jfree.chart.renderer;
  • definizione dell‘asse delle ascisse tramite una delle classi del package org.jfree.chart.axis.

Un primo esempio di applicazione

Vediamo adesso un esempio pratico di utilizzo. Creiamo una classe Java la quale, a runtime, genererà  un Time Series chart e lo visualizzerà  in una interfaccia Swing. Un Time Series chart è un grafico in cui l‘asse delle ascisse è un asse temporale. Chiamiamo la classe di esempio TimeSeriesExample. Essa estende la classe org.jfree.ui.ApplicationFrame. Quest‘ultima, facente parte di JCommon, eredita tutte le caratteristiche di javax.swing.JFrame (essendone una specializzazione) e prevede già  la gestione degli eventi della finestra dell‘applicazione.
TimeSeriesExample dovrà  fare l‘overriding del costruttore di ApplicationFrame:

public TimeSeriesExample( String pStrTitle ) {super( pStrTitle );ChartPanel lChartPanel = (ChartPanel)createDemoPanel();lChartPanel.setPreferredSize( new java.awt.Dimension( 500, 270 ) );lChartPanel.setMouseZoomable( true, false );setContentPane( lChartPanel );}

Il parametro in ingresso al costruttore è il title del frame. Il metodo createDemoPanel costruisce il Panel (org.jfree.chart.ChartPanel) destinato a contenere il grafico:

public static JPanel createDemoPanel() {JFreeChart lChart = createChart( createDataset() );return new ChartPanel( lChart );}

Il grafico vero e proprio è un oggetto di tipo org.jfree.chart.JFreeChart. Viene creato dal metodo createChart a partire da un Dataset popolato dal metodo createDataset:

private static XYDataset createDataset() {TimeSeries lTimeSeries1 = new TimeSeries( "MokaByte Index", Month.class );lTimeSeries1.add( new Month( 1, 2005 ), 181.8 );lTimeSeries1.add( new Month( 2, 2005), 167.3 );lTimeSeries1.add( new Month( 3, 2005 ), 153.8 );lTimeSeries1.add( new Month( 4, 2005 ), 167.6 );lTimeSeries1.add( new Month( 5, 2005 ), 158.8 );lTimeSeries1.add( new Month( 6, 2005 ), 148.3 );lTimeSeries1.add( new Month( 7, 2005), 153.9 );lTimeSeries1.add( new Month( 8, 2005 ), 142.7 );lTimeSeries1.add( new Month( 9, 2005 ), 123.2 );lTimeSeries1.add( new Month( 10, 2005 ), 131.8 );lTimeSeries1.add( new Month( 11, 2005 ), 139.6 );lTimeSeries1.add( new Month( 12, 2005 ), 142.9 );lTimeSeries1.add( new Month( 1, 2006), 138.7 );lTimeSeries1.add( new Month( 2, 2006 ), 137.3 );lTimeSeries1.add( new Month( 3, 2006 ), 143.9 );lTimeSeries1.add( new Month( 4, 2006 ), 139.8 );TimeSeries lTimeSeries2 = new TimeSeries( "MokaCode Index", Month.class );lTimeSeries2.add( new Month( 1, 2005 ), 129.6 );lTimeSeries2.add( new Month( 2, 2005), 123.2 );lTimeSeries2.add( new Month( 3, 2005 ), 117.2 );lTimeSeries2.add( new Month( 4, 2005 ), 124.1 );lTimeSeries2.add( new Month( 5, 2005 ), 122.6 );lTimeSeries2.add( new Month( 6, 2005 ), 119.2 );lTimeSeries2.add( new Month( 7, 2005 ), 116.5 );lTimeSeries2.add( new Month( 8, 2005 ), 112.7 );lTimeSeries2.add( new Month( 9, 2005 ), 101.5 );lTimeSeries2.add( new Month( 10, 2005 ), 106.1 );lTimeSeries2.add( new Month( 11, 2005 ), 110.3 );lTimeSeries2.add( new Month( 12, 2005 ), 111.7 );lTimeSeries2.add( new Month( 1, 2006 ), 111.0 );lTimeSeries2.add( new Month( 2, 2006 ), 109.6 );lTimeSeries2.add( new Month( 3, 2006 ), 113.2 );lTimeSeries2.add( new Month( 4, 2006 ), 111.6 );TimeSeriesCollection lDataset = new TimeSeriesCollection();lDataset.addSeries( lTimeSeries1 );lDataset.addSeries( lTimeSeries2 );return lDataset;}

Il Dataset utilizzato è di tipo org.jfree.data.time.TimeSeriesCollection, specifico per le serie temporali. Questa classe implementa l‘interfaccia org.jfree.data.xy.XYDataset, dato che i Time Series chart sono una specializzazione degli XY Line chart. Nell‘esempio che stiamo costruendo il diagramma conterrà  due curve relative, ciascuna relativa ad una serie temporale diversa. Entrambe vanno assegnate ad un unico Dataset.
Il grafico vero e proprio è generato dal metodo createChart. Un Chart viene creato invocando il metodo dedicato della classe org.jfree.chart.ChartFactory. Questa prevede un metodo di create specifico per ogni tipo di Chart previsto dalla libreria. Nel caso dell‘esempio:

// Creazione dell‘oggetto Chart tramite il ChartFactory.// I parametri in ingresso al metodo createTimeSeriesChart sono:// titolo// label per l‘asse delle ascisse// label per l‘asse delle ordinate// Dataset con i dati con cui popolare il grafico// boolean che indica se creare la legenda oppure no// boolean che indica se creare i tooltip oppure no// boolean che indica se creare dei collegamenti a punti del graficoJFreeChart lChart = ChartFactory.createTimeSeriesChart("Mokabyte Time Series Example","Date","Valori",pDataset,true,true,false);

Tramite la classe org.jfree.chart.plot.XYPlot dobbiamo impostare le proprietà  del diagramma:

XYPlot lXYPlot = (XYPlot)lChart.getPlot();lXYPlot.setBackgroundPaint( Color.lightGray );lXYPlot.setDomainGridlinePaint( Color.white );lXYPlot.setRangeGridlinePaint( Color.white );lXYPlot.setAxisOffset( new RectangleInsets( 5.0, 5.0, 5.0, 5.0 ) );lXYPlot.setDomainCrosshairVisible( true );lXYPlot.setRangeCrosshairVisible( true );

Dall‘istanza di XYPlot ne ricaviamo una di org.jfree.chart.renderer.xy.XYItemRenderer per poter quindi eseguire il rendering delle due curve nel diagramma, visualizzando i marcatori dei punti:

XYItemRenderer lXYItemRenderer = lXYPlot.getRenderer();if ( lXYItemRenderer instanceof XYLineAndShapeRenderer ) {XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer)lXYItemRenderer;renderer.setBaseShapesVisible( true );renderer.setBaseShapesFilled( true );}

Infine dobbiamo impostare l‘asse delle ascisse. Poichà© nell‘esempio stiamo facendo riferimento a un Time Series chart, dobbiamo ricorrere ad un oggetto di tipo org.jfree.chart.axis.DateAxis (la classe del package org.jfree.chart.axis specifica per il caso in cui i valori dell‘asse delle ascisse siano date o time):

DateAxis lXYAxis = (DateAxis)lXYPlot.getDomainAxis();lXYAxis.setDateFormatOverride( new SimpleDateFormat( "MMM-yyyy" ) );

L‘esecuzione della classe produrrà  un grafico come quello riportato in figura 5.

L‘esempio completo è allegato all‘articolo.

Per generare grafici diversi dai Times Series chart i passi da compiere sono analoghi a quelli di questo esempio.

Conclusioni

In questa prima parte sono state descritte le principali feature di JFreeChart ed è stato spiegato un primo esempio di utilizzo all‘interno di una applicazione Java standalone. Nella seconda ed ultima parte vedremo come utilizzare praticamente le API della libreria in un‘applicazione web e come generare grafici a partire da un Dataset popolato con valori recuperati da un database.

Bibliografia

[1] David Gilbert "The JFreeChart Class Library - Installation Guide"
http://www.jfree.org/jfreechart/index.php

Condividi

Pubblicato nel numero
106 aprile 2006
Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna…
Articoli nella stessa serie