Continuiamo la carrellata tra API Java che possono risultare utili per affrontare specifici problemi. In questo numero passiamo in rassegna JFreeChart, una libreria Java pura che consente di realizzare grafici a partire da dati, utilizzando le tipologie di grafici più comuni e diffuse.
JFreeChart e le sue caratteristiche
JFreeChart è una libreria Java pura che ha come oggetto i grafici: tramite questa libreria, gli sviluppatori potranno facilmente incorporare grafici di qualità professionale nelle loro applicazioni. Le caratteristiche di JFreeChart sono:
- una API ben documentata, che supporta un’ampia gamma di tipi di grafici;
- un design flessibile che è facile da estendere, sia per le applicazioni lato server che lato client;
- il supporto per molti tipi di output , tra cui Swing e componenti JavaFX , file immagine (tra cui PNG e JPEG) , e formati di file grafici vettoriali (inclusi PDF, EPS e SVG) ;
- JFreeChart è open source o, più specificamente , “software libero”. È distribuito in accordo con i termini della GNU Lesser General Public Licence (LGPL) che ne consente l’uso in applicazioni proprietarie.
Andando sul sito della libreria [1] è possibile scaricare nella sezione download il file JAR da includere nel vostro progetto.
Grafico a torta
Il diagramma circolare (comunemente indicato come “grafico a torta” o “diagramma a torta”) si usa in statistica descrittiva per illustrare graficamente delle variabili quantitative misurate su classi di categorie; usando la “torta” e i suoi “spicchi” si evita di stabilire, anche involontariamente, un ordine che non esiste nelle categorie, cosa che accadrebbe invece utilizzando un istogramma.
Un diagramma circolare viene costruito dividendo un cerchio in spicchi: più lo spicchio è grande (vale a dire, maggiore è l’angolo), maggiore è la classe di frequenza rappresentata: in definitiva, come in un istogramma, c’è una proporzionalità diretta fra le aree e le frequenze da rappresentare.
Grafico a torta in JFreeChart
Supponiamo di voler costruire un grafico a torta che rispecchi la percentuale di marchi che sono nella gamma A, B, C, e D per CSC408: è un esempio con valori e nomi alla buona, usato nella documentazione della libreria. Il codice seguente illustra come sia possibile ottenere tale risultato in maniera piuttosto lineare.
public class PieChartExample { public static void main(String[] args) { // Creiamo un semplice grafico a torta DefaultPieDataset pieDataset = new DefaultPieDataset(); // Imposto il valore dell'elemento A a 75 pieDataset.setValue("A", new Integer(75)); // Imposto il valore dell'elemento B a 10 pieDataset.setValue("B", new Integer(10)); // Imposto il valore dell'elemento C a 10 pieDataset.setValue("C", new Integer(10)); // Imposto il valore dell'elemento D a 5 pieDataset.setValue("D", new Integer(5)); JFreeChart chart = ChartFactory.createPieChart ("CSC408 Mark Distribution", // Titolo pieDataset, // Dataset true, // Mostra Legenda true, // Usa tooltips false // Dice se il grafico deve generare un URL? ); try { ChartUtilities.saveChartAsJPEG(new File("C:\chart.jpg"), chart, 500,300); } catch (Exception e) { System.out.println("Problem occurred creating chart."); } } }
Figura 1 – Il grafico a torta.
Grafico XY
Detti anche diagrammi a due variabili questi grafici rappresentano due variabili (x, y) su un piano cartesiano, dove sono individuate da una coppia di coordinate. Una variante più complessa è rappresentata da quei grafici che aggiungano una terza coordinata.
Grafico XY in JFreeChart
Nell’esempio che segue, costruiremo con JFreeChart una linea con la seguente serie di coordinate (x, y):
{(1, 1), (1, 2), (2, 1), (3, 9), (4, 10)}
Ecco il codice
public class XYChartExample { public static void main(String[] args) { // Creo un semplice grafico XY XYSeries series = new XYSeries("XYGraph"); //Creo punti (X,Y) series.add(1, 1); series.add(1, 2); series.add(2, 1); series.add(3, 9); series.add(4, 10); // Aggiungo la serie di punti al dataset XYSeriesCollection dataset = new XYSeriesCollection(); dataset.addSeries(series); // Genero il grafico JFreeChart chart = ChartFactory.createXYLineChart( "XY Chart", // Titolo "x-axis", // Etichetta asse X "y-axis", // Etichetta asse Y dataset, // Dataset PlotOrientation.VERTICAL, // Orientamento grafico true, // Mostra Legenda true, // Usa tooltips false // Dice se il grafico deve generare un URL ); try { ChartUtilities.saveChartAsJPEG(new File("C:\chart.jpg"), chart, 500, 300); } catch (IOException e) { System.err.println("Problem occurred creating chart."); } } }
Figura 2 – Grafico per la rappresentazione di due variabili su un piano.
Grafico a barre
Il diagramma a colonne o a barre o “istogramma” si realizza utilizzando delle colonne come elementi rappresentativi di un dato. In pratica, il grafico si disegna usando tanti rettangoli quante sono le modalità da rappresentare. Tali rettangoli sono paralleli all’asse delle ordinate, hanno base fissa di dimensione uguale per ciascuna barra, ma l’altezza di ciascuna colonna è direttamente proporzionale al dato che essa rappresenta.
Istogramma in JFreeChart
Costruiamo un grafico a barre che confronta i profitti guadagnati dai seguenti ipotetici venditori: Jane, Tom, Jill, John, Fred.
public class BarChartExample { public static void main(String[] args) { // Creo Diagramma a barre DefaultCategoryDataset dataset = new DefaultCategoryDataset(); // Barre: valore, asseY, asseX 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."); } } }
Figura 3 – L’istogramma o grafico a colonne.
Grafici con intervallo temporale
Una particolare versione del grafico a due variabili è quello in cui si rappresenta un andamento temporale. In tal caso, si uniscono i punti sul grafico, collocando per convenzione sull’asse orizzontale il tempo che scorre, mentre sull’asse verticale il valore di y indicherà il variare del valore.
Grafico con intervallo temporale in JFreeChart
Supponiamo di voler monitorare la popolazione di una piccola città su intervalli mensili.
public class TimeSeriesExample { public static void main(String[] args) { // Creo grafico ad intervallo temporale TimeSeries pop = new TimeSeries("Population", Day.class); // Data, Valore pop.add(new Day(10, 1, 2004), 100); pop.add(new Day(10, 2, 2004), 150); pop.add(new Day(10, 3, 2004), 250); pop.add(new Day(10, 4, 2004), 275); pop.add(new Day(10, 5, 2004), 325); pop.add(new Day(10, 6, 2004), 425); TimeSeriesCollection dataset = new TimeSeriesCollection(); dataset.addSeries(pop); JFreeChart chart = ChartFactory.createTimeSeriesChart( "Population of CSC408 Town", "Date", "Population", dataset, true, true, false); try { ChartUtilities.saveChartAsJPEG(new File("C:\chart.jpg"), chart, 500, 300); } catch (IOException e) { System.err.println("Problem occurred creating chart."); } } }
Figura 4 – Un grafico per la rappresentazione dell’andamento di un valore (in ordinate) in un determinato periodo temporale (in ascisse).
Grafici “dashboard” o “cruscotto”
In anni recenti, grande rilevanza ha assunto il grafico "a cruscotto". Simile concettualmente al tachimetro di un'automobile, esso ha il pregio di rappresentare in maniera molto intuitiva dei valori, specie se si ha l'accortezza di colorare le varie "fasce di merito" con una codifica colore immediatamente intelligibile: il classico rosso, giallo e verde di semaforica provenienza è in grado di indicare immediatamente all'utente se il valore mostrato è negativo, accettabile o ampiamente positivo.
Cruscotto con JFreeChart
Vediamo un esempio semplice ma efficace: il grafico delle vendite di una società. Tenendo fuori tutti gli altri fattori, immaginiamo che a un certo livello di vendite corrisponda direttamente l’andamento dei conti della società [2]. Nel codice che segue si suppongono i seguenti valori:
- 0-6500: la società è in perdita;
- 6501-7000 : la società è in pareggio;
- 7001-10000: la società è in attivo.
Vediamo l’esempio:
public class AchievementChartWithMeterChart extends ApplicationFrame { public AchievementChartWithMeterChart(String s) { super(s); JPanel panel = createPanel(); panel.setPreferredSize(new Dimension(500, 350)); setContentPane(panel); } private static JFreeChart createChart(ValueDataset valuedataset) { MeterPlot meterplot = new MeterPlot(valuedataset); //Imposto il valore minimo emassimo del range meterplot.setRange(new Range(0.0D, 10000D)); //Valori di perdita 0 - 6500 meterplot.addInterval(new MeterInterval("Loss", new Range(0.0D, 6500D), Color.red, new BasicStroke(2.0F), new Color(255, 0, 0, 128))); //Valore di pareggio 6500 - 7000 meterplot.addInterval(new MeterInterval("break even", new Range(6501D, 7000D), Color.yellow, new BasicStroke(2.0F), new Color(255, 255, 0, 64))); //Valore di Guadagno 7000 - 10000 meterplot.addInterval(new MeterInterval("Profit", new Range(7001D, 10000D), Color.green, new BasicStroke(2.0F), new Color(0, 255, 0, 64))); meterplot.setNeedlePaint(Color.darkGray); meterplot.setDialBackgroundPaint(Color.white); meterplot.setDialOutlinePaint(Color.black); meterplot.setDialShape(DialShape.CHORD); meterplot.setMeterAngle(180); meterplot.setTickLabelsVisible(true); meterplot.setTickLabelFont(new Font("Arial", 1, 12)); meterplot.setTickLabelPaint(Color.black); meterplot.setTickSize(5D); meterplot.setTickPaint(Color.gray); meterplot.setValuePaint(Color.black); meterplot.setValueFont(new Font("Arial", 1, 14)); JFreeChart jfreechart = new JFreeChart("Sales Chart", JFreeChart.DEFAULT_TITLE_FONT, meterplot, true); return jfreechart; } public static JPanel createPanel() { //Imposto come valore scelto 7500 dataset = new DefaultValueDataset(7500D); JFreeChart chart = createChart(dataset); ChartPanel chartpanel = new ChartPanel(chart); return chartpanel; } public static void main(String args[]) { AchievementChartWithMeterChart meterChart = new AchievementChartWithMeterChart( "Meter Chart Example"); meterChart.pack(); RefineryUtilities.centerFrameOnScreen(meterChart); meterChart.setVisible(true); } private static DefaultValueDataset dataset; }
Figura 5 – Il grafico “cruscotto” è molto immediato e semplice da comprendere. Proprio per tale motivo, in anni passati ha avuto un successo così grande da essere impiegato spesso a sproposito, in situazioni in cui non si prestava bene a illustrare l’informazione del tipo di dato sottostante.
Conclusioni
Una libreria come JFreeChart ha avuto numerosi utilizzi e può tornare utile in molte occasioni, quando si voglia, per una qualunque ragione, mantenere un approccio “pure Java”. Gli esempi presentati sono solo un esempio delle varie possibilità.