1

Is it possible to move/shift the tick labels into the chart. Currently I see api's to hide/show tick labels is there an API that moves the tick labels inside the chart? If there isn't an API then is there a technique that I can use/apply to get this done?

Current code

public class Graph extends Application{
private NumberAxis xAxis;
private NumberAxis yAxis;

public static void main(final String[] args)
{
    launch(args);
}

@Override
public void start(final Stage primaryStage) throws Exception
{
    xAxis = new NumberAxis(0, 300, 20);
    xAxis.setAutoRanging(false);
    xAxis.setAnimated(false);
    xAxis.setMinorTickVisible(false);
    xAxis.setTickLabelsVisible(false);
    xAxis.setTickMarkVisible(false);

    yAxis = new NumberAxis(30, 240, 30);
    yAxis.setAutoRanging(false);
    yAxis.setAnimated(false);
    yAxis.setTickMarkVisible(false);
    yAxis.setMinorTickVisible(false);
    yAxis.setMinorTickCount(3);

    final LineChart<Number, Number> ctg = new LineChart<>(xAxis, yAxis);

    ctg.setAnimated(false);
    ctg.setCreateSymbols(false);
    ctg.setAlternativeRowFillVisible(false);
    ctg.setLegendVisible(false);
    ctg.setHorizontalGridLinesVisible(true);
    ctg.setVerticalGridLinesVisible(true);

    Series<Number, Number> series = new LineChart.Series<>();
    ctg.getData().add(series);

    for (int i = 0; i < 300; i += 5) {

        XYChart.Series minorYGrid = new XYChart.Series();
        minorYGrid.getData().add(new XYChart.Data(i, 30));
        minorYGrid.getData().add(new XYChart.Data(i, 240));
        ctg.getData().add(minorYGrid);
    }

    for (int i = 40; i <= 240; i += 10) {

        XYChart.Series minorXGrid = new XYChart.Series();
        minorXGrid.getData().add(new XYChart.Data(0, i));
        minorXGrid.getData().add(new XYChart.Data(500, i));
        ctg.getData().add(minorXGrid);
    }

    final Scene scene = new Scene(ctg, 1600, 400);
    scene.getStylesheets().add("resources/application.css");
    primaryStage.setScene(scene);
    primaryStage.show();
}
}

Current result

enter image description here

Expected result enter image description here

SDS
  • 828
  • 3
  • 17
  • 35

1 Answers1

2

Translating a Single Axis

You can translate the y axis on the chart.

For example:

yAxis.translateXProperty().bind(
    xAxis.widthProperty().divide(2)
);

To ensure the axis is displayed on top of the chart, you could set the depth buffer to true on the scene and set the z co-ordinate of the yAxis to -1.

yAxis.setTranslateZ(-1);

Translating Multiple Axes

Your "Expected result" actually has multiple vertical axes. Unfortunately there is no clone method to clone a node in JavaFX. So you will have to create a new axis and layer it on top of the chart. One way to accomplish that (which is a bit overkill and inefficient), is to create a completely new chart and layer it on top of the old one, similar to what is done in the solution to draw layers of XYCharts. The other way to do it, which is probably preferable but a bit trickier, would be just create another axis and stack it over the original chart.

Sample Code

multi-axis chart

MultiAxisChart.java

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class MultiAxisChart extends Application {

    @Override
    public void start(final Stage primaryStage) throws Exception {
        final StackPane chartStack = createChartStack();

        final Scene scene = new Scene(chartStack, 1600, 400, true);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private StackPane createChartStack() {
        LineChart<Number, Number> bottomChart = createChart();
        LineChart<Number, Number> topChart    = createChart();

        bottomChart.getYAxis().translateXProperty().bind(
                bottomChart.getXAxis().widthProperty().multiply(1.0/3)
        );
        topChart.getYAxis().translateXProperty().bind(
                topChart.getXAxis().widthProperty().multiply(2.0/3)
        );

        bottomChart.getYAxis().setTranslateZ(-1);
        topChart.getYAxis().setTranslateZ(-1);

        topChart.getStylesheets().addAll(getClass().getResource(
                "overlay-chart.css"
        ).toExternalForm());

        return new StackPane(bottomChart, topChart);
    }

    private LineChart<Number, Number> createChart() {
        NumberAxis xAxis = new NumberAxis(0, 300, 20);
        xAxis.setAutoRanging(false);
        xAxis.setAnimated(false);
        xAxis.setMinorTickVisible(false);
        xAxis.setTickLabelsVisible(false);
        xAxis.setTickMarkVisible(false);

        NumberAxis yAxis = new NumberAxis(30, 240, 30);
        yAxis.setAutoRanging(false);
        yAxis.setAnimated(false);
        yAxis.setTickMarkVisible(false);
        yAxis.setMinorTickVisible(false);
        yAxis.setMinorTickCount(3);

        final LineChart<Number, Number> ctg = new LineChart<>(xAxis, yAxis);

        ctg.setAnimated(false);
        ctg.setCreateSymbols(false);
        ctg.setAlternativeRowFillVisible(false);
        ctg.setLegendVisible(false);
        ctg.setHorizontalGridLinesVisible(true);
        ctg.setVerticalGridLinesVisible(true);

        return ctg;
    }

    public static void main(final String[] args) {
        launch(args);
    }
}

overlay-chart.css

/** file: overlay-chart.css (place in same directory as MultiAxisChart) */
.chart-plot-background {
    -fx-background-color: transparent;
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Is there a way to 1. move 30 and 240 inside the graph boundary 2. center the y-axis labels over the y-axis line 3. set the y-axis line transparent while the label still appears The expected result screenshot is what I'm looking for. – SDS Oct 14 '14 at 20:19
  • Yes, that can all be done SDS: 1 is already done in my solution 2 is an additional translate request and 3 is a css style. I am not going to update this solution with those modifications though. – jewelsea Oct 14 '14 at 20:33