感谢您阅读我的问题。
我目前正在使用JavaFX-8、SceneBuilder和Eclipse。
我想做一个有四个象限的散点图,有两个固定的数轴(数据位置不相关,我只需要显示每个象限上的点......只关心点在哪个象限)。每个象限都必须有一个特定颜色的背景。
我发现了这个问题,所以我尝试扩展散点图,目的是覆盖layoutPlotChildren()方法。我尝试了一个最低限度的实现,看看它是否能与我的FXML一起运行(我确实将新组件导入了FXML)。这是我的最低实现:
public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {
public ScatterQuadrantChart(Axis<X> xAxis, Axis<Y> yAxis) {
super(xAxis, yAxis);
} }
然后,我得到了NotSuchmetodError初始化错误。我发现了一个类似的错误,但来自此处扩展LineChart的人,但我不太确定我需要在自己的类上做什么。
我尝试添加一个无参数构造函数,但我需要调用super和cant,因为我也不能调用“getXAxis()”方法。我该怎么办?
另外,剩下的另一个问题是,一旦我解决了这个问题,layoutPlotChildren()方法应该做什么?
谢谢你的阅读。
您看到的问题之所以出现,是因为FXMLLoader
实例化类的默认机制是调用无参数构造函数。您的ScatterQuadrantChart
没有参数构造函数,因此NoSuchMethodError
。
在Java8之前,解决这个问题的唯一方法是为类创建一个构建器类,就像在您链接的帖子中一样。JavaFX 8引入(但未能记录)一种机制来指定构造函数参数的值,该参数将由FXMLLoader
使用@NamedArg
注释识别。
因此,在Java 8中,您可以修改您的散象限图
:
public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {
public ScatterQuadrantChart(@NamedArg("xAxis")Axis<X> xAxis,
@NamedArg("yAxis)Axis<Y> yAxis) {
super(xAxis, yAxis);
}
}
然后你的FXML看起来像
<ScatterQuadrantChart>
<xAxis>
<NumberAxis ... />
</xAxis>
<yAxis>
<NumberAxis ... />
</yAxis>
</ScatterQuadrantChart>
我不知道SceneBuilder是否会或如何与此交互,但FXML会工作。
至于实现,您需要向绘图中添加一些节点来表示象限。我可能只会使用普通区域。在构造函数中创建它们并调用getPlotChildren()。添加(…)
添加它们。然后在
layoutPlotChildren()
方法中,首先调用超类方法(它将布置散点图节点),然后调整象限大小并重新定位。您可以使用getXAxis()。getDisplayPosition(…)
根据实际除法器值计算出位置。
在现实生活中,你应该向象限中添加样式类,这样你就可以在外部用css等样式对它们进行样式化,但是一个非常基本的实现可能看起来像
import javafx.beans.NamedArg;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.chart.Axis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.layout.Region;
public class ScatterQuadrantChart<X,Y> extends ScatterChart<X,Y> {
private final Property<X> xQuadrantDivider = new SimpleObjectProperty<>();
private final Property<Y> yQuadrantDivider = new SimpleObjectProperty<>();
private final Region nwQuad ;
private final Region neQuad ;
private final Region swQuad ;
private final Region seQuad ;
public ScatterQuadrantChart(@NamedArg("xAxis") Axis<X> xAxis,
@NamedArg("yAxis") Axis<Y> yAxis) {
super(xAxis, yAxis);
nwQuad = new Region();
neQuad = new Region();
swQuad = new Region();
seQuad = new Region();
nwQuad.setStyle("-fx-background-color: lightsalmon ;");
neQuad.setStyle("-fx-background-color: antiquewhite ;");
swQuad.setStyle("-fx-background-color: aqua ;");
seQuad.setStyle("-fx-background-color: lightskyblue ;");
getPlotChildren().addAll(nwQuad, neQuad, swQuad, seQuad);
ChangeListener<Object> quadListener = (obs, oldValue, newValue) -> layoutPlotChildren();
xQuadrantDivider.addListener(quadListener);
yQuadrantDivider.addListener(quadListener);
}
@Override
public void layoutPlotChildren() {
super.layoutPlotChildren();
X x = xQuadrantDivider.getValue();
Y y = yQuadrantDivider.getValue();
if (x != null && y != null) {
Axis<X> xAxis = getXAxis();
Axis<Y> yAxis = getYAxis();
double xPixels = xAxis.getDisplayPosition(x);
double yPixels = yAxis.getDisplayPosition(y);
double totalWidth = xAxis.getWidth();
double totalHeight = yAxis.getHeight();
nwQuad.resizeRelocate(0, 0, xPixels, yPixels);
swQuad.resizeRelocate(0, yPixels, xPixels, totalHeight - yPixels);
neQuad.resizeRelocate(xPixels, 0, totalWidth - xPixels, yPixels);
seQuad.resizeRelocate(xPixels, yPixels, totalWidth - xPixels, totalHeight - yPixels);
}
}
public final Property<X> xQuadrantDividerProperty() {
return this.xQuadrantDivider;
}
public final X getXQuadrantDivider() {
return this.xQuadrantDividerProperty().getValue();
}
public final void setXQuadrantDivider(final X xQuadrantDivider) {
this.xQuadrantDividerProperty().setValue(xQuadrantDivider);
}
public final Property<Y> yQuadrantDividerProperty() {
return this.yQuadrantDivider;
}
public final Y getYQuadrantDivider() {
return this.yQuadrantDividerProperty().getValue();
}
public final void setYQuadrantDivider(final Y yQuadrantDivider) {
this.yQuadrantDividerProperty().setValue(yQuadrantDivider);
}
}
测试代码:
import java.util.Random;
import java.util.stream.Stream;
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.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ScatterQuadrantChartTest extends Application {
@Override
public void start(Stage primaryStage) {
final Random rng = new Random();
ScatterQuadrantChart<Number, Number> chart = new ScatterQuadrantChart<>(new NumberAxis(), new NumberAxis());
Series<Number, Number> series = new Series<>();
for (int i=0; i<20; i++) {
series.getData().add(new Data<>(rng.nextDouble() * 100, rng.nextDouble() * 100));
}
chart.getData().add(series);
chart.setXQuadrantDivider(50);
chart.setYQuadrantDivider(50);
BorderPane root = new BorderPane(chart);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对
散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对齐方式。 数据 颜色 设置数据系列的
散点图沿 X 和 Y 轴放置的各个数据点来绘制数据。 图表属性 选择图表类型后,可以更改其属性来自定义图表: 选项 描述 常规 背景颜色 设置图表区域的背景颜色。 不透明度 设置背景颜色的不透明度。 显示边框 显示图表外部边框。 边界颜色 设置图表外部边框的颜色。 显示标题 显示图表的主要标题。 标题 指定图表的标题。 标题字体 设置标题的字体样式。 位置 设置标题的位置。 对齐 设置标题的水平对
后果 我有这个数据框 代码是 但它不渲染。为什么啊?
这是一个非常特殊的绘图请求,但我有数据要以非常特殊的方式查看。情况如下: 1) 我拥有的数据分为25个数据箱,每个数据箱包含不同数量的数据点。仓位值越大,粗略地说,仓位中的数据点数量就越少(这只是数据处理的结果)。 2)我可以访问bin值。 我可以在matplotlib中轻松生成“errorbar”类型的绘图(y轴从半径缩放到以下度数): 但是,对于我想研究的内容来说,这并不是特别有见地。我真的很
散点图用于在水平轴和垂直轴上绘制数据点,它表示了因变量随自变量变化的趋势。通俗地讲,它反映的是一个变量受另一个变量的影响程度。 散点图将序列显示为一组点,其中每个散点值都由该点在图表中的坐标位置表示。对于不同类别的点,则由图表中不同形状或颜色的标记符表示。同时,您也可以设置标记符的颜色或大小。 下面示例,绘制了学生考试成绩的散点图,其中蓝色代表男孩成绩,红色表示女孩的成绩。 代码执行后,输出结果如