【问题标题】:JavaFX charts not layering correctlyJavaFX 图表未正确分层
【发布时间】:2020-03-25 03:05:08
【问题描述】:

我正在构建一个需要为其生成图表的 Java 桌面应用程序。其中之一需要是一个条形图,上面有一个折线图。

我使用 StackPane 来叠加这两个图表并分别填充它们,但正如您在图片中看到的那样,它们没有正确叠加,折线图从 y 轴的左侧开始。此外,当左侧 y 轴没有标签 (???) 时,这会发生变化,即线条正确显示但条形图混乱。

我还为每个图表设置了两个不同的 Y 轴,但没有显示正确的 Y 轴。

我怎样才能使所有内容都很好地叠加并且每个图表都正确定位?我做错了什么?

输出:

public class Graphs implements Initializable {

@FXML StackPane stackPane;
@FXML BarChart barChart;
@FXML CategoryAxis xAxis;
@FXML NumberAxis yAxis;
@FXML NumberAxis yAxisRight;
@FXML LineChart lineChartEffective;

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {


    xAxis.setCategories(FXCollections.<String>observableArrayList("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"));


    yAxis.setLowerBound(0);
    yAxis.setUpperBound(100);
    yAxis.setTickUnit(10);


     yAxisRight.setSide(Side.RIGHT);
     yAxisRight.setLowerBound(0);
     yAxisRight.setUpperBound(50);
     yAxisRight.setTickUnit(1);


     barChart.setLegendVisible(false);
     barChart.setAnimated(false);

     barChart.setLegendVisible(false);
     barChart.setAnimated(false);

     barChart.setAlternativeRowFillVisible(false);
     barChart.setAlternativeColumnFillVisible(false);
     barChart.setHorizontalGridLinesVisible(false);
     barChart.setVerticalGridLinesVisible(false);
     barChart.getXAxis().setVisible(true);
     barChart.getYAxis().setVisible(true);


    barChart.getData().add(getAverageLoadPerFTE());

    xAxis.setLabel("Month");
    yAxis.setLabel("Level (%)");
    yAxisRight.setLabel("Level (u)");


    lineChartEffective.setLegendVisible(false);
    lineChartEffective.setAnimated(false);
    lineChartEffective.setCreateSymbols(true);
    lineChartEffective.setAlternativeRowFillVisible(false);
    lineChartEffective.setAlternativeColumnFillVisible(false);
    lineChartEffective.setHorizontalGridLinesVisible(false);
    lineChartEffective.setVerticalGridLinesVisible(false);
    lineChartEffective.getXAxis().setVisible(false);
    lineChartEffective.getYAxis().setVisible(true);
    lineChartEffective.getStylesheets().addAll(getClass().getResource("chartEffective.css").toExternalForm());
    lineChartEffective.getData().add( getEffectiveCustomerSupport());



}

private XYChart.Series<String,Number> getAverageLoadPerFTE() {
    XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
    series.getData().add(new XYChart.Data<String,Number>("Jan", 58 ));
    series.getData().add(new XYChart.Data<String,Number>("Feb", 54 ));
    series.getData().add(new XYChart.Data<String,Number>("Mar", 47 ));
    series.getData().add(new XYChart.Data<String,Number>("Apr", 34 ));
    series.getData().add(new XYChart.Data<String,Number>("May", 33 ));
    series.getData().add(new XYChart.Data<String,Number>("Jun", 32 ));
    series.getData().add(new XYChart.Data<String,Number>("Jul", 30 ));
    series.getData().add(new XYChart.Data<String,Number>("Aug", 36 ));
    series.getData().add(new XYChart.Data<String,Number>("Sep", 29 ));
    series.getData().add(new XYChart.Data<String,Number>("Oct", 33 ));
    series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
    series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));



    series.setName("Average load per FTE");

    return series;
}

private XYChart.Series<String,Number> getEffectiveCustomerSupport() {
        XYChart.Series<String, Number> series = new XYChart.Series<String, Number>();
        series.getData().add(new XYChart.Data<String,Number>("Jan", 2.9 ));
        series.getData().add(new XYChart.Data<String,Number>("Feb", 2.7 ));
        series.getData().add(new XYChart.Data<String,Number>("Mar", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Apr", 3.4 ));
        series.getData().add(new XYChart.Data<String,Number>("May", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Jun", 3.2 ));
        series.getData().add(new XYChart.Data<String,Number>("Jul", 3.3 ));
        series.getData().add(new XYChart.Data<String,Number>("Aug", 4 ));
        series.getData().add(new XYChart.Data<String,Number>("Sep", 3.8 ));
        series.getData().add(new XYChart.Data<String,Number>("Oct", 4.1 ));
        series.getData().add(new XYChart.Data<String,Number>("Nov", 0 ));
        series.getData().add(new XYChart.Data<String,Number>("Dec", 0 ));


        series.setName("Effective customer support");

        return series;
    }


}

Graphs.fxml:

 <?xml version="1.0" encoding="UTF-8"?>

    <?import javafx.scene.layout.*?>

    <?import javafx.scene.chart.LineChart?>
    <?import javafx.scene.chart.CategoryAxis?>
    <?import javafx.scene.chart.NumberAxis?>
    <?import javafx.scene.chart.BarChart?>
    <AnchorPane prefHeight="731.0" prefWidth="878.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Graphs">
       <children>

          <StackPane fx:id="stackPane" layoutX="26.0" layoutY="32.0" prefHeight="523.0" prefWidth="708.0">
             <children>
                <BarChart fx:id="barChart" >
                  <xAxis>
                    <CategoryAxis side="BOTTOM" />
                  </xAxis>
                  <yAxis>
                    <NumberAxis fx:id = "yAxis" side="LEFT" />
                  </yAxis>
                </BarChart>

                 <LineChart fx:id="lineChartEffective"  stylesheets="@chartEffective.css">
                     <xAxis>
                         <CategoryAxis fx:id = "xAxis" side="BOTTOM" />
                     </xAxis>
                     <yAxis>
                         <NumberAxis fx:id="yAxisRight" side="RIGHT"/>
                     </yAxis>
                 </LineChart>

             </children>
          </StackPane>

       </children>
    </AnchorPane>

chartsEffective.css:

      .chart-plot-background {
        -fx-background-color: transparent;
        }
        .default-color0.chart-series-line {
        -fx-stroke: #4b0082;
        }
        .default-color0.chart-line-symbol {
            -fx-background-color: #4b0082, white;
        }

【问题讨论】:

  • hmm ...想知道为什么您希望不同的图表按其绘图内容(即实际包含条形/线条的内部区域)对齐?
  • @kleopatra 因为两个图表的 x 轴相同(一年中的月份)
  • 你不能在图表之间共享轴' - 它们只是插入各自父节点的节点。还要注意 StackPane 的布局约束:它会尝试将所有子级调整为相同大小,如果不可能,则使用默认对齐方式(即居中)对它们进行布局。除了将 y 轴放在不同的侧面之外,还可以不按照您的预期布局它们。
  • 有关自定义布局的想法,请参阅stackoverflow.com/q/49139565/203657

标签: java javafx charts bar-chart linechart


【解决方案1】:

绘图区域对齐

您可以使用HBox 和Pane 填充符来抵消图表之间的宽度差异。这也可以使用translateX 或StackPane 对齐选项来完成,但是当您动态最小化/最大化/调整窗口大小时,这些解决方案可能会出现故障。

private static <X, Y> HBox wrapChart(XYChart<X, Y> chart1, XYChart<X, Y> chart2, boolean left)
{
    Pane filler = new Pane();
    filler.minWidthProperty().bind(chart2.getYAxis().widthProperty());
    filler.maxWidthProperty().bind(chart2.getYAxis().widthProperty());
    HBox.setHgrow(chart1, Priority.ALWAYS);
    return left ? new HBox(chart1, filler) : new HBox(filler, chart1);
}

stackPane.getChildren().addAll
(
    wrapChart(leftChart, rightChart, true),
    wrapChart(rightChart, leftChart, false)
)

次要元素对齐

但它还有更多问题。当您更改轴side 属性时,标题和图例位置也会更改。你需要决定如何处理这些问题。您也可以删除冲突的元素或将它们完美对齐。

以下部分描述了如何将辅助元素与默认边对齐 (BOTTOM)。这也适用于TOP 方面。

标题对齐

for(Node n : leftChart.lookupAll(".chart-title"))
    n.translateXProperty().bind(rightChart.getYAxis().widthProperty().divide(2));
for(Node n : rightChart.lookupAll(".chart-title"))
    n.translateXProperty().bind(leftChart.getYAxis().widthProperty().multiply(-1).divide(2));

图例对齐

重叠图例

如果图例相同,则可以将它们重叠或简单地隐藏其中一个。

for(Node n : leftChart.lookupAll(".chart-legend"))
    n.translateXProperty().bind(rightChart.getYAxis().widthProperty().divide(2));
for(Node n : rightChart.lookupAll(".chart-legend"))
    n.translateXProperty().bind(leftChart.getYAxis().widthProperty().divide(2).multiply(-1));

将图例移近它们的轴

如果图例不同,那么您可以将它们移近它们的轴

for(Node n : leftChart.lookupAll(".chart-legend"))
    n.translateXProperty().bind(n.layoutXProperty().divide(2).multiply(-1));
for(Node n : rightChart.lookupAll(".chart-legend"))
    n.translateXProperty().bind(n.layoutXProperty().divide(2));

杂项

您也可以使用DoubleXYChart,它包含以上所有代码等等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多