将自定义行添加到JavaFX LineChart

时间:2018-03-01 15:55:30

标签: javafx javafx-8

我正在使用Java FX折线图来绘制蛋白质结构,但我在这个图表上试图表示“健身债券”时遇到了麻烦(这是两个疏水酸相距1个单位的距离,但不是'顺序连接,如下面的链接所示)。

This is what my chart looks like now.

This is what I am trying to get my chart to look like.

我的健身债券是List<Pair<Point, Point>>

例如,我需要做类似的事情:

for (Pair<Point, Point> pair : pointPairs) {
   //draw red line from pair.getKey() to pair.getValue()
}

健身粘合可以是水平线或垂直线。

如何在每个点对之间的图表上直接获取此点对列表并绘制自定义线?

1 个答案:

答案 0 :(得分:0)

这可以通过每个线段使用单独的Series来实现。备查;如果你能提供一个最小的,可运行的问题例子,那将是最有帮助的。

以下是基于您的要求的示例:

<强> FitnessBnids.java

包裹申请;

import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
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;

public class FitnessBonds extends Application
{

  public static void main( final String[] args )
  {
    Application.launch( args );
  }

  @Override
  public void start( final Stage primaryStage )
  {
    final XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
    series1.setData( FXCollections.observableArrayList(
        createData( 0, 0 ),
        createData( 1, 0 ),

        createData( 1, -1 ),
        createData( 0, -1 ),

        createData( 0, -2 ),
        createData( 1, -2 ),

        createData( 2, -2 ),
        createData( 2, -1 ),

        createData( 3, -1 ),
        createData( 3, 0 ),

        createData( 4, 0 ),
        createData( 4, -1 ),

        createData( 4, -2 ),
        createData( 3, -2 ),

        createData( 3, -3 ),
        createData( 3, -4 ),

        createData( 2, -4 ),
        createData( 1, -4 ),

        createData( 1, -3 ),
        createData( 2, -3 ) ) );

    final List<XYChart.Series<Number, Number>> bonds = bruteForceSearchUnconnectedNodesOneDistance( series1.getData().stream()
        .map( data -> new Point2D( data.getXValue().doubleValue(), data
            .getYValue().doubleValue() ) )
        .collect( toList() ) );


    final ObservableList<XYChart.Series<Number, Number>> series = FXCollections
        .observableArrayList( series1 );

    series.addAll( bonds );

    final NumberAxis xAxis = new NumberAxis();
    xAxis.setLowerBound( -2 );
    xAxis.setUpperBound( 5 );
    xAxis.setAutoRanging( false );
    final NumberAxis yAxis = new NumberAxis();
    yAxis.setLowerBound( -5 );
    yAxis.setUpperBound( 5 );
    yAxis.setAutoRanging( false );

    final LineChart lineChart = new LineChart<>( xAxis, yAxis,
        series );

    lineChart.setCreateSymbols( true );
    lineChart.setAnimated( true );
    lineChart.setAxisSortingPolicy( LineChart.SortingPolicy.NONE );

    lineChart.setPadding( new Insets( 32 ) );
    final Scene scene = new Scene( new StackPane( lineChart ) );

    scene.getStylesheets().add( FitnessBonds.class.getResource( "fit.css" ).toExternalForm() );

    primaryStage.setScene( scene );
    primaryStage.show();
  }

  private List<XYChart.Series<Number, Number>> bruteForceSearchUnconnectedNodesOneDistance( final List<Point2D> data )
  {
    if ( data.size() < 2 )
    {
      return Collections.emptyList();
    }

    final List<XYChart.Series<Number, Number>> list = new ArrayList<>();

    for ( int i = 1; i < data.size(); ++i )
    {
      try
      {
        final Point2D previousNode = data.get( i - 1 );
        final Point2D nextNode = data.get( i + 1 );
        final Point2D node = data.get( i );

        final List<Point2D> allAround = getAllAroundDistanceOne( node );
        allAround.stream()
            .filter( data::contains )
            .filter( point -> !nextNode.equals( point ) )
            .filter( point -> !previousNode.equals( point ) )
            //FIXME this does not eliminate duplicates
            .forEach( point -> list.add( new XYChart.Series<>( FXCollections.observableArrayList(
                createBondData( node.getX(), node.getY() ),
                createBondData( point.getX(), point.getY() ) ) ) ) );
      }
      catch ( final IndexOutOfBoundsException exception )
      {
        continue;
      }
    }

    return list;
  }

  private List<Point2D> getAllAroundDistanceOne( final Point2D node )
  {
    return Stream.of(
        new Point2D( 0, 1 ),
        new Point2D( 1, 0 ),
        new Point2D( 0, -1 ),
        new Point2D( -1, 0 ) )
        .map( node::add )
        .collect( toList() );
  }

  private XYChart.Data<Number, Number> createData( final double x, final double y )
  {
    final XYChart.Data<Number, Number> data = new XYChart.Data<>( x, y );
    data.setNode( new Circle( 4, Color.BLUE ) );
    return data;
  }

  private XYChart.Data<Number, Number> createBondData( final double x, final double y )
  {
    final XYChart.Data<Number, Number> data = new XYChart.Data<>( x, y );
    data.setNode( new Circle( 6, Color.GREEN ) );
    return data;
  }
}

<强> fit.css

.default-color0.chart-series-line { -fx-stroke: black; }

请注意,根据您的说明

  

这是两个疏水酸距离1个单位的距离   彼此之间没有顺序连接,如链接所示   下文)

您的示例中应该有更多链接。我只能假设对什么构成健身债券的约束&#34;更严格。但在我的例子中,你会看到更多链接。