JavaFX扩展图

时间:2016-02-26 22:44:36

标签: java javafx

如何使用JavaFX库在Scatter图上绘制直线最佳拟合线产品矩相关系数?我试过谷歌的一些例子,但没有一个是准确的,甚至类似于我正在尝试做的事情。我是JavaFX的新手,所以感谢任何帮助。互联网上有几个例子,但都是针对完全不同的图书馆,这对我没用。

我有以下代码显示Scatter图(只是一个例子):

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

1 个答案:

答案 0 :(得分:3)

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

基本思想是继承ScatterChart并覆盖layoutPlotChildren方法。通过引用CHART_COLOR_N的查找颜色N=1...8,您可以使用CSS为每条最佳拟合线着色与相应系列中的数据颜色相同。

这是一个例子(我只使用行的公式的虚拟值,你可以用实际的计算代替):

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++ ;
        }
    }


}

with best-fit-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 ;
    }