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.
Related
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...
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 ?
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);
}
}
I created a Bar char but there is a big gap between the bars (I think it's because I use one element in each series). I tried setBarGap() but it doesn't change anything. here is what i do : http://i.imgur.com/k3ZEYCT.png? and here is an example of what i want : http://i.imgur.com/fb7tMx5.png
ObservableList<XYChart.Series<String, Number>> answer = FXCollections.observableArrayList();
for(int i=1;i<9;i++){
....
...
...
XYChart.Series<String, Number> series6 = new XYChart.Series<String, Number>();
series6.getData().add(new XYChart.Data(String.valueOf(i), 2*i));
answer.add(series6);
}
XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
series1.getData().add(new Data<String, Number>(">8",rs2.getInt(1)));
answer.add(series1);
return answer;
The problem is you add more than one category for all data series. If one data series is named "1", and the other is named "2" and these are added to different series then the layout needs to save room in each category's group of bars for the missing category. Like there's a space in "2" group for "1" bars, but you haven't added any.
Make sure you never add more than one category - they all have to have the same value. Since it seems you're using different series for the color and legend, then just don't name the categories.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Side;
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 BarChartSample extends Application {
#Override public void start(Stage stage) {
stage.setTitle("Bar Chart Sample");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart<String,Number> bc = new BarChart(xAxis,yAxis);
bc.setTitle("Frequency of visit");
bc.setLegendSide(Side.RIGHT);
//if you want axis labels
xAxis.setLabel("");
yAxis.setLabel("");
bc.getData().addAll(makeSerie("daily",20),
makeSerie("twice a week",30),
makeSerie("weekly",40),
makeSerie("monthly",50));
xAxis.setVisible(false);
xAxis.setTickMarkVisible(false);
xAxis.setTickLabelsVisible(false);
bc.setBarGap(20);
Scene scene = new Scene(bc);
stage.setScene(scene);
stage.show();
}
//just to save typing
private XYChart.Series<String, Number> makeSerie(String name, Number value){
return new XYChart.Series(name,
FXCollections.observableArrayList(new XYChart.Data("", value)));
}
public static void main(String[] args) {
launch(args);
}
}
How can I achieve fixed Axis width using JavaFx line graph.
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.stage.Stage;
public class Axis extends Application
{
private Timeline animation;
public static void main(final String[] args)
{
launch(args);
}
#Override
public void start(final Stage stage) throws Exception
{
final NumberAxis x = new NumberAxis();
final NumberAxis y = new NumberAxis();
x.setAutoRanging(false);
y.setAutoRanging(false);
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(x, y);
// final Series series = new LineChart.Series<Number, Number>();
//
// series.getData().add(new XYChart.Data(20, 23));
// series.getData().add(new XYChart.Data(35, 14));
// series.getData().add(new XYChart.Data(43, 15));
// series.getData().add(new XYChart.Data(60, 24));
// series.getData().add(new XYChart.Data(10, 34));
//
// lineChart.getData().add(series);
lineChart.setPrefHeight(10);
lineChart.setPrefWidth(10);
lineChart.setMinHeight(10);
lineChart.setMinWidth(10);
lineChart.setMaxHeight(10);
lineChart.setMaxWidth(10);
final Scene scene = new Scene(lineChart, 800, 800);
stage.setScene(scene);
stage.show();
}
#Override
public void stop()
{
animation.pause();
}
}
I would like the grid (sample marked in red) not to scale when I resize the window. Currently the grid resizes when the window is resized as shown below
I am not able to achieve what I need using the minWidth and maxWidth API's
Preventing resizing of a Graph
You can prevent the graph resizing by setting it's preferred, min and max sizes:
lineChart.setMinSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
lineChart.setPrefSize(800, 600);
lineChart.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
The only exception to this is when the chart is the root of the scene, in which case you should wrap the chart in a Pane or Group to prevent it being resized to fit the scene (because of a layout quirk in the JavaFX 8 rendering logic).
Also note, wrapping any resizable node a Group will size the node (excluding transforms and effects) to it's preferred dimensions and never change them.
Unfortunately, setting the preferred size of the graph isn't exactly the same as setting the preferred sizes of the graph's axes directly, as it makes the entire chart that size, not a specific axis line, which is probably what you are looking for with your question.
Preventing resizing of a Graph Axis
I don't know how to do this.
You might think you could do the following:
xAxis.setMinWidth(Control.USE_PREF_SIZE);
xAxis.setPrefWidth(800);
xAxis.setMaxWidth(Control.USE_PREF_SIZE);
But this doesn't work in Java 8 when the axis is embedded inside a chart. This is because the XYChart layout routine ignores the preferred, min and max sizes of it's axes when it lays out the chart contents.
This is perhaps a bug, so you might want to log it as such at https://javafx-jira.kenai.com.