I have a 3D dataset XYZDataset that I want to plot as a 2D plot, by keeping (x,y) coordinates and by representing the z axis using a spectrum of colors.
Bas
Your updated example creates an XYBlockRenderer, as shown here, and applies a custom PaintScale to the renderer; the scale is also used to create a matching PaintScaleLegend. After using the XYBlockRenderer to create an XYPlot, the original XYBlockRenderer is discarded and replaced with an XYLineAndShapeRenderer, which overrides getItemShape(). The new XYLineAndShapeRenderer knows nothing about the PaintScale.
Instead, override getItemFillPaint() in your XYLineAndShapeRenderer, as shown here. Instead of the List<Color> shown, use the getPaint() method of your custom PaintScale to interpolate the desired Shape color for each data point based on its corresponding z value.
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true) {
@Override
public Paint getItemFillPaint(int row, int col) {
return scale.getPaint(dataset.getZValue(row, col));
}
…
};
In addition,
To get a different spectrum, specify the desired boundary hues in the PaintScale.
private static final float H1 = 0f;
private static final float H2 = (float) (Math.PI / 8);
Use DatasetUtils.findZBounds() to determine the dataset range.
Range r = DatasetUtils.findZBounds(dataset);
Construct and manipulate Swing GUI objects only on the event dispatch thread.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Paint;
import java.awt.Shape;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.Range;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.chart.util.ShapeUtils;
import org.jfree.data.general.DatasetUtils;
/**
* @see https://stackoverflow.com/a/54180207/230513
* @see https://stackoverflow.com/a/37235165/230513
*/
public class Plot2D {
public static JFreeChart createChart(XYZDataset dataset,
String title, String x, String y, String z, Range r) {
NumberAxis xAxis = new NumberAxis(x);
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
NumberAxis yAxis = new NumberAxis(y);
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
SpectrumPaintScale scale = new SpectrumPaintScale(r);
NumberAxis scaleAxis = new NumberAxis(z);
scaleAxis.setAxisLinePaint(Color.white);
scaleAxis.setTickMarkPaint(Color.white);
PaintScaleLegend legend = new PaintScaleLegend(scale, scaleAxis);
legend.setSubdivisionCount(128);
legend.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
legend.setPadding(new RectangleInsets(10, 10, 10, 10));
legend.setStripWidth(20);
legend.setPosition(RectangleEdge.RIGHT);
legend.setBackgroundPaint(Color.WHITE);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true) {
@Override
public Paint getItemFillPaint(int row, int col) {
return scale.getPaint(dataset.getZValue(row, col));
}
@Override
public Shape getItemShape(int row, int col) {
return ShapeUtils.createDiagonalCross(5, 2);
}
};
renderer.setUseFillPaint(true);
renderer.setSeriesShapesFilled(0, true);
renderer.setSeriesShapesVisible(0, true);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(false);
plot.setRangeGridlinePaint(Color.white);
plot.setRenderer((renderer));
JFreeChart chart = new JFreeChart(title, plot);
chart.addSubtitle(legend);
chart.removeLegend();
chart.setBackgroundPaint(Color.white);
return chart;
}
private static class SpectrumPaintScale implements PaintScale {
private static final float H1 = 0f;
private static final float H2 = (float) (Math.PI / 8);
private final Range range;
public SpectrumPaintScale(Range r) {
this.range = r;
}
@Override
public double getLowerBound() {
return range.getLowerBound();
}
@Override
public double getUpperBound() {
return range.getUpperBound();
}
@Override
public Paint getPaint(double value) {
float scaledValue = (float) (value / (getUpperBound() - getLowerBound()));
float scaledH = H1 + scaledValue * (H2 - H1);
return Color.getHSBColor(scaledH, 1f, 1f);
}
}
public static void main(String[] args) {
double xyz[][] = {
{ 1, 2, 3, 4, 5 }, // x
{ 1000, 3000, 9215, 4000, 1000 }, // y
{ 1341, 500, 3125, 1000, 7022 } // z
};
final DefaultXYZDataset dataset = new DefaultXYZDataset();
dataset.addSeries("Series", xyz);
Range r = DatasetUtils.findZBounds(dataset);
EventQueue.invokeLater(() -> {
JFrame f = new JFrame("Color Map");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFreeChart chart = Plot2D.createChart(dataset, "Color Map",
"Order Call", "Time in Ms", "Size in Ko", r);
f.add(new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 300);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}