下面列出了怎么用javafx.scene.chart.Axis的API类实例代码及写法,或者点击链接到github查看源代码。
public static Chart plotFunction(List<Function<Double, Double>> functions, Number xStart, Number xEnd) {
int div = 500;
double x0 = xStart.doubleValue();
double x1 = xEnd.doubleValue();
double step = 1./div* (x1-x0);
Axis<Number> xAxis = new NumberAxis(x0, x1, .1* (x1-x0));
Axis<Number> yAxis = new NumberAxis();
ObservableList<XYChart.Series<Number, Number>> series = FXCollections.observableArrayList();
LineChart<Number,Number> chart = new LineChart(xAxis, yAxis, series);
chart.setCreateSymbols(false);
for (Function<Double, Double> f: functions) {
XYChart.Series<Number, Number> mainSeries = new XYChart.Series();
series.add(mainSeries);
ObservableList<XYChart.Data<Number, Number>> data = FXCollections.observableArrayList();
mainSeries.setData(data);
for (double x = x0; x < x1; x= x +step) {
final Number y = f.apply(x);
data.add(new XYChart.Data<>(x,y));
}
}
return chart;
}
/**
* Given graphical coordinates in the reference's coordinate system, returns x and y axis value as
* a point via the {@link Axis#getValueForDisplay(double)} and {@link Axis#toNumericValue(Object)}
* methods.
*
* @param minX lower X value (upper left point)
* @param minY lower Y value (upper left point)
* @param maxX upper X value (bottom right point)
* @param maxY upper Y value (bottom right point)
*/
@SuppressWarnings( "unchecked" )
public Rectangle2D getDataCoordinates( double minX, double minY, double maxX, double maxY ) {
if ( minX > maxX || minY > maxY ) {
throw new IllegalArgumentException( "min > max for X and/or Y" );
}
Axis xAxis = chart.getXAxis();
Axis yAxis = chart.getYAxis();
double xStart = getXShift( xAxis, referenceNode );
double yStart = getYShift( yAxis, referenceNode );
double minDataX = xAxis.toNumericValue( xAxis.getValueForDisplay( minX - xStart ) );
double maxDataX = xAxis.toNumericValue( xAxis.getValueForDisplay( maxX - xStart ) );
//The "low" Y data value is actually at the maxY graphical location as Y graphical axis gets
//larger as you go down on the screen.
double minDataY = yAxis.toNumericValue( yAxis.getValueForDisplay( maxY - yStart ) );
double maxDataY = yAxis.toNumericValue( yAxis.getValueForDisplay( minY - yStart ) );
return new Rectangle2D( minDataX,
minDataY,
maxDataX - minDataX,
maxDataY - minDataY );
}
/**
* Returns the plot area in the reference's coordinate space.
*/
public Rectangle2D getPlotArea() {
Axis<?> xAxis = chart.getXAxis();
Axis<?> yAxis = chart.getYAxis();
double xStart = getXShift( xAxis, referenceNode );
double yStart = getYShift( yAxis, referenceNode );
//If the direct method to get the width (which is based on its Node dimensions) is not found to
//be appropriate, an alternative method is commented.
// double width = xAxis.getDisplayPosition( xAxis.toRealValue( xAxis.getUpperBound() ) );
double width = xAxis.getWidth();
// double height = yAxis.getDisplayPosition( yAxis.toRealValue( yAxis.getLowerBound() ) );
double height = yAxis.getHeight();
return new Rectangle2D( xStart, yStart, width, height );
}
@Override
public Axis<Number> build() {
final NumberAxis axis = new NumberAxis();
axis.setAutoRanging(true);
axis.setForceZeroInRange(false);
return axis;
}
@Override
public void handle(long l) {
if (isAxis) {
((Axis<?>) nodeToLayout).requestAxisLayout();
} else {
nodeToLayout.requestLayout();
}
}
private void bindMouseEvents(final LineChart<?, ?> baseChart, final Double strokeWidth) {
getChildren().add(detailsWindow);
detailsWindow.prefHeightProperty().bind(heightProperty());
detailsWindow.prefWidthProperty().bind(widthProperty());
detailsWindow.setMouseTransparent(true);
setOnMouseMoved(null);
setMouseTransparent(false);
final Axis<?> xAxis = baseChart.getXAxis();
final Axis<?> yAxis = baseChart.getYAxis();
final Line xLine = new Line();
final Line yLine = new Line();
yLine.setFill(Color.GRAY);
xLine.setFill(Color.GRAY);
yLine.setStrokeWidth(strokeWidth / 2);
xLine.setStrokeWidth(strokeWidth / 2);
xLine.setVisible(false);
yLine.setVisible(false);
final Node chartBackground = baseChart.lookup(".chart-plot-background");
for (final Node n : chartBackground.getParent().getChildrenUnmodifiable()) {
if ((n != chartBackground) && (n != xAxis) && (n != yAxis)) {
n.setMouseTransparent(true);
}
}
}
/**
* Construct a new CandleStickChart with the given axis.
*
* @param xAxis The x axis to use
* @param yAxis The y axis to use
*/
public CandleStickChart(Axis<Number> xAxis, Axis<Number> yAxis) {
super(xAxis, yAxis);
setAnimated(false);
xAxis.setAnimated(false);
yAxis.setAnimated(false);
}
/**
* This is called when the range has been invalidated and we need to update it. If the axis are auto
* ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
* axis passing it that data.
*/
@Override
protected void updateAxisRange() {
// For candle stick chart we need to override this method as we need to let the axis know that they need to be able
// to cover the whole area occupied by the high to low range not just its center data value
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
if (xa.isAutoRanging()) {
xData = new ArrayList<Number>();
}
if (ya.isAutoRanging()) {
yData = new ArrayList<Number>();
}
if (xData != null || yData != null) {
for (Series<Number, Number> series : getData()) {
for (Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null) {
CandleStickExtraValues extras = (CandleStickExtraValues) data.getExtraValue();
if (extras != null) {
yData.add(extras.getHigh());
yData.add(extras.getLow());
} else {
yData.add(data.getYValue());
}
}
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
}
/**
* Construct a new CandleStickChart with the given axis.
*
* @param xAxis The x axis to use
* @param yAxis The y axis to use
*/
public CandleStickChart(Axis<Number> xAxis, Axis<Number> yAxis) {
super(xAxis, yAxis);
setAnimated(false);
xAxis.setAnimated(false);
yAxis.setAnimated(false);
}
/**
* This is called when the range has been invalidated and we need to update it. If the axis are auto
* ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
* axis passing it that data.
*/
@Override
protected void updateAxisRange() {
// For candle stick chart we need to override this method as we need to let the axis know that they need to be able
// to cover the whole area occupied by the high to low range not just its center data value
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
if (xa.isAutoRanging()) {
xData = new ArrayList<Number>();
}
if (ya.isAutoRanging()) {
yData = new ArrayList<Number>();
}
if (xData != null || yData != null) {
for (Series<Number, Number> series : getData()) {
for (Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null) {
CandleStickExtraValues extras = (CandleStickExtraValues) data.getExtraValue();
if (extras != null) {
yData.add(extras.getHigh());
yData.add(extras.getLow());
} else {
yData.add(data.getYValue());
}
}
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
}
@Override
protected void updateAxisRange() {
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
if (xa.isAutoRanging()) {
xData = new ArrayList<>();
}
if (ya.isAutoRanging())
yData = new ArrayList<>();
if (xData != null || yData != null) {
for (XYChart.Series<Number, Number> series : getData()) {
for (XYChart.Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null)
yData.add(data.getYValue());
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
}
/**
* This is called when the range has been invalidated and we need to update it. If the axis are auto
* ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
* axis passing it that data.
*/
@Override
protected void updateAxisRange() {
// For candle stick chart we need to override this method as we need to let the axis know that they need to be able
// to cover the whole area occupied by the high to low range not just its center data value
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
if (xa.isAutoRanging()) {
xData = new ArrayList<>();
}
if (ya.isAutoRanging()) {
yData = new ArrayList<>();
}
if (xData != null || yData != null) {
for (XYChart.Series<Number, Number> series : getData()) {
for (XYChart.Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null) {
if (data.getExtraValue() instanceof CandleData) {
CandleData candleData = (CandleData) data.getExtraValue();
yData.add(candleData.high);
yData.add(candleData.low);
} else {
yData.add(data.getYValue());
}
}
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
}
/**
* Given graphical coordinates in the reference's coordinate system, returns x and y axis value as
* a point via the {@link Axis#getValueForDisplay(double)} and {@link Axis#toNumericValue(Object)}
* methods.
*/
@SuppressWarnings( "unchecked" )
public Point2D getDataCoordinates( double x, double y ) {
Axis xAxis = chart.getXAxis();
Axis yAxis = chart.getYAxis();
double xStart = getXShift( xAxis, referenceNode );
double yStart = getYShift( yAxis, referenceNode );
return new Point2D(
xAxis.toNumericValue( xAxis.getValueForDisplay( x - xStart ) ),
yAxis.toNumericValue( yAxis.getValueForDisplay( y - yStart ) )
);
}
private static <T> DoubleProperty toDoubleProperty( final Axis<T> axis, final Property<T> property ) {
final ChangeListener<Number>[] doubleChangeListenerAry = new ChangeListener[1];
final ChangeListener<T>[] realValListenerAry = new ChangeListener[1];
final DoubleProperty result = new SimpleDoubleProperty() {
/** Retain references so that they're not garbage collected. */
private final Object[] listeners = new Object[] {
doubleChangeListenerAry, realValListenerAry
};
};
doubleChangeListenerAry[0] = new ChangeListener<Number>() {
@Override
public void changed( ObservableValue<? extends Number> observable, Number oldValue, Number newValue ) {
property.removeListener( realValListenerAry[0] );
property.setValue( axis.toRealValue(
newValue == null ? null : newValue.doubleValue() )
);
property.addListener( realValListenerAry[0] );
}
};
result.addListener(doubleChangeListenerAry[0]);
realValListenerAry[0] = new ChangeListener<T>() {
@Override
public void changed( ObservableValue<? extends T> observable, T oldValue, T newValue ) {
result.removeListener( doubleChangeListenerAry[0] );
result.setValue( axis.toNumericValue( newValue ) );
result.addListener( doubleChangeListenerAry[0] );
}
};
property.addListener(realValListenerAry[0]);
return result;
}
/**
* Constructs a new <code>TimelineChart</code> component given a parent
* panel and axes.
*
* @param parent the panel containing this chart.
* @param xAxis the x axis.
* @param yAxis the y axis.
*
* @see TimelinePanel
* @see NumberAxis
*/
public TimelineChart(final TimelinePanel parent, final Axis<Number> xAxis, final NumberAxis yAxis) {
super(xAxis, yAxis);
this.parent = parent;
timeline = this;
this.xAxis = (NumberAxis) xAxis;
this.yAxis = yAxis;
// this.xAxis.setLowerBound(System.currentTimeMillis() - (31536000000l * 5));
// this.xAxis.setUpperBound(System.currentTimeMillis());
// setExtents(System.currentTimeMillis() - (31536000000l * 5), System.currentTimeMillis(), true);
tooltip = createTooltip();
formatAxes();
// Create the selection box:
selection = createSelectionRectange();
selection.setStroke(Color.SILVER);
selection.setStrokeWidth(2d);
final LinearGradient gradient
= new LinearGradient(0.0, 0.0, 0.0, 0.75, true, CycleMethod.NO_CYCLE, new Stop[]{
new Stop(0, Color.LIGHTGREY),
new Stop(1, Color.GREY.darker())
});
selection.setFill(gradient);
selection.setSmooth(true);
// Round the edges of the rectangle:
selection.setArcWidth(5.0);
selection.setArcHeight(5.0);
getChildren().add(selection);
// Install event handlers:
// Handles zooming for the timeline:
setOnScroll(new EventHandler<ScrollEvent>() {
@Override
public void handle(final ScrollEvent t) {
final double mouseX = t.getX();
performZoom(t, mouseX);
t.consume();
}
});
// Recognise mouse presses:
setOnMousePressed(timelineMouseHandler);
// Handles scrolling back and forth:
setOnMouseDragged(timelineMouseHandler);
// Handles determination of time under the mouse cursor, and sets tooltips accordingly:
setOnMouseMoved(timelineMouseHandler);
// Handles the change of the mouse cursor for the timeline:
setOnMouseEntered(timelineMouseHandler);
// Handles the release of selection events:
setOnMouseReleased(timelineMouseHandler);
setOnMouseClicked(timelineMouseHandler);
// Style the timeline:
setAnimated(true);
setLegendVisible(false);
setVerticalZeroLineVisible(false);
}
/**
* This is called when the range has been invalidated and we need to update
* it.
*
* If the axis are auto-ranging then we compile a list of all data that the
* given axis has to plot and call invalidateRange() on the axis passing it
* that data.
*/
@Override
protected void updateAxisRange() {
//THIS IS ONE EPIC DIRTY FIX FOR A WEIRD BUG IN JAVAFX!!
// turning axis.autoranging to false causes immense lag. but this method
// needs it to be false... so we set it to false
// then run this method once and set it to true then never run this method again. It seems to work.
if (!firstaxisUpdate) {
firstaxisUpdate = true;
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
shiftYAxis = this.getHeight() - yAxis.getHeight();
if (xa.isAutoRanging()) {
xData = new ArrayList<>();
}
if (ya.isAutoRanging()) {
yData = new ArrayList<>();
}
if (xData != null || yData != null) {
ObservableList<XYChart.Series<Number, Number>> list = getData();
if (list != null) {
for (Series<Number, Number> series : list) {
for (Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null && data.getExtraValue() instanceof Interaction) {
final Interaction intr = (Interaction) data.getExtraValue();
if (intr != null) {
yData.add(intr.getTopVertex().getDisplayPos());
yData.add(intr.getBottomVertex().getDisplayPos());
} else {
yData.add(data.getYValue());
}
}
}
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
this.xAxis.setAutoRanging(true);
this.yAxis.setAutoRanging(true);
}
}
public ScatterChart<X, Y> build(GraphReadMethods graph, ScatterPlotState state, Set<ScatterData> currentData, Set<ScatterData> currentSelectedData) {
currentData.clear();
currentSelectedData.clear();
XYChart.Series<X, Y> series = new XYChart.Series<>();
series.setName(state.getXAttribute() + " vs. " + state.getYAttribute());
final int selectedAttribute = graph.getAttribute(state.getElementType(), VisualConcept.VertexAttribute.SELECTED.getName());
final int labelAttribute = graph.getAttribute(state.getElementType(), VisualConcept.VertexAttribute.LABEL.getName());
final int elementCount = state.getElementType().getElementCount(graph);
for (int elementPosition = 0; elementPosition < elementCount; elementPosition++) {
final int elementId = state.getElementType().getElement(graph, elementPosition);
if (!state.isSelectedOnly() || graph.getBooleanValue(selectedAttribute, elementId)) {
final String elementLabel = graph.getStringValue(labelAttribute, elementId);
final X vertexXValue = xAxisBuilder.getValue(graph, state.getElementType(), state.getXAttribute().getId(), elementId);
final Y vertexYValue = yAxisBuilder.getValue(graph, state.getElementType(), state.getYAttribute().getId(), elementId);
final XYChart.Data<X, Y> data = new XYChart.Data<>(vertexXValue, vertexYValue);
final ScatterData scatterData = new ScatterData(elementId, elementLabel, data);
currentData.add(scatterData);
if (graph.getBooleanValue(selectedAttribute, elementId)) {
currentSelectedData.add(scatterData);
}
series.getData().add(data);
}
}
final Axis<X> xAxis = xAxisBuilder.build();
xAxis.setLabel(state.getXAttribute().getName());
final Axis<Y> yAxis = yAxisBuilder.build();
yAxis.setLabel(state.getYAttribute().getName());
final ScatterChart<X, Y> scatterChart = new ScatterChart<>(xAxis, yAxis);
scatterChart.setLegendVisible(false);
scatterChart.setHorizontalGridLinesVisible(false);
scatterChart.setVerticalGridLinesVisible(false);
scatterChart.getData().clear();
scatterChart.getData().add(series);
return scatterChart;
}
@Override
public Axis<Number> build() {
final LogarithmicAxis axis = new LogarithmicAxis();
axis.setAutoRanging(true);
return axis;
}
@Override
public Axis<String> build() {
final CategoryAxis axis = new CategoryAxis();
axis.setAutoRanging(true);
return axis;
}
@Override
public Axis<Date> build() {
final DateAxis axis = new DateAxis();
axis.setAutoRanging(true);
return axis;
}
public ChartLayoutAnimator(Parent nodeToLayout) {
this.nodeToLayout = nodeToLayout;
isAxis = nodeToLayout instanceof Axis;
}
public SmoothedChart(final Axis<X> xAxis, final Axis<Y> yAxis) {
super(xAxis, yAxis);
init();
registerListeners();
}
public SmoothedChart(final Axis<X> xAxis, final Axis<Y> yAxis, final ObservableList<Series<X, Y>> data) {
super(xAxis, yAxis, data);
init();
registerListeners();
}
@SuppressWarnings("unchecked")
public final B xAxis(final Axis AXIS) {
properties.put("xAxis", new SimpleObjectProperty(AXIS));
return (B)this;
}
@SuppressWarnings("unchecked")
public final B yAxis(final Axis AXIS) {
properties.put("yAxis", new SimpleObjectProperty(AXIS));
return (B)this;
}
public LabeledHorizontalBarChart(Axis xAxis, Axis yAxis) {
super(xAxis, yAxis);
init();
}
public LabeledBarChart(Axis xAxis, Axis yAxis) {
super(xAxis, yAxis);
init();
}
@Override
public void start(Stage stage) throws Exception {
loadData();
tree = new J48();
tree.buildClassifier(data);
noClassificationChart = buildChart("No Classification (click to add new data)", buildSingleSeries());
clusteredChart = buildChart("Clustered", buildClusteredSeries());
realDataChart = buildChart("Real Data (+ Decision Tree classification for new data)", buildLabeledSeries());
noClassificationChart.setOnMouseClicked(e -> {
Axis<Number> xAxis = noClassificationChart.getXAxis();
Axis<Number> yAxis = noClassificationChart.getYAxis();
Point2D mouseSceneCoords = new Point2D(e.getSceneX(), e.getSceneY());
double x = xAxis.sceneToLocal(mouseSceneCoords).getX();
double y = yAxis.sceneToLocal(mouseSceneCoords).getY();
Number xValue = xAxis.getValueForDisplay(x);
Number yValue = yAxis.getValueForDisplay(y);
reloadSeries(xValue, yValue);
});
Label lblDecisionTreeTitle = new Label("Decision Tree generated for the Iris dataset:");
Text txtTree = new Text(tree.toString());
String graph = tree.graph();
SwingNode sw = new SwingNode();
SwingUtilities.invokeLater(() -> {
TreeVisualizer treeVisualizer = new TreeVisualizer(null, graph, new PlaceNode2());
treeVisualizer.setPreferredSize(new Dimension(600, 500));
sw.setContent(treeVisualizer);
});
Button btnRestore = new Button("Restore original data");
Button btnSwapColors = new Button("Swap clustered chart colors");
StackPane spTree = new StackPane(sw);
spTree.setPrefWidth(300);
spTree.setPrefHeight(350);
VBox vbDecisionTree = new VBox(5, lblDecisionTreeTitle, new Separator(), spTree,
new HBox(10, btnRestore, btnSwapColors));
btnRestore.setOnAction(e -> {
loadData();
reloadSeries();
});
btnSwapColors.setOnAction(e -> swapClusteredChartSeriesColors());
lblDecisionTreeTitle.setTextFill(Color.DARKRED);
lblDecisionTreeTitle.setFont(Font.font(Font.getDefault().getFamily(), FontWeight.BOLD, FontPosture.ITALIC, 16));
txtTree.setTranslateX(100);
txtTree.setFont(Font.font(Font.getDefault().getFamily(), FontWeight.BOLD, FontPosture.ITALIC, 14));
txtTree.setLineSpacing(1);
txtTree.setTextAlignment(TextAlignment.LEFT);
vbDecisionTree.setTranslateY(20);
vbDecisionTree.setTranslateX(20);
GridPane gpRoot = new GridPane();
gpRoot.add(realDataChart, 0, 0);
gpRoot.add(clusteredChart, 1, 0);
gpRoot.add(noClassificationChart, 0, 1);
gpRoot.add(vbDecisionTree, 1, 1);
stage.setScene(new Scene(gpRoot));
stage.setTitle("Íris dataset clustering and visualization");
stage.show();
}
public SmoothedChart(final Axis<X> xAxis, final Axis<Y> yAxis) {
super(xAxis, yAxis);
init();
registerListeners();
}
public SmoothedChart(final Axis<X> xAxis, final Axis<Y> yAxis, final ObservableList<Series<X, Y>> data) {
super(xAxis, yAxis, data);
init();
registerListeners();
}