我有一个3D数据集XYZDataset
,我想通过保留(x,y)坐标并通过使用多种颜色的光谱表示z轴来绘制为2D图。
基于此example,这是我的绘图类以及光谱颜色类。
package com.ingilab.algo.comparator.tools.plot;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Shape;
import org.jfree.chart.ChartFactory;
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.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.util.ShapeUtilities;
public class Plot2D extends ApplicationFrame {
private static final int N = 100;
/**
* A demonstration application showing an XY series containing a null value.
*
* @param title the frame title.
*/
final XYSeries series;
public Plot2D(final String title, String X, String Y, XYSeries series) {
super(title);
this.series = series;
final XYSeriesCollection data = new XYSeriesCollection(series);
final JFreeChart chart = ChartFactory.createScatterPlot(
title,
X,
Y,
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
public Plot2D (final String title, JFreeChart chart) {
super(title);
series = null;
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a sample chart.
*
* @param dataset the dataset.
* @param max
*
* @return A sample chart.
*/
public static JFreeChart createChart(XYZDataset dataset,
String title, String x, String y, String z, double max) {
NumberAxis xAxis = new NumberAxis(x);
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
NumberAxis yAxis = new NumberAxis(y);
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setLowerMargin(0.0);
yAxis.setUpperMargin(0.0);
XYBlockRenderer renderer = new XYBlockRenderer();
SpectrumPaintScale scale = new SpectrumPaintScale(0, max);
//PaintScale scale = new GrayPaintScale(-2.0, 1.0);
renderer.setPaintScale(scale);
//Z axis
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);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(false);
plot.setRangeGridlinePaint(Color.white);
plot.setRenderer(new XYLineAndShapeRenderer(false, true) {
@Override
public Shape getItemShape(int row, int col) {
return ShapeUtilities.createDiagonalCross(5, 2);
}
});
JFreeChart chart = new JFreeChart(title, plot);
chart.addSubtitle(legend);
chart.removeLegend();
chart.setBackgroundPaint(Color.white);
return chart;
}
////////////////////////////////////
// //
// PaintScaleColor //
// //
////////////////////////////////////
private static class SpectrumPaintScale implements PaintScale {
private static final float H1 = 0f;
private static final float H2 = 1f;
private final double lowerBound;
private final double upperBound;
public SpectrumPaintScale(double lowerBound, double upperBound) {
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
@Override
public double getLowerBound() {
return lowerBound;
}
@Override
public double getUpperBound() {
return upperBound;
}
@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)
{
final DefaultXYZDataset timePerSizePerChrno = new
DefaultXYZDataset();
ydb [0][1] = 1;
ydb [1][1] = 78.0;
ydb [2][1] = 1341.0;
ydb [0][2] = 2;
ydb [1][2] = 100.0;
ydb [2][2] = 475.0;
ydb [0][1] = 3;
ydb [1][1] = 9215.0;
ydb [2][1] = 684.0;
ydb [0][1] = 4;
ydb [1][1] = 90.0;
ydb [2][1] = 251.0;
ydb [0][1] = 5;
ydb [1][1] = 75.0;
ydb [2][1] = 7022.0;
double maxZ = 7022;
timePerSizePerChrno.addSeries("Series", ydb);
//////////////////////////////////////////
// PLOTING RESUlTS //
//////////////////////////////////////////
final Plot2D plot3 = new Plot2D("Loading Performance Color Map", Plot2D.createChart (timePerSizePerChrno,
"Loading Performance Color Map", "Order Call", "Time in Ms", "Size in Ko", maxZ));
plot3.pack();
RefineryUtilities.centerFrameOnScreen(plot3);
plot3.setVisible(true);
}
}
我遇到的问题是颜色光谱应用于XYZDataset
系列,而不应用于z值(我的数据集中有一个唯一的序列)。
例如上图。您可以看到所有点都是红色,我希望它们根据它们的值映射到右侧的光谱。我还想删除光谱末尾的红色,因为它可能会造成混淆(光谱以红色开始和结束)。
关于给定系列的任何猜测,只要知道z值在[0,maxZ]之间,就可以使用颜色光谱绘制不同点(x,y)。
答案 0 :(得分:2)
您更新后的示例创建了XYBlockRenderer
,如图here所示,并将自定义PaintScale
应用于渲染器;该比例尺还用于创建匹配的PaintScaleLegend
。在使用XYBlockRenderer
创建XYPlot
之后,原始的XYBlockRenderer
将被丢弃,并被XYLineAndShapeRenderer
取代,而getItemShape()
会覆盖XYLineAndShapeRenderer
。新的PaintScale
对getItemFillPaint()
一无所知。
相反,请覆盖XYLineAndShapeRenderer
中的List<Color>
,如图here所示。代替显示的getPaint()
,可以使用自定义PaintScale
的{{1}}方法,根据每个数据点对应的 z来插入所需的Shape
颜色值。
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true) {
@Override
public Paint getItemFillPaint(int row, int col) {
return scale.getPaint(dataset.getZValue(row, col));
}
…
};
此外,
要获得不同的光谱,请在PaintScale
中指定所需的边界色。
private static final float H1 = 0f;
private static final float H2 = (float) (Math.PI / 8);
使用DatasetUtils.findZBounds()
确定数据集范围。
Range r = DatasetUtils.findZBounds(dataset);
在event dispatch thread上仅 构造和操作Swing GUI对象。
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);
});
}
}