JavaFx create a chart from dataframe - java

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;
}
}

Related

I'm trying to print a receipt on a seperate screen

I am trying to make a cashier program that prints the chosen products with the price on a separate screen. I'm almost there but can't figure out how to do the last part.
When i choose my products i get these returns:
[Ljava.lang.String;#3774e19
instead of like:
Pizza Margherita - (eur)6.-
This is my code:
public class Main extends Application {
int screenWidth = 500;
int screenHeight = 300;
int pizzaCounter = 0;
int totalPrice = 0;
double korting = 1.0;
int buttonCounter = 0;
int count = 0;
Text pizzaCounterText = new Text();
final StackPane root = new StackPane();
final StackPane root2 = new StackPane();
public static final ObservableList data = FXCollections.observableArrayList();
ListView<String> receipt = new ListView<>(data);
Button[] buttons = new Button[8];
String[] producten = new String[8];
String[] totaal = new String[200];
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Kassa");
TextArea textArea = new TextArea();
VBox vbox = new VBox(textArea);
receipt.setEditable(false);
receipt.setStyle("-fx-font-size:20.0;");
root2.getChildren().add(receipt);
HBox hbox = new HBox();
Button discount = new Button("10% korting");
Button afrekenen = new Button("Afrekenen!");
discount.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (korting == 1) {
korting = 0.9;
} else {
korting = 1;
}
}
});
afrekenen.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.setScene(new Scene(root2, screenWidth, screenHeight));
primaryStage.show();
}
});
hbox.getChildren().addAll(discount, afrekenen);
Scene scene = new Scene(vbox, -310, -40);
primaryStage.setScene(scene);
primaryStage.show();
pizzaCounterText.setText("Items bought: " + Integer.toString(pizzaCounter) + "\nTotal: " + Integer.toString(totalPrice) + ",--");
producten[0] = "Pizza Margherita-6";
producten[1] = "Pizza Funghi-10";
producten[2] = "Pizza Prociutto-8";
producten[3] = "Pizza Hawaii-11";
producten[4] = "Pizza Shoarma-12";
producten[5] = "Pizza Salami-10";
producten[6] = "Cola Regular-2";
producten[7] = "Cola Zero-2";
// maakt de buttons
for (int i = 0; i < 8; i++) {
String[] parts = producten[i].split("-");
buttons[i] = createButton(i, parts[0], Integer.parseInt(parts[1]));
}
root.setAlignment(TOP_LEFT);
pizzaCounterText.setTranslateX(screenWidth - 300);
pizzaCounterText.setTranslateY(screenHeight - 40);
vbox.setTranslateX(screenWidth - 500);
vbox.setTranslateY(screenHeight - 40);
hbox.setTranslateX(screenWidth - 350);
hbox.setTranslateY(screenHeight - 90);
root.getChildren().add(hbox);
root.getChildren().add(vbox);
root.getChildren().add(pizzaCounterText);
primaryStage.setScene(new Scene(root, screenWidth, screenHeight));
primaryStage.show();
}
public Button createButton(int index, String name, int price) {
Button btn = new Button();
btn.setText(name);
btn.setMinWidth(100);
int column = buttonCounter % 3;
int row = buttonCounter / 3;
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
totalPrice += price;
pizzaCounter++;
do {
totaal[count] = name;
count++;
data.add(producten);
} while (bonActive());
pizzaCounterText.setText("Items bought: " + Integer.toString(pizzaCounter) + "\nTotal: " + Double.toString(totalPrice * korting));
System.out.println(Arrays.deepToString(totaal));
}
});
btn.setTranslateX(50 + 150 * column);
btn.setTranslateY(35 + 50 * row);
root.getChildren().add(btn);
buttonCounter++;
return btn;
}
public boolean bonActive() {
return false;
}
public void bon() {
for (int i = 0; i < totaal.length; i++) {
System.out.println(totaal[i]);
}
}
}
You are adding on the ObservableList data every time the array String[] producten so it's displaying this object. I think what you want to do is something like :
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
totalPrice += price;
pizzaCounter++;
do {
totaal[count] = name;
count++;
data.add(name + " " + price);
} while (bonActive());
pizzaCounterText.setText("Items bought: " + Integer.toString(pizzaCounter) + "\nTotal: " + Double.toString(totalPrice * korting));
System.out.println(Arrays.deepToString(totaal));
}
});
But I think you should do some Pojo like :
static class Pizza {
String name;
int price;
public Pizza(String name, int price) {
this.name = name;
this.price = price;
}
#Override
public String toString() {
return "Pizza{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
And also have a strong type on your generic object : ObservableList<Pizza> data = FXCollections.observableArrayList();

ScalaFX/JavaFX 8 get nearest Nodes

Currently experimenting with ScalaFX a bit.
Imagine the following:
I have some nodes and they are connected by some edges.
Now when I click the mousebutton I want to select the ones next to the mouse click, e.g. if I click between 1 and 2, I want those two to be selected, if I click before 0, only that one (as it's the first) etc.
Currently (and just as a proof of concept) I am doing this by adding in some helper structures. I have a HashMap of type [Index, Node] and select them like so:
wrapper.onMouseClicked = (mouseEvent: MouseEvent) =>
{
val lowerIndex: Int = (mouseEvent.sceneX).toString.charAt(0).asDigit
val left = nodes.get(lowerIndex)
val right = nodes.get(lowerIndex+1)
left.get.look.setStyle("-fx-background-color: orange;")
right.get.look.setStyle("-fx-background-color: orange;")
}
this does it's just, but I need to have an additional datastructure and it will get really tedious in 2D, like when I have a Y coordinate as well.
What I would prefer would be some method like mentioned in
How to detect Node at specific point in JavaFX?
or
JavaFX 2.2 get node at coordinates (visual tree hit testing)
These questions are based on older versions of JavaFX and use deprecated methods.
I could not find any replacement or solution in ScalaFX 8 so far. Is there a nice way to get all the nodes within a certain radius?
So "Nearest neighbor search" is the general problem you are trying to solve.
Your problem statement is a bit short on details. E.g., are nodes equidistant from each other? are nodes arranged in a grid pattern or randomly? is the node distance modeled based upon a point at the node center, a surrounding box, the actual closest point on an arbitrarily shaped node? etc.
I'll assume randomly placed shapes that may overlap, and picking is not based upon painting order, but on the closest corners of the bounding boxes of shapes. A more accurate picker might work by comparing the clicked point against against an elliptical area surrounding the actual shape rather than the shapes bounding box (as the current picker will be a bit finicky to use for things like overlapping diagonal lines).
A k-d tree algorithm or an R-tree could be used, but in general a linear brute force search will probably just work fine for most applications.
Sample brute force solution algorithm
private Node findNearestNode(ObservableList<Node> nodes, double x, double y) {
Point2D pClick = new Point2D(x, y);
Node nearestNode = null;
double closestDistance = Double.POSITIVE_INFINITY;
for (Node node : nodes) {
Bounds bounds = node.getBoundsInParent();
Point2D[] corners = new Point2D[] {
new Point2D(bounds.getMinX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMaxY()),
new Point2D(bounds.getMinX(), bounds.getMaxY()),
};
for (Point2D pCompare: corners) {
double nextDist = pClick.distance(pCompare);
if (nextDist < closestDistance) {
closestDistance = nextDist;
nearestNode = node;
}
}
}
return nearestNode;
}
Executable Solution
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.*;
import java.util.Random;
public class FindNearest extends Application {
private static final int N_SHAPES = 10;
private static final double W = 600, H = 400;
private ShapeMachine machine;
public static void main(String[] args) {
launch(args);
}
#Override
public void init() throws MalformedURLException, URISyntaxException {
double maxShapeSize = W / 8;
double minShapeSize = maxShapeSize / 2;
machine = new ShapeMachine(W, H, maxShapeSize, minShapeSize);
}
#Override
public void start(final Stage stage) throws IOException, URISyntaxException {
Pane pane = new Pane();
pane.setPrefSize(W, H);
for (int i = 0; i < N_SHAPES; i++) {
pane.getChildren().add(machine.randomShape());
}
pane.setOnMouseClicked(event -> {
Node node = findNearestNode(pane.getChildren(), event.getX(), event.getY());
highlightSelected(node, pane.getChildren());
});
Scene scene = new Scene(pane);
configureExitOnAnyKey(stage, scene);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
private void highlightSelected(Node selected, ObservableList<Node> children) {
for (Node node: children) {
node.setEffect(null);
}
if (selected != null) {
selected.setEffect(new DropShadow(10, Color.YELLOW));
}
}
private Node findNearestNode(ObservableList<Node> nodes, double x, double y) {
Point2D pClick = new Point2D(x, y);
Node nearestNode = null;
double closestDistance = Double.POSITIVE_INFINITY;
for (Node node : nodes) {
Bounds bounds = node.getBoundsInParent();
Point2D[] corners = new Point2D[] {
new Point2D(bounds.getMinX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMaxY()),
new Point2D(bounds.getMinX(), bounds.getMaxY()),
};
for (Point2D pCompare: corners) {
double nextDist = pClick.distance(pCompare);
if (nextDist < closestDistance) {
closestDistance = nextDist;
nearestNode = node;
}
}
}
return nearestNode;
}
private void configureExitOnAnyKey(final Stage stage, Scene scene) {
scene.setOnKeyPressed(keyEvent -> stage.hide());
}
}
Auxiliary random shape generation class
This class is not key to the solution, it just generates some shapes for testing.
class ShapeMachine {
private static final Random random = new Random();
private final double canvasWidth, canvasHeight, maxShapeSize, minShapeSize;
ShapeMachine(double canvasWidth, double canvasHeight, double maxShapeSize, double minShapeSize) {
this.canvasWidth = canvasWidth;
this.canvasHeight = canvasHeight;
this.maxShapeSize = maxShapeSize;
this.minShapeSize = minShapeSize;
}
private Color randomColor() {
return Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256), 0.1 + random.nextDouble() * 0.9);
}
enum Shapes {Circle, Rectangle, Line}
public Shape randomShape() {
Shape shape = null;
switch (Shapes.values()[random.nextInt(Shapes.values().length)]) {
case Circle:
shape = randomCircle();
break;
case Rectangle:
shape = randomRectangle();
break;
case Line:
shape = randomLine();
break;
default:
System.out.println("Unknown Shape");
System.exit(1);
}
Color fill = randomColor();
shape.setFill(fill);
shape.setStroke(deriveStroke(fill));
shape.setStrokeWidth(deriveStrokeWidth(shape));
shape.setStrokeLineCap(StrokeLineCap.ROUND);
shape.relocate(randomShapeX(), randomShapeY());
return shape;
}
private double deriveStrokeWidth(Shape shape) {
return Math.max(shape.getLayoutBounds().getWidth() / 10, shape.getLayoutBounds().getHeight() / 10);
}
private Color deriveStroke(Color fill) {
return fill.desaturate();
}
private double randomShapeSize() {
double range = maxShapeSize - minShapeSize;
return random.nextDouble() * range + minShapeSize;
}
private double randomShapeX() {
return random.nextDouble() * (canvasWidth + maxShapeSize) - maxShapeSize / 2;
}
private double randomShapeY() {
return random.nextDouble() * (canvasHeight + maxShapeSize) - maxShapeSize / 2;
}
private Shape randomLine() {
int xZero = random.nextBoolean() ? 1 : 0;
int yZero = random.nextBoolean() || xZero == 0 ? 1 : 0;
int xSign = random.nextBoolean() ? 1 : -1;
int ySign = random.nextBoolean() ? 1 : -1;
return new Line(0, 0, xZero * xSign * randomShapeSize(), yZero * ySign * randomShapeSize());
}
private Shape randomRectangle() {
return new Rectangle(0, 0, randomShapeSize(), randomShapeSize());
}
private Shape randomCircle() {
double radius = randomShapeSize() / 2;
return new Circle(radius, radius, radius);
}
}
Further example placing objects in a zoomable/scrollable area
This solution uses the nearest node solution code from above and combines it with the zoomed node in a ScrollPane code from: JavaFX correct scaling. The purpose is to demonstrate that the choosing algorithm works even on nodes which have had a scaling transform applied to them (because it is based upon boundsInParent). The code is just meant as a proof of concept and not as a stylistic sample of how to structure the functionality into a class domain model :-)
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.*;
import javafx.collections.ObservableList;
import javafx.event.*;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
public class GraphicsScalingApp extends Application {
private static final int N_SHAPES = 10;
private static final double W = 600, H = 400;
private ShapeMachine machine;
public static void main(String[] args) {
launch(args);
}
#Override
public void init() throws MalformedURLException, URISyntaxException {
double maxShapeSize = W / 8;
double minShapeSize = maxShapeSize / 2;
machine = new ShapeMachine(W, H, maxShapeSize, minShapeSize);
}
#Override
public void start(final Stage stage) {
Pane pane = new Pane();
pane.setPrefSize(W, H);
for (int i = 0; i < N_SHAPES; i++) {
pane.getChildren().add(machine.randomShape());
}
pane.setOnMouseClicked(event -> {
Node node = findNearestNode(pane.getChildren(), event.getX(), event.getY());
System.out.println("Found: " + node + " at " + event.getX() + "," + event.getY());
highlightSelected(node, pane.getChildren());
});
final Group group = new Group(
pane
);
Parent zoomPane = createZoomPane(group);
VBox layout = new VBox();
layout.getChildren().setAll(createMenuBar(stage, group), zoomPane);
VBox.setVgrow(zoomPane, Priority.ALWAYS);
Scene scene = new Scene(layout);
stage.setTitle("Zoomy");
stage.getIcons().setAll(new Image(APP_ICON));
stage.setScene(scene);
stage.show();
}
private Parent createZoomPane(final Group group) {
final double SCALE_DELTA = 1.1;
final StackPane zoomPane = new StackPane();
zoomPane.getChildren().add(group);
final ScrollPane scroller = new ScrollPane();
final Group scrollContent = new Group(zoomPane);
scroller.setContent(scrollContent);
scroller.viewportBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> observable,
Bounds oldValue, Bounds newValue) {
zoomPane.setMinSize(newValue.getWidth(), newValue.getHeight());
}
});
scroller.setPrefViewportWidth(256);
scroller.setPrefViewportHeight(256);
zoomPane.setOnScroll(new EventHandler<ScrollEvent>() {
#Override
public void handle(ScrollEvent event) {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA
: 1 / SCALE_DELTA;
// amount of scrolling in each direction in scrollContent coordinate
// units
Point2D scrollOffset = figureScrollOffset(scrollContent, scroller);
group.setScaleX(group.getScaleX() * scaleFactor);
group.setScaleY(group.getScaleY() * scaleFactor);
// move viewport so that old center remains in the center after the
// scaling
repositionScroller(scrollContent, scroller, scaleFactor, scrollOffset);
}
});
// Panning via drag....
final ObjectProperty<Point2D> lastMouseCoordinates = new SimpleObjectProperty<Point2D>();
scrollContent.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
lastMouseCoordinates.set(new Point2D(event.getX(), event.getY()));
}
});
scrollContent.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double deltaX = event.getX() - lastMouseCoordinates.get().getX();
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
double deltaH = deltaX * (scroller.getHmax() - scroller.getHmin()) / extraWidth;
double desiredH = scroller.getHvalue() - deltaH;
scroller.setHvalue(Math.max(0, Math.min(scroller.getHmax(), desiredH)));
double deltaY = event.getY() - lastMouseCoordinates.get().getY();
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
double deltaV = deltaY * (scroller.getHmax() - scroller.getHmin()) / extraHeight;
double desiredV = scroller.getVvalue() - deltaV;
scroller.setVvalue(Math.max(0, Math.min(scroller.getVmax(), desiredV)));
}
});
return scroller;
}
private Point2D figureScrollOffset(Node scrollContent, ScrollPane scroller) {
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
double hScrollProportion = (scroller.getHvalue() - scroller.getHmin()) / (scroller.getHmax() - scroller.getHmin());
double scrollXOffset = hScrollProportion * Math.max(0, extraWidth);
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
double vScrollProportion = (scroller.getVvalue() - scroller.getVmin()) / (scroller.getVmax() - scroller.getVmin());
double scrollYOffset = vScrollProportion * Math.max(0, extraHeight);
return new Point2D(scrollXOffset, scrollYOffset);
}
private void repositionScroller(Node scrollContent, ScrollPane scroller, double scaleFactor, Point2D scrollOffset) {
double scrollXOffset = scrollOffset.getX();
double scrollYOffset = scrollOffset.getY();
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
if (extraWidth > 0) {
double halfWidth = scroller.getViewportBounds().getWidth() / 2;
double newScrollXOffset = (scaleFactor - 1) * halfWidth + scaleFactor * scrollXOffset;
scroller.setHvalue(scroller.getHmin() + newScrollXOffset * (scroller.getHmax() - scroller.getHmin()) / extraWidth);
} else {
scroller.setHvalue(scroller.getHmin());
}
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
if (extraHeight > 0) {
double halfHeight = scroller.getViewportBounds().getHeight() / 2;
double newScrollYOffset = (scaleFactor - 1) * halfHeight + scaleFactor * scrollYOffset;
scroller.setVvalue(scroller.getVmin() + newScrollYOffset * (scroller.getVmax() - scroller.getVmin()) / extraHeight);
} else {
scroller.setHvalue(scroller.getHmin());
}
}
private SVGPath createCurve() {
SVGPath ellipticalArc = new SVGPath();
ellipticalArc.setContent("M10,150 A15 15 180 0 1 70 140 A15 25 180 0 0 130 130 A15 55 180 0 1 190 120");
ellipticalArc.setStroke(Color.LIGHTGREEN);
ellipticalArc.setStrokeWidth(4);
ellipticalArc.setFill(null);
return ellipticalArc;
}
private SVGPath createStar() {
SVGPath star = new SVGPath();
star.setContent("M100,10 L100,10 40,180 190,60 10,60 160,180 z");
star.setStrokeLineJoin(StrokeLineJoin.ROUND);
star.setStroke(Color.BLUE);
star.setFill(Color.DARKBLUE);
star.setStrokeWidth(4);
return star;
}
private MenuBar createMenuBar(final Stage stage, final Group group) {
Menu fileMenu = new Menu("_File");
MenuItem exitMenuItem = new MenuItem("E_xit");
exitMenuItem.setGraphic(new ImageView(new Image(CLOSE_ICON)));
exitMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
stage.close();
}
});
fileMenu.getItems().setAll(exitMenuItem);
Menu zoomMenu = new Menu("_Zoom");
MenuItem zoomResetMenuItem = new MenuItem("Zoom _Reset");
zoomResetMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.ESCAPE));
zoomResetMenuItem.setGraphic(new ImageView(new Image(ZOOM_RESET_ICON)));
zoomResetMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
group.setScaleX(1);
group.setScaleY(1);
}
});
MenuItem zoomInMenuItem = new MenuItem("Zoom _In");
zoomInMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.I));
zoomInMenuItem.setGraphic(new ImageView(new Image(ZOOM_IN_ICON)));
zoomInMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
group.setScaleX(group.getScaleX() * 1.5);
group.setScaleY(group.getScaleY() * 1.5);
}
});
MenuItem zoomOutMenuItem = new MenuItem("Zoom _Out");
zoomOutMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.O));
zoomOutMenuItem.setGraphic(new ImageView(new Image(ZOOM_OUT_ICON)));
zoomOutMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
group.setScaleX(group.getScaleX() * 1 / 1.5);
group.setScaleY(group.getScaleY() * 1 / 1.5);
}
});
zoomMenu.getItems().setAll(zoomResetMenuItem, zoomInMenuItem,
zoomOutMenuItem);
MenuBar menuBar = new MenuBar();
menuBar.getMenus().setAll(fileMenu, zoomMenu);
return menuBar;
}
private void highlightSelected(Node selected, ObservableList<Node> children) {
for (Node node : children) {
node.setEffect(null);
}
if (selected != null) {
selected.setEffect(new DropShadow(10, Color.YELLOW));
}
}
private Node findNearestNode(ObservableList<Node> nodes, double x, double y) {
Point2D pClick = new Point2D(x, y);
Node nearestNode = null;
double closestDistance = Double.POSITIVE_INFINITY;
for (Node node : nodes) {
Bounds bounds = node.getBoundsInParent();
Point2D[] corners = new Point2D[]{
new Point2D(bounds.getMinX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMinY()),
new Point2D(bounds.getMaxX(), bounds.getMaxY()),
new Point2D(bounds.getMinX(), bounds.getMaxY()),
};
for (Point2D pCompare : corners) {
double nextDist = pClick.distance(pCompare);
if (nextDist < closestDistance) {
closestDistance = nextDist;
nearestNode = node;
}
}
}
return nearestNode;
}
// icons source from:
// http://www.iconarchive.com/show/soft-scraps-icons-by-deleket.html
// icon license: CC Attribution-Noncommercial-No Derivate 3.0 =?
// http://creativecommons.org/licenses/by-nc-nd/3.0/
// icon Commercial usage: Allowed (Author Approval required -> Visit artist
// website for details).
public static final String APP_ICON = "http://icons.iconarchive.com/icons/deleket/soft-scraps/128/Zoom-icon.png";
public static final String ZOOM_RESET_ICON = "http://icons.iconarchive.com/icons/deleket/soft-scraps/24/Zoom-icon.png";
public static final String ZOOM_OUT_ICON = "http://icons.iconarchive.com/icons/deleket/soft-scraps/24/Zoom-Out-icon.png";
public static final String ZOOM_IN_ICON = "http://icons.iconarchive.com/icons/deleket/soft-scraps/24/Zoom-In-icon.png";
public static final String CLOSE_ICON = "http://icons.iconarchive.com/icons/deleket/soft-scraps/24/Button-Close-icon.png";
}

Changing the colors of Gantt renderer

I want to change the colors of the renderers in my chart. I'm using JFreeChart
in the same line. I want to have different collors according to the task description.
The problem is I keep having the same color in a line.
package testJFreeChart;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.IntervalCategoryItemLabelGenerator;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.CategoryItemRendererState;
import org.jfree.chart.renderer.category.GanttRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.GanttCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.SimpleTimePeriod;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.TextAnchor;
public class GanttDemo2 extends ApplicationFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final TaskSeriesCollection model = new TaskSeriesCollection();
public GanttDemo2(final String title) {
super(title);
final IntervalCategoryDataset dataset = createSampleDataset();
// create the chart...
final JFreeChart chart = ChartFactory.createGanttChart(
"Diagramme de Gantt", // chart title
"Processus", // domain axis label
"temps(ms)", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
final CategoryPlot plot = (CategoryPlot) chart.getPlot();
DateAxis range = (DateAxis) plot.getRangeAxis();
range.setDateFormatOverride(new SimpleDateFormat("SSS"));
range.setMaximumDate(new Date(300));
// add the chart to a panel...
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
//GanttRenderer personnalisé..
MyRenderer renderer = new MyRenderer(model);
renderer.setBaseItemLabelGenerator(new CategoryItemLabelGenerator() {
public String generateLabel(CategoryDataset dataSet, int series, int categories) {
String label = "task";
return label;
}
public String generateColumnLabel(CategoryDataset dataset, int categories) {
//System.out.println(dataset.getColumnKey(categories).toString());
return dataset.getColumnKey(categories).toString();
}
public String generateRowLabel(CategoryDataset dataset, int series) {
return dataset.getRowKey(series).toString();
}
});
renderer.setBaseItemLabelsVisible(true);
renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE9, TextAnchor.CENTER_LEFT));
plot.setRenderer(renderer);
plot.setBackgroundPaint(Color.WHITE);
}
/** #see http://stackoverflow.com/questions/8938690 */
private static class MyRenderer extends GanttRenderer {
private static final int PASS = 2; // assumes two passes
private final List<Color> clut = new ArrayList<Color>();
private final TaskSeriesCollection model;
private int row;
private int col;
private int index;
public MyRenderer(TaskSeriesCollection model) {
this.model = model;
}
#Override
public Paint getItemPaint(int row, int col) {
if (clut.isEmpty() || this.row != row || this.col != col) {
initClut(row, col);
this.row = row;
this.col = col;
index = 0;
}
int clutIndex = index++ / PASS;
return clut.get(clutIndex);
}
private void initClut(int row, int col) {
clut.clear();
Color result = Color.cyan;
TaskSeries series = (TaskSeries) model.getRowKeys().get(row);
List<Task> tasks = series.getTasks(); // unchecked
int taskCount = tasks.get(col).getSubtaskCount();
taskCount = Math.max(1, taskCount);
System.out.println("---->" + taskCount);
String description;
for (int i = 0; i < taskCount; i++) {
// if(taskCount!=1){
//clut.remove(result);
description = tasks.get(col).getSubtask(i).getDescription();
System.out.println(description + " " + i);
if (description.equals("bloque")) {
result = Color.green;
clut.add(result);
System.out.println("yessssss");
}
if (description.equals("ES")) {
result = Color.yellow;
clut.add(result);
}
if (description.equals("Exec")) {
result = Color.blue;
clut.add(result);
System.out.println("NOOOOO");
}
// }
clut.add(result);
}
}
}
private IntervalCategoryDataset createSampleDataset() {
final TaskSeries s1 = new TaskSeries("");
final Task t = new Task("P0", new SimpleTimePeriod(30, 50));
final Task st0 = new Task("Exec", new SimpleTimePeriod(10, 20));
// Task st01 = new Task( "ES",new SimpleTimePeriod(30,60));
t.addSubtask(st0);
// t.addSubtask(st01);
s1.add(t);
final Task t1 = new Task("P1", new SimpleTimePeriod(5, 10));
final Task st11 = new Task("ES", new SimpleTimePeriod(10, 20));
Task st12 = new Task("Exec", new SimpleTimePeriod(30, 60));
t1.addSubtask(st11);
t1.addSubtask(st12);
s1.add(t1);
final Task t3 = new Task("P2", new SimpleTimePeriod(0, 40));
final Task st31 = new Task("bloque", new SimpleTimePeriod(5, 30));
final Task st32 = new Task("Exec", new SimpleTimePeriod(50, 60));
t3.addSubtask(st31);
t3.addSubtask(st32);
s1.add(t3);
model.add(s1);
return model;
}
public static void main(final String[] args) {
final GanttDemo2 demo = new GanttDemo2("Gantt Chart Demo 2");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
It should be row 1 color blue; row 2 color yellow then blue; row 3 color green then blue.
The variation below seems to produce the desired result. Note that legend will not use the new colors unless you use the approach suggested here.
Console:
----> 1
exec: 0
blue
----> 2
ES: 0
yellow
exec: 1
blue
----> 2
bloque: 0
green
exec: 1
blue
Code:
package chart;
import java.awt.Color;
import java.awt.Paint;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.GanttRenderer;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.SimpleTimePeriod;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class GanttDemo2 extends ApplicationFrame {
private static final long serialVersionUID = 1L;
public static final TaskSeriesCollection model = new TaskSeriesCollection();
public GanttDemo2(final String title) {
super(title);
final IntervalCategoryDataset dataset = createSampleDataset();
// create the chart...
final JFreeChart chart = ChartFactory.createGanttChart(
"Diagramme de Gantt", // chart title
"Processus", // domain axis label
"temps(ms)", // range axis label
dataset, // data
false, // include legend
true, // tooltips
false // urls
);
final CategoryPlot plot = (CategoryPlot) chart.getPlot();
DateAxis range = (DateAxis) plot.getRangeAxis();
range.setDateFormatOverride(new SimpleDateFormat("SSS"));
range.setMaximumDate(new Date(100));
// add the chart to a panel...
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
//GanttRenderer personnalisé..
MyRenderer renderer = new MyRenderer(model);
plot.setRenderer(renderer);
plot.setBackgroundPaint(Color.WHITE);
}
/**
* #see https://stackoverflow.com/questions/8938690
*/
private static class MyRenderer extends GanttRenderer {
private static final int PASS = 2; // assumes two passes
private final List<Color> clut = new ArrayList<>();
private final TaskSeriesCollection model;
private int row;
private int col;
private int index;
public MyRenderer(TaskSeriesCollection model) {
this.model = model;
}
#Override
public Paint getItemPaint(int row, int col) {
if (clut.isEmpty() || this.row != row || this.col != col) {
initClut(row, col);
this.row = row;
this.col = col;
index = 0;
}
int clutIndex = index++ / PASS;
return clut.get(clutIndex);
}
private void initClut(int row, int col) {
clut.clear();
TaskSeries series = (TaskSeries) model.getRowKeys().get(row);
List<Task> tasks = series.getTasks(); // unchecked
int taskCount = tasks.get(col).getSubtaskCount();
taskCount = Math.max(1, taskCount);
System.out.println("----> " + taskCount);
String description;
for (int i = 0; i < taskCount; i++) {
description = tasks.get(col).getSubtask(i).getDescription();
System.out.println(description + ": " + i);
if (description.equals("bloque")) {
clut.add(Color.green);
System.out.println("green");
}
if (description.equals("ES")) {
clut.add(Color.yellow);
System.out.println("yellow");
}
if (description.equals("exec")) {
clut.add(Color.blue);
System.out.println("blue");
}
}
}
}
private IntervalCategoryDataset createSampleDataset() {
final TaskSeries s1 = new TaskSeries("");
final Task t0 = new Task("P0", new SimpleTimePeriod(30, 50));
final Task st0 = new Task("exec", new SimpleTimePeriod(10, 20));
// Task st01 = new Task( "ES",new SimpleTimePeriod(30,60));
t0.addSubtask(st0);
// t.addSubtask(st01);
s1.add(t0);
final Task t1 = new Task("P1", new SimpleTimePeriod(5, 10));
final Task st11 = new Task("ES", new SimpleTimePeriod(10, 20));
Task st12 = new Task("exec", new SimpleTimePeriod(30, 60));
t1.addSubtask(st11);
t1.addSubtask(st12);
s1.add(t1);
final Task t2 = new Task("P2", new SimpleTimePeriod(0, 40));
final Task st31 = new Task("bloque", new SimpleTimePeriod(5, 30));
final Task st32 = new Task("exec", new SimpleTimePeriod(50, 60));
t2.addSubtask(st31);
t2.addSubtask(st32);
s1.add(t2);
model.add(s1);
return model;
}
public static void main(final String[] args) {
final GanttDemo2 demo = new GanttDemo2("Gantt Chart Demo 2");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}

How to draw moving and Running sine wave chart using JFree chart in java?

I m using JFreeChart to draw Running or Moving Sine Wave in java with netbeans. I write code for it , but it does not like moving or running sine wave graph. So if you have any idea regarding that then suggest me.
My code is below
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
public class DrawChart extends ApplicationFrame implements ActionListener {
public XYSeries series;
public DrawChart(final String title) {
super(title);
series = new XYSeries("Sine", true, true);
XYSeriesCollection dataset = new XYSeriesCollection(series);
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart);
final JButton button = new JButton("Add New Data Item");
button.setActionCommand("ADD_DATA");
button.addActionListener(this);
final JPanel content = new JPanel(new BorderLayout());
content.add(chartPanel);
content.add(button, BorderLayout.SOUTH);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(content);
}
private JFreeChart createChart(final XYDataset dataset) {
JFreeChart jfreechart = ChartFactory.createXYLineChart("Sin Curve", "Angle (Deg)", "Value", dataset, PlotOrientation.VERTICAL, true, true, true);
jfreechart.setBackgroundPaint(Color.white);
XYPlot xyplot = (XYPlot) jfreechart.getPlot();
xyplot.setBackgroundPaint(Color.lightGray);
xyplot.setDomainGridlinePaint(Color.white);
xyplot.setRangeGridlinePaint(Color.white);
return jfreechart;
}
public void actionPerformed(final ActionEvent e) {
if (e.getActionCommand().equals("ADD_DATA")) {
for (int i = 0; i < 100; i++) {
final double x = (i)/10.0 ;
final double y = Math.sin(x);
this.series.addOrUpdate(x, y);
}
}
}
public static void main(final String[] args) {
final DrawChart demo = new DrawChart("Dynamic Data view");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
Starting from this example, substituting Math.sin() for nextGaussian() produced the illustration below. A javax.swing.Timer paces the animation at 1 Hz.
private ChartPanel createPane() {
final XYSeries series = new XYSeries("Data");
for (int i = 0; i < random.nextInt(N) + N / 2; i++) {
series.add(i, Math.sin(i));
}
XYSeriesCollection dataset = new XYSeriesCollection(series);
new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
series.add(series.getItemCount(), Math.sin(series.getItemCount()));
}
}).start();
…
}
Try this JavaFX. It's more flexible.
This is what I gathered and came up with using JavaFX
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.animation.AnimationTimer;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
public class ACS extends Application
{
private static final int MAX_DATA_POINTS = 200;
private Series series;
private float xSeriesData = 0;
private final ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
private ExecutorService executor;
private AddToQueue addToQueue;
private Timeline timeline2;
private NumberAxis xAxis;
private void init(final Stage primaryStage)
{
xAxis = new NumberAxis(0, MAX_DATA_POINTS, 1);
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(false);
final NumberAxis yAxis = new NumberAxis(0, 200, 1);
yAxis.setAutoRanging(false);
// -- Chart
final LineChart<Number, Number> sc = new LineChart<Number, Number>(xAxis, yAxis) {
// Override to remove symbols on each data point
#Override
protected void dataItemAdded(final Series<Number, Number> series, final int itemIndex, final Data<Number, Number> item)
{}
};
sc.setAnimated(false);
sc.setId("liveAreaChart");
sc.setTitle("Animated Area Chart");
// -- Chart Series
series = new LineChart.Series<Number, Number>();
series.setName("Area Chart Series");
sc.getData().add(series);
final Scene scene = new Scene(sc, 800, 800);
scene.getStylesheets().add("site.css");
sc.getStyleClass().add("thick-chart");
primaryStage.setScene(scene);
}
#Override
public void start(final Stage primaryStage) throws Exception
{
init(primaryStage);
primaryStage.show();
// -- Prepare Executor Services
executor = Executors.newCachedThreadPool();
addToQueue = new AddToQueue();
executor.execute(addToQueue);
// -- Prepare Timeline
prepareTimeline();
}
public static void main(final String[] args)
{
launch(args);
}
private class AddToQueue implements Runnable
{
double PERIOD = 20;
double SCALE = 20;
int pos = 0;
#Override
public void run()
{
try {
final double Min = 20;
final double Max = 55;
// add a item of random data to queue
//uncomment the line below to generate a normal graph
// dataQ.add(Min + (Math.random() * ((Max - Min))));
dataQ.add(((Math.sin((++pos * 2 * Math.PI) / PERIOD) * (SCALE / 2)) + (SCALE / 2)));
Thread.sleep(1000);
executor.execute(this);
}
catch (final InterruptedException ex) {
// Logger.getLogger(ACS.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
// -- Timeline gets called in the JavaFX Main thread
private void prepareTimeline()
{
// Every frame to take any data from queue and add to chart
new AnimationTimer() {
#Override
public void handle(final long now)
{
addDataToSeries();
}
}.start();
}
private void addDataToSeries()
{
for (int i = 0; i < 20; i++) { // -- add 20 numbers to the plot+
if (dataQ.isEmpty()) {
break;
}
// series.getData().add(new LineChart.Data(xSeriesData++, dataQ.remove()));
final Number datapoint = dataQ.remove();
xSeriesData = xSeriesData + 1;
System.out.println(xSeriesData + " " + datapoint);
series.getData().add(new LineChart.Data(xSeriesData, datapoint));
}
// remove points to keep us at no more than MAX_DATA_POINTS
if (series.getData().size() > (MAX_DATA_POINTS * 10)) {
series.getData().remove(0, series.getData().size() - (MAX_DATA_POINTS * 10));
}
// update
xAxis.setLowerBound(xSeriesData - (MAX_DATA_POINTS));
xAxis.setUpperBound(xSeriesData - 1);
}
}

Update graph with JFreeChart and slider

I have a time history for arrays describing the pressure along a pipe. So I have an array of pressure values along the length of the pipe for each delta t. I want to plot the pressures along the length of the pipe with JFreeChart and chose which delta t to plot with a slider, so that whenever the user moves the slider the graphic is updates with values from a different delta t. I'm also resetting the tile to be the pressure at the last portion of the pipe. What happens is that the title is updates, meaning the data is being properly updates, but the curve remains the same. I have read every possible topic on forums and tried everything I could think of but it's not working! Here's the code of my class that extends JPanel, in which the method jSlider1StateChanged hears the change in the slider position, createChart creaters a new chart when the program is started, and dataSetGen(int ndt) generates the graph's new dataset based on the slider position:
public class MyMainPanel extends JPanel {
private JFreeChart jc;
private OutputPipe op;
private DefaultXYDataset ds;
private javax.swing.JFrame jFrame1;
private javax.swing.JSlider jSlider1;
private pipevisualizer.MyChartPanel pnlChartPanel;
private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {
int ndt = ((JSlider) evt.
getSource()).
getValue();
System.out.println("Slider1: " + ((JSlider) evt.
getSource()).
getValue());
dataSetGen(ndt);
int a = 0;
jc.fireChartChanged();
}
private void dataSetGen(int ndt) {
ArrayList<OutputPipeDt> opDtArray = op.getOpLit();
OutputPipeDt opDt = opDtArray.get(ndt);
double[] H = opDt.getH();
double[] l = new double[H.length];
double[] p = new double[H.length];
double dX = op.getPipeLength() / H.length;
double slope = op.getPipeSlope();
double el = op.getPipeUSElev();
for (int i = 0; i < H.length; i++) {
l[i] = dX * i;
p[i] = el - dX * slope * i;
}
double[][] dataH = new double[2][H.length];
dataH[0] = l;
dataH[1] = H;
double[][] dataP = new double[2][H.length];
dataP[0] = l;
dataP[1] = p;
ds = new DefaultXYDataset();
ds.addSeries("pipe head", dataH);
ds.addSeries("pipe profile", dataP);
jc.setTitle("H[end] = " + Double.toString(dataH[1][l.length - 1]));
jc.fireChartChanged();
}
private JFreeChart createChart(OutputPipe op, int ndt) {
ArrayList<OutputPipeDt> opDtArray = op.getOpLit();
OutputPipeDt opDt = opDtArray.get(ndt);
double[] H = opDt.getH();
double[] l = new double[H.length];
double[] p = new double[H.length];
double dX = op.getPipeLength() / H.length;
double slope = op.getPipeSlope();
double el = op.getPipeUSElev();
for (int i = 0; i < H.length; i++) {
l[i] = dX * i;
p[i] = el - dX * slope * i;
}
double[][] dataH = new double[2][H.length];
dataH[0] = l;
dataH[1] = H;
double[][] dataP = new double[2][H.length];
dataP[0] = l;
dataP[1] = p;
DefaultXYDataset ds = new DefaultXYDataset();
ds.addSeries("pipe head", dataH);
ds.addSeries("pipe profile", dataP);
JFreeChart chart = ChartFactory.createXYLineChart(
"t = " + Double.toString(op.getOpLit().get(ndt).getT()),
// chart title
"X",
// x axis label
"Y",
// y axis label
ds,
// data
PlotOrientation.VERTICAL,
true,
// include legend
true,
// tooltips
false // urls
);
return chart;
}
}
I thought that any changes to the datasets would make the graph redraw itself.
Sorry if the code might be to big to be on the post, but I don't know exactly which parts should I paste to be more or less clear.
Absent a complete example, you may be able to use the approach shown here; it uses plot.setDataset() to replace the dataset on receiving each event.
Addendum: This example that shows temperature versus length over time may get you started.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see https://stackoverflow.com/a/15207445/230513
*/
public class ChartSliderTest {
private static final int N = 25;
private static final double K = 273.15;
private static final Random random = new Random();
private static XYDataset getDataset(int n) {
final XYSeries series = new XYSeries("Temp (K°)");
double temperature;
for (int length = 0; length < N; length++) {
temperature = K + n * random.nextGaussian();
series.add(length + 1, temperature);
}
return new XYSeriesCollection(series);
}
private static JFreeChart createChart(final XYDataset dataset) {
JFreeChart chart = ChartFactory.createXYLineChart(
"ChartSliderTest", "Length (m)", "Temp (K°)", dataset,
PlotOrientation.VERTICAL, false, false, false);
return chart;
}
private static void display() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final List<XYDataset> list = new ArrayList<XYDataset>();
for (int i = 0; i <= 10; i++) {
list.add(getDataset(i));
}
JFreeChart chart = createChart(list.get(5));
final XYPlot plot = (XYPlot) chart.getPlot();
plot.getRangeAxis().setRangeAboutValue(K, K / 5);
ChartPanel chartPanel = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 400);
}
};
f.add(chartPanel);
final JSlider slider = new JSlider(0, 10);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
plot.setDataset(list.get(slider.getValue()));
}
});
Box p = new Box(BoxLayout.X_AXIS);
p.add(new JLabel("Time:"));
p.add(slider);
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}

Categories

Resources