patternjavaMinor
JFreeChart Dynamic Scatter Chart
Viewed 0 times
jfreechartchartscatterdynamic
Problem
I have a model that consists of a 100 'agents' that change their x and y coordinates randomly. I use JFreeChart scatter chart to represent agents' locations.
```
package jfreecharttest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class ScatterChartExample {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Dynamic chart");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BoxLayout(
frame.getContentPane(), BoxLayout.PAGE_AXIS));
DynamicChartPanel panel = new DynamicChartPanel();
frame.getContentPane().add(panel);
JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent evt) {
if (panel.isStarted()) {
panel.stop();
button.setText("Start");
} else {
panel.start();
button.setText("Stop");
}
}
});
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
}
}
class DynamicChartPanel extends JPanel{
private final ChartPanel content;
private final XYSeri
```
package jfreecharttest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class ScatterChartExample {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Dynamic chart");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BoxLayout(
frame.getContentPane(), BoxLayout.PAGE_AXIS));
DynamicChartPanel panel = new DynamicChartPanel();
frame.getContentPane().add(panel);
JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent evt) {
if (panel.isStarted()) {
panel.stop();
button.setText("Start");
} else {
panel.start();
button.setText("Stop");
}
}
});
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
}
}
class DynamicChartPanel extends JPanel{
private final ChartPanel content;
private final XYSeri
Solution
The
I believe the probability for no collisions on the very last generation is something like
\$(1 - \frac{1}{101^2})^{100} = 0.990244456...\$
This makes the probability for a collision less than one percent.
Also, the first randomization you're not using the min-values of the X and Y bounds.
When you use the min and max values for the randomization,
If you still want to maintain collision-detection, despite the very low probability of collisions, you can use a
I am not familiar with JFreeChart, but it seems to me that the
A better name for
I also don't like names like
The way you're currently using
I have to say though that overall your code is very readable and easy to understand, and I really like that you're using
locationTaken is a big performance bottleneck as it iterates through all points whenever you're adding a new one. Depending on the size of the fields (currently 0-100, 0-100), it is also very low probability for any collision.I believe the probability for no collisions on the very last generation is something like
\$(1 - \frac{1}{101^2})^{100} = 0.990244456...\$
This makes the probability for a collision less than one percent.
Also, the first randomization you're not using the min-values of the X and Y bounds.
When you use the min and max values for the randomization,
+ getXMin() should be outside the random.nextInt parameter, otherwise you'll just produce a value from 0 to an even higher number.If you still want to maintain collision-detection, despite the very low probability of collisions, you can use a
HashSet to check if the values exist already, like below.Set added = new HashSet<>();
for (int i = 0; i < agentCount; i++) {
int x;
int y;
do {
x = random.nextInt(getXMax() - getXMin() + 1) + getXMin();
y = random.nextInt(getYMax() - getYMin() + 1) + getYMin();
}
while (!added.add(new Point(x, y)));
}I am not familiar with JFreeChart, but it seems to me that the
updateAgentLocationSeries() method can be modified to instead of removing the locations and then re-adding them with new values, it can loop through the locations and update them. See the XYSeries.addOrUpdate method. If you use this you will have to use XYDataItem instead of your current class though.A better name for
Agent would be Point, and that class is usable enough to be a public class in a separate file.I also don't like names like
getyMax, the character after get should be uppercase. I'd prefer getYMax.The way you're currently using
private final int moveRange; and many others is by giving them a fixed value in the constructor. If you don't intend on providing that parameter using constructor arguments, you should change these fields to constants, such as:private static final int MOVE_RANGE = 4;I have to say though that overall your code is very readable and easy to understand, and I really like that you're using
final excessively! Good job.Code Snippets
Set<Point> added = new HashSet<>();
for (int i = 0; i < agentCount; i++) {
int x;
int y;
do {
x = random.nextInt(getXMax() - getXMin() + 1) + getXMin();
y = random.nextInt(getYMax() - getYMin() + 1) + getYMin();
}
while (!added.add(new Point(x, y)));
}private static final int MOVE_RANGE = 4;Context
StackExchange Code Review Q#52069, answer score: 4
Revisions (0)
No revisions yet.