jueves, 22 de enero de 2009

Invertir los Ejes en una Grafica de jfreechart

Bien esta semana he tenido que actualizar un par de gráficas dentro de un reporte, para esto las gráficas se generan con jfreechart que es una librería para hacer dicha tarea de manera mas fácil y obteniendo resultados muy buenos.

Las gráficas que se estaban generando tenían un pequeño detalle y es que la gráfica debería de contener los valores negativos de las y en la parte superior y no en la parte inferior que es como esta por default y es por eso que revisando ejemplos, asi como el api de jfreechart pues encontré la forma de hacerlo y se puede hacer tanto para el eje x como para el eje y.

por ejemplo tenemos la siguiente grafica con dos series de valores, uno corresponde a la funcion
y = x, y el segundo corresponde a la serie de valores y = x + 2

Bien para esto tengo el siguiente código:

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.io.File;
import java.io.*;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class EjemploGrafica {

public BufferedImage generaGrafica(ArrayList areo, ArrayList oseo, String title) {
System.out.println(" Generando la grafica con titulo " + title);
BufferedImage buf = null;
try {

XYSeries series = this.llenaSerie(areo,"Serie Uno");
XYSeries series2 = this.llenaSerie(oseo,"Serie Dos");

XYSeriesCollection data = new XYSeriesCollection(series);
XYSeriesCollection data2 = new XYSeriesCollection(series2);
//Se crea el objeto para generar la grafica
JFreeChart chart = ChartFactory.createXYLineChart(
title,
"",
"",
null,
PlotOrientation.VERTICAL,
false,
true,
false
);

chart.setBorderVisible(true);
chart.setBorderPaint(Color.black);
XYPlot plot = chart.getXYPlot();
pintaSerieCirculo(plot,data );
pintaSerieCirculo(plot,data2 );

/*Comentar esta linea si únicamente queremos que retorne la BufferreImage y el catch con la IOException */
ChartUtilities.saveChartAsJPEG(new File("c:\\Barchart.jpg"), chart, 500,
300);

buf = chart.createBufferedImage(500,300);
} catch (IOException e) {
e.printStackTrace();
System.err.println("Error creando grafico.");
} catch (Exception e) {
System.out.println(e.toString());
System.err.println("Error creando grafico.");
}

return buf;
}


private void pintaSerie(XYPlot plot, XYSeriesCollection data){
int index = plot.getDatasetCount();

System.out.println(" numero de data sets " + index);
plot.setDataset(index,data);
System.out.println(" numero de data sets " + index);
StandardXYItemRenderer sxyiRender = new StandardXYItemRenderer();
//sxyiRender.setPlotImages(true);
plot.setRenderer(index,sxyiRender);
}

private void pintaSerieCirculo(XYPlot plot, XYSeriesCollection data){
int index = plot.getDatasetCount();

System.out.println(" numero de data sets " + index);
plot.setDataset(index,data);
System.out.println(" numero de data sets " + index);
StandardXYItemRenderer sxyiRender = new StandardXYItemRenderer();
//sxyiRender.setPlotImages(true);
sxyiRender.setShapesFilled(true);
sxyiRender.setBaseSeriesVisible(true);
sxyiRender.setBaseShapesVisible(true);
plot.setRenderer(index,sxyiRender);

}

private XYSeries llenaSerie(ArrayList data, String title) {
BeanValoresGrafica valores = null;
XYSeries series = new XYSeries(title);
for(Object valorXy : data){
valores = (BeanValoresGrafica) valorXy;
series.add(valores.getX(), valores.getY());
}
return series;
}

public static void main(String[] args) {
BeanValoresGrafica b = null;
ArrayList a = new ArrayList();
for(int i = -5 ; i < b =" new" ab =" new" i =" -2" b =" new">

Ahora yo necesito que mi gráfica quede asi :
Como observan los valores negativos de y se encuentran en la parte superior y no en la inferior para invertirlos realizaremos lo siguiente (incluir esta parte de codigo despues de obtener el objeto XYPlot y las llamadas del metodo pintaSerieCirculo)

.
.
pintaSerieCirculo(plot,data2 );
plot.setDomainAxisLocation(AxisLocation.TOP_OR_LEFT);
NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis();
//*Invierte los valores del eje x */
// domainAxis.setInverted(true);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
//*Aqui es donde se invirte el eje y*/
rangeAxis.setInverted(true);
ChartUtilities.saveChartAsJPEG(new File("c:\\Barchart.jpg"), chart, 500,
300);



El metodo que genera la grafica nos retorna un objeto de tipo java.awt.image.BufferedImage este objeto podemos utilizarlo par mostrarlo en una aplicación swing o en un reporte de jasperreport o guardar la imagen en jpg y adjuntarla en algún informe, etc.

Bien pues es lo que yo necesitaba y espero que les sirva

La grafica final :

Como observan es lo mismo que lo anterior solo que se colocaron las etiquetas del eje x en la parte superior para eso tenemos el siguiente código:

AxisLocation axloc = plot.getDomainAxisLocation();
plot.setDomainAxisLocation(AxisLocation.TOP_OR_LEFT);


Bueno eso es todo, ha se me olvidaba que yo utilizo un bean para pasar valores le coloco el bean que no es la gran cosa pero es parte del codigo

import java.io.Serializable;

public class BeanValoresGrafica implements Serializable {


public BeanValoresGrafica() {
}

private double x;
private double y;

public double getX(){
return x;
}

public double getY(){
return y;
}

public double setX(double x){
return this.x = x;
}

public double setY(double y){
return this.y = y;
}

}

4 comentarios:

Anónimo dijo...

Interesante

Diego dijo...

tu trabajo esta excelente, me gustaria saber si me puedes guiar para realizar un programa que necesito hacer, necesito graficar los datos que me envia un circuito por el puerto USB, pero no se como empezar, que me aconsejas guardar esos datos en una array y luego graficarlos o que me decis,cualquier ayuda me sirve. mi correo es diego5817@gmail.com

Anónimo dijo...

Que bueno que existen personas como tu que transmiten sus conocimientos!!, esto era justo lo que buscaba!!!
Saludoa!!!!

lutero dijo...

Muchisimas gracias justo lo que andaba buscando