Scatter chart with connected dots javafx - javafx

I am learning javafx for creating GUI. I want to implement a simple line chart of X-Y NumberAxis. As per the property of line chart, the lines connecting the data points never intersect.
For example - Suppose for data points
series.getData().add(new XYChart.Data(1.5,1.5));
series.getData().add(new XYChart.Data(2.5,4.5));
series.getData().add(new XYChart.Data(4.5,2.5));
series.getData().add(new XYChart.Data(1.0,2.0));
series.getData().add(new XYChart.Data(3.0,3.0));`
The output for these points in line chart is -
]1)
where as it should be as the following edited image of scatter chart output of same points -
Is there a way to change this behavior of line chart? OR connect the dots of scatter chart?
Note that I am going to add points dynamically and lower bound, upper bound of both the axis are going to vary continuously.

Switch the sorting policy off for the chart.
lineChart.setAxisSortingPolicy(LineChart.SortingPolicy.NONE);
When I use this, I get this beautiful child's scribble.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class LineChartSample extends Application {
#Override public void start(Stage stage) {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number,Number> lineChart =
new LineChart<>(xAxis, yAxis);
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.getData().addAll(
new XYChart.Data<>(4, 24),
new XYChart.Data<>(1, 23),
new XYChart.Data<>(6, 36),
new XYChart.Data<>(8, 45),
new XYChart.Data<>(2, 14),
new XYChart.Data<>(9, 43),
new XYChart.Data<>(7, 22),
new XYChart.Data<>(12, 25),
new XYChart.Data<>(10, 17),
new XYChart.Data<>(5, 34),
new XYChart.Data<>(3, 15),
new XYChart.Data<>(11, 29)
);
lineChart.setAxisSortingPolicy(LineChart.SortingPolicy.NONE);
Scene scene = new Scene(lineChart,800,600);
lineChart.getData().add(series);
lineChart.setLegendVisible(false);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX LineChart Mouse Hover Values [duplicate]

I am in the process of creating a line chart in JavaFX. All is good currently and it successfully creates the chart with the data I need from a database stored procedure. Anyway what I require if possible is for every data point on the LineChart to have a mouse hover event on it which states the value behind the specific point, for example £150,000. I have seen examples of this been done on PieCharts where it shows the % value on hover but I cannot find examples anywhere for LineCharts, can this even be done?
Can anyone point me in the right direction if possible?
Code so far:
private static final String MINIMIZED = "MINIMIZED";
private static final String MAXIMIZED = "MAXIMIZED";
private static String chartState = MINIMIZED;
// 12 Month Sales Chart
XYChart.Series<String, Number> series = new XYChart.Series<>();
XYChart.Series<String, Number> series2 = new XYChart.Series<>();
public void getDeltaData() {
try {
Connection con = DriverManager.getConnection(connectionUrl);
//Get all records from table
String SQL = "";
Statement stmt = con.createStatement();
//Create the result set from query execution.
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next()) {
series.getData().add(new XYChart.Data<String, Number>(rs.getString(1),
Double.parseDouble(rs.getString(7))));
series2.getData().add(new XYChart.Data<String, Number>(rs.getString(1),
Double.parseDouble(rs.getString(8))));
}
rs.close();
stmt.close();
} catch (Exception e) {
}
yearChart = createChart();
}
protected LineChart<String, Number> createChart() {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
// setup chart
series.setName("Target");
series2.setName("Actual");
xAxis.setLabel("Period");
yAxis.setLabel("£");
yearChart.getData().add(series);
yearChart.getData().add(series2);
yearChart.setCreateSymbols(false);
return yearChart;
}
Answer provided by jewelsea is a perfect solution to this problem.
Thank you, jewelsea.
Use XYChart.Data.setNode(hoverPane) to display a custom node for each data point. Make the hoverNode a container like a StackPane. Add mouse event listeners so that you know when the mouse enters and leaves the node. On enter, place a Label for the value inside the hoverPane. On exit, remove the label from the hoverPane.
There is some example code to demonstrate this technique.
Output of the sample code is shown with the cursor hovered over the 22 node.
Using Tooltip:
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.control.Tooltip;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication250 extends Application
{
#Override
public void start(Stage stage)
{
stage.setTitle("Line Chart Sample");
//defining the axes
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
//creating the chart
final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Stock Monitoring, 2010");
//defining a series
XYChart.Series<Number, Number> series = new XYChart.Series();
series.setName("My portfolio");
//populating the series with data
Random rand = new Random();
TreeMap<Integer, Integer> data = new TreeMap();
//Create Chart data
for (int i = 0; i < 3; i++) {
data.put(rand.nextInt(51), rand.nextInt(51));
}
Set set = data.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry me = (Map.Entry) i.next();
System.out.println(me.getKey() + " - " + me.getValue());
series.getData().add(new XYChart.Data(me.getKey(), me.getValue()));//Add data to series
}
lineChart.getData().add(series);
//loop through data and add tooltip
//THIS MUST BE DONE AFTER ADDING THE DATA TO THE CHART!
for (Data<Number, Number> entry : series.getData()) {
System.out.println("Entered!");
Tooltip t = new Tooltip(entry.getYValue().toString());
Tooltip.install(entry.getNode(), t);
}
Scene scene = new Scene(lineChart, 800, 600);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}

Reduce number of tick labels on JavaFX xAxis

Up from a certain number of plotted ticks the labels on the xAxis are rotated by 90 degrees into a vertical position.
I would like to keep them horizontal and only plot as many as are fitting to the xAxis.
This shows how it looks and how I would like it to look:
Trying xAxis.setTickLabelRotation() is not showing any effect if there is not enough space to rotate the labels it seems.
I did a work around hiding the xAxis labels, positioning a HBox below the chart and fill it with a few labels that are horizontal. But that is no clean solution and did lead to other issues I would like to avoid.
This example:
JavaFX manually set NumberAxis ticks
shows how to subclass a NumberAxis but I did not make it yet to transfer that to achieve my goal. My idea is to subclass the NumberAxis, overwrite the methods that are responsible for plotting the labels on the xAxis and use a formatter that turns the numbers into the date format to be plotted.
Would that be the right approach and what would be the methods to address? I spent a lot of time going through the sources without success. Any hint into the right direction would be highly appreciated.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LineChartSample extends Application {
#Override
public void start(Stage stage) {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<String, Number> lineChart = new LineChart<String, Number>(xAxis, yAxis);
lineChart.setAnimated(false);
lineChart.setCreateSymbols(false);
XYChart.Series series = new XYChart.Series();
for (int i = 0; i < 100; i+=1)
series.getData().add(new XYChart.Data(msToDateString(i), Math.random()));
Scene scene = new Scene(lineChart, 800, 150);
lineChart.getData().add(series);
stage.setScene(scene);
stage.show();
}
//msToDateString-----------------------------------------------------------------
private static DateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS");
private static Date result = new Date();
public static String msToDateString(long milliseconds) {
result.setTime(milliseconds);
return df.format(result);
}
public static void main(String[] args) {
launch(args);
}
}
I know this is an old topic now, but I came across this question while trying to deal with the similar problem myself. I was using custom LineChart class (extended) and had to override layoutPlotChildren() method to be able to put additional shapes to the plot list. To make graph more readable, I wanted to show every second tick on the X axis. In the end, I solved this problem by iterating tick marks and making every second mark invisible. Here is the snippet of the code:
public class MyLineChart extends LineChart<String, Double> {
public MyLineChart (
#NamedArg("xAxis") final Axis<String> xAxis,
#NamedArg("yAxis") final Axis<Double> yAxis) {
super(xAxis, yAxis);
}
...
#Override
protected void layoutPlotChildren() {
super.layoutPlotChildren();
...
ObservableList<Axis.TickMark<String>> tickMarks = getXAxis().getTickMarks();
for (int i = 0; i < tickMarks.size(); i++) {
tickMarks.get(i).setTextVisible(i % 2 == 0);
}
}
Hope this helps...

JavaFX : Barchart with multiple (2) y axis

I would like to create a JavaFX barchart with takes 2 y-axis, since the series-values are too wide apart, resulting in second series not showing off properly in the chart.
I have dummed-down the code to its very basics, for the purpose of this question:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class MultiAxisTryout extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("Bar Chart Multi Example");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart bc =
new BarChart(xAxis,yAxis);
bc.setTitle("Cost & Delta by JV");
xAxis.setLabel("JV");
XYChart.Series series1 = new XYChart.Series();
series1.setName("Cost");
XYChart.Series series2 = new XYChart.Series();
series2.setName("Delta");
series1.getData().add(new XYChart.Data("1000000", 25000));
series1.getData().add(new XYChart.Data("1200000", 30000));
series2.getData().add(new XYChart.Data("1000000", 22));
series2.getData().add(new XYChart.Data("1200000", 86));
Scene scene = new Scene(bc ,1800,1000);
scene.setFill(null);
bc.setAnimated(false);
bc.getData().addAll(series1,series2);
stage.setScene(scene);
stage.show();
}
}
The result looks like this :
As you can see, the second series is not showing off very well in the barchart, so it would be nice to have a second y-axis with its own scale, showing off better in the barchart.
Is this possible in JavaFx ?

javafx charts not working

I am using javafx charts for my project and after running my program I am getting this chart. what I want it to snap 3rd point first and then on to 4th point. Is there any way to do that. Thanks
I'm pretty sure that the 'AreaChart' that you're using plots data monotonically. So no matter what order the points get added to your series, the chart will plot them as monotonic.
note: Monotonic means that for every x value, there is a single y value.
If you want to break the 'monotonicness' of your plot and you're willing to give up the shaded area, you could construct it as a lineChart and then you would need to change your sorting policy. I've attached an example below to show you how to fix it.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Pane root = new Pane();
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
LineChart chart = new LineChart(xAxis,yAxis);
XYChart.Series series = new XYChart.Series();
chart.getData().add(series);
chart.setAxisSortingPolicy(LineChart.SortingPolicy.NONE);
series.getData().add(new XYChart.Data(0,1));
series.getData().add(new XYChart.Data(1,2));
series.getData().add(new XYChart.Data(2,1));
series.getData().add(new XYChart.Data(1,0));
root.getChildren().add(chart);
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Unfortunately, if you're looking for both, it's going to come down to having to build your own chart class by extending from XYChart or maybe even AreaChart and defining your own custom AreaChart.

JavaFX - How to position the axis label to avoid conflicting with the tick marks

The below code is a simple line chart where the yAxis tick labels are wide in terms of their character length/width. The yAxis label positioned by default is placed too close to the yAxis, meaning the text conflicts with the tick marks. Is it possible to avoid this by increasing the gap between the label and the axis?
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class Example extends Application {
#Override
public void start(Stage stage) {
final NumberAxis xAxis = new NumberAxis(0, 10, 2);
final NumberAxis yAxis = new NumberAxis(1.3378, 1.3390, 0.0001);
xAxis.setLabel("xAxis");
yAxis.setLabel("yAxis");
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis){
#Override public String toString(Number object){
return String.format("%1.4f", object); }
});
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
XYChart.Series series = new XYChart.Series();
final XYChart.Data d1 = new XYChart.Data(0.0,1.3379);
final XYChart.Data d2 = new XYChart.Data(2.0,1.3387);
final XYChart.Data d3 = new XYChart.Data(2.5,1.3385);
final XYChart.Data d4 = new XYChart.Data(3.5,1.3387);
final XYChart.Data d5 = new XYChart.Data(8.0,1.3378);
final XYChart.Data d6 = new XYChart.Data(9.5,1.3388);
series.getData().addAll(d1, d2, d3, d4, d5, d6);
lineChart.getData().add(series);
lineChart.setLegendVisible(false);
final Scene scene = new Scene(lineChart, 400, 300);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I don't think it is possible to relocate "yAxis" label or increase the gap, but you may want to use the following workaround to avoid the text conficts:
lineChart.getYAxis().setTickLabelRotation(-90);
And you will get the following chart:
It is possible to locate the label of an axis.
For Example to move the Label 10 Pixel to the left, just use:
lineChart.getYAxis()
.lookup(".axis-label")
.setStyle("-fx-label-padding: -10 0 0 0;");

Resources