Search code examples
javafxlinelinechart

LineChart FX - Delete solid line


I have a curious question about the graph LineChart JavaFX.

I have this graph: Grapg dots forming a "jump" on the X axis (as shown by the two red points I scored) and therefore JavaFX draws me the line between these two points. How do I remove that line between each "jump"?

I post the code:

public class ControllerIndividua {

    public static void plotIndividuaFull(String path, Stage stage, String name) {
        final NumberAxis xAxisIntensity = new NumberAxis(); //Dichiarazione asseX
        final NumberAxis yAxisIntensity = new NumberAxis();//Dichiarazione asseY

        DetectionS1.countS1();

        //Dichiarazione del tipo di grafico
        final LineChart<Number, Number> lineChartIntensity = new LineChart<Number, Number>(xAxisIntensity,yAxisIntensity);

        ArrayList<Double> extractedData; //Lista dei valori dello dell' intensità
        ArrayList<Double> extractedTime; //Lista del tempo
        ArrayList<Double> extractedS1; //Lista del tempo
        ArrayList<Double> extractedS1Time; //Lista del tempo

        //Gestione e settaggio del grafico
        lineChartIntensity.getData().clear();

        try {
            //Popolamento delle liste
            extractedTime = IntensityExtractor.pointsTime();
            extractedData = IntensityExtractor.pointsIntensity();
            extractedS1 = DetectionS1.S1pitch();
            extractedS1Time = DetectionS1.pointsS1Time();
            XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
            XYChart.Series<Number, Number> seriesS1 = new XYChart.Series<Number, Number>(); //Creazione seconda serie
            series.setName("Intensità di:\t" + name.toUpperCase());

            for (int j = 0; j < extractedS1.size(); j++) {
                seriesS1.getData().add(new XYChart.Data<Number, Number>(extractedS1Time.get(j), extractedS1.get(j)));
                lineChartIntensity.getStyleClass().add("CSSintensity");
            }

            //Creazione finestra e stampa del grafico
            Scene scene = new Scene(lineChartIntensity, 1000, 600);
            lineChartIntensity.getData().addAll(series,seriesS1);
            scene.getStylesheets().add("application/application.css");
            stage.setScene(scene);
            stage.show();
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }
    }
}

Someone also has a little idea on how I could do?

Thank you all in advance.


Solution

  • This is an old question with an accepted answer but I came across it and was curious. I wanted to know if it was possible to put a gap in a LineChart (at least without having to create a custom chart implementation). It turns out that there is. The solution is kind of hacky and brittle. It involves getting the Path by using XYChart.Series.getNode() and manipulating the list of PathElements. The following code gives an example:

    import javafx.application.Application;
    import javafx.application.Platform;
    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.shape.LineTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(), new NumberAxis());
            chart.getXAxis().setLabel("X");
            chart.getYAxis().setLabel("Y");
            chart.setLegendVisible(false);
            chart.getData().add(new XYChart.Series<>());
    
            for (int x = 0; x <= 10; x++) {
                chart.getData().get(0).getData().add(new XYChart.Data<>(x, Math.pow(x, 2)));
            }
    
            /*
             * Had to wrap the call in a Platform.runLater otherwise the Path was
             * redrawn after the modifications are made.
             */
            primaryStage.setOnShown(we -> Platform.runLater(() -> {
                Path path = (Path) chart.getData().get(0).getNode();
                LineTo lineTo = (LineTo) path.getElements().get(8);
                path.getElements().set(8, new MoveTo(lineTo.getX(), lineTo.getY()));
            }));
    
            primaryStage.setScene(new Scene(new StackPane(chart), 500, 300));
            primaryStage.setTitle("LineChart Gap");
            primaryStage.show();
        }
    
    }
    

    This code results in the following:

    Screenshot of LineChart with gap in the line

    This is possible because the ObservableList of PathElements seems to be a MoveTo followed by a bunch of LineTos. I simply picked a LineTo and replaced it with a MoveTo to the same coordinates. I haven't quite figured out which index of LineTo matches with which XYChart.Data, however, and picked 8 for the example randomly.

    There are a couple of issues with this solution. The first and obvious one is that this relies on the internal implementation of LineChart. The second is where the real brittleness comes from though. Any change to the data, either axes' value ranges, the chart's width or height, or pretty much anything that causes the chart to redraw itself will cause the Path to be recomputed and redrawn. This means if you use this solution you'll have to reapply the modification every time the chart redraws itself.