Gráficos de barras con JavaFX

Ejemplo básico

Ejemplo sacado de los tutoriales de JavaFX

Pintar un gráfico “a pelo”

/*
 * Main.fx
 * @author: juantxu
 * Created on 23-jul-2009, 7:46:27
 * @copyleft
 */

package guitest1;

import javafx.scene.Scene;
import javafx.scene.layout.LayoutInfo;
import javafx.scene.layout.HBox;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;
import javafx.stage.Stage;

def values = [
  BarChart.Data { value:  14   category: "Pedro" }
  BarChart.Data { value:  19   category: "María" }
  BarChart.Data { value:  14   category: "Eustaquio" }
  BarChart.Data { value: 213   category: "Zeus" }
  BarChart.Data { value: 149   category: "Esquilo" }
  BarChart.Data { value: 306   category: "Homero" }
  BarChart.Data { value: 167   category: "Baco" }
];

Stage {
  title: "Mi Gráfico de barras"
  scene: Scene {
    width: 580
    height: 420
    content:
      HBox{
      content:[
          BarChart {
              title: "Estadisticas de accesos"
              layoutInfo: LayoutInfo {width: 580}
              data: BarChart.Series {
                       name: "Accesos"
                       data: values
              }
              categoryAxis: CategoryAxis {
                      categories: for (value in values) value.category
              }
              valueAxis: NumberAxis {
                      lowerBound: 0
                      upperBound: 340
                      tickUnit: 20
              }
         }
      ]
    }
  }
 }

Y esto se ve tal que así:

Pero este ejemplo es un poco pobre. ¿No puedo leer los valores desde un XML? Vamos a probarlo.

Primera aproximación utilizando clases java

Para empezar decirte que vas a necesitar JDOM para parsear el XML. La idea es tener unas clases java que me lea el xml y que me lo sirva en forma de un arraylist que javaFX usará como origen de datos.

Pongamos que tenemos este XML con pares de datos : /tmp/datos.xml

<?xml version="1.0"?>
<datos tipo="clave y valor">
  <par>
   <clave>Uria</clave>
    <valor>10</valor>
  </par>
    <par>
   <clave>Cafe</clave>
    <valor>12</valor>
  </par>
  <par>
   <clave>te aromatico</clave>
    <valor>24</valor>
  </par>
  <par>
   <clave>kawa</clave>
    <valor>55</valor>
  </par>
  <par>
   <clave>limon</clave>
    <valor>18</valor>
  </par>
  <par>
   <clave>te</clave>
    <valor>12</valor>
  </par>
</datos>

Lo que vamos a hacer es un DTO valorYSerie.java que contendrá cada valor y su serie

valorYSerie.java

package net.juantxu.barcharXml.datos;
/**
 * 
 * @author juantxu
 * @version 1.0
 * @date 25/07/2009
 */
public class valorYSerie {
private String serie;
private int valor;

public String getSerie() {
  return serie;
}

public void setSerie(String serie) {
  this.serie = serie;
}

public int getValor() {
   return valor;
}

public void setValor(int valor) {
  this.valor = valor;
}
}

Por otra parte vamos a definir una interfaz que nos servirá para implementar después el lector desde XML . valorYSerieDAO.java

package net.juantxu.barcharXml.datos;

import java.util.List;

/**
 *
 * @author juantxu
 */
public interface valorYSerieDAO {
List<valorYSerie> getValores(String url);

}

Por fin el parseador propiamente dicho

package net.juantxu.barcharXml.datos;

import java.util.*;
import org.jdom.*;
import org.jdom.input.*;

/**
 *
 * @author juantxu
 */
public class valorYSerieDAOXML implements valorYSerieDAO{

    ArrayList valoresYSeries;

    @Override
    public List<valorYSerie> getValores(String url) {
          valoresYSeries = new ArrayList();

       try {
        SAXBuilder builder=new SAXBuilder(false);
        //usar el parser Xerces y no queremos
        //que valide el documento
        Document doc=builder.build(url);
        //construyo el arbol en memoria desde el fichero
        // que se lo pasaré por parametro.
        Element raiz=doc.getRootElement();
        //cojo el elemento raiz
        //todos los hijos que tengan como nombre
        List pares=raiz.getChildren("par");
        Iterator i = pares.iterator();
        while (i.hasNext()){
            valorYSerie par = new valorYSerie();
            Element e= (Element)i.next();
            // cada par clave /valor se mete en un bean y este a su vez en la lista
            Element clave =e.getChild("clave");
            Element valor =e.getChild("valor");
            par.setSerie( clave.getText());
            par.setValor(Integer.valueOf(valor.getText()));
            valoresYSeries.add(par);
            }
        
     }catch (Exception e){
        e.printStackTrace();
     }
          return this.valoresYSeries;
  }



}

Ya lo tenemos todo, ahora sólo hace falta recoger los valores y pintar nuestro gráfico de barras:

/*
 * Main.fx
 * @author juantxu
 * Created on 25-jul-2009, 8:38:00
 */

package barcharxml;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;
import net.juantxu.barcharXml.datos.valorYSerieDAOXML;
import net.juantxu.barcharXml.datos.valorYSerie;


var valoresDao = valorYSerieDAOXML{};
var valores = valoresDao.getValores("/tmp/pares.xml");  // la ubicación de nuestro xml


var barras: BarChart.Data[] =[];
// relleno los valores de las series/
for (par:valorYSerie in valores){
   insert BarChart.Data {
           value: par.getValor();
           category: par.getSerie();
       } into barras;
}

Stage {
    title: "Grafico de barras"
    width: 400
    height: 400
    scene: Scene {
        content: [
                     BarChart {  // grafico de barras
              title: "Estadisticas de accesos"
              width:300;  // ancho  del grafico
              height:300; //
              data: BarChart.Series {
                       name: "Nombre de la Serie"
                       data: barras
              }
              categoryGap: 10;  // separacion entre barras
              categoryAxis: CategoryAxis {
                      categories: for (value in barras) value.category
              }
              valueAxis: NumberAxis {
                      lowerBound: 0
                      upperBound: 50
                      //tickUnit: 50
              }
         }


        ]
    }
}

y aquí tienes el resultado:

Pero todo esto es muy complicado. Para evitar todo este rollo tenemos el objeto HttpRequest y el objeto PullParser

Grafico de barras que lee los datos de un xml

Este ejemplo puede ser muy útil. La utilidad viene del hecho que lee de un xml externo por lo que los datos pueden ser actualizados facilmente.

/*
 * Main.fx
 * @author juantxu
 * Created on 01-ago-2009, 12:27:52
 * @copyleft
 */

package httprequestsample;

import javafx.data.pull.Event;
import javafx.data.pull.PullParser;
import javafx.data.xml.QName;
import java.io.InputStream;

import javafx.scene.chart.BarChart;
import javafx.scene.chart.part.CategoryAxis;
import javafx.scene.chart.part.NumberAxis;

import javafx.io.http.HttpRequest;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;




var series:String[];  // esto lo usaré para pintar las claves de las series
var valoresDelGrafico: BarChart.Data[] =[]; // esto es un array de valores del grafico
var seriesDelGrafico: BarChart.Series[] = []; //esto es un array de series del grafico
var grafico: BarChart; // el grafico
var serie1: BarChart.Series;  // la serie que meteré en el array de series una vez lleno


// declaro el grafico
grafico =BarChart {
        categoryAxis: CategoryAxis {
            categories: bind series  // enlazo las categorías al array de las series
        }
        valueAxis: NumberAxis {
            lowerBound: 0
            upperBound: 25
            tickUnit: 20
            label:"Grafico de valores"  // pongo una etiqueta
        }
        data: bind  seriesDelGrafico  // enlazo los datos a las series del grafico
    }

/**
*esta es la función que parsea los datos que recibo del XML
*/
function parsea(input: InputStream) {
        // Parsea propiamente dicho
        def parser = PullParser {  // defino el parseador y al final de la función ...
            input: input
            onEvent: function(event: Event) {
                // los datos están en atributos de los elementos
                // por lo que los leo de al iniciar el nodo
                if (event.type == PullParser.START_ELEMENT) {
                    if(event.qname.name == "par" ) {
                        var clave = event.getAttributeValue(QName{name:"clave"}) as String;
                        var valor =  event.getAttributeValue(QName{name:"valor"}) as String ;
                        insert BarChart.Data {
                                     value: Number.parseFloat(valor)
                                    } into  valoresDelGrafico;
                        insert clave into series;
                    }        
                }
            }
        }
        parser.parse();  // ... le digo que parsee
    }

/**
*  objeto HttpRequest qeu realizará la petición y invocará al parseador
*/
def recolectorDeDatos: HttpRequest = HttpRequest {
    location: "http://en.juantxu.net/data/media/java/javafx/barchart/pares_atributos.xml"; // la url
      onInput: function(is: java.io.InputStream) {
        try {
            parsea(is);  // cuando le llegan los datos parsea.
        } finally {
            is.close();
        }
    }
    onDone: function() {
        pintaMiGrafico();  // cuando haya terminado pintará mi grafico
        }
}
recolectorDeDatos.start();

/**
* función que pinta el grafico una vez terminado el parseo.
*/
function pintaMiGrafico(){

    serie1 = BarChart.Series{data: valoresDelGrafico name: "Serie1"};
    seriesDelGrafico= [serie1];
}




/**
* Texto que servirá de titulo.
*/
var titulo =  Text {
                font : Font {
                    size : 16
                }
                x: 200
                y: 50
                content: "Titulo del Grafico"
            }


/**
* La escena
*/
Stage {
    title: "Grafico desde un XML"
    width: 500
    height: 500
    scene: Scene {
    content: Group {
           content: [titulo, grafico  ];
        }
    }
}

Y esto es como quedaría este mismo ejemplo que recarga los datos cada vez que se lo pides:

 
java/javafx/barchart.txt · Última modificación: 2009/08/27 07:05 por juantxu
 
Excepto donde se indique lo contrario, el contenido de esta wiki se autoriza bajo la siguiente licencia:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki