OSBI.FR - Open Source Business Intelligence

Impression de rapports Pentaho en noir et blanc

Voilà une demande sur laquelle je suis déjà tombé à plusieurs reprises, la dernière fois c’était chez un constructeur automobile du nord de la France, pour lequel toutes les impressions de rapports Pentaho sont réalisées en noir et blanc (par souci écologique et économique).

Comment donc dans ce contexte interpréter un graphique Pentaho lorsque celui-ci ne peut pas être imprimé en couleur ?

Dans Report Designer, les graphiques prennent un jeu de couleurs par défaut (qu’on peut modifier dans l’option « series-color » du graphe), comme par exemple dans le « Bar Chart » ci-dessous :

Or lorsqu’on imprime tout ça en noir et blanc, il n’est pas toujours facile de s’y retrouver !

Pas évident par exemple de distinguer ci-dessous la série « Planes » de la série « Trains », ou encore celle de « Ships » :

La solution est donc de mettre en place des motifs en noir et blanc (un peu comme dans Excel), directement au travers des classes Java de la librairie graphique JFreeChart

Vous ne le savez peut-être pas, mais tous les paramétrages possibles pour un graphique JFreeChart ne sont pas « câblés » dans l’interface de conception de Pentaho Report Designer.

Ceux-ci sont néanmoins tous accessibles via du code Java depuis l’option « Chart Post-Processing Script » (on utilise alors le langage « beanshell ») :

Par exemple, si on souhaite désactiver l’affichage des ombres des barres du graphique, il suffit d’écrire le script suivant :

// récupération des objets nécessaires
plot = chart.getPlot();
renderer = plot.getRenderer();
 
// Suppression de l'ombre sur les graphes
renderer.setShadowVisible(false);

Si maintenant on souhaite définir des motifs en noir et blanc pour les barres du graphique, il faut passer par des textures (classe « TexturePaint »).

A cet effet, je me suis librement inspiré d’un code Java trouvé sur le forum de jfreechart afin d’afficher des motifs différenciés pour chaque série du graphe.

Voilà le résultat :

 

Ci-dessous le code Java inséré dans « Chart Post-Processing Script » :

import java.awt.image.BufferedImage;
import java.awt.geom.GeneralPath;
 
// récupération des objets nécessaires
plot = chart.getPlot();
renderer = plot.getRenderer();
 
// Suppression de l'ombre sur les graphes
renderer.setShadowVisible(false); 
 
// Affectation de motifs en fonction des séries
 
// Motif 1
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	big.setColor(Color.white);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.gray);
	big.fillRect(0, 1, 5, 5);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);		
	renderer.setSeriesPaint(0, tp);
 
// Motif 2
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	big.setColor(Color.white);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.gray);
	big.fillRect(1, 1, 4, 4);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(1, tp);
 
// Motif 3
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	float[] x = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	float[] y = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	GeneralPath path = new GeneralPath();
	path.moveTo(x[0], y[0]);
	for (int j = 1; j < x.length; j++) {
	  path.lineTo(x[j], y[j]);
	}
	big.setColor(Color.gray);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.white);
	big.setStroke(new BasicStroke(1.0f));
	big.draw(path);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(2, tp);		
 
// Motif 4 
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	big.setColor(Color.white);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.gray);
	big.fillRect(1, 0, 5, 5);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(3, tp);		
 
// Motif 5
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	float[] x = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	float[] y = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	GeneralPath path = new GeneralPath();
	path.moveTo(x[0], y[0]);
	for (int j = 1; j < x.length; j++) {
		path.lineTo(x[j], y[j]);
	}
	big.setColor(Color.white);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.gray);
	big.setStroke(new BasicStroke(2.0f));
	big.draw(path);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(4, tp);		
 
// Motif 6
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	float[] x = { 5.0f, 4.5f, 4.0f, 3.5f, 3.0f, 2.5f, 2.0f, 1.5f, .5f };
	float[] y = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	GeneralPath path = new GeneralPath();
	path.moveTo(x[0], y[0]);
	for (int j = 1; j < x.length; j++) {
	  path.lineTo(x[j], y[j]);
	}
	big.setColor(Color.gray);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.white);
	big.setStroke(new BasicStroke(1.0f));
	big.draw(path);
	Rectangle r = new Rectangle(0, 0, 5, 5);
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(5, tp);		
 
// Motif 7
	BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
	Graphics2D big = bi.createGraphics();
	float[] x = { 5.0f, 4.5f, 4.0f, 3.5f, 3.0f, 2.5f, 2.0f, 1.5f, .5f };
	float[] y = { .5f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f };
	GeneralPath path = new GeneralPath();
	path.moveTo(x[0], y[0]);
	for (int j = 1; j < x.length; j++) {
		path.lineTo(x[j], y[j]);
	}
	big.setColor(Color.white);
	big.fillRect(0, 0, 5, 5);
	big.setColor(Color.gray);
	big.setStroke(new BasicStroke(2.0f));
	big.draw(path);
	Rectangle r = new Rectangle(0, 0, 5, 5);
 
	TexturePaint tp = new TexturePaint(bi, r);
	renderer.setSeriesPaint(6, tp);

Beaucoup d’autres options sont paramétrables de cette façon, notamment l’ajustement dynamique des couleurs du graphe en fonction des données ou encore la mise en place de dégradés…

Je vous invite à lire les articles de Slawomir Chodnicki sur ce sujet !

A bientôt 😉

1 Comment

  1. Bonjour,

    pour supprimer les ombre du ring chart (si besoin)

    import org.jfree

    .chart.plot.CategoryPlot;

    import org.jfree.chart.plot.RingPlot;
    final RingPlot plot = (RingPlot) chart.getPlot();
    plot.setInteriorGap(0.0);
    plot.setShadowPaint(null);

Les commentaires sont fermés.