gpt4 book ai didi

javafx - 如何使堆叠条形图中的负值从上一个堆叠开始?

转载 作者:行者123 更新时间:2023-12-01 12:23:35 27 4
gpt4 key购买 nike

我想在堆叠条形图中可视化每月的收入与支出金额,但差异应该立即可见。

我正在使用以下示例代码:

public class Statistics extends Application {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final StackedBarChart<String, Number> sbc = new StackedBarChart<>(xAxis, yAxis);
final XYChart.Series<String, Number> incoming = new XYChart.Series<>();
final XYChart.Series<String, Number> outgoing = new XYChart.Series<>();

@Override
public void start(Stage stage) {
xAxis.setLabel("Month");
xAxis.setCategories(FXCollections.observableArrayList(
Arrays.asList("Jan", "Feb", "Mar")));
yAxis.setLabel("Value");
incoming.setName("Incoming");
incoming.getData().add(new XYChart.Data("Jan", 25601.34));
incoming.getData().add(new XYChart.Data("Feb2", 20148.82));
incoming.getData().add(new XYChart.Data("Mar2", 10000));
outgoing.setName("Outgoing");
outgoing.getData().add(new XYChart.Data("Jan", -7401.85));
outgoing.getData().add(new XYChart.Data("Feb2", -1941.19));
outgoing.getData().add(new XYChart.Data("Mar2", -5263.37));
Scene scene = new Scene(sbc, 800, 600);
sbc.getData().addAll(incoming, outgoing);
stage.setScene(scene);
stage.show();
}
}

结果是:

Stacked bar chart with negative values below zero

如您所见,负值 outgoing 显示在零以下,而不是从正值 incoming 中减去,这使得很难看到两个。

我想要的是负值的条形图从正值条形图的顶部开始,但由于它们随后会重叠,因此还要沿 x 轴应用偏移量。在“Jan”系列的示例中,这应该类似于:

enter image description here

我正在尝试使用 getNode().setTranslateX/Y(),但这似乎不是一个好的解决方案,因为翻译单位不是图表中的刻度,而是其他东西。

如何优雅地创建第二张图片中的“堆叠”条形图?

最佳答案

你的问题真的很酷!

所以,在这里我想分享我使用 BarChart 而不是 StackedBarChart 的解决方案。它可能有点老套,但它是唯一对我有用的。

我想到的第一件事就是简单地获取条形图并更改其 Y 坐标,但不幸的是我们无法直接访问条形图。因此,在深入了解 XYChart 的源代码后,我发现图表的所有内容都位于 Group plotContent 中,但它的 getter 是 protected。在这种情况下,要做的事情之一就是扩展类并增加方法的范围。所以(最后),代码来了:

public class Statistics extends Application {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
// here I use the modified version of chart
final ModifiedBarChart<String, Number> chart = new ModifiedBarChart<>(xAxis, yAxis);
final XYChart.Series<String, Number> incoming = new XYChart.Series<>();
final XYChart.Series<String, Number> outgoing = new XYChart.Series<>();

@Override
public void start(Stage stage) {
xAxis.setLabel("Month");
xAxis.setCategories(FXCollections.observableArrayList(
Arrays.asList("Jan", "Feb", "Mar")));
yAxis.setLabel("Value");


incoming.setName("Incoming");
incoming.getData().add(new XYChart.Data("Jan", 25601.34));
incoming.getData().add(new XYChart.Data("Feb", 20148.82));
incoming.getData().add(new XYChart.Data("Mar", 10000));

outgoing.setName("Outgoing");
// To set the min value of yAxis you can either set lowerBound to 0 or don't use negative numbers here
outgoing.getData().add(new XYChart.Data("Jan", -7401.85));
outgoing.getData().add(new XYChart.Data("Feb", -1941.19));
outgoing.getData().add(new XYChart.Data("Mar", -5263.37));

chart.getData().addAll(incoming, outgoing);

Scene scene = new Scene(chart, 800, 600);

stage.setScene(scene);
stage.show();

// and here I iterate over all plotChildren elements
// note, that firstly all positiveBars come, then all negative ones
int dataSize = incoming.getData().size();
for (int i = 0; i < dataSize; i++) {
Node positiveBar = chart.getPlotChildren().get(i);
// subtract 1 to make two bars y-axis aligned
chart.getPlotChildren().get(i + dataSize).setLayoutY(positiveBar.getLayoutY() - 1);
}

}

// note, that I extend BarChart here
private static class ModifiedBarChart<X, Y> extends BarChart<X, Y> {

public ModifiedBarChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis) {
super(xAxis, yAxis);
}

public ModifiedBarChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis, @NamedArg("data") ObservableList<Series<X, Y>> data) {
super(xAxis, yAxis, data);
}

public ModifiedBarChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis, @NamedArg("data") ObservableList<Series<X, Y>> data, @NamedArg("categoryGap") double categoryGap) {
super(xAxis, yAxis, data, categoryGap);
}


@Override
public ObservableList<Node> getPlotChildren() {
return super.getPlotChildren();
}
}

结果: The result

关于javafx - 如何使堆叠条形图中的负值从上一个堆叠开始?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41902008/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com