What to do with StackedAreaChart rendering bug - javafx

I often encounter a really troublesome bug in StackedAreaChart. Instead of getting
I get
The bug seems to rear its head often when data-points-per-display-pixel density is high (though not extraordinarily), non-linear, and/or when successive data series' x-components are not aligned. For example, the two images above are the of the same window, simply resized.
Here is the code that reproduces the bug on Windows 7 32-bit and 64-bit platforms:
public class ChartTest extends Application {
#Override
public void start(Stage primaryStage) {
NumberAxis xAxis = new NumberAxis(0, 100, 10);
NumberAxis yAxis = new NumberAxis(0, 100, 10);
StackedAreaChart<Number,Number> chart;
chart = new StackedAreaChart(xAxis,yAxis);
chart.setLegendVisible(false);
chart.setCreateSymbols(false);
chart.getData().add(genSeries(0));
chart.getData().add(genSeries(1));
StackPane root = new StackPane();
root.getChildren().add(chart);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
private Series<Number,Number> genSeries(int a){
Series<Number,Number> s = new Series<>();
ObservableList<XYChart.Data<Number, Number>> d = s.getData();
for(int i=0; i<50; i++){
double x = Math.sqrt(2*i+a);
d.add(new XYChart.Data<>(x, i));
}
return s;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Does anyone know anything about this bug, how to work around it, or under what conditions exactly it appears?
It can get really bothersome:

Related

JavaFX multi linechart and series - curves missing

I would like to plot one serie per chart, and in the end all the series together in one chart, but did not succeed. I'm asking for help. The code is simple and straight forward. Here is my code:
The main class;
public class TestChart extends Application {
GenPlots genPlots =new GenPlots();
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(event -> {
genPlots.GenPlots("Hello");
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 200, 250);
primaryStage.setTitle("TestCharts");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
And the class aimed to generate the series and the charts:
public class GenPlots {
public GenPlots() {};
Axis xAxis = new NumberAxis();
Axis yAxis = new NumberAxis();
LineChart<Number, Number> lineChart = new LineChart<Number, Number>
(xAxis, yAxis);
LineChart<Number, Number> lineChartMulti = new LineChart<Number,
Number>(xAxis, yAxis);
String serName="*";
// generate the linecharts
public void GenPlots (String hello) {
lineChart.getData().clear();
lineChartMulti.getData().clear();
for (int j=1; j<4;j++) {
XYChart.Series serSIF = new XYChart.Series();
serSIF=getSeries();
serName=String.valueOf(j);
serSIF.setName("Only one "+serName);
lineChart.getData().add(serSIF);
displayChart(lineChart,serName);
lineChartMulti.getData().add(serSIF);
}
displayChart(lineChartMulti,serName+"All Series");
} // end method
// get the series with values - sample
public XYChart.Series getSeries()
{
double x=0.0;
double fx=0.0;
XYChart.Series serL = new XYChart.Series();
for (int k=1; k<5;k++)
{
x=x+2;
fx=x*x*j;
serL.getData().add(new XYChart.Data(x,fx));
}
return serL;
}
// plot the lineCharts
public void displayChart( LineChart<Number, Number>lineChart, String
chartTitle )
{
Stage window = new Stage();
window.initModality(Modality.NONE);
StackPane vb = new StackPane();
vb.setPadding(new Insets(20, 20, 20, 20));
lineChart.setTitle(chartTitle);
vb.getChildren().add(lineChart);
Scene scene = new Scene(vb,500,600);
window.setScene(scene);
window.show();
}
}
Also, the last plots with all series are showing correctly, but the other ones , - one serie per chart - are distorted , or not plotted at all. It seems that the series are resetted to null each time a linechart is generated. I thinks is due to the that series are observable, but I can not figure out how to resolve this problem. Ask kindly for your contribution
I found the solution, which could be usefull for other people:
save the series in a ObservableList-
ObservableList<XYChart.Series<Number,Number>> ser = FXCollections.observableArrayList();
If needed do not clear the series itself, rather the ObservableList.

JavaFX unable to display rectangle inside grid

So my teacher has just started teaching us how to use JavaFx and up until now, I had thought I had a pretty good grasp of the material. But, I am stuck and I don't quite know how to fix the issue or even what's causing the issue. I am trying to create a green rectangle that is three nodes high on a grid that is 64x64. The grid shows up just fine but for the life of me, I cannot understand why the rectangle is not showing up as well. Can someone please help me figure out why the rectangle won't show up? I am sure it's a small stupid issue but again I can't see it. Here is my code:
public class test2 extends Application {
private Cell[][] cell = new Cell[64][64];
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
pane.setStyle("-fx-background-color: black");
for (int col = 1; col < 64; col++)
for (int row = 1; row < 64; row++)
pane.add(cell[col][row] = new Cell(), row, col);
Rectangle rectangle = new Rectangle(1,3);
rectangle.setFill(Color.GREEN);
VBox box2 = new VBox(rectangle);
box2.setAlignment(Pos.CENTER);
BorderPane bp = new BorderPane();
bp.setCenter(pane);
Scene scene = new Scene(bp, 1000, 700);
primaryStage.setScene(scene);
primaryStage.show();
}
public class Cell extends Pane{
public Cell(){
setStyle("-fx-border-color: white");
setPrefSize(1000, 1000);
return;
}
}
public static void main(String[] args) {
launch(args);
}

How can I assign an EventListener to a Path in javafx?

I have this piece of code which doesn't work correctly.
I want to set a listener for when a user clicks inside the square, yet
neither the pop-up nor the message "clicked" are displayed when I click
inside the square.
What am I missing?
This method is inside the Coords class.
public static void drawMyShape(final GraphicsContext ctx) {
Path path = new Path();
MoveTo mT = new MoveTo();
LineTo lT[] = new LineTo[4];
mT.setX(200.0);
mT.setY(200.0);
lT[0] = new LineTo(400.0, 200.0);
lT[1] = new LineTo(400.0, 400.0);
lT[2] = new LineTo(200.0, 400.0);
lT[3] = new LineTo(200.0, 200.0);
path.setStroke(Color.BEIGE);
path.getElements().addAll(mT, lT[0], lT[1], lT[2], lT[3]);
path.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
final Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initOwner(Main.prim_stage);
VBox box = new VBox(20);
box.getChildren().add(new Text("Hey"));
Scene s = new Scene(box, 300, 200);
dialog.setScene(s);
dialog.show();
System.out.println("Clicked");
}
});
ctx.setLineWidth(4.0);
ctx.beginPath();
ctx.moveTo(mT.getX(), mT.getY());
for (int i = 0; i < lT.length; i++) {
ctx.lineTo(lT[i].getX(), lT[i].getY());
}
ctx.closePath();
ctx.stroke();
}
EDITED ON SUGGESTION by users.
So his is the main program:
public class Main extends Application {
public static Pane root;
private static Canvas main_canvas;
private static GraphicsContext ctx;
private static Rectangle2D bounds;
private static Scene scene;
public static Stage prim_stage;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Switzerland Advertising");
initElements(primaryStage);
Coords.drawMyShape(ctx);
primaryStage.show();
System.out.println("Launched");
}
public static void main(String[] args) {
launch(args);
}
}
Everything is instanciated inside the following function, which works correctly and displays a full screen application with a canvas and a square drawn into it (image at the bottom).
private void initElements(final Stage primaryStage) {
prim_stage = primaryStage;
// ----------------------------------------
bounds = Screen.getPrimary().getVisualBounds();
double w = bounds.getWidth();
double h = bounds.getHeight();
// ----------------------------------------
// init elements of scene
root = new Pane();
main_canvas = new Canvas(w, h);
// ----------------------------------------
// init scene elements
scene = new Scene(root, w, h);
primaryStage.setX(bounds.getMinX());
primaryStage.setY(bounds.getMinY());
primaryStage.setWidth(w);
primaryStage.setHeight(h);
primaryStage.setScene(scene);
// ----------------------------------------
ctx = main_canvas.getGraphicsContext2D();
// set elements in main pane
root.getChildren().add(main_canvas);
// ----------------------------------------
}
So how can I make the pop-up window appear whenever I click inside the region drawn on the canvas?
This is the program
Your path is just a local variabl within your method. It has to be attached to the scene graph in order to get events. But when you attach it to the scene graph, drawing the same path on a canvas also does not make much sense.

Color Change in Area Chart

i have a Java-Class that extends the AreaChart. There i would like to implement a method that makes more or less something like this:
public void addNewColorToData(xCoordinate, yCoordinate, redColor, greenColor, blueColor);
-> The Function should get the parameters of the Data for the xCoordinate, yCoordinate and then for the RGB Value of the representes Line.
Is it possible to create with Inline-Styles a new Color for this ?
Here you can see a Sample. There are a lot of Color-Fills for the Area Chart!
Is it possible to add there some new colors?
I need to add a Inline Style stuff like this in CSS:
.default-color0.chart-series-area-fill { -fx-fill: #007Fc350; }
Thank you for your help
Based on this answer, to create an inline style based on r,g,b parameters (given these are integers from 0 to 255) you just need to override the CHART_COLOR_1 (up to CHART_COLOR_8) value to modify the line color and CHART_COLOR_1_TRANS_20 (up to CHART_COLOR_8_TRANS_20) to modify the area color:
private AreaChart<String, Number> areaChart;
private void changeColor(int redColor, int greenColor, int blueColor, double opacity){
/* int redColor=0, greenColor=127, blueColor=195;
double opacity=0.4;
*/
areaChart.setStyle("CHART_COLOR_1: rgb("+redColor+","+greenColor+","+blueColor+");" +
"CHART_COLOR_1_TRANS_20: rgba("+redColor+","+greenColor+","+blueColor+");");
}
EDIT
I'm adding this short MVCE for the sake of clarity:
#Override
public void start(Stage primaryStage) {
AreaChart<String, Number> areaChart=new AreaChart<>(new CategoryAxis(),new NumberAxis());
ObservableList<XYChart.Data<String,Integer>> xyList
= FXCollections.observableArrayList(
new XYChart.Data<>("P1", 30),
new XYChart.Data<>("P2", 40),
new XYChart.Data<>("P3", 30));
XYChart.Series series = new XYChart.Series(xyList);
areaChart.getData().addAll(series);
Button button = new Button("Change style");
button.setOnAction(e->{
int redColor=0, greenColor=127, blueColor=195;
double opacity=0.3;
areaChart.setStyle("CHART_COLOR_1: rgb("+redColor+","+greenColor+","+blueColor+"); "
+ "CHART_COLOR_1_TRANS_20: rgba("+redColor+","+greenColor+","+blueColor+","+opacity+");");
});
VBox root = new VBox(5, button, areaChart);
Scene scene = new Scene(root, 400, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
This would be the result:

Sort ObservableList from high to low - javafx

Is there any way to sort a ObservableList based on the values from high to low?
Say I have a
ObservableList<XYChart.Data> data;
containing a String and a Double. I want the list sorted based on the Double from highest to lowest values. The reason I want this is because charts look way better if their values are shown from the highest to the lowest.
I have something like this now:
sortedData = new SortedList<>(data);
sortedData.comparatorProperty().bind(mycomparatorProperty());
You can create a Comparator, compare by the Y value, and then reverse the order:
data.sort(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed());
This will sort your collection as intented.
Or you can return a new collection:
List<XYChart.Data<String,Double>> sortedData =
data.stream()
.sorted(Comparator.comparing(XYChart.Data<String,Double>::getYValue).reversed())
.collect(Collectors.toList());
EDIT
For the sake of clarity, this is a full sample:
public class FXMain extends Application {
private final ObservableList<XYChart.Data<String,Double>> data =
FXCollections.observableArrayList(
new XYChart.Data("P1",200d),
new XYChart.Data("P2",150d),
new XYChart.Data("P3",250d));
#Override
public void start(Stage primaryStage) {
Button btn = new Button"Sort data!");
btn.setOnAction(e -> {
ObservableList<XYChart.Data<String,Double>> data2 =
data.stream()
.sorted(Comparator.
comparing(XYChart.Data<String,Double>::getYValue).reversed())
.peek(System.out::println)
.collect(Collectors.toCollection(()->FXCollections.observableArrayList()));
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Resources