最佳拟合,相关系数的线的实际公式计算可以在其他地方容易地找到(和声音一有点像家庭作业问题),所以我会省略这些;这听起来像你只是想知道如何添加节点(例如实际的行)到图表。
基本思路是将子类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 ;
}
您是一名救生员。你的代码会在散布图上生成一条线,这是我真正需要的 - 每个其他例子都非常糟糕,因为他们在散点图顶部放置了折线图,并且改变了渐变使其更加可见,这是荒谬的,可笑的效率低下。我已经写了一个方法来计算这些值,并使用你的类来绘制计算出的x和y值上的线。现在一切正常。再次感谢 :) – TheDerp