如何使用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);
}
}
答案 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 ;
}