How to Remove Line from LineChart? - java

I have been trying to figure out how to remove a plotted line from a LineChart once it has already been made. I have tried just recreating the scene with the series I do want, but that didn't work. I have done some troubleshooting and found that the series is in fact changed and reduced to null, but the line persists even though the series is empty. Then once you change the series to new numbers it tries to connect the points to the old points that aren't supposed to exist. If someone could help me with this it would be very much appreciated.
public class GraphSection {
NumberAxis xAxis;
NumberAxis yAxis;
LineChart<Number, Number> lineChart;
Scene scene;
XYChart.Series series1, series2, series3, series4;
public GraphSection(){
xAxis = new NumberAxis();
yAxis = new NumberAxis();
lineChart = new LineChart<Number,Number>(xAxis,yAxis);
lineChart.setTitle("Test Graph");
lineChart.setCreateSymbols(false);
lineChart.setLegendVisible(false);
series1 = new XYChart.Series();
series2 = new XYChart.Series();
series3 = new XYChart.Series();
series4 = new XYChart.Series();
lineChart.getData().addAll(series1, series2, series3, series4);
scene = new Scene(lineChart,400,300);
}
public Scene getGraph(){
return this.scene;
}
public void addPoints(int n){
if(n == 1){
//Test Points
series1.getData().add(new XYChart.Data(1,50));
series1.getData().add(new XYChart.Data(2,60));
series1.getData().add(new XYChart.Data(3,70));
series1.getData().add(new XYChart.Data(4,80));
series1.getData().add(new XYChart.Data(5,90));
}
else if(n == 2){
//More Test Points
series1.getData().add(new XYChart.Data(1,70));
series1.getData().add(new XYChart.Data(2,80));
series1.getData().add(new XYChart.Data(3,90));
series1.getData().add(new XYChart.Data(4,100));
series1.getData().add(new XYChart.Data(5,110));
}
else if(n == 3){
}
else if(n == 4){
}
}
public void removePoints(int n){
Series s;
LineChart l = this.lineChart;
if(n == 1){
s = this.series1;
s.getData().clear();
l.removeSeriesFromDisplay(s); //This is the method I would guess I need but
//it is "not visible" and thus produces
// an error when I try to compile.
}
else if(n==2){
series2 = this.series2;
}
else if(n==3){
series3 = this.series3;
}
else if(n==4){
series4 = this.series4;
}
}
}
EDIT: So while .remove() will work to get it to remove the line from the graph it also throws the IllegalStateException. This, while ugly, doesn't cause the program to crash, however, then when I add data points back into the series it will not graph the new points. So a potential solution would be to dynamically add a series into the LineChart. If anyone knows how to do this, that might solve my problem.
EDIT: I have changed .addPoints(2); to add points to the series1 and I am including pictures below (Adding after the remove() just gives a blank chart).I am also including the code I am calling the class from.
//Bottom
JFXPanel bottom = new JFXPanel();
final GraphSection gs = new GraphSection();
bottom.setScene(gs.getGraph());
gs.addPoints(1);
//ActionListeners
testButton1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
gs.removePoints(1);
System.out.println(gs.series1.getData()); //Used for debugging
}
});
testButton2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
gs.addPoints(2);
System.out.println(gs.series1.getData());
}
});
Start with .addPoints(1);
This is what happens with just .getData().clear();

Yes, the problem was in fact trying to use a JFXPanel within a Swing JFrame. This meant that illegalStateException was popping up as a result. By altering the code to run on a JavaFX stage this allowed for remove() to work, and then you can easily dynamically add new series with lineChart.getData().add(Series);. You can incorporate swing components with SwingNodes, though my advice would be to recode your GUI into all JavaFX.

Related

Netbeans IDE "stops working" apprently after creating new ActionTimer, ChangeListener

#Override
public void start(Stage stage) {
// The class Random is used to randomize the dice rolls
Random random = new Random();
NumberAxis xAxis = new NumberAxis();
// y-axes represents the average of the rolls. The average is always between [1-6]
NumberAxis yAxis = new NumberAxis(1, 6, 1);
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
// removing elements of the chart, e.g. circles on points
lineChart.setLegendVisible(false);
lineChart.setAnimated(false);
lineChart.setCreateSymbols(false);
// we create a variable representing the data and add it to the chart
XYChart.Series average = new XYChart.Series();
lineChart.getData().add(average);
new AnimationTimer() {
private long previous;
private long sum;
private long count;
#Override
public void handle(long current) {
if (current - previous < 100_000_000L) {
return;
}
previous = current;
// roll the dice
int number = random.nextInt(6) + 1;
// we grow the sum and increment the count
sum += number;
count++;
// we add a new data point to the chart
average.getData().add(new XYChart.Data(count, 1.0 * sum / count));
}
}.start();
Scene scene = new Scene(lineChart, 400, 300);
stage.setScene(scene);
stage.show();
}
I am doing the mooc.fi Java course, right now at part 14, and there was an example code I wanted to try out. This is the problematic part of the code.
When I paste this into the DiceRolling class (that extends Application) above the main method, the IDE loses all its functionalities. What it means is that Ctrl+Space shows no suggestion nowhere in the code, if I select part of the code with mouse I cannot Ctrl+X it out, stops checking if the code has mistakes in it (talking about the red underline), and it just overall stops checking the code. I could narrow the reason down to the new ActionTimer part of the code. The problem occurs only after the first curly bracket is written there.
I have experienced this problem earlier, at that time I was creating a new ChangeListener inside a lambda expression and the first curly bracket caused the problem there too. I have no idea why it happens, or if it has a meaning or it's just a bug.

How to speed up drawing graphs (charts) in Java? (own library)

How to write a java library that would display graphs (charts) with large datasets (100-200 thousand points)? I think that such a large graph does not need to be displayed entirely, I probably only need to display a part of it, for example, a thousand points. But I need to be able to move around the graph and scale it.
It is also necessary that the charts are built in real time. As I understand it, for any action with the chart, the data must be displayed again, that is, thereby updated.
Maybe for speed it will be possible to do parallel execution of some parts of the code for drawing the chart. Because the speed of execution will be the main thing in this library.
I also plan to convert the chart to svg to be inserted into the html page.
Now I just build a graph using JavaFX, and it is very slow to build on a couple of thousand points and JavaFX does not seem to have tools for scaling.
public class FXLineChart {
private List<Long> dataset;
public FXLineChart(List<Long> dataset) {
this.dataset = dataset;
}
public void drawChart(Stage stage) {
stage.setTitle("Chart");
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lineChart =
new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setTitle("Check dataset");
XYChart.Series series = new XYChart.Series();
for (int i = 0; i < dataset.size(); i++) {
series.getData().add(new XYChart.Data(i, dataset.get(i)));
}
lineChart.getData().add(series);
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
}
JFreeChart is slightly better, but the chart slows down at several tens of thousands of points. I did not find information about real time in JFreeChart.
Maybe someone has a code for a similar task or idea? The challenge is that according to the assignment it should be its own library.

JavaFX Chart - space between legends [duplicate]

This question already has an answer here:
Fix spacing between different series in JavaFX line chart
(1 answer)
Closed 3 years ago.
I have this code:
public static void main(String[] args){ launch(args); }
#Override
public void start(Stage primaryStage){
NumberAxis xAxis = new NumberAxis(0, 23, 1);
xAxis.setLabel("XX");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("YY");
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
series1.setName("Loooooooooooooongest");
XYChart.Series<Number, Number> series2 = new XYChart.Series<>();
series2.setName("Short");
XYChart.Series<Number, Number> series3 = new XYChart.Series<>();
series3.setName("Loooooong");
lineChart.getData().addAll(series1, series2, series3);
primaryStage.setScene(new Scene(lineChart));
primaryStage.sizeToScene();
primaryStage.centerOnScreen();
primaryStage.show();
}
It looks like this:
Every legend has allocated space like the longest legend.
How I can remove all that space?
You can probably use a CSS Property. Maybe something like -fx-padding or -fx-margin. Not sure right now.
This could give you a good idea about for using CSS Properties in JavaFX: How to set specific color to JavaFX XYChart.Series?
Also it's a great idea to use the JavaFX-SceneBuilder. You can apply CSS there and directly see what it does.

JavaFX BarChart doesn't display double or float values(only int,long and short)

I generated a BarChart in JavaFx using code(without SceneBuilder) and it fails to display double values on NumberAxis.I tried with int,long and short values and it works fine, but for some reason I cannot configure it to work with real numbers.
Here is my code:
private BarChart<String, Number> createBarChartMedii(Map<Student, Double> studentAndAverageGrades) {
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("Student");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Average");
BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);
barChart.setTitle("Grades Average");
XYChart.Series<String, Number> series = new XYChart.Series<>();
studentAndAverageGrades.forEach((student, average) -> {
series.getData().add(new XYChart.Data<>(student.getNume(),average));
});
barChart.getData().addAll(series);
return barChart;
}
This is the output:
click for image
If I modify the line which adds data into the series(inside the lambda function in foreach) with this one:
series.getData().add(new XYChart.Data<>(student.getNume(),average.intValue()));
it populates the BarChart

Updating JavaFX BarChart data causes memory leak

I've discovered what I believe is a memory leak in JavaFX (1.8u40 GA and 1.8u60 b10 EA) BarChart triggered by replacing all the data values in the series. This is exasperated by our application which does this several times a second.
Using jvisualvm shows an uncontrolled growth in the number of javafx.scene.layout.StackPane instances which eventually results in an OutOfMemoryError. Styled StackPane nodes are used internally by BarChart for the bars.
I've tried a different strategies to update the list. All exhibit the same issue.
// 1
series.getData().clear();
series.getData().addAll(list);
// 2
series.getData().setAll(list);
// 3
series.setData(list)
Interestingly the example in the Oracle BarChart tutorial updates values by adding all the bars/points first, and then mutating them using XYChart.Data.setYValue(). This could work, but is not convenient for us as the number of data points can vary dynamically.
Specific questions
Is there anyway to avoid this issue, other than a extra logic using the setYValue() approach above.
Have I stumbled across an actual memory leak in JavaFX? or just an artefact of my misuse of the API? Surely freeing internal nodes when data is updated is JavaFX responsibility
Example
public class ChartUpdate extends Application {
private int clock;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis(0, 100, 10);
yAxis.setAutoRanging(false);
BarChart<String, Number> graph = new BarChart<>(xAxis, yAxis);
graph.setAnimated(false);
Series<String, Number> series = new Series<>();
graph.getData().add(series);
stage.setScene(new Scene(graph));
stage.show();
Timeline timeLine = new Timeline();
timeLine.getKeyFrames().add(
new KeyFrame(Duration.millis(500),
(e) -> {
ObservableList<Data<String, Number>> list = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
list.add(new Data<>(String.valueOf(i), (clock + i) % 100));
}
series.setData(list);
clock++;
}));
timeLine.setCycleCount(Animation.INDEFINITE);
timeLine.play();
}
}
Update (16th April 2015) Raised https://bugs.openjdk.java.net/browse/JDK-8094805 and posted to OpenJFX mailing list
In summary this was a genuine issue accepted by JavaFX team and fixed by JDK-8094805 in 8u60
See https://bugs.openjdk.java.net/browse/JDK-8094805 for more detail.

Categories

Resources