Agregar una línea en un gráfico JavaFX

Tengo problemas para agregar una línea en una posición definida en JavaFX. La línea tiene que ser una línea constante como se muestra aquí: ¿Cómo agregar un marcador de valor al gráfico JavaFX?

Mi problema es que mi definición de diseño es un poco más complicada. Echar un vistazo:

gráfico

La parte importante es la de arriba. Quiero tener la línea en la línea y = 60. La parte izquierda con RadioBoxes es un VBox. La parte con el Diagtwig (Scatter-) es un StackPane (porque quiero que ocupe el rest del ancho). Dentro de este StackPane está el gráfico y un grupo. El único hijo del Grupo es la línea.

Creo que el problema es que el StackPane centra al Grupo con la línea sobre el gráfico. Pero no puedo obtener la combinación de diseños que 1. extiende la tabla 2. establece la línea por encima de la tabla 3. no centra la línea

Intenté muchas combinaciones, pero no puedo conseguirlo como quiero. ¡¿Alguien tiene una idea?!

Desafortunadamente, los ValueMarkers no son compatibles con XYCharts (ese es probablemente el lugar en la jerarquía donde debería hacerse) (Mis-) el uso de datos con valor constante es un truco que podría (o no) ser aceptable / posible en algunos contextos.

Una salida más limpia es un gráfico personalizado que admite dichos marcadores. Fi un ScatterChart personalizado como:

public class ScatterXChart extends ScatterChart { // data defining horizontal markers, xValues are ignored private ObservableList> horizontalMarkers; public ScatterXChart(Axis xAxis, Axis 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's 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 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 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 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()); } } } 

Un fragmento de prueba del gráfico (fi insertar en el ejemplo en línea en el tutorial de Oracle):

 // instantiate chart NumberAxis xAxis = new NumberAxis(0, 10, 1); NumberAxis yAxis = new NumberAxis(-100, 500, 100); ScatterXChart sc = new ScatterXChart<>(xAxis,yAxis); // .. fill with some data ... // ui to add/change/remove a value marker Data 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)); 

Apéndice:

Si bien no recomendaría el enfoque en la pregunta relacionada (agregando la línea de marcador al padre del gráfico y gestionando su posición / longitud externamente), es posible usarlo en contenedores de tamaño variable. Las cosas cruciales para hacer que funcione:

  • escuchar los cambios de tamaño / ubicación del gráfico y actualizar la línea de manera apropiada
  • establecer la propiedad administrada del marcador en falso

en el código (updateShift es la parte en el original que calcula 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); 

¿Por qué no agregas esa línea a tu gráfico? Tengo gráficos en los que se muestran los percentiles 100, 99, 95 y 50, y la forma en que lo resuelvo es agregar una línea con el valor y correcto para cada percentil.

Para hacer esto, solo agrega una línea con dos puntos, uno a y = 60 x = 70 (el valor del eje x más a la izquierda) y el otro a y = 60 y x = 120 (el eje x a la derecha) valor).

La ventaja de esto es que no tiene que alinear la línea horizontal usted mismo manualmente, lo malo es que esta línea horizontal también será parte de la leyenda. Sin embargo, ya que no tienes una leyenda que debería estar bien.

Si decide agregar una leyenda, asegúrese de nombrar la línea horizontal de manera apropiada, l