Realizzare Grafici in Java
Con questo tutorial cercheremo di introdurre il lettore all’uso di un’interessante libreria, nello specifico JFreeChart, grazie alla quale è possibile costruire ed inserire grafici di varia natura all’interno delle interfacce grafiche definite in Java®.
A questo proposito ipotizziamo di trovarci in un situazione del tipo seguente: “Si sono importati una serie di dati da Excel® e gli si vuole dare una forma grafica al fine di rendere più agevole l’interpretazione da parte dell’utente finale”. Se cercassimo di risolvere il problema precedente utilizzando le classi definite all’interno del package Graphics saremmo obbligati a scrivere moltissimo codice anche per rappresentare una semplice spezzata, infatti si dovrebbe:
- Definire il contesto grafico in cui rappresentare i dati quindi dovremmo:
- Definire il sistema di riferimento
- Rappresentare visivamente il sistema di riferimento (assi X e Y)
- Definire le formule per la rappresentazione in scala dei dati
- Definire una serie di testo per:
i. Il titolo
ii. La legenda
2.Costruire la polilinea che sarà utilizzata per rappresentare i dati, il che implica la necessità di utilizzare il metodo addPoint;
Chiaramente non è questa la soluzione ideale per questa ragione si ricorre spesso a strumenti esterni, nel nostro caso specifico il package JFreeChart; precisiamo sin da subito che la nostra non vuole essere una guida esaustiva, ma semplicemente vuole essere un incipt per tutti coloro che sono interessanti a dare un aspetto più professionale a tutti quei progetti che operano su quantità di dati di una certa entità.
Cominciamo anzitutto con il dire che JFreeChart è un progetto opensource, il che significa che la libreria stessa è liberamente modificabile, essa è scaricabile dal sito: //www.jfree.org/jfreechart/.
Cominciamo con il dire che con JFreeChart è possibile realizzare il seguente insieme di grafici:
- A Torta sia 2d che 3D
- A Barre
- Linea
- A dispersione e a bolle
- Serie Temporali
- Combinati
- Pareto
- Gant
- Ecc
Inoltre un ulteriore elemento a favore per l’uso di questa libreria vi è il fatto che è possibile esportare i grafici prodotti in molteplici formati tra i quali ricordiamo:
- EPS
- SVG
Così come è già avvenuto per altri articoli, cercheremo di descrivere il comportamento di questa libreria per mezzo di una serie di esempi, ci sembra infatti questo il metodo migliore per far comprendere il modo in cui utilizzare le funzionalità messeci a disposizione da questo package, per tutti coloro che fossero interessati a conoscere nel dettaglio la struttura delle classi alla base di questo package si rimanda alla documentazione online.
Detto questo il primo esempio che presenteremo riguarda la creazione di un semplice grafico a torta:
public class GraficoATorta extends ApplicationFrame { public GraficoATorta( final String titolo) { super (titlo); final PieDataset dataset = createDataset(); final JFreeChart chart = createChart(dataset); final ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize( new java.awt.Dimension( 500 , 270 )); setContentPane(chartPanel); } /** * Creazione del dataset da utilizzare per la generazione del grafi * Ogni grafico ha un suo dataset specifico * @return un dataset di default . */ private PieDataset createDataset() { final DefaultPieDataset dataset = new DefaultPieDataset(); dataset.setValue( "Uno" , new Double( 43.2 )); dataset.setValue( "Due" , new Double( 10.0 )); dataset.setValue( "Tre" , new Double( 27.5 )); dataset.setValue( "Quattro" , new Double( 17.5 )); dataset.setValue( "Cinque" , new Double( 11.0 )); dataset.setValue( "Sei" , new Double( 19.4 )); return dataset; } /** * Metodo deputato alla creazione del grafico. * @param dataset il dataset creato dal metodo createDataset * @return il grafico . */ private JFreeChart createChart( final PieDataset dataset) { final JFreeChart chart = ChartFactory.createPieChart( "Grafico a Torta" , // Titolo dataset, // Fonte dei dati false, // La legenda non sarà inclusa true, // Utilizza i Tooltips false // Configura il grafico per generare una URL ); final PiePlot plot = (PiePlot) chart.getPlot(); plot.setInteriorGap( 0.0 ); plot.setLabelGenerator( null ); return chart; } public static void main( final String[] args) {
|
Nota:
La Classe ApplicationFrame è definita all’interno del Package JCommon, Scaricabile dallo stesso sito del package di JFreeChart.
L’output prodotto dal codice precedente è il seguente:
Se ci si posizione su uno degli spicchi saranno visualizzate le seguenti informazioni:
- Label utilizzata nella definizione del dataset;
- Il valore numerico associato alla label;
- Un valore percentuale corrispondente al valore indicato.
Questo stesso esempio può essere esteso per inserire un’ulteriore serie di elementi in primis:
- La Legenda;
- Fornire per ogni spicco tutte le informazioni presenti all’interno del tooltip
- Rappresentare in 3d il grafico
Infine vedremo di esportare il grafico in formato PDF.
Per inserire la Legenda è sufficiente modificare impostare su true il corrispondente parametro nel costruttore, che quindi diventa:
final JFreeChart chart = ChartFactory.createPieChart( "Grafico a Torta" , // Titolo dataset, // Fonte dei dati true, // La legenda non sarà inclusa true, // Utilizza i Tooltips false // Configura il grafico per generare una URL ); |
Per visualizzare all’interno dell’area del grafico le informazioni presenti nel tooltip è necessario sostituire l’istruzione:
plot.setLabelGenerator(
null
);
Con il seguente comando:
plot.setLabelGenerator(new StandardPieSectionLabelGenerator(“{2} {0}={1}”));
Il risultato di questo cambio è il seguente:
In particolare i placeholder utilizzati per la definizione della label vanno così interpretati:
- {2}: il valore percentuale associato allo spicchio
- {0}: la label utilizzata nella definizione del dataset
- {1}: il valore numerico presente nel dataset
Se desideriamo infine esportare il grafico in formato JPG/PNG/PDF, si dovranno inserire i seguenti blocchi di codice:
Esempio nel caso del formato PNG:
try {ChartUtilities.saveChartAsJPNG(new File(“E:\\chart2.png”), chart, 1024, 768);
} catch (IOException ex) { System.out.println(ex.getLocalizedMessage()); } |
Descriviamo ora, una ulteriore serie di esempi con cui si illustrano altre caratteristiche di questa libreria:
Creazione di un grafico al linea:
/** To change this template, choose Tools | Templates
* and open the template in the editor. */
import java.io.File; import java.io.IOException; import java.text.NumberFormat; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.labels.StandardXYItemLabelGenerator; import org.jfree.chart.labels.XYItemLabelGenerator; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities;
/** * * @author Alessandro */ public class GraficoALinea extends ApplicationFrame {
public GraficoATorta(final String titolo) { super(titolo); final XYDataset dataset = createDataset(); final JFreeChart chart = createChart(dataset); final ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new java.awt.Dimension(700, 470)); setContentPane(chartPanel); try { ChartUtilities.saveChartAsPNG(new File(“E:\\chart3.png”), chart, 1024, 768); } catch (IOException ex) { System.out.println(ex.getLocalizedMessage()); } }
/** * Creazione del dataset da utilizzare per la generazione del grafi * Ogni grafico ha un suo dataset specifico * @return un dataset di default. */ private XYDataset createDataset() { final XYSeries dataset = new XYSeries(“Dati”); dataset.add(1, 1); dataset.add(2, 5); dataset.add(3, -3); dataset.add(4, 0); dataset.add(5, 9); dataset.add(6, 15); return new XYSeriesCollection(dataset); } /** * Metodo deputato alla creazione del grafico. * @param dataset il dataset creato dal metodo createDataset * @return il grafico. */ private JFreeChart createChart(final XYDataset dataset) { final JFreeChart chart = ChartFactory.createXYLineChart(“Grafico a Linea”, //titolo “Label”, //label asse delle X “Valori”, //label asse dell Y dataset, // sorgente dei dati PlotOrientation.VERTICAL, //orientamento del grafico true, // mostra la legenda true, //usa i tooltip false ); XYPlot plot = (XYPlot) chart.getPlot(); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, true); plot.setRenderer(renderer); renderer.setBaseShapesVisible(true); renderer.setBaseShapesFilled(true); NumberFormat format = NumberFormat.getNumberInstance(); format.setMaximumFractionDigits(2); XYItemLabelGenerator generator = new StandardXYItemLabelGenerator( StandardXYItemLabelGenerator.DEFAULT_ITEM_LABEL_FORMAT, format, format); renderer.setBaseItemLabelGenerator(generator); renderer.setBaseItemLabelsVisible(true); return chart; } public static void main(final String[] args) {
final GraficoALinea demo = new GraficoALinea(“Grafici al gusto di caffè”); demo.pack(); RefineryUtilities.centerFrameOnScreen(demo); demo.setVisible(true);
}
}
|
L’output prodotto dal codice precedente è il seguente:
Nel caso in cui si volessero rappresentare più serie di valori utilizzando lo stesso codice si potrebbe adottare un codice simile al seguente:
import java.io.File;import java.io.IOException;
import java.text.NumberFormat; import java.util.Random; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.labels.StandardXYItemLabelGenerator; import org.jfree.chart.labels.XYItemLabelGenerator; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities;
/** * * @author Alessandro */ public class GraficoALinea extends ApplicationFrame {
public GraficoALinea(final String titolo) { super(titolo); final XYDataset dataset = createDataset(); final JFreeChart chart = createChart(dataset); final ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new java.awt.Dimension(900, 470)); setContentPane(chartPanel); try { ChartUtilities.saveChartAsPNG(new File(“E:\\chart3.png”), chart, 1024, 768); } catch (IOException ex) { System.out.println(ex.getLocalizedMessage()); } }
/** * Creazione del dataset da utilizzare per la generazione del grafi * Ogni grafico ha un suo dataset specifico * @return un dataset di default. */ private XYDataset createDataset() { XYSeriesCollection dataset = new XYSeriesCollection(); final XYSeries serie1 = generaSerie(“Serie1”); final XYSeries serie2 = generaSerie(“Serie2”); final XYSeries serie3 = generaSerie(“serie3”); dataset.addSeries(serie1); dataset.addSeries(serie2); dataset.addSeries(serie3); return dataset; } private XYSeries generaSerie(String label) { XYSeries serie = new XYSeries(label); Random generatore = new Random(); for(int i = 1; i <=10; i++) serie.add(i, generatore.nextInt(70)); return serie; } /** * Metodo deputato alla creazione del grafico. * @param dataset il dataset creato dal metodo createDataset * @return il grafico. */ private JFreeChart createChart(final XYDataset dataset) { final JFreeChart chart = ChartFactory.createXYLineChart(“Grafico a Linea”, //titolo “Label”, //label asse delle X “Valori”, //label asse dell Y dataset, // sorgente dei dati PlotOrientation.VERTICAL, //orientamento del grafico true, // mostra la legenda true, //usa i tooltip false ); /* final JFreeChart chart = ChartFactory.createPieChart( “Grafico a Torta”, // Titolo dataset, // Fonte dei dati true, // La legenda non sarà inclusa true, false ); final PiePlot plot = (PiePlot) chart.getPlot(); plot.setInteriorGap(0.0);*/ XYPlot plot = (XYPlot) chart.getPlot(); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, true); plot.setRenderer(renderer); renderer.setBaseShapesVisible(true); renderer.setBaseShapesFilled(true); NumberFormat format = NumberFormat.getNumberInstance(); format.setMaximumFractionDigits(2); XYItemLabelGenerator generator = new StandardXYItemLabelGenerator( StandardXYItemLabelGenerator.DEFAULT_ITEM_LABEL_FORMAT, format, format); renderer.setBaseItemLabelGenerator(generator); renderer.setBaseItemLabelsVisible(true); return chart; } public static void main(final String[] args) {
final GraficoALinea demo = new GraficoALinea(“Grafici al gusto di caffè”); demo.pack(); RefineryUtilities.centerFrameOnScreen(demo); demo.setVisible(true);
}
} |
L’output prodotto dal codice precedente assumerebbe la forma seguente:
Appare chiaro che il processo di inserimento per una nuova serie di valori si riduce a dover definire una nuova istanza della classe XYSeries ed al suo successivo popolamento, dopo di che tutto ciò che si dovrà fare è il suo inserimento all’interno del dataset da utilizzare come fonte dei dati.
Un altro tipo di grafico che può spesso rivelarsi utile ai fini di una corretta interpretazione di una serie di dati è il grafico a barre; anche in questo caso la fonte dei dati è un dataset, nello specifico un DefaultCategoryDataset in questo caso però la sua strutturazione è leggermente più articolata, in quanto oltre alla definizione dei dati “grezzi” (valori da usare per l’asse delle X e delle Y) è necessario specificare anche un ulteriore elemento che viene utilizzato quale indicatore di categoria di appartenenza per i valori specificati.
Un primo semplice esempio di creazione di un grafico a barre è il seguente:
public class BarChartExample {public static void main(String[] args) {
// Create a simple Bar chart DefaultCategoryDataset dataset = new DefaultCategoryDataset(); dataset.setValue(6, “Profit”, “Jane”); dataset.setValue(7, “Profit”, “Tom”); dataset.setValue(8, “Profit”, “Jill”); dataset.setValue(5, “Profit”, “John”); dataset.setValue(12, “Profit”, “Fred”); JFreeChart chart = ChartFactory.createBarChart(“Comparison between Salesman”, “Salesman”, “Profit”, dataset, PlotOrientation.VERTICAL, false, true, false); try { ChartUtilities.saveChartAsJPEG(new File(“C:\\chart.jpg”), chart, 500, 300); } catch (IOException e) { System.err.println(“Problem occurred creating chart.”); } |
L’output prodotto in questo caso assumerebbe la forma seguente:
In molte circostanze si può però avere bisogno di rappresentare più serie di dati contemporaneamente, in questa circostanza la struttura del dataset è costruita pensandola come se fosse una sorta di “matrice”, così come appare nel prossimo esempio:
import org.jfree.chart.ChartFactory;import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data.category.CategoryDataset; import org.jfree.data.general.DatasetUtilities; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; public class BarChartDemo1 extends ApplicationFrame { public BarChartDemo1(String title) { super(title);
final CategoryDataset dataset = createDataset(); final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new java.awt.Dimension(500, 270)); setContentPane(chartPanel); }
private CategoryDataset createDataset() { final double[][] data = new double[][] { {210,300,320,265,299}, {200,304,201,201,340}, }; return DatasetUtilities.createCategoryDataset(“Team “, “Match “, data); }
private JFreeChart createChart(final CategoryDataset dataset) { final JFreeChart chart = ChartFactory.createBarChart( “Bar Chart Demo”, “Category”, “Score”, dataset, PlotOrientation.VERTICAL, true, true, false); //titolo,Label Asse X,Label Asse Y, fonte, orientamento del grafico, legenda, tooltip, url return chart; }
public static void main(final String[] args) { BarChartDemo1 chart = new BarChartDemo1(“Vertical Bar Chart Demo”); chart.pack(); RefineryUtilities.centerFrameOnScreen(chart); chart.setVisible(true); } } |
L’output prodotto dal precedente codice è il seguente:
Chiaramente è anche possibile combinare tra loro i grafici così come avviene nell’esempio seguente:
/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2004, by Object Refinery Limited and Contributors. * * Project Info: //www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation; * either version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ------------------------------ * CombinedCategoryPlotDemo1.java * ------------------------------ * (C) Copyright 2003, 2004, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited). * Contributor(s): -; * * $Id: CombinedCategoryPlotDemo1.java,v 1.14 2004/05/10 16:45:22 mungady Exp $ * * Changes * ------- * 16-May-2003 : Version 1 (DG); * */ package org.jfree.chart.demo; import java.awt.Font;
|
L’output prodotto in questo caso è il seguente:
Osservando il codice notiamo, come il risultato finale sia stato ottenuto producendo singolarmente i due chart, dopo di che non si è fatto altro anche aggiungere i due componenti al frame principale, chiaramente la tecnica utilizzata per questo esempio può essere impiegata anche per combinare nello stesso frame grafici della stessa natura. Chiaramente un risultato analogo può essere ottenuto anche agendo sui layout del frame principale, in questo caso, però i grafici andranno creati ed aggiunti singolarmente, in questa circostanza inoltre la flessibilità offerta dai layout definiti direttamente o importabili ci consentono di ottenere strutture ancora più articolate.
Con questo ultimo esempio si conclude la nostra breve rassegna circa alcuna delle funzionalità messe a disposizione da questa interessante libreria, per tutti coloro che fossero interessati ad approfondire gli argomenti cui si è fatto cenno in questo breve tutorial si rimanda al sito del progetto: JFreeChart
Commenti