JFreeChart chart is lagging - java

This program is supposed to graph and animate a sine wave by using a thread to "move over" the points in the XYSeries that draws the wave. After a few seconds, the chart starts to flash and zooms in and out randomly. I don't know if this is a problem with my code or with my computer (probably the code).
import java.awt.geom.Point2D;
import static java.lang.Math.PI;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
public class WaveGraph extends JFrame
{
double numOfWaves = 2;
double waveAmp = 2;
double waveLength = 10;
double waveRes = 20;
double median = ((waveLength*numOfWaves)/2);
int numOfPoints = (int)(numOfWaves*waveRes);
boolean going = true;
boolean left = true;
XYSeriesCollection dataset = new XYSeriesCollection();
Point2D.Double[] points;
WaveGraph()
{
XYSeries buoys = new XYSeries("Buoys");
XYSeries series = new XYSeries("Wave");
points = new Point2D.Double[numOfPoints];
for(int i=0; i<numOfPoints; i++)
{
Point2D.Double temp = new Point2D.Double();
temp.x = i*(waveLength/waveRes);
temp.y = waveAmp*Math.sin((2*PI)/waveLength*temp.x);
points[i] = temp;
series.add(points[i].x, points[i].y);
if(i==(numOfPoints/2)-1)
buoys.add(median, points[i].y);
}
buoys.add(median, 0);
dataset.addSeries(series);
dataset.addSeries(buoys);
JFreeChart chart = ChartFactory.createXYLineChart(
"Sine Wave", // chart title
"Wavelength(meters)", // x axis label
"Amplitude (meters)", dataset, // data
PlotOrientation.VERTICAL,
false, // include legend
false, // tooltips
false // urls
);
XYPlot plot = (XYPlot)chart.getPlot();
XYLineAndShapeRenderer renderer
= (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setSeriesShapesFilled(1, true);
renderer.setSeriesShapesVisible(1, true);
NumberAxis domain = (NumberAxis)plot.getDomainAxis();
domain.setRange(0.00, waveLength*numOfWaves);
NumberAxis range = (NumberAxis)plot.getRangeAxis();
range.setRange(-waveAmp*1.3, waveAmp*1.3);
ChartPanel cp = new ChartPanel(chart);
cp.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(cp);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
WaveRunner run = new WaveRunner();
}
class WaveRunner extends Thread
{
WaveRunner()
{
this.start();
}
public void run()
{
double[] temp = new double[numOfPoints];
XYSeries temp2, temp3;
while(going)
{
temp2 = dataset.getSeries(0);
temp3 = dataset.getSeries(1);
temp2.delete(0, numOfPoints-1);
temp3.delete(0, 1);
for(int i=0; i<numOfPoints; i++)
{
if(left){
try{
temp[i] = points[i+1].y;
}
catch(java.lang.ArrayIndexOutOfBoundsException exc){
temp[numOfPoints-1] = points[0].y;
}}
else{
try{
temp[i] = points[i-1].y;
}
catch(java.lang.ArrayIndexOutOfBoundsException exc){
temp[0] = points[numOfPoints-1].y;
}}
}
for(int i=0; i<numOfPoints; i++)
{
points[i].y = temp[i];
temp2.add(points[i].x, points[i].y);
if(i==(numOfPoints/2))
{
temp3.add(median, points[i].y);
temp3.add(median, 0);
}
}
try
{
Thread.sleep(50);
}
catch(InterruptedException exc)
{}
}
}
}
public static void main(String[] args)
{
WaveGraph test = new WaveGraph();
}
}

Your example is incorrectly synchronized in that it updates the chart's dataset from WaveRunner. The chart's model is displayed in a ChartPanel, so it should be updated only on the event dispatch thread. Instead, pace the animation using Swing Timer, as shown here and here, or SwingWorker, as shown here.

Related

JFreeChart is plotting data but not drawing linear regression

I have used JFreeChart to represent my array of x and y. These arrays get plotted just fine, however theregression line is broken and never gets drawn. All the functions work such as plotting values except drawinputpoint and drawregressionline function. Somehow these two never work. I don't mind drawwinginputpoint a lot, but I like to be able to drawregressionline. My array has correct data, so not sure what is the issue. I am importing my arrays data into dataset in createDateSetFromFile function. My Home_JFrame has targetx and targety array. These have arraylist and has Double data type.
package gradleproject2;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
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.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.data.function.LineFunction2D;
import org.jfree.data.general.DatasetUtils;
import org.jfree.data.statistics.Regression;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import gradleproject2.Home_JFrame;
import org.jfree.ui.RefineryUtilities;
public class PriceEstimator extends ApplicationFrame{
private static final long serialVersionUID = 1L;
XYDataset inputData;
JFreeChart chart;
public static void main(String[] args) throws IOException {
PriceEstimator demo = new PriceEstimator();
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.drawRegressionLine();
if (args.length >= 1 && args[0] != null) {
// Estimate the linear function given the input data
double regressionParameters[] = Regression.getOLSRegression(
demo.inputData, 0);
double x = Double.parseDouble(args[0]);
// Prepare a line function using the found parameters
LineFunction2D linefunction2d = new LineFunction2D(
regressionParameters[0], regressionParameters[1]);
// This is the estimated price
double y = linefunction2d.getValue(x);
demo.drawInputPoint(x, y);
}
}
public PriceEstimator() throws IOException {
super("Linear Regression");
// Read sample data from prices.txt file
inputData = createDatasetFromFile();
// Create the chart using the sample data
chart = createChart(inputData);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
public XYDataset createDatasetFromFile() throws IOException {
ClassLoader classLoader = getClass().getClassLoader();
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series = new XYSeries("Stock Item");
// Read the price and the date
for (int row = 0; row < Home_JFrame.targetx.size(); row++) {
series.add(Home_JFrame.targetx.get(row), Home_JFrame.targety.get(row));
}
dataset.addSeries(series);
Home_JFrame.targetx.clear();
Home_JFrame.targety.clear();
return dataset;
}
private JFreeChart createChart(XYDataset inputData) throws IOException {
// Create the chart using the data read from the prices.txt file
JFreeChart chart = ChartFactory.createScatterPlot(
"Stock Price", "Stock Date", "Stock Opening Price", inputData,
PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot();
plot.getRenderer().setSeriesPaint(0, Color.blue);
return chart;
}
private void drawRegressionLine() {
// Get the parameters 'a' and 'b' for an equation y = a + b * x,
// fitted to the inputData using ordinary least squares regression.
// a - regressionParameters[0], b - regressionParameters[1]
double regressionParameters[] = Regression.getOLSRegression(inputData,
0);
// Prepare a line function using the found parameters
LineFunction2D linefunction2d = new LineFunction2D(
regressionParameters[0], regressionParameters[1]);
// Creates a dataset by taking sample values from the line function
XYDataset dataset = DatasetUtils.sampleFunction2D(linefunction2d,
0D, 300, 100, "Fitted Regression Line");
// Draw the line dataset
XYPlot xyplot = chart.getXYPlot();
xyplot.setDataset(1, dataset);
XYLineAndShapeRenderer xylineandshaperenderer = new XYLineAndShapeRenderer(
true, false);
xylineandshaperenderer.setSeriesPaint(0, Color.YELLOW);
xyplot.setRenderer(1, xylineandshaperenderer);
}
private void drawInputPoint(double x, double y) {
// Create a new dataset with only one row
XYSeriesCollection dataset = new XYSeriesCollection();
String title = "Stock Date Distance: " + x + ", Stock Opening Price: " + y;
XYSeries series = new XYSeries(title);
series.add(x, y);
dataset.addSeries(series);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setDataset(2, dataset);
XYItemRenderer renderer = new XYLineAndShapeRenderer(false, true);
plot.setRenderer(2, renderer);
}
}
It looks like you want a trend line though a scatter plot, but you may be creating unnecessary renderers in addition to the one instantiated by your chosen ChartFactory. To study the problem in isolation, modify this complete example to create a scatter plot and change the existing renderer to condition the trend line's display as desired.
JFreeChart chart = ChartFactory.createScatterPlot(…);
XYPlot plot = chart.getXYPlot();
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer();
r.setSeriesLinesVisible(1, Boolean.TRUE);
r.setSeriesShapesVisible(1, Boolean.FALSE);
Code:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import org.jfree.chart.*;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.statistics.Regression;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see https://stackoverflow.com/a/37716411/230513
* #see http://stackoverflow.com/a/37716411/230513
*/
public class RegressionTest {
private static final int N = 16;
private static final Random R = new Random();
private static XYDataset createDataset() {
XYSeries series = new XYSeries("Data");
for (int i = 0; i < N; i++) {
series.add(i, R.nextGaussian() + i);
}
XYSeriesCollection xyData = new XYSeriesCollection(series);
double[] coefficients = Regression.getOLSRegression(xyData, 0);
double b = coefficients[0]; // intercept
double m = coefficients[1]; // slope
XYSeries trend = new XYSeries("Trend");
double x = series.getDataItem(0).getXValue();
trend.add(x, m * x + b);
x = series.getDataItem(series.getItemCount() - 1).getXValue();
trend.add(x, m * x + b);
xyData.addSeries(trend);
return xyData;
}
private static JFreeChart createChart(final XYDataset dataset) {
JFreeChart chart = ChartFactory.createScatterPlot("Test", "X", "Y",
dataset, PlotOrientation.VERTICAL, true, false, false);
XYPlot plot = chart.getXYPlot();
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer();
r.setSeriesLinesVisible(1, Boolean.TRUE);
r.setSeriesShapesVisible(1, Boolean.FALSE);
return chart;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
XYDataset dataset = createDataset();
JFreeChart chart = createChart(dataset);
ChartPanel chartPanel = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
};
f.add(chartPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}

How to make plots in Java like in Matlab (same syntax)

Plotting in Matlab is very easy and straightforward. For example:
figure('Position_',[100,80,1000,600])
plot(x,y1,'-.or','MarkerSize',0.2,'MarkerFaceColor','r','LineWidth',2)
xlabel('Matrix1')
ylabel('Matrix2')
grid on
hold on
axis([-1,1,0,var1*1.2])
plot(x,y2,'-k','MarkerSize',0.5,'MarkerFaceColor','k','LineWidth',4)
title('My plot')
figuresdir = 'dir';
saveas(gcf,strcat(figuresdir, 'plotimage'), 'bmp');
I found, however, that plotting in Java is more difficult and I have to use packages like JMathPlot or JFreeChart. However, I find it difficult to merge plots and print them to a file using these packages.
Is there an easy way to make plots in Java that uses (about) the same syntax as Matlab does?
Well, Matlab is designed specifically to make things such as plotting as easy as possible. Other languages simply don't have the same kind of support for quick-and-easy plots.
Therefore I decided to write a little Matlab-style charting class based on JFreeChart, just for you:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Stroke;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYTitleAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
public class MatlabChart {
Font font;
JFreeChart chart;
LegendTitle legend;
ArrayList<Color> colors;
ArrayList<Stroke> strokes;
XYSeriesCollection dataset;
public MatlabChart() {
font = JFreeChart.DEFAULT_TITLE_FONT;
colors = new ArrayList<Color>();
strokes = new ArrayList<Stroke>();
dataset = new XYSeriesCollection();
}
public void plot(double[] x, double[] y, String spec, float lineWidth, String title) {
final XYSeries series = new XYSeries(title);
for (int i = 0; i < x.length; i++)
series.add(x[i],y[i]);
dataset.addSeries(series);
FindColor(spec,lineWidth);
}
public void RenderPlot() {
// Create chart
JFreeChart chart = null;
if (dataset != null && dataset.getSeriesCount() > 0)
chart = ChartFactory.createXYLineChart(null,null,null,dataset,PlotOrientation.VERTICAL,true, false, false);
else
System.out.println(" [!] First create a chart and add data to it. The plot is empty now!");
// Add customization options to chart
XYPlot plot = chart.getXYPlot();
for (int i = 0; i < colors.size(); i++) {
plot.getRenderer().setSeriesPaint(i, colors.get(i));
plot.getRenderer().setSeriesStroke(i, strokes.get(i));
}
((NumberAxis)plot.getDomainAxis()).setAutoRangeIncludesZero(false);
((NumberAxis)plot.getRangeAxis()).setAutoRangeIncludesZero(false);
plot.setBackgroundPaint(Color.WHITE);
legend = chart.getLegend();
chart.removeLegend();
this.chart = chart;
}
public void CheckExists() {
if (chart == null) {
throw new IllegalArgumentException("First plot something in the chart before you modify it.");
}
}
public void font(String name, int fontSize) {
CheckExists();
font = new Font(name, Font.PLAIN, fontSize);
chart.getTitle().setFont(font);
chart.getXYPlot().getDomainAxis().setLabelFont(font);
chart.getXYPlot().getDomainAxis().setTickLabelFont(font);
chart.getXYPlot().getRangeAxis().setLabelFont(font);
chart.getXYPlot().getRangeAxis().setTickLabelFont(font);
legend.setItemFont(font);
}
public void title(String title) {
CheckExists();
chart.setTitle(title);
}
public void xlim(double l, double u) {
CheckExists();
chart.getXYPlot().getDomainAxis().setRange(l, u);
}
public void ylim(double l, double u) {
CheckExists();
chart.getXYPlot().getRangeAxis().setRange(l, u);
}
public void xlabel(String label) {
CheckExists();
chart.getXYPlot().getDomainAxis().setLabel(label);
}
public void ylabel(String label) {
CheckExists();
chart.getXYPlot().getRangeAxis().setLabel(label);
}
public void legend(String position) {
CheckExists();
legend.setItemFont(font);
legend.setBackgroundPaint(Color.WHITE);
legend.setFrame(new BlockBorder(Color.BLACK));
if (position.toLowerCase().equals("northoutside")) {
legend.setPosition(RectangleEdge.TOP);
chart.addLegend(legend);
} else if (position.toLowerCase().equals("eastoutside")) {
legend.setPosition(RectangleEdge.RIGHT);
chart.addLegend(legend);
} else if (position.toLowerCase().equals("southoutside")) {
legend.setPosition(RectangleEdge.BOTTOM);
chart.addLegend(legend);
} else if (position.toLowerCase().equals("westoutside")) {
legend.setPosition(RectangleEdge.LEFT);
chart.addLegend(legend);
} else if (position.toLowerCase().equals("north")) {
legend.setPosition(RectangleEdge.TOP);
XYTitleAnnotation ta = new XYTitleAnnotation(0.50,0.98,legend,RectangleAnchor.TOP);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("northeast")) {
legend.setPosition(RectangleEdge.TOP);
XYTitleAnnotation ta = new XYTitleAnnotation(0.98,0.98,legend,RectangleAnchor.TOP_RIGHT);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("east")) {
legend.setPosition(RectangleEdge.RIGHT);
XYTitleAnnotation ta = new XYTitleAnnotation(0.98,0.50,legend,RectangleAnchor.RIGHT);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("southeast")) {
legend.setPosition(RectangleEdge.BOTTOM);
XYTitleAnnotation ta = new XYTitleAnnotation(0.98,0.02,legend,RectangleAnchor.BOTTOM_RIGHT);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("south")) {
legend.setPosition(RectangleEdge.BOTTOM);
XYTitleAnnotation ta = new XYTitleAnnotation(0.50,0.02,legend,RectangleAnchor.BOTTOM);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("southwest")) {
legend.setPosition(RectangleEdge.BOTTOM);
XYTitleAnnotation ta = new XYTitleAnnotation(0.02,0.02,legend,RectangleAnchor.BOTTOM_LEFT);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("west")) {
legend.setPosition(RectangleEdge.LEFT);
XYTitleAnnotation ta = new XYTitleAnnotation(0.02,0.50,legend,RectangleAnchor.LEFT);
chart.getXYPlot().addAnnotation(ta);
} else if (position.toLowerCase().equals("northwest")) {
legend.setPosition(RectangleEdge.TOP);
XYTitleAnnotation ta = new XYTitleAnnotation(0.02,0.98,legend,RectangleAnchor.TOP_LEFT);
chart.getXYPlot().addAnnotation(ta);
}
}
public void grid(String xAxis, String yAxis) {
CheckExists();
if (xAxis.equalsIgnoreCase("on")){
chart.getXYPlot().setDomainGridlinesVisible(true);
chart.getXYPlot().setDomainMinorGridlinesVisible(true);
chart.getXYPlot().setDomainGridlinePaint(Color.GRAY);
} else {
chart.getXYPlot().setDomainGridlinesVisible(false);
chart.getXYPlot().setDomainMinorGridlinesVisible(false);
}
if (yAxis.equalsIgnoreCase("on")){
chart.getXYPlot().setRangeGridlinesVisible(true);
chart.getXYPlot().setRangeMinorGridlinesVisible(true);
chart.getXYPlot().setRangeGridlinePaint(Color.GRAY);
} else {
chart.getXYPlot().setRangeGridlinesVisible(false);
chart.getXYPlot().setRangeMinorGridlinesVisible(false);
}
}
public void saveas(String fileName, int width, int height) {
CheckExists();
File file = new File(fileName);
try {
ChartUtilities.saveChartAsJPEG(file,this.chart,width,height);
} catch (IOException e) {
e.printStackTrace();
}
}
public void FindColor(String spec, float lineWidth) {
float dash[] = {5.0f};
float dot[] = {lineWidth};
Color color = Color.RED; // Default color is red
Stroke stroke = new BasicStroke(lineWidth); // Default stroke is line
if (spec.contains("-"))
stroke = new BasicStroke(lineWidth);
else if (spec.contains(":"))
stroke = new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
else if (spec.contains("."))
stroke = new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dot, 0.0f);
if (spec.contains("y"))
color = Color.YELLOW;
else if (spec.contains("m"))
color = Color.MAGENTA;
else if (spec.contains("c"))
color = Color.CYAN;
else if (spec.contains("r"))
color = Color.RED;
else if (spec.contains("g"))
color = Color.GREEN;
else if (spec.contains("b"))
color = Color.BLUE;
else if (spec.contains("k"))
color = Color.BLACK;
colors.add(color);
strokes.add(stroke);
}
}
With this, you can plot in Java with syntax very close to Matlab:
public class Demo {
public static void main(String[] args) {
// Create some sample data
double[] x = new double[100]; x[0] = 1;
double[] y1 = new double[100]; y1[0] = 200;
double[] y2 = new double[100]; y2[0] = 300;
for(int i = 1; i < x.length; i++){
x[i] = i+1;
y1[i] = y1[i-1] + Math.random()*10 - 4;
y2[i] = y2[i-1] + Math.random()*10 - 6;
}
// JAVA: // MATLAB:
MatlabChart fig = new MatlabChart(); // figure('Position',[100 100 640 480]);
fig.plot(x, y1, "-r", 2.0f, "AAPL"); // plot(x,y1,'-r','LineWidth',2);
fig.plot(x, y2, ":k", 3.0f, "BAC"); // plot(x,y2,':k','LineWidth',3);
fig.RenderPlot(); // First render plot before modifying
fig.title("Stock 1 vs. Stock 2"); // title('Stock 1 vs. Stock 2');
fig.xlim(10, 100); // xlim([10 100]);
fig.ylim(200, 300); // ylim([200 300]);
fig.xlabel("Days"); // xlabel('Days');
fig.ylabel("Price"); // ylabel('Price');
fig.grid("on","on"); // grid on;
fig.legend("northeast"); // legend('AAPL','BAC','Location','northeast')
fig.font("Helvetica",15); // .. 'FontName','Helvetica','FontSize',15
fig.saveas("MyPlot.jpeg",640,480); // saveas(gcf,'MyPlot','jpeg');
}
}
Now we can compare the final JFreeChart figure to same Matlab figure that we get from this code:
figure('Position',[100 100 640 480]); hold all;
plot(x,y1,'-r','LineWidth',2);
plot(x,y2,':k','LineWidth',3);
title('Stock 1 vs. Stock 2');
xlim([10 100]);
ylim([200 300]);
xlabel('Days');
ylabel('Price');
grid on;
legend('AAPL','BAC','Location','northeast');
saveas(gcf,'MyPlot','jpeg');
Result Java (with the MatlabChart() class):
Result Matlab:
The MatlabChart() class I wrote has support for some of the basic plotting syntax in Matlab. You can indicate line styles (:,-,.), change line colors (y,m,c,r,g,b,w,k), change the LineWidth and change the position of the legend (northoutside,eastoutside,soutoutside, westoutside,north,east,south,west,northeast,southeast,southwest,northwest). You can also turn the grid on for the x and y-axis independently. For example: grid("off","on"); turns the x-axis grid off and turns the y-axis grid on.
That should make plotting in Java a lot easier for those used to plotting in Matlab :)

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

Dynamically repaint ScatterPlot in jfreechart

I have a scatterplot which plots positions of agents. These positions change. I was wondering how can I repaint/redraw the scatterplot with the new positions
my drawing method. I need to redraw in the updatePositions function. Is there any way to implement any listener for ScatterPlot?
private ChartPanel createPanel() {
JFreeChart jfreechart = ChartFactory.createScatterPlot(
title, "", "", initPositions(),PlotOrientation.VERTICAL, true, true, false);
XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
xyPlot.setDomainCrosshairVisible(true);
xyPlot.setRangeCrosshairVisible(true);
XYItemRenderer renderer = xyPlot.getRenderer();
renderer.setSeriesPaint(0, Color.blue);
adjustAxis((NumberAxis) xyPlot.getDomainAxis(), true);
adjustAxis((NumberAxis) xyPlot.getRangeAxis(), false);
xyPlot.setBackgroundPaint(Color.white);
return new ChartPanel(jfreechart);
}
private void adjustAxis(NumberAxis axis, boolean vertical) {
axis.setRange(-1, lattice+1);
axis.setTickUnit(new NumberTickUnit(1));
axis.setVerticalTickLabels(vertical);
}
private XYDataset initPositions() {
XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
for (int i = 0; i < populationSize; i++) {
if(population.get(i).status==1){
healthy.add(population.get(i).position[0], population.get(i).position[1]);
}else if(population.get(i).status==2){
infected.add(population.get(i).position[0], population.get(i).position[1]);
}else if(population.get(i).status==3){
recovered.add(population.get(i).position[0], population.get(i).position[1]);
}
}
xySeriesCollection.addSeries(healthy);
xySeriesCollection.addSeries(infected);
xySeriesCollection.addSeries(recovered);
return xySeriesCollection;
}
public void clear(){
healthy.clear();
infected.clear();
recovered.clear();
}
public void updatePositions(ArrayList<Person> pop ){
population = pop;
for (int i = 0; i < populationSize; i++) {
if(population.get(i).status==1){
healthy.addOrUpdate(population.get(i).position[0], population.get(i).position[1]);
}else if(population.get(i).status==2){
infected.addOrUpdate(population.get(i).position[0], population.get(i).position[1]);
}else if(population.get(i).status==3){
recovered.addOrUpdate(population.get(i).position[0], population.get(i).position[1]);
}
}
}
this is the method in the main class. The update of the positions is done at the "move" function
public static void main(String [] args){
createPopulation(populationSize);
initInfection(infectRatio);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DrawArea demo = new DrawArea("Demo", lattice, populationSize,population);
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
demo.pack();
demo.setLocationRelativeTo(null);
demo.setVisible(true);
for(int i =0;i<1000;i++){
for(int j=0; j<populationSize; j++){
population.get(j).move(0.8);
}
demo.clear();
demo.updatePositions(population);
}
}
});
}
As shown below, the chart (view) listens to its dataset (model) and updates itself accordingly. When the Move button is pressed, each XYDataItem in the series in modified in update() to reflect its new position.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see http://stackoverflow.com/a/19749344/230513
* #see http://stackoverflow.com/a/7208723/230513
*/
public class ScatterMove extends JFrame {
private static final int N = 16;
private static final String title = "Scatter Move Demo";
private static final Random rand = new Random();
private XYSeries moved = new XYSeries("Population");
public ScatterMove(String s) {
super(s);
update();
final ChartPanel chartPanel = createDemoPanel();
this.add(chartPanel, BorderLayout.CENTER);
JPanel control = new JPanel();
control.add(new JButton(new AbstractAction("Move") {
#Override
public void actionPerformed(ActionEvent e) {
moved.clear();
update();
}
}));
this.add(control, BorderLayout.SOUTH);
}
private void update() {
for (int i = 0; i < N; i++) {
moved.add(new XYDataItem(rand.nextGaussian(), rand.nextGaussian()));
}
}
private ChartPanel createDemoPanel() {
JFreeChart jfreechart = ChartFactory.createScatterPlot(
title, "X", "Y", createSampleData(),
PlotOrientation.VERTICAL, true, true, false);
XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
XYItemRenderer renderer = xyPlot.getRenderer();
NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
domain.setRange(-3.0, 3.0);
domain.setTickUnit(new NumberTickUnit(1));
NumberAxis range = (NumberAxis) xyPlot.getRangeAxis();
range.setRange(-3.0, 3.0);
range.setTickUnit(new NumberTickUnit(1));
return new ChartPanel(jfreechart){
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
};
}
private XYDataset createSampleData() {
XYSeriesCollection xySeriesCollection = new XYSeriesCollection();
xySeriesCollection.addSeries(moved);
return xySeriesCollection;
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ScatterMove demo = new ScatterMove(title);
demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
demo.pack();
demo.setLocationRelativeTo(null);
demo.setVisible(true);
}
});
}
}

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