I am using JavaFX Linechart in an application. I would like to read X and Y axis of the graph from the display. I mean from the graph. How can I do that? I would like to save the values in an ArrayList/ Array.
Thanks in advance.
I am using JavaFX Linechart in an application. I would like to read X and Y axis of the graph from the display. I mean from the graph. How can I do that? I would like to save the values in an ArrayList/ Array.
Thanks in advance.
Since I believe your question could be asking for either the visual coordinates of your data or the real data used to plot the chart I'm going to provide answers for both.
A LineChart
extends from XYChart
which has a data property. This property contains an ObservableList
of XYChart.Series
. Each XYChart.Series
also has its own data property. This property contains an ObservableList
of XYChart.Data
. Each XYChart.Data
has a property for its X value and a property for its Y value. Access these properties to get the X and Y values used to plot the graph.
Since the chart already contains the data you're looking for in a collection there may be no need to add it to a separate ArrayList
or array.
A XYChart
(which again LineChart
extends from) has a X axis and a Y axis. These are of the type Axis
which provides the following method: getDisplayPosition(Object)
. This method takes as an argument the real data that was plotted on the axis. For example, if you plotted the point (4, 16) you'd get the display positions by:
chart.getXAxis().getDisplayPosition(4);
chart.getYAxis().getDisplayPosition(16);
When using a LineChart
(and most likely other charts but I've only tested it with a LineChart
) these coordinates are not relative to the LineChart
. Instead they are relative to a child Region
that has a style-class of chart-plot-background
(at least in my testing). Here is the code I used to test getting the visual coordinates. It creates a LineChart
with an exponential function from [0-10] and adds Circle
s to a Group
stacked on top of the LineChart
in the same positions as the plotted data.
Note: I used the var
keyword a lot which was added to Java 10. You'll either need Java 10+ to run this or you'll need to replace the var
keywords with the explicit type.
import javafx.animation.Animation;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
var chart = createChart();
var group = new Group();
group.setManaged(false);
primaryStage.setOnShown(we -> addFadingCircles(group, chart));
var root = new StackPane(chart, group);
var scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Workshop");
primaryStage.setResizable(false);
primaryStage.show();
}
private LineChart<Number, Number> createChart() {
var xAxis = new NumberAxis();
xAxis.setLabel("X");
var yAxis = new NumberAxis();
yAxis.setLabel("Y");
var chart = new LineChart<>(xAxis, yAxis);
var series = new XYChart.Series<Number, Number>();
for (int x = 0; x <= 10; x++) {
series.getData().add(new XYChart.Data<>(x, Math.pow(x, 2)));
}
chart.getData().add(series);
return chart;
}
/*
* This method assumes that "group" is stacked on top of "chart" and takes up the
* same area in the scene-graph.
*/
private void addFadingCircles(Group group, LineChart<Number, Number> chart) {
var animation = new ParallelTransition();
animation.setAutoReverse(true);
animation.setCycleCount(Animation.INDEFINITE);
var plotRegion = chart.lookup(".chart-plot-background");
for (var series : chart.getData()) {
for (var data : series.getData()) {
var xPos = chart.getXAxis().getDisplayPosition(data.getXValue());
var yPos = chart.getYAxis().getDisplayPosition(data.getYValue());
var scenePoint = plotRegion.localToScene(xPos, yPos);
var groupPoint = group.sceneToLocal(scenePoint);
var circle = new Circle(groupPoint.getX(), groupPoint.getY(), 10);
circle.setFill(Color.DEEPSKYBLUE);
var fadeTrans = new FadeTransition(Duration.millis(500), circle);
fadeTrans.setFromValue(0.0);
fadeTrans.setToValue(0.8);
animation.getChildren().add(fadeTrans);
group.getChildren().add(circle);
}
}
animation.play();
}
}
Running this code results in:
If your goal is to add things to the Node
used to indicate plotted data it may be better to manipulate the node property of the XYChart.Data
, however.