I am drawing a kind of heatmap using XYZ dataset and XY block renderer. The block's color is a function of the Z value and color is assigned using grayscale. i.e. the block with 0 Z value is assigned white color and one with maximum is assigned black color. My grayscale goes from 0 to 100 (or more lets say). If the scale is this big, the blocks with count as 0 and 10 will have very little difference in color values. To understand, lets say the whole grid is divided in blocks. One block hasZ value of 100, one has 2 and all others are 0. Then, this block with 2 as Z value is not much visible because of very light shade.
I want to give outline to blocks of some color so that they are distinguishable. I tried with setBaseItemOutline() etc functions but none does this.
Any help on this?
Edit: Below
One of my classes is this:
public class BlockRenderer extends ApplicationFrame {
/**
* Constructs the demo application.
*
* @param title the frame title.
*/
public BlockRenderer(String title) {
super(title);
JPanel chartPanel = createDemoPanel();
//chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a chart for the specified dataset.
*
* @param dataset the dataset.
*
* @return A chart instance.
*/
private static JFreeChart createChart(XYZDataset dataset) {
NumberAxis xAxis = new NumberAxis("X");
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
NumberAxis yAxis = new NumberAxis("Y");
yAxis.setAutoRangeIncludesZero(false);
yAxis.setInverted(true);
yAxis.setLowerMargin(0.0);
yAxis.setUpperMargin(0.0);
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
XYBlockRenderer renderer = new XYBlockRenderer();
CustomGrayPaintScale paintScale = new CustomGrayPaintScale(0,1000);
renderer.setPaintScale(paintScale);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setAxisOffset(new RectangleInsets(5, 5, 5, 5));
JFreeChart chart = new JFreeChart("XYBlockChartDemo3", plot);
chart.removeLegend();
chart.setBackgroundPaint(Color.white);
SymbolAxis scaleAxis = new SymbolAxis(null, new String[] {"", "OK",
"Uncertain", "Bad"});
scaleAxis.setRange(0.5, 3.5);
scaleAxis.setPlot(new PiePlot());
scaleAxis.setGridBandsVisible(false);
PaintScaleLegend psl = new PaintScaleLegend(paintScale, scaleAxis);
psl.setAxisOffset(5.0);
psl.setPosition(RectangleEdge.BOTTOM);
psl.setMargin(new RectangleInsets(5, 5, 5, 5));
chart.addSubtitle(psl);
renderer.setBaseToolTipGenerator(new XYToolTipGenerator() {
@Override
public String generateToolTip(XYDataset dataset, int arg1, int arg2) {
// TODO Auto-generated method stub
XYZDataset xyzDataset = (XYZDataset)dataset;
return String.valueOf(xyzDataset.getZValue(arg1, arg2));
}
});
return chart;
}
/**
* Utility method called by createDataset().
*
* @param data the data array.
* @param c the column.
* @param r the row.
* @param value the value.
*/
private static void setValue(double[][] data,
int c, int r, double value) {
data[0][(r) * 10 + c] = c;
data[1][(r) * 10 + c] = r;
data[2][(r) * 10 + c] = value;
}
/**
* Creates a sample dataset.
*/
private static XYZDataset createDataset() {
double[] xvalues = new double[10*10];
double[] yvalues = new double[10*10];
double[] zvalues = new double[10*10];
double[][] data = new double[][] {xvalues, yvalues, zvalues};
// set the default z-value to zero throughout the data array.
int count [][] = new int[10][10];
for ( int i=0; i<10; i++ ) {
for ( int j=0; j<10; j++ ) {
count[i][j] = i*j;
if ( i==0 && j== 5 )
count[i][j] = 3;
}
}
for ( int i=0; i<10; i++ ) {
for ( int j=0; j<10; j++ ) {
setValue(data,j,i,count[i][j]);
}
}
DefaultXYZDataset dataset = new DefaultXYZDataset();
dataset.addSeries("Series 1", data);
System.out.println(dataset.getZValue(0, 1));
return dataset;
}
/**
* Creates a panel for the demo.
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
return new ChartPanel(createChart(createDataset()));
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
BlockRenderer demo = new BlockRenderer("Block Chart Demo 3");
//demo.pack();
demo.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH);
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
I have made CustomGrayPaintScale class to get white color for 0 Z values by over riding its getPaint()
. If above class is run, we'll notice that the blocks are not much distinguishable. There is cell in the top row with value as 3 and all others in that row are 0. Because of my large range, its color value is not much different from its adjacent. So, I wanted something which can draw outline to these blocks. Also, I want to assign lets say blue color to some block items and others should have the paintscale on the basis of Z value only (Better if paint scale is designed which assigns different intensity levels of any color ex green to all the items, not the spectrum paint scale which gives all the different colors to the block).
How can I achieve this?
XYBlockRenderer
ignores the outline properties inherited from the parent, AbstractRenderer
. The drawItem()
method simply sets the paint returned from the PaintScale
, using the same color for both fill()
and draw()
. Some possible approaches would include these:
Override drawItem()
and set a different paint after fill()
but before draw()
, perhaps using a brighter()
or darker()
color.
Use a PaintScale
other than GrayPaintScale
, such as LookupPaintScale
or your own implementation. You can specify more distinctive colors at the problem end, perhaps using Color.getHSBColor()
to vary the hue, saturation and/or brightness.
PaintScale
interface.XYLineAndShapeRenderer
.GanttRenderer
.