i have following code:
final TreeMap<Integer, Double> ADLMap = new TreeMap<>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final String currency = "currreny";
ADL(currency);
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<Number, Number>(xAxis, yAxis);
lineChart.setTitle("Stock Monitoring, 2010");
//defining a series
XYChart.Series ADLChart = new XYChart.Series();
XYChart.Series regularChart = new XYChart.Series();
ADLChart.setName("My portfolio");
chartMap.entrySet().forEach(entry -> regularChart.getData().add(new XYChart.Data(entry.getKey(), entry.getValue())));
//populating the series with data
ADLMap.entrySet().forEach(entry -> ADLChart.getData().add(new XYChart.Data(entry.getKey(), entry.getValue())));
System.out.println(ADLMap);
lineChart.setCreateSymbols(false);
Scene scene = new Scene(lineChart, 1200, 1000);
//lineChart.getData().add(regularChart);
lineChart.getData().add(ADLChart);
stage.setScene(scene);
stage.show();
final double SCALE_DELTA = 1.1;
lineChart.setOnScroll(new EventHandler<ScrollEvent>() {
public void handle(ScrollEvent event) {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
lineChart.setScaleX(lineChart.getScaleX() * scaleFactor);
lineChart.setScaleY(lineChart.getScaleY() * scaleFactor);
}
});
lineChart.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
if (event.getClickCount() == 2) {
lineChart.setScaleX(1.0);
lineChart.setScaleY(1.0);
}
}
});
}
private void ADL(final String currency) {
double counter = -4000000.0;
int mapCounter = 0;
while (counter < 4000000) {
ADLMap.put(mapCounter++, counter++);
}
}
the Map contains following values:
keys n+1 n€IN
Values from range from -10.000.000 to + 10.000.000
My Problem: It doesn't plot values at all. At least i cannot see any.
Can someone please help?
My mistake was that a complex algorithm produced an inifnity nuber which was placed in the TreeMap. The Graph couldn't plot it ofc.
Related
I have JavaFX project and I need coordinates of each dot in the orange line from image bellow.
https://i.stack.imgur.com/A7zVa.png
I spent a lot of hours googling but I can not find a solution.
It is a simple application. I need those coordinates beacuse I need to make G CODE for CNC machine.
My Code is:
public class KS2 extends Application {
private LineChart<Number, Number> chart;
#Override
public void start(Stage primaryStage) throws Exception {
final NumberAxis xAxis = new NumberAxis(0.0, 150.0, 2);
final NumberAxis yAxis = new NumberAxis(0.0, 100.0, 2);
// Flip the axis
// yAxis.setScaleY(-1);
Rectangle r = new Rectangle(0, 0, 80, 50);
r.setFill(Color.TRANSPARENT);
r.setStrokeWidth(0.5);
r.setStroke(Color.BLACK);
this.chart = new LineChart<Number, Number>(xAxis, yAxis) {
#Override
public void layoutPlotChildren() {
super.layoutPlotChildren();
r.getTransforms().setAll(chartDisplayTransform(xAxis, yAxis));
// note nodes don't get removed from the plot children, and this method may be
// called often:
if (!getPlotChildren().contains(r)) {
getPlotChildren().add(r);
}
}
};
this.chart.setAnimated(false);
XYChart.Series series = new XYChart.Series();
series.getData().add(new XYChart.Data(54, 50));
series.getData().add(new XYChart.Data(80, 0));
//series.setName("My portfolio");
this.chart.getData().add(series);
VBox vbox = new VBox(this.chart);
Scene scene = new Scene(vbox, 400, 200);
primaryStage.setScene(scene);
primaryStage.setHeight(600);
primaryStage.setWidth(400);
primaryStage.show();
}
private Transform chartDisplayTransform(NumberAxis xAxis, NumberAxis yAxis) {
return new Affine(xAxis.getScale(), 0, xAxis.getDisplayPosition(0), 0, yAxis.getScale(),
yAxis.getDisplayPosition(0));
}
public static void main(String[] args) {
Application.launch(args);
}
}
For my project I have to realize a zoomable lineChart. I found many code of zoom but none of them is working. In fact, I think that the problem is the fact that my windows is divided in many windows, and in 4 of these windows, there are the charts. Thus, the zoom looks like it works but when I use the zoom, the new axis is not what it's supposed to be :
1) I'm choosing where i want to zoom :
https://imgur.com/a/j6LwrsH
2) chart is "reloading" with new axis :
https://imgur.com/a/SyeqnEV
public class ZoomableLineChart<X extends Number, Y extends Number> extends LineChart<X, Y> {
private final Region userTrackArea = new Region();
XYChart.Series series;
double valueX;
double valueY;
BorderPane chartContainer;
public ZoomableLineChart( Axis xAxis, Axis yAxis, XYChart.Series series, BorderPane border, double valueX, double valueY ) {
super(xAxis, yAxis);
this.chartContainer = border;
this.valueX = valueX;
this.valueX = valueX;
final LineChart<Number, Number> chart = createChart();
chart.getData().add(series);
final StackPane StackChartContainer = new StackPane();
StackChartContainer.getChildren().add(chart);
StackChartContainer.setOnMouseClicked(this::handleMouseTrackingClicked);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
StackChartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
final HBox controls = new HBox();
controls.setSpacing(10);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
final Button zoomButton = new Button("Zoom");
final Button resetButton = new Button("Reset");
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect, chart);
}
});
resetButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final NumberAxis xAxis = (NumberAxis)chart.getXAxis();
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
final NumberAxis yAxis = (NumberAxis)chart.getYAxis();
yAxis.setLowerBound(0);
yAxis.setUpperBound(100);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
});
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
controls.getChildren().add(zoomButton);
controls.getChildren().add(resetButton);
border.setCenter(StackChartContainer);
border.setBottom(controls);
}
private void handleMouseTrackingClicked(final MouseEvent mouseEvent) {
final NumberAxis xAxis = (NumberAxis) getXAxis();
final NumberAxis yAxis = (NumberAxis) getYAxis();
final double mouseX = mouseEvent.getX();
final double mouseY = mouseEvent.getY();
valueX = xAxis.getValueForDisplay(mouseX).doubleValue();
valueY = yAxis.getValueForDisplay(mouseY).doubleValue();
// System.out.printf("Mouse %f %f -> value %f (%f %f) %f (%f %f)", mouseX, mouseY,
// valueX, xAxis.getLowerBound(), xAxis.getUpperBound(),
// valueY, yAxis.getLowerBound(), yAxis.getUpperBound()).println();
System.out.println(valueX + "," + valueY);
}
public static BorderPane creerGrapheZoomable(XYChart.Series series, BorderPane chartContainer) {
final LineChart<Number, Number> chart = createChart();
chart.getData().add(series);
final StackPane StackChartContainer = new StackPane();
StackChartContainer.getChildren().add(chart);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
StackChartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
final HBox controls = new HBox();
controls.setSpacing(10);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
final Button zoomButton = new Button("Zoom");
final Button resetButton = new Button("Reset");
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect, chart);
}
});
resetButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final NumberAxis xAxis = (NumberAxis)chart.getXAxis();
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
final NumberAxis yAxis = (NumberAxis)chart.getYAxis();
yAxis.setLowerBound(0);
yAxis.setUpperBound(100);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
});
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
controls.getChildren().add(zoomButton);
controls.getChildren().add(resetButton);
chartContainer.setCenter(StackChartContainer);
chartContainer.setBottom(controls);
return chartContainer;
}
private static LineChart<Number, Number> createChart() {
final NumberAxis xAxis = createAxis();
final NumberAxis yAxis = createAxis();
final LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
chart.setAnimated(false);
chart.setCreateSymbols(false);
return chart ;
}
private static NumberAxis createAxis() {
final NumberAxis xAxis = new NumberAxis();
xAxis.setAutoRanging(false);
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
return xAxis;
}
private static void setUpZooming(final Rectangle rect, final Node zoomingNode) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Mouse Event OK");
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
System.out.println(event.getX() + " " + event.getY() );
rect.setWidth(0);
rect.setHeight(0);
}
});
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double x = event.getX();
double y = event.getY();
rect.setX(Math.min(x, mouseAnchor.get().getX()));
rect.setY(Math.min(y, mouseAnchor.get().getY()));
System.out.println(x + ' ' + y);
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
}
});
}
private static void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) {
Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY());
Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight());
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
Point2D yAxisInScene = yAxis.localToScene(0, 0);
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
Point2D xAxisInScene = xAxis.localToScene(0, 0);
double xOffset = zoomTopLeft.getX() - yAxisInScene.getX() ;
double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
double xAxisScale = xAxis.getScale();
double yAxisScale = yAxis.getScale();
xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale);
yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale);
System.out.println(yAxis.getLowerBound() + " , " + yAxis.getUpperBound());
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
public int getValueX() {
return (int) valueX;
}
public int getValueY() {
return (int) valueY;
}
}
I would like to create a chart in JavaFX. I have such a file:
And I don't know how to put "date" for x or y axis. How should I do it.
I have something like this, but I'm not sure if it is properly.
draw.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
newWindow.setTitle("Chart");
//defining the axes
if(choice1.getValue().toString()=="val" && choice2.getValue().toString()=="total"){}
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<Number,Number>(xAxis,yAxis);
lineChart.setTitle("Chart");
//defining a series
XYChart.Series series = new XYChart.Series();
series.setName("My portfolio");
//populating the series with data
for(int i=0; i<d.size(); i++){
series.getData().add(new XYChart.Data(d.get(choice1.getValue().toString()).get(i), d.get(choice2.getValue().toString()).get(i)));
}
Scene scene = new Scene(lineChart,800,600);
lineChart.getData().add(series);
newWindow.setScene(scene);
newWindow.show();
}
});
LineChart linechart = new LineChart(xAxis, yAxis);
ChoiceBox choice1 = new ChoiceBox(FXCollections.observableArrayList(
"id", "date", "total", "val")
);
ChoiceBox choice2 = new ChoiceBox(FXCollections.observableArrayList(
"id", "date", "total", "val")
);
Button draw = new Button("Draw!");
HBox hb = new HBox(30);
hb.getChildren().addAll(choice1, choice2);
I create an example that demo's your chart. Since you attached your data as an image, I had to create fake data. In this example, I created a DataFrame class to hold each line of data. I added this data to a List named fakeData. I then create and name each Series that will be added to the Chart. After that, I filter the fake data by ID. If the filtered ID equals the Series name, I added the data to the Series. This chart shows Date to Total. If you need Date to Val, replace seriesList.get(i).getData().add(new XYChart.Data(dataFrame.getDate(), dataFrame.getTotal())); with seriesList.get(i).getData().add(new XYChart.Data(dataFrame.getDate(), dataFrame.getVal()));.
Main
import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
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;
public class LineChartSample extends Application
{
String alphbets = "abcdefghij";
#Override
public void start(Stage stage)
{
List<DataFrame> fakeData = generateFakeDataFrames();
stage.setTitle("Line Chart Sample");
//defining the axes
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Date");
//creating the chart
final LineChart<String, Number> lineChart = new LineChart(xAxis, yAxis);
lineChart.setTitle("Fake Chart");
//defining a series
List<XYChart.Series<String, Number>> seriesList = new ArrayList();
for (int i = 0; i < alphbets.length(); i++) {
XYChart.Series<String, Number> series = new XYChart.Series();
series.setName(alphbets.charAt(i) + "");
seriesList.add(series);
}
for (int i = 0; i < seriesList.size(); i++) {
char tempChar = alphbets.charAt(i);
//Filter the fake data
List<DataFrame> subList = fakeData.stream().filter((t) -> {
return t.getId() == tempChar;
}).collect(Collectors.toList());
//Add the filtered data to the correct series
for (DataFrame dataFrame : subList) {
System.out.println(seriesList.get(i).getName() + " :" + dataFrame.getId() + " " + dataFrame.getDate() + " " + dataFrame.getTotal());//Check to see if data is correct.
seriesList.get(i).getData().add(new XYChart.Data(dataFrame.getDate(), dataFrame.getTotal()));
}
}
Scene scene = new Scene(lineChart, 800, 600);
lineChart.getData().addAll(seriesList);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
public List<LocalDate> createDates()
{
List<LocalDate> localDates = new ArrayList();
LocalDate localDate = LocalDate.of(1985, Month.FEBRUARY, 4);
for (int i = 0; i <= 4; i++) {
localDates.add(localDate.plusDays(i));
}
return localDates;
}
public List<DataFrame> generateFakeDataFrames()
{
Random random = new Random();
List<DataFrame> dataFrames = new ArrayList();
List<LocalDate> dates = createDates();
for (int i = 0; i < 50; i++) {
double total = (random.nextDouble() * 2 - 1) * 3;
double val = (random.nextDouble() * 2 - 1) * 2000;
dataFrames.add(new DataFrame(alphbets.charAt(i % 10), dates.get(i / 10).toString(), total, val));
}
return dataFrames;
}
}
DataFrame Class
/**
*
* #author blj0011
*/
public class DataFrame
{
private char id;
private String date;
private double total;
private double val;
public DataFrame(char id, String date, double total, double val)
{
this.id = id;
this.date = date;
this.total = total;
this.val = val;
}
public double getVal()
{
return val;
}
public void setVal(double val)
{
this.val = val;
}
public char getId()
{
return id;
}
public void setId(char id)
{
this.id = id;
}
public String getDate()
{
return date;
}
public void setDate(String date)
{
this.date = date;
}
public double getTotal()
{
return total;
}
public void setTotal(double total)
{
this.total = total;
}
#Override
public String toString()
{
return id + ", " + date + ", " + total + ", " + date + ", " + val;
}
}
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
Expected result
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
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;
}
I have a dynamic Area Chart and I want to add a green point on the last point where my chart is displayed(the recent value on my chart).For example with displaying the line border i want a big green point to be displayed on my area chart? I'm working with an example shown here .
How to do this? There's my code:
public class essaijfree2 extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 2 * 60;
private static final int FAST = 100;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
public essaijfree2(final String title) {
super(title);
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(1, COUNT, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));
dataset.addSeries(gaussianData(), 0, "Gaussian data");
JFreeChart chart = createChart(dataset);
XYPlot xyPlot = (XYPlot) chart.getPlot();
XYDifferenceRenderer r = new XYDifferenceRenderer(Color.green,Color.red, true);
xyPlot.setRenderer(r);
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
dataset.advanceTime();
dataset.appendData(newData);
}
});
}
private float randomValue() {
return (float) (random.nextGaussian() * MINMAX / 3);
}
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
a[i] = randomValue();
}
return a;
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createXYAreaChart(
TITLE, "hh:mm:ss", "milliVolts", dataset,PlotOrientation.VERTICAL, true, true, false);
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
ValueAxis range = plot.getRangeAxis();
range.setRange(-MINMAX, MINMAX);
return result;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
essaijfree2 demo = new essaijfree2(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
I'd look at an XYShapeAnnotation positioned at the coordinates of the last added datum. Some examples are seen here. You can use a RadialGradientPaint with varying alpha to get the halo effect. I've never tried doing it dynamically, but XYPlot includes the methods addAnnotation() and removeAnnotation(); both notify all registered listeners.
I recommend to create your own XYAnnotation that a) doesn´t used predefined x and y values but instead picks them from the dataset and that b) uses a shape whose bounds are defined in Java2D space so that the shape size remains constant when you zoom in.
Here is an example:
public class ItemAnnotationDemo {
public static void main(String[] args) {
int count = 20;
double[][] data = new double[2][count];
for(int i = 0; i < count; i++){
data[0][i] = i;
data[1][i] = i;
}
DefaultXYDataset dataset = new DefaultXYDataset();
dataset.addSeries("Values", data);
NumberAxis xAxis = new NumberAxis("x axis");
NumberAxis yAxis = new NumberAxis("y axis");
XYItemRenderer renderer = new XYLineAndShapeRenderer(true, true);
renderer.addAnnotation(new XYItemAnnotation(
new Rectangle2D.Double(-10, -8, 20, 16),
new Color(128,128,128,128),
new BasicStroke(3.0f),
Color.RED,0,Integer.MAX_VALUE));
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart(plot);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ChartPanel(chart));
frame.pack();
frame.setVisible(true);
}
}
class XYItemAnnotation extends AbstractXYAnnotation{
private Shape shape;
private Paint outline;
private Paint fill;
private Stroke stroke;
private int si;
private int ii;
public XYItemAnnotation(Shape shape, Paint fillPaint, Stroke outlineStroke, Paint outlinePaint, int seriesIndex, int itemIndex){
super();
this.shape = shape;
this.fill = fillPaint;
this.stroke = outlineStroke;
this.outline = outlinePaint;
this.si = seriesIndex;
this.ii = itemIndex;
}
public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int datasetIndex, PlotRenderingInfo info){
XYDataset dataset = plot.getDataset(datasetIndex);
if(dataset == null) return;
if(si > dataset.getSeriesCount() - 1 ) return;
int item = Math.max(0, ii);
item = Math.min(item, dataset.getItemCount(si) - 1);
double dx = dataset.getXValue(si, item);
double dy = dataset.getYValue(si, item);
if(Double.isNaN(dx) || Double.isNaN(dy)) return;
if(!domainAxis.getRange().contains(dx) || !rangeAxis.getRange().contains(dy)) return;
PlotOrientation orientation = plot.getOrientation();
RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
plot.getDomainAxisLocation(), orientation);
RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
plot.getRangeAxisLocation(), orientation);
double jx = domainAxis.valueToJava2D(dx, dataArea, domainEdge);
double jy = rangeAxis.valueToJava2D(dy, dataArea, rangeEdge);
if (orientation == PlotOrientation.HORIZONTAL) {
double temp = jx;
jx = jy;
jy = temp;
}
Shape trans = ShapeUtilities.createTranslatedShape(shape, jx, jy);
g2.setPaint(fill);
g2.fill(trans);
g2.setPaint(outline);
g2.setStroke(stroke);
g2.draw(trans);
}
}