2016-02-26 115 views
1

如何使用JavaFX库在散点图上绘制最佳拟合和产品时刻相关系数的直线?我试过谷歌的几个例子,但没有一个是精确的,甚至与我试图做的类似。我是JavaFX的新手,所以任何帮助表示赞赏。在互联网上有几个例子,但都是完全不同的图书馆,这对我没有任何帮助。JavaFX延伸图表

我有以下代码,其显示散点图(只是一个例子):

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.ScatterChart; 
import javafx.scene.chart.XYChart; 
import javafx.stage.Stage; 

public class Scatter extends Application { 

    @Override 
    public void start(Stage stage) { 
     final NumberAxis xAxis = new NumberAxis(0, 100, 20); 
     final NumberAxis yAxis = new NumberAxis(0, 100, 20);   
     final ScatterChart<Number,Number> sc = new 
      ScatterChart<Number,Number>(xAxis,yAxis); 
     xAxis.setLabel("Average across all exams");     
     yAxis.setLabel("Spring Term test marks"); 
     sc.setTitle("Students marks"); 

     XYChart.Series plots = new XYChart.Series(); 
     plots.getData().add(new XYChart.Data(10,15)); 
     plots.getData().add(new XYChart.Data(15,20)); 
     plots.getData().add(new XYChart.Data(77,77)); 
     plots.getData().add(new XYChart.Data(55,13)); 
     plots.getData().add(new XYChart.Data(44,22)); 
     plots.getData().add(new XYChart.Data(45,43)); 

     sc.getData().add(plots); 
     Scene scene = new Scene(sc, 600, 600); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

回答

2

最佳拟合,相关系数的线的实际公式计算可以在其他地方容易地找到(和声音一有点像家庭作业问题),所以我会省略这些;这听起来像你只是想知道如何添加节点(例如实际的行)到图表。

基本思路是将子类ScatterChart覆盖并覆盖layoutPlotChildren方法。您可以使用CSS通过参考N=1...8的查找颜色CHART_COLOR_N来为每个最佳拟合线着色与相应系列中的数据相同的颜色。

下面是一个例子(我只是用虚值的公式为线,您可以用实际的计算替换):

import java.util.ArrayList; 
import java.util.List; 

import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.ScatterChart; 
import javafx.scene.shape.Line; 

public class ScatterPlotWithBestFitLine extends ScatterChart<Number, Number> { 

    private final NumberAxis xAxis ; 
    private final NumberAxis yAxis ; 

    private final List<Line> lines = new ArrayList<>(); 


    public ScatterPlotWithBestFitLine(NumberAxis xAxis, NumberAxis yAxis) { 
     super(xAxis, yAxis); 
     this.xAxis = xAxis ; 
     this.yAxis = yAxis ; 

     getStylesheets().add("best-fit-line.css"); 
    } 

    @Override 
    protected void layoutPlotChildren() { 

     getPlotChildren().removeAll(lines); 
     lines.clear(); 

     super.layoutPlotChildren(); 

     int index = 0 ; 
     for (Series<Number, Number> series : getData()) { 

      Line line = new Line(); 
      line.setStartX(xAxis.getDisplayPosition(xAxis.getLowerBound())); 
      line.setEndX(xAxis.getDisplayPosition(xAxis.getUpperBound())); 

      int count = (index % 8) + 1 ; 
      line.getStyleClass().add("best-fit-line"); 
      line.getStyleClass().add("best-fit-line-"+count); 

      // TODO compute actual line of best fit... 
      // can iterate through values with: 

      // for (Data<Number, Number> d : series.getData()) { 
      //  double x = d.getXValue().doubleValue(); 
      //  double y = d.getYValue().doubleValue(); 
      // } 

      // just dummy values: 
      double m = 0 ; 
      double b = (getData().size() - index) * yAxis.getLowerBound() + (index + 1) * yAxis.getUpperBound()/2 ; 

      line.setStartY(yAxis.getDisplayPosition(m * xAxis.getLowerBound() + b)); 
      line.setEndY(yAxis.getDisplayPosition(m * xAxis.getUpperBound() + b)); 

      getPlotChildren().add(line); 
      lines.add(line); 

      index++ ; 
     } 
    } 


} 

与最适合的-line.css:

.best-fit-line { 
    -fx-stroke-width: 2 ; 
} 

.best-fit-line-1 { 
    -fx-stroke: CHART_COLOR_1 ; 
} 
.best-fit-line-2 { 
    -fx-stroke: CHART_COLOR_2 ; 
} 
.best-fit-line-3 { 
    -fx-stroke: CHART_COLOR_3 ; 
} 
.best-fit-line-4 { 
    -fx-stroke: CHART_COLOR_4 ; 
} 
.best-fit-line-5 { 
    -fx-stroke: CHART_COLOR_5 ; 
} 
.best-fit-line-6 { 
    -fx-stroke: CHART_COLOR_6 ; 
} 
.best-fit-line-7 { 
    -fx-stroke: CHART_COLOR_7 ; 
} 
.best-fit-line-8 { 
    -fx-stroke: CHART_COLOR_8 ; 
} 

和演示:

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart.Data; 
import javafx.scene.chart.XYChart.Series; 
import javafx.stage.Stage; 

public class ScatterPlotTest extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ScatterPlotWithBestFitLine plot = new ScatterPlotWithBestFitLine(new NumberAxis(), new NumberAxis()); 

     plot.getData().add(createSeries("Data", new double[] { 
       {10,15}, 
       {15,20}, 
       {77,77}, 
       {55,13}, 
       {44,22}, 
       {45,43} 
     })); 


     Scene scene = new Scene(plot, 600, 600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private Series<Number, Number> createSeries(String name, double[][] values) { 
     Series<Number, Number> series = new Series<>(); 
     series.setName("Data"); 
     for (double[] point : values) { 
      series.getData().add(new Data<>(point[0],point[1])); 
     } 
     return series ; 
    }    

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

你真的不指定显示个方面你想要做什么相关系数。您可以创建一个标签(如果情节中有多个系列,则可以创建多个标签),并以相同的方式将它们添加到图表(某处)。或者,您可以将相关系数包含在系列名称中,以便它出现在图例中。如果数据发生变化,使用nameProperty()与数据之间的绑定将确保它保持最新状态:

private Series<Number, Number> createSeries(String name, double[][] values) { 
     Series<Number, Number> series = new Series<>(); 
     ObservableList<Data<Number, Number>> data = FXCollections.observableArrayList(
      d -> new Observable[] {d.XValueProperty(), d.YValueProperty()}); 

     for (double[] point : values) { 
      series.getData().add(new Data<>(point[0],point[1])); 
     } 

     series.nameProperty().bind(Bindings.createStringBinding(() -> 
      String.format("%s (r=%.3f)", name, computeCorrelation(data)), 
      data); 

     return series ; 
    } 

    private double computeCorrelation(List<Data<Number, Number>> data) { 
     //TODO compute correlation from data... 
     return 0 ; 
    } 
+0

您是一名救生员。你的代码会在散布图上生成一条线,这是我真正需要的 - 每个其他例子都非常糟糕,因为他们在散点图顶部放置了折线图,并且改变了渐变使其更加可见,这是荒谬的,可笑的效率低下。我已经写了一个方法来计算这些值,并使用你的类来绘制计算出的x和y值上的线。现在一切正常。再次感谢 :) – TheDerp