我有大量的2D坐标(即,容易在100k到200k x,y对的数量级),我想将其视为散点图。对于这个目的的应用,有这么多的点是有道理的,我不能/不会因为不同的原因减少数量。要在Java中绘制它,我使用JFreeChart。我已经玩过ChartFactory.createScatterPlot()
和50k随机生成的点,虽然这给出了设置外观(点大小/颜色/形状)的最大灵活性,但显示许多点的速度很慢。这意味着,显示需要一些时间,缩放也会延迟/不平滑。然而,一旦只有几个点实际可见,即深度放大,可视化就会很好地响应。
相反,FastScatterPlot()
允许轻松绘制500k随机生成的2D点,但外观并不是很好,因为我只设置了目前的颜色(使用,例如,setPaint(Color.BLUE)
)但是不是形状或大小。尺寸是个问题,因为个别点非常小。
如何更改FastScatterPlot
中的磅值或形状?
与此相关,有没有办法让ChartFactory.createScatterPlot()
返回的图表更具响应性?
我的数据是固定的,渲染必须主要不一定在运行时更改,因此如果有方法断开任何侦听器或类似的以提高性能,这也是一个选项。
提前致谢。
答案 0 :(得分:1)
对于速度,您可以尝试FastScatterPlot
方法render()
评论中建议的备用source计算; profile进行比较。对于大小,您可以使用相同的方法更改渲染大小;以下将使每个点的大小翻两番。
g2.fillRect(transX, transY, 2, 2);
答案 1 :(得分:1)
感谢 trashgod 提示,我决定以下列方式扩展FastScatterPlot
。您现在可以在ExtendedFastScatterPlot
的构造函数中指定颜色,大小和形状,它可以很好地处理500k点。与使用fillOval()
所有点相比,使用fillRect()
一半的点似乎会减慢速度,但只要情节总体上可以接受响应,这不是真正的问题。与XYPlot
相比,它现在响应更快。努力一点,物超所值!
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CrosshairState;
import org.jfree.chart.plot.FastScatterPlot;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.ui.RectangleEdge;
public class ExtendedFastScatterPlot extends FastScatterPlot {
/**
*
*/
private static final long serialVersionUID = 1L;
int[] sizes;
Paint[] colors;
int[] shapes;
public ExtendedFastScatterPlot(float[][] data, NumberAxis domainAxis, NumberAxis rangeAxis, int[] sizes, Paint[] colors, int[] shapes) {
super(data,domainAxis,rangeAxis);
this.sizes = sizes;
this.colors = colors;
this.shapes = shapes;
}
@Override
public void render(Graphics2D g2, Rectangle2D dataArea, PlotRenderingInfo info, CrosshairState crosshairState) {
//g2.setPaint(Color.BLUE);
if (this.getData() != null) {
for (int i = 0; i < this.getData()[0].length; i++) {
float x = this.getData()[0][i];
float y = this.getData()[1][i];
int size = this.sizes[i];
int transX = (int) this.getDomainAxis().valueToJava2D(x, dataArea, RectangleEdge.BOTTOM);
int transY = (int) this.getRangeAxis().valueToJava2D(y, dataArea, RectangleEdge.LEFT);
g2.setPaint(this.colors[i]);
if( 1 == this.shapes[i])
{
g2.fillRect(transX, transY, size, size);
}
else
{
g2.fillOval(transX, transY, size, size);
}
}
}
}
}