JFreeChart: Evolução das equipes de Formula 1
Posted by admin on November 17th, 2008
A algum (muito) tempo atras, eu fiz um post sobre o JFreeChart, e algumas dicas de personalização dos gráficos gerados. A minha idéia era fazer mais alguns posts, mas eu achei que aqueles gráficos com dados fake ficaram tão fraquinhos que eu coloquei os outros posts na geladeira por um tempo.
Agora eu resolvi por uma abordagem diferente. Eu achei um conjunto de dados interessante, e resolvi fazer um gráfico com ele, mostrando os passos pra se chegar no resultado final.
Chega de enrolação e vamos direto ao que interessa:
Evolução das equipes de Formula 1 de 1998 a 2008:

Agora vamos ao passo a passo pra construir esse gráfico:
Primeiramente o código básico pra gerar o gráfico. O tipo de gráfico que faz mais sentido pra esse caso é um TimeSeries, já que nós estamos representando a variação de alguma coisa (classificação das equipes) ao longo do tempo (em cada ano).
public class Charts extends ApplicationFrame {
public static void main( String[] args ) {
Charts chart = new Charts(“Teste Bar Chart”);
chart.pack();
chart.setVisible(true);
}
public static JFreeChart getTimeSerie() {
JFreeChart chart = ChartFactory.createTimeSeriesChart(“Historico F-1 - Construtores”, “Ano”, “Equipe”,
getTimeSet(), true, false, false);
}
public static TimeSeriesCollection getTimeSet() {
TimeSeriesCollection ts = new TimeSeriesCollection();
//Um monte de código pra inserir o resultado final de todos os anos no TimeSeriesCollection
return ts;
}
}
Com esse código nos conseguimos o gráfico a seguir:

Da pra ver alguns defeitos nesse gráfico:
- O primeiro colocado está na parte de baixo do gráfico e o último na parte de cima
- A escala das posições está de 0,5 em 0,5. Alguém já viu uma equipe ficar na posição 2,5?
- O gráfico está colado nos eixos, o que deixa a visualização ruim
Vamos então resolver esses problemas e ver como é que fica o nosso gráfico:
chart.getXYPlot().getRangeAxis().setInverted(true);
chart.getXYPlot().getRangeAxis().setRange(0, 12);
chart.getXYPlot().getDomainAxis().setRange(new Year(1997).getMiddleMillisecond(), new Year(2009).getFirstMillisecond());
chart.getXYPlot().getRangeAxis().setStandardTickUnits(new TickUnitSource() {
@Override
public TickUnit getCeilingTickUnit(TickUnit arg0) {
return new NumberTickUnit(1);
}
@Override
public TickUnit getCeilingTickUnit(double arg0) {
return new NumberTickUnit(1);
}
@Override
public TickUnit getLargerTickUnit(TickUnit arg0) {
return new NumberTickUnit(1);
}
});
A primeira linha resolve o primeiro problema. Definindo o Range Axis como inverted, ele passa a começar com o menor valor em cima.
As duas linhas seguintes resolvem o problema do gráfico sem espaços. Definindo o range como 0 a 12 e Year(1997) a Year(2009), nós colocamos um espaço antes e depois de cada dimensão do gráfico.
As linhas seguintes definem que o gráfico vai ter exatamente uma unidade entre cada valor das linhas do Range. Deve existir uma maneira mais fácil de fazer isso, mas eu não consegui achar.
Corrigidos os primeiros defeitos, eis o nosso gráfico:

Melhorzinho, mas ainda não está bom.
- Onde estão a Stewart, a Benetton, a Jaguar e as outras equipes que participaram dos anos anteriores
- O que aconteceu com a McLaren em 2007
Pra responder essas perguntas vamos colocar anotações no gráfico:
XYPlot plot = chart.getXYPlot();
plot.addAnnotation(getAnnotation(“Tyrrel”, new Year(1998).getFirstMillisecond(), 10));
plot.addAnnotation(getAnnotation(“Stewart”, new Year(1999).getFirstMillisecond(), 4));
plot.addAnnotation(getAnnotation(“Benneton”, new Year(2001).getFirstMillisecond(), 7));
plot.addAnnotation(getAnnotation(“Jaguar”, new Year(2004).getFirstMillisecond(), 7));
plot.addAnnotation(getAnnotation(“BAR”, new Year(2005).getFirstMillisecond(), 7));
plot.addAnnotation(getAnnotation(“Sauber”, new Year(2005).getFirstMillisecond(), 8));
plot.addAnnotation(getAnnotation(“Jordan”, new Year(2005).getFirstMillisecond(), 9));
plot.addAnnotation(getAnnotation(“Minardi”, new Year(2005).getFirstMillisecond(), 10));
plot.addAnnotation(getAnnotation(“MF1″, new Year(2006).getFirstMillisecond(), 10));
plot.addAnnotation(getAnnotation(“Spyker”, new Year(2007).getFirstMillisecond(), 10));
plot.addAnnotation(getAnnotation(“Saiu”, new Year(2001).getFirstMillisecond(), 9, Color.RED));
plot.addAnnotation(getAnnotation(“Saiu”, new Year(2002).getFirstMillisecond(), 9, Color.RED));
plot.addAnnotation(getAnnotation(“Perdeu Pontos”, new Year(2007).getFirstMillisecond(), 11, Color.RED));
plot.addAnnotation(getAnnotation(“Saiu”, new Year(2008).getFirstMillisecond(), 11, Color.RED));
/*…*/
public static XYTextAnnotation getAnnotation(String text, double x, double y, Color color) {
XYTextAnnotation cta = new XYTextAnnotation(text, x, y);
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 12);
cta.setFont(font);
cta.setPaint(color);
return cta;
}
public static XYTextAnnotation getAnnotation(String text, double x, double y) {
return getAnnotation(text, x, y, Color.DARK_GRAY);
}
E agora o resultado:

Agora da pra saber que até 2001 a Renault chamava Benneton, que em 2007 a McLaren perdeu os pontos do campeonato, e que as linhas que não têm continuidade foram equipes que saíram da Formula 1.
Mas… ainda não é o gráfico que foi visto ali em cima. Esse ta com as linhas muito finas, e as cores da linhas não estão legais. Ferrari representada por uma linha azul e McLaren por uma vermelha. Não tem associação nenhuma com as cores das equipes!
Vamos então aos ajustes finais do gráfico. Agora é só pra ficar mais bonitinho:
plot.getRenderer().setSeriesPaint(0, Color.DARK_GRAY);
plot.getRenderer().setSeriesPaint(1, Color.RED);
plot.getRenderer().setSeriesPaint(2, Color.BLUE);
plot.getRenderer().setSeriesPaint(3, Color.ORANGE);
plot.getRenderer().setSeriesPaint(4, Color.YELLOW);
plot.getRenderer().setSeriesPaint(5, Color.BLUE.darker());
plot.getRenderer().setSeriesPaint(6, Color.PINK);
plot.getRenderer().setSeriesPaint(7, Color.MAGENTA.darker());
plot.getRenderer().setSeriesPaint(8, Color.GREEN);
plot.getRenderer().setSeriesPaint(9, Color.GREEN.darker());
plot.getRenderer().setSeriesPaint(10, Color.RED.darker());
plot.getRenderer().setSeriesPaint(11, Color.CYAN);
plot.getRenderer().setSeriesPaint(12, Color.GRAY);
for (int i = 0 ; i <= 12 ; i++) {
plot.getRenderer().setSeriesStroke(i, new BasicStroke(3f));
}
Agora sim temos o gráfico que pode ser visto lá em cima.
O código fonte completo pra gerar os gráficos você encontra aqui.
Você vai precisar do jar do JFreeChart e do jCommons(que vem no zip do JFreeChart)
Posted in Coisas de Computeiro, Java Básico, O mundo a nossa volta | 1 Comment »




