如何在FastScatterPlot(JFreeChart)中更改磅值或形状?

时间:2014-11-19 13:14:35

标签: java jfreechart

我有大量的2D坐标(即,容易在100k到200k x,y对的数量级),我想将其视为散点图。对于这个目的的应用,有这么多的点是有道理的,我不能/不会因为不同的原因减少数量。要在Java中绘制它,我使用JFreeChart。我已经玩过ChartFactory.createScatterPlot()和50k随机生成的点,虽然这给出了设置外观(点大小/颜色/形状)的最大灵活性,但显示许多点的速度很慢。这意味着,显示需要一些时间,缩放也会延迟/不平滑。然而,一旦只有几个点实际可见,即深度放大,可视化就会很好地响应。

相反,FastScatterPlot()允许轻松绘制500k随机生成的2D点,但外观并不是很好,因为我只设置了目前的颜色(使用,例如,setPaint(Color.BLUE))但是不是形状或大小。尺寸是个问题,因为个别点非常小。

如何更改FastScatterPlot中的磅值或形状?

与此相关,有没有办法让ChartFactory.createScatterPlot()返回的图表更具响应性?

我的数据是固定的,渲染必须主要不一定在运行时更改,因此如果有方法断开任何侦听器或类似的以提高性能,这也是一个选项。

提前致谢。

2 个答案:

答案 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);
               }
           }
       }
   }
}