Um dos aspectos mais importantes da reportagem é tornar o conteúdo o mais visível possível para que a essência das informações contidas na reportagem chegue ao seu público de forma rápida e sem esforço. Os gráficos desempenham um papel crucial nesse sentido. Apresentar dados brutos e tentar imaginar o cenário associado aos dados não é muito fácil, mas os gráficos representam uma essência pictórica dos dados e ajudam o espectador a entender a ideia por trás dos dados brutos muito rapidamente. JavaFX tem suporte embutido para apresentar dados brutos em forma pitoresca dinamicamente. A API tem duas facetas:uma pode estender as classes da API e criar um gráfico personalizado do zero ou usar as classes específicas de gráfico disponíveis para criar um gráfico com código mínimo. Este artigo aborda os principais aspectos das APIs de gráfico do JavaFX e mostra como implementá-las. Exemplos rápidos são fornecidos para ajudá-lo.
Gráficos JavaFX
Os gráficos JavaFX não são apenas fáceis de integrar com outras partes do aplicativo, mas também estão imbuídos da política extensível de tecnologia orientada a objetos que pode ser personalizada conforme a necessidade do desenvolvedor. Isso não é uma coisa nova, porque os projetos orientados a objetos sempre devem ser extensíveis, mas a parte interessante da API de gráficos JavaFX é que existem muitas classes de gráficos prontas que podem ser instanciadas com pouca ou nenhuma alteração em seu propriedades para obter gráficos com aparência profissional. Essas classes de gráficos são mais comuns, personalizáveis e atendem a quase todas as necessidades do desenvolvedor. Na maioria dos casos, quase não há necessidade de criar um gráfico personalizado do zero.
JavaFX fornece oito desses tipos de gráficos na biblioteca de API com sua funcionalidade integrada. Embora existam muitas classes e interfaces de suporte na biblioteca de API de gráficos JavaFX, a implementação concreta de oito é organizada hierarquicamente da seguinte forma.
Figura 1: O gráfico de hierarquia da biblioteca da API do gráfico JavaFX
Portanto, os oito tipos comuns de gráfico são:gráfico de pizza , gráfico de barras , gráfico de área , gráfico de linhas , gráfico de dispersão , gráfico de bolhas , gráfico de área empilhada e gráfico de barras empilhadas .
O gráfico de pizza
O gráfico de pizza é um formato de gráfico comum em que as informações são renderizadas em uma estrutura típica de fatias de pizza. Cada fatia de pizza representa o valor proporcional dos dados. A maneira mais fácil de criar um gráfico de pizza em JavaFX é instanciar o PieChart class e defina os dados da seguinte forma:
PieChart pie=new PieChart();
Podemos definir os dados para um gráfico de pizza com a ajuda do setData() método, que recebe um parâmetro do tipo ObservableList
PieChart.Data(String title, Double value)
Aqui está um exemplo rápido para criar um gráfico de pizza.
package org.mano.example; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.chart.PieChart; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createPieChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public PieChart createPieChart() { PieChart pie = new PieChart(); ObservableList<PieChart.Data> data = FXCollections.observableArrayList(); data.addAll(new PieChart.Data("Asia", 30.0), new PieChart.Data("Africa", 20.3), new PieChart.Data("North America", 16.3), new PieChart.Data("South America", 12.0), new PieChart.Data("Antartica", 8.9), new PieChart.Data("Europe", 6.7), new PieChart.Data("Australia", 5.2)); pie.setData(data); pie.setTitle("The Continents: Land Area"); return pie; } }
Saída
Figura 2: O gráfico de pizza finalizado do código anterior
O Gráfico XY
O XYChart é uma classe abstrata que forma a base de todos os gráficos de dois eixos em JavaFX. Os gráficos de dois eixos são aqueles em que normalmente um único elemento representa um par e é plotado em uma área de coordenadas cartesianas marcada pelo eixo x como colunas e pelo eixo y como linhas. As derivadas concretas desta classe abstrata são:BarChart , Gráfico de Área , Gráfico de Bolhas , Gráfico de linhas , Gráfico de Dispersão , StckedAreaChart , e StackBarChart . Ao contrário do XYChart , o Gráfico de pizza não estabelece dados em formato de eixo x e y. Esta é a principal diferença entre um PieChart e um XYChart . Os dados em um XYChart é ordenado em série. Mas, a forma como esta série de dados será renderizada depende da implementação ou tipo do XYChart realmente instanciado.
Porque XYChart é representado em um formato de eixo x e y, o construtor de XYChart é o seguinte.
XYChart(Axis<X> xAxis, Axis<Y> yAxis)
Eixo é uma classe abstrata que estende Region . Existem duas subclasses concretas desta classe, chamadas CategoryAxis e ValueAxis . O CategoryAxis é instanciado para renderizar rótulos do gráfico em formato de string enquanto o ValueAxis renderiza as entradas de dados em Número formato. O Número também é uma classe abstrata que forma a classe base para todos os tipos numéricos em Java, como as classes wrapper:Double , Inteiro , Flutuar , Longo , Curto , e assim por diante.
Exemplo de gráfico de barras
Um gráfico de barras é normalmente usado para mostrar a diferença relativa entre as diferentes séries de uma determinada categoria. O exemplo a seguir ilustra como criar um em Java.
package org.mano.example; import java.util.*; import javafx.application.Application; import javafx.collections.*; import javafx.scene.Scene; import javafx.scene.chart.*; import javafx.scene.chart.XYChart.Series; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createBarChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { ObservableList<XYChart.Series<String, Double>> data = FXCollections.observableArrayList(); Series<String, Double> as = new Series<>(); Series<String, Double> bs = new Series<>(); Series<String, Double> cs = new Series<>(); Series<String, Double> ds = new Series<>(); Series<String, Double> es = new Series<>(); Series<String, Double> fs = new Series<>(); as.setName("A-Series"); bs.setName("B-Series"); cs.setName("C-Series"); ds.setName("D-Series"); es.setName("E-Series"); fs.setName("F-Series"); Random r = new Random(); for (int i = 1900; i < 2017; i += 10) { as.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); bs.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); cs.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); ds.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); es.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); fs.getData().add(new XYChart.Data<> (Integer.toString(i), r.nextDouble())); } data.addAll(as, bs, cs, ds, es, fs); return data; } public XYChart<CategoryAxis, NumberAxis> createBarChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); BarChart bc = new BarChart<>(xAxis, yAxis); bc.setData(getDummyChartData()); bc.setTitle("Bar Chart on Random Number"); return bc; } }
Saída
Figura 3: O gráfico de barras finalizado do código anterior
Exemplo de gráfico de dispersão
Os itens de dados em um gráfico de dispersão são representados como símbolos dentro da área do eixo XY. O código do gráfico de barras anterior pode ser facilmente convertido para criar um gráfico de dispersão fazendo as seguintes alterações.
package org.mano.example; import java.util.*; import javafx.application.Application; import javafx.collections.*; import javafx.scene.Scene; import javafx.scene.chart.*; import javafx.scene.chart.XYChart.Series; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.util.StringConverter; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createScatterChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { // ... Same as above } public XYChart<CategoryAxis, NumberAxis> createScatterChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); ScatterChart sc = new ScatterChart<>(xAxis, yAxis); sc.setData(getDummyChartData()); sc.setTitle("Scatter chart on random data"); return sc; } }
Saída
Figura 4: O gráfico de dispersão finalizado do código anterior
Exemplo de gráfico de linha
Como podemos ver, os itens de dados no gráfico de dispersão são representados com a ajuda de pontos ou símbolos. Às vezes, é conveniente conectar os pontos. Isso melhora a visibilidade da mudança nas tendências de um ponto marcado para outro. O gráfico de linhas faz exatamente isso. O próximo exemplo ilustra a ideia.
package org.mano.example; // ... Import statements same as above public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createLineChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { // ... Same as above } public XYChart<CategoryAxis, NumberAxis> createLineChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); LineChart lc = new LineChart<>(xAxis, yAxis); lc.setData(getDummyChartData()); lc.setTitle("Line chart on random data"); return lc; } }
Saída
Figura 5: O gráfico de linhas acabado do código anterior
Exemplo de StackedBarChart
O StackBarChart é outra versão do BarChart no sentido de que aqui, em vez de representar barras diferentes uma ao lado da outra, o StackedBarChart empilha as categorias em cima de outra.
package org.mano.example; // ... Import statements same as above public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createStackedBarChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { // ... Same as above } public XYChart<CategoryAxis, NumberAxis> createStackedBarChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); StackedBarChart sbc = new StackedBarChart<>(xAxis, yAxis); sbc.setData(getDummyChartData()); sbc.setTitle("Stacked bar chart on random data"); return sbc; } }
Saída
Figura 6: O gráfico de barras empilhado finalizado do código anterior
Exemplo de gráfico de área
Em um AreaChart , a região sob as linhas que conectam os pontos é preenchida para representar uma categoria.
package org.mano.example; // ... Import statements same as above public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createAreaChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { // ... Same as above } public XYChart<CategoryAxis, NumberAxis> createAreaChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); AreaChart ac = new AreaChart<>(xAxis, yAxis); ac.setData(getDummyChartData()); ac.setTitle("Area chart on random data"); return ac; } }
Saída
Figura 7: O gráfico de área finalizado do código anterior
Exemplo de StackedAreaChart
O StackedAreaChart mostra a soma dos valores da mesma categoria e não mostra áreas individuais como o AreaChart faz. Esta é, em essência, outra versão do AreaChart .
package org.mano.example; // ... Import statements same as above public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createStackedAreaChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<String, Double>> getDummyChartData() { // ... Same as above } public XYChart<CategoryAxis, NumberAxis> createStackedAreaChart() { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); StackedAreaChart sac = new StackedAreaChart<>(xAxis, yAxis); sac.setData(getDummyChartData()); sac.setTitle("Stacked area chart on random data"); return sac; } }
Saída
Figura 8: O gráfico de área empilhado finalizado do código anterior
Exemplo de gráfico de bolhas
O Gráfico de Bolhas plota bolhas para pontos de dados na série. Esta variação do XYChart utiliza as propriedades adicionais do XYChart.Data classe no sentido de que é um XYChart especial implementação entre todas as subclasses do XYChart . Aqui, um item de dados é indicado por dois ou três parâmetros, como valor x, valor y e, opcionalmente, o valor que significa o raio da bolha. Aqui está um exemplo para ilustrar como criar um em Java.
package org.mano.example; import java.util.*; import javafx.application.Application; import javafx.collections.*; import javafx.scene.Scene; import javafx.scene.chart.*; import javafx.scene.chart.XYChart.Series; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.util.StringConverter; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { stage.setTitle("JavaFX Chart Demo"); StackPane pane = new StackPane(); pane.getChildren().add(createBubbleChart()); stage.setScene(new Scene(pane, 400, 200)); stage.show(); } public ObservableList<XYChart.Series<Integer, Double>> getDummyChartData2() { ObservableList<XYChart.Series<Integer, Double>> data = FXCollections.observableArrayList(); Series<Integer, Double> as = new Series<>(); Series<Integer, Double> bs = new Series<>(); Series<Integer, Double> cs = new Series<>(); Series<Integer, Double> ds = new Series<>(); Series<Integer, Double> es = new Series<>(); Series<Integer, Double> fs = new Series<>(); as.setName("A-Series"); bs.setName("B-Series"); cs.setName("C-Series"); ds.setName("D-Series"); es.setName("E-Series"); fs.setName("F-Series"); Random r = new Random(); for (int i = 1900; i < 2017; i += 10) { double d = r.nextDouble(); as.getData().add(new XYChart.Data<> (i, r.nextInt(32)+r.nextDouble(), 2 * d)); bs.getData().add(new XYChart.Data<> (i,r.nextInt(32)+r.nextDouble(), 4 * d)); cs.getData().add(new XYChart.Data<> (i,r.nextInt(32)+r.nextDouble(), 3 * d)); ds.getData().add(new XYChart.Data<> (i,r.nextInt(32)+r.nextDouble(), 5 * d)); es.getData().add(new XYChart.Data<> (i,r.nextInt(32)+r.nextDouble(), 1.5 * d)); fs.getData().add(new XYChart.Data<> (i,r.nextInt(32)+r.nextDouble(), 1.7 * d)); } data.addAll(as, bs, cs, ds, es, fs); return data; } public BubbleChart<Number, Number> createBubbleChart() { NumberAxis xAxis = new NumberAxis(); NumberAxis yAxis = new NumberAxis(); yAxis.setAutoRanging(false); yAxis.setLowerBound(0); yAxis.setUpperBound(30); xAxis.setAutoRanging(false); xAxis.setLowerBound(1900); xAxis.setUpperBound(2017); xAxis.setTickUnit(10); xAxis.setTickLabelFormatter(new StringConverter<Number>() { @Override public String toString(Number object) { return String.valueOf(object.intValue() / 10); } @Override public Number fromString(String string) { return Integer.valueOf(string) * 10; } }); BubbleChart blc = new BubbleChart<>(xAxis, yAxis); blc.setData(getDummyChartData2()); blc.setTitle("Bubble chart on random data"); return blc; } }
Saída
Figura 9: O gráfico de bolhas finalizado do código anterior
Conclusão
Pode-se usar Cascading Style Sheets (CSS) para modificar a aparência padrão dos gráficos JavaFX, como alterar o esquema de cores, modificar suas legendas e eixos ou símbolos do gráfico e assim por diante. JavaFX fornece muitas tags CSS específicas de gráfico para conseguir isso. A parte mais importante da API de gráficos JavaFX é que ela fornece diferentes variações de tipos de gráficos prontos para uso. Cabe aos desenvolvedores escolher o tipo certo de gráfico que melhor corresponda ao seu esquema de relatório de dados.