Adding a String in a JavaFX Chart

I am having problems adding a line at a specific position in JavaFX. The string should be a constant string, as shown here: How to add a value marker to a JavaFX chart?

My problem is that my layout definition is a bit more complicated. Take a look:

chart

The important part is the one on top. I want to have a line on the y = 60 line. The left side with RadioBoxes is a VBox. The (Scatter-) Chart part is StackPane (because I want it to fill the rest of the width). Inside this StackPane there is a chart and a group. The only child of the group is a string.

I think the problem is that the StackPane centers the group with the line above the chart. But I can’t get a combination of layouts that 1. stretches the chart 2. sets a line above the chart 3. does not center the line

I tried many combinations, but I just can't get it the way I want. Does anyone have an idea ?!

+5
source share
2 answers

Unfortunately, ValueMarkers are not supported in XYCharts (which, probably, a place in the hierarchy should have been made) (Mis-), using data with a constant value, this is a hack that may (or may not) be acceptable / possible in some contexts.

A cleaner output is a custom chart that supports such markers. FI custom ScatterChart, for example:

public class ScatterXChart<X, Y> extends ScatterChart<X, Y> { // data defining horizontal markers, xValues are ignored private ObservableList<Data<X, Y>> horizontalMarkers; public ScatterXChart(Axis<X> xAxis, Axis<Y> yAxis) { super(xAxis, yAxis); // a list that notifies on change of the yValue property horizontalMarkers = FXCollections.observableArrayList(d -> new Observable[] {d.YValueProperty()}); // listen to list changes and re-plot horizontalMarkers.addListener((InvalidationListener)observable -> layoutPlotChildren()); } /** * Add horizontal value marker. The marker Y value is used to plot a * horizontal line across the plot area, its X value is ignored. * * @param marker must not be null. */ public void addHorizontalValueMarker(Data<X, Y> marker) { Objects.requireNonNull(marker, "the marker must not be null"); if (horizontalMarkers.contains(marker)) return; Line line = new Line(); marker.setNode(line ); getPlotChildren().add(line); horizontalMarkers.add(marker); } /** * Remove horizontal value marker. * * @param horizontalMarker must not be null */ public void removeHorizontalValueMarker(Data<X, Y> marker) { Objects.requireNonNull(marker, "the marker must not be null"); if (marker.getNode() != null) { getPlotChildren().remove(marker.getNode()); marker.setNode(null); } horizontalMarkers.remove(marker); } /** * Overridden to layout the value markers. */ @Override protected void layoutPlotChildren() { super.layoutPlotChildren(); for (Data<X, Y> horizontalMarker : horizontalMarkers) { double lower = ((ValueAxis) getXAxis()).getLowerBound(); X lowerX = getXAxis().toRealValue(lower); double upper = ((ValueAxis) getXAxis()).getUpperBound(); X upperX = getXAxis().toRealValue(upper); Line line = (Line) horizontalMarker.getNode(); line.setStartX(getXAxis().getDisplayPosition(lowerX)); line.setEndX(getXAxis().getDisplayPosition(upperX)); line.setStartY(getYAxis().getDisplayPosition(horizontalMarker.getYValue())); line.setEndY(line.getStartY()); } } } 

A fragment of testing a chart (fi insert into an online example in the oracle textbook):

 // instantiate chart NumberAxis xAxis = new NumberAxis(0, 10, 1); NumberAxis yAxis = new NumberAxis(-100, 500, 100); ScatterXChart<Number,Number> sc = new ScatterXChart<>(xAxis,yAxis); // .. fill with some data ... // ui to add/change/remove a value marker Data<Number, Number> horizontalMarker = new Data<>(0, 110); Button add = new Button("Add Marker"); add.setOnAction(e -> sc.addHorizontalValueMarker(horizontalMarker)); Slider move = new Slider(yAxis.getLowerBound(), yAxis.getUpperBound(), 0); move.setShowTickLabels(true); move.valueProperty().bindBidirectional(horizontalMarker.YValueProperty()); Button remove = new Button("Remove Marker"); remove.setOnAction(e -> sc.removeHorizontalValueMarker(horizontalMarker)); 

Application:

Although I would not recommend an approach in a related question (adding a marker line to the parent of the chart and controlling its position / length from the outside), you can use it in resizable containers. The most important things to make it work:

  • listen to changes in size / location of the chart and update the line accordingly.
  • set marker driven property to false

in code (updateShift is the part of the original that calculates yShift / lineX):

 Pane pane = new StackPane(chart); chart.widthProperty().addListener(o -> updateShift(chart)); chart.heightProperty().addListener(o -> updateShift(chart)); valueMarker.setManaged(false); pane.getChildren().add(valueMarker); 
+6
source

Why don't you add this line to your chart? I have charts where I show the 100, 99, 95, and 50 percentiles, and the way I solve this is to add a row with the correct y value for each percentile.

To do this, simply add a line with two dots, one at y = 60 x = 70 (the leftmost value of the x axis) and the other at y = 60 and x = 120 (the rightmost value of the x axis).

The surface of this is that you do not need to manually align the horizontal line yourself, but the disadvantage is that this horizontal line will also be part of the legend. However, seeing that you have no legend, everything should be in order.

If you decide to add a legend, be sure to indicate the horizontal line, l

0
source

All Articles