Код ниже (jdk-13, javafx-sdk-13, Apache Netbeans 11.1) фактически работает, но я думаю, что делаю что-то не так.
а) Мне действительно нужны две серии, чтобы показать положительные и отрицательные значения в разных цветах?
б) Почему я должен добавить каждую серию дважды с противоположными значениями, чтобы показать их?
В соответствии со ссылкой это должно быть возможно с классом стиля "негативный": "Если значение данныхотрицательный, добавлен «отрицательный» класс стилей, например, .negative.chart-bar. »
Но я не могу заставить это работать.
BarChart, который я не люблю использовать, потому что мое реальное приложение имеет более 100 значений, а полосы становятся слишком тонкими. Кроме того, столбцы не отцентрированы должным образом.
Решения в этом примере я могу использовать для своего реального приложения, но, может быть, есть правильный способ сделать это?
/*
package hellofx;
import static javafx.application.Application.launch;
import java.util.Arrays;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.Tab;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Sample application to check stacked bar chart issues.
* Problem 1: How to show negative values in a stacked bar chart.
* Problem 2: How to show negative values as different colours.
* Problem 3: (Solved) How to show different positive values for 1st series
* in different charts.
* Different tabs show the different approaches.
* @author frank.meier
*/
public class HelloFX extends Application{
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private static final int NUMCAT = 20;
private static final double MAX = 10;
private static final double MIN = -10;
@Override
public void start(Stage primaryStage){
Insets insets = new Insets(10,10,10,10);
// Define Button
Button btnUpdate = new Button();
btnUpdate.setMinSize(100, 10);
btnUpdate.setText("Update Chart");
// Define Category Labels (xAxis)
CategoryAxis xAxisPosNeg = new CategoryAxis();
CategoryAxis xAxisPos = new CategoryAxis();
CategoryAxis xAxisBar = new CategoryAxis();
String[] categoryLabels = new String[NUMCAT];
for(int i = 0;i < NUMCAT;i++){
categoryLabels[i] = String.valueOf(i+1);
}
// Assign xAxis Labels
xAxisPosNeg.setCategories(FXCollections.<String>
observableArrayList(Arrays.asList(categoryLabels)));
xAxisPos.setCategories(FXCollections.<String>
observableArrayList(Arrays.asList(categoryLabels)));
xAxisBar.setCategories(FXCollections.<String>
observableArrayList(Arrays.asList(categoryLabels)));
// Define Value Axis (yAxis)
NumberAxis yAxisPosNeg = new NumberAxis();
yAxisPosNeg.setLowerBound(MIN);
yAxisPosNeg.setUpperBound(MAX);
NumberAxis yAxisPos = new NumberAxis();
yAxisPos.setLowerBound(MIN);
yAxisPos.setUpperBound(MAX);
NumberAxis yAxisBar = new NumberAxis();
yAxisBar.setLowerBound(MIN);
yAxisBar.setUpperBound(MAX);
// Define Chart and Series
StackedBarChart<String,Number> sbcPosNeg = new StackedBarChart<>(xAxisPosNeg,yAxisPosNeg);
XYChart.Series<String,Number> seriesPNPos = new XYChart.Series<>();
XYChart.Series<String,Number> seriesPNNeg = new XYChart.Series<>();
sbcPosNeg.setId("stacked-bar-chart-pos-neg");
StackedBarChart<String,Number> sbcPosOnly = new StackedBarChart<>(xAxisPos,yAxisPos);
XYChart.Series<String,Number> seriesPOPos = new XYChart.Series<>();
sbcPosOnly.setId("stacked-bar-chart-pos-only");
BarChart<String,Number> sbcBar = new BarChart<>(xAxisBar,yAxisBar);
XYChart.Series<String,Number> seriesBar = new XYChart.Series<>();
sbcBar.setId("bar-chart-pos-neg");
// Configure Chart
sbcPosNeg.setAnimated(false);
yAxisPosNeg.setAutoRanging(false);
sbcPosNeg.setCategoryGap(1);
sbcPosOnly.setAnimated(false);
yAxisPos.setAutoRanging(false);
sbcPosOnly.setCategoryGap(1);
sbcBar.setAnimated(false);
yAxisBar.setAutoRanging(false);
sbcBar.setCategoryGap(1);
// Button Click Event
btnUpdate.setOnAction((ActionEvent e) -> {
updateSeries(categoryLabels,seriesPNPos,seriesPNNeg,seriesPOPos,seriesBar);
});
// Calculate Values for Chart
updateSeries(categoryLabels,seriesPNPos, seriesPNNeg,seriesPOPos,seriesBar);
sbcPosNeg.getData().addAll(seriesPNPos, seriesPNNeg);
sbcPosOnly.getData().addAll(seriesPOPos);
sbcBar.getData().addAll(seriesBar);
// Define Scene Layout and Show
VBox vboxTab1 = new VBox(sbcPosOnly);
VBox vboxTab2 = new VBox(sbcBar);
VBox vboxTab3 = new VBox(sbcPosNeg);
vboxTab1.setPadding(insets);
vboxTab1.setAlignment(Pos.CENTER);
vboxTab2.setPadding(insets);
vboxTab2.setAlignment(Pos.CENTER);
vboxTab3.setPadding(insets);
vboxTab3.setAlignment(Pos.CENTER);
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("SBC: Pos.only", vboxTab1);
Tab tab2 = new Tab("BC: Gap too large", vboxTab2);
Tab tab3 = new Tab("SBC: Works, but why?", vboxTab3);
tabPane.getTabs().addAll(tab1,tab2,tab3);
VBox vbox = new VBox(new Label("Bar Charts Tests"));
vbox.setMinSize(200, 400);
vbox.setPadding(insets);
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(tabPane,btnUpdate);
Scene scene = new Scene(vbox);
Stage stage = new Stage();
stage.setScene(scene);
scene.getStylesheets().add("helloFX/Chart.css");
stage.show();
} // End Start
/**
* Calculates Series values randomly for each category label
* @param cat Category String Array
* @param seriesPos Series<String,Number>
* @param seriesNeg Series<String,Number>
* @param seriesPosOnly Series<String,Number>
*/
private static void updateSeries (String[] cat,
XYChart.Series<String,Number> seriesPos,
XYChart.Series<String,Number> seriesNeg,
XYChart.Series<String,Number> seriesPosOnly,
XYChart.Series<String,Number> seriesBar)
{
seriesPos.getData().clear();
seriesNeg.getData().clear();
seriesPosOnly.getData().clear();
seriesBar.getData().clear();
for(String cat1:cat){
double v = ((Math.random()*(MAX-MIN))+MIN);
if(v < 0){
// This series is used to add only negative values
// but value has to be added and substracted again. Why?
seriesNeg.getData().add(new XYChart.Data<>(cat1,v));
seriesNeg.getData().add(new XYChart.Data<>(cat1,-v));
}
else if (v >= 0){
seriesPos.getData().add(new XYChart.Data<>(cat1,v));
seriesPos.getData().add(new XYChart.Data<>(cat1,-v));
} // End else if
//
// This series only shows positive Values.Why?
seriesPosOnly.getData().add(new XYChart.Data<>(cat1,v));
// If this line is uncommented negative values are shown also
// but how can negative values be colored differently ?
//seriesPosOnly.getData().add(new XYChart.Data<>(cat1,-v));
// Bar chart shows negative values also, but the gap is too large.
seriesBar.getData().add(new XYChart.Data<>(cat1,v));
} // End iterate for categories
} // End Method updateSeries
} // End Class
И вотCSS:
#stacked-bar-chart-pos-neg .default-color0.chart-bar{
-fx-bar-fill : red;
}
#stacked-bar-chart-pos-neg .default-color1.chart-bar{
-fx-bar-fill : blue;
}
#stacked-bar-chart-pos-only .default-color0.chart-bar{
-fx-bar-fill : green;
}
#stacked-bar-chart-pos-only .default-color0.negative.chart-bar {
-fx-bar-fill : yellow;
}
#bar-chart-pos-neg .default-color0.chart-bar {
-fx-bar-fill : lightgreen;
-fx-bar-gap : 0;
}
#bar-chart-pos-neg .default-color0.chart-bar.negative {
-fx-bar-fill : yellow;
}