2016-02-26 118 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