I'm trying to make a pretty simple chart which graphs measured forces over the period of a second. I have plain-jane example which is outputting the following graph:
Here's my code:
TimeSeries series1 = new TimeSeries("Force", "Domain", "Range");
//generate values
for (int i = 0; i < 1000; i++) {
series1.add(new TimeSeriesDataItem(new Millisecond(i, 0, 0, 0, 1, 1, 2012), i));
}
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(series1);
JFreeChart chart = ChartFactory.createXYLineChart("Measured Forces",
"Time", "Force in Pounds", dataset, PlotOrientation.VERTICAL,
false, false, false);
ChartUtilities.saveChartAsPNG(new File("/home/rfkrocktk/Desktop/chart.png"), chart, 1280, 720);
How can I transform those ugly 1,325,404,800,000 values into simple 0-1,000 values representing the overall time measured instead of the exact system time?
I've been looking for constructors that match my requirements, but I can't seem to find them.
ChartFactory.createXYLineChart() creates two instances of NumberAxis, one for each of the domain and range. As an alternative, consider ChartFactory.createTimeSeriesChart(), which uses a DateAxis for the domain. In either case, you can use setXxxFormatOverride() on the axis to get any desired format. The example shown here specifies a factory DateFormat.
As far as I know, TimeSeries does not support the concept of 'relative time' - all of the x value types (like Millisecond) are based on java.util.Date, which yields an absolute time.
I think you might be better off using XYSeries instead of TimeSeries. Then the x values can be integers.
The trick is to use RelativeDateFormat for the domain axis formatting with ChartFactory.createTimeSeriesChart(). This prints labels in the format of #h#m#.###s. For example, you might see "0h0m2.529s".
JFreeChart chart;
XYPlot plot;
DateAxis axis;
TimeSeriesCollection dataset;
TimeSeries series;
RelativeDateFormat format;
long startTime;
series = new TimeSeries("Time");
dataset = new TimeSeriesCollection(series);
chart = ChartFactory.createTimeSeriesChart("Relative", "Elapsed Time", "Value", dataset, true, true, true);
plot = chart.getXYPlot();
axis = (DateAxis) plot.getDomainAxis();
format = new RelativeDateFormat();
startTime = System.currentTimeMillis();
axis.setDateFormatOverride(format);
format.setBaseMillis(startTime);
Related
I'm trying to to make a chart that takes data from serial port and plot them in y axes and i want current time in x axes.. I think that i set my code correctly because i managed to run it as XY chart now in TimeSeries chart my only issue is that in method series.add(TIME, SERIALDATA); i dont know how to initialize TIME , i know that i want an object RegularTimePeriod but i dont know how to do that..
here is the code.. i know that only some lines are missing please help me to find them...
void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 817, 525);
final TimeSeries series = new TimeSeries("Charts");
final SerialDataReceived serialdataprint = new SerialDataReceived();
final TimeSeriesCollection data = new TimeSeriesCollection(series);
final JFreeChart chart = ChartFactory.createXYLineChart(
"Tmperature IN",
"Time",
"C",
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setBounds(10, 11, 477, 224);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
chartPanel.setVisible(true);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(chartPanel);
chartPanel.setLayout(null);
Thread outtempthread=new Thread() { //THREAD THAT RUNS ALL THE TIME
public void run() {
try {
while (true){
Thread.sleep(2000);
double intemp = serialdataprint.getintemp(); //THIS WHERE I TAKE MY SERIAL DATA
series.add(I WANT TO DISPLAY HERE LETS SAY 13:23:15, intemp); //HERE IS MY PROBLEM
}}
catch (InterruptedException ie) {}
}
};
outtempthread.start();
}
I've only ever used TimeSeries measured in days so I used the org.jfree.data.time.Day class.
Here's the jfreechart javadoc for all the different time classes : http://www.jfree.org/jfreechart/api/javadoc/org/jfree/data/time/package-summary.html
Try out a few and see what's right for you.
Since you appear to only need hour,minute second of a single day, you might be able to use the Second class.
Here is how you would make a TimeSeries that way:
int todaysDay =...
int todaysMonth =...
int todaysYear =...
TimeSeries series = new TimeSeries(name, Second.class);
//this should mark 'inTemp' as 13:23:15
series.add(new Second(15,23,13,todaysDay, todaysMonth, todaysYear),
inTemp);
ok!! finally i found the solution! i don't know if is the correct way but it works an now i have real time in my chart every time my serial port updates here is the fix code!
String timeStamp1 = new SimpleDateFormat("mm").format(Calendar.getInstance().getTime());
int minute = Integer.parseInt(timeStamp1);
double intemp = serialdataprint.getintemp();
series.addOrUpdate(new Minute(minute,hour), intemp);
A couple of pointers:
The ChartFactory.createXYLineChart() method will create a line chart where both the X and Y axes are numerical. Try the createTimeSeriesChart() to get a chart that shows dates on the X axis (or create a new DateAxis() instance and call plot.setDomainAxis() to change the X axis);
The TimeSeriesCollection class is a good dataset to use for time series data if you need the structure that it provides (it enforces a regular time period and prevents duplicates among other things). However, bear in mind that it is simply an implementation of the XYDataset interface where the x-values returned are "milliseconds since 1-Jan-1970" (the standard encoding of "dates" in Java). You can simplify your code by using an XYSeriesCollection (which also implements the XYDataset interface), and call System.currentTimeInMillis() to get the current x-value when new data comes in. The date axis on your chart will take care of presenting a date scale for this data.
I am using JFreeChart library to create Chart on website (library integrated with my application according to this tutorial). Everything looks great except one thing: for some reason, for some data line chart is not completly visible (please see screen).
I don't know why is it happening. I'm posting code responsible for configuration:
public JFreeChart createChart()
{
NumberAxis numberaxis = new NumberAxis("X");
numberaxis.setAutoRangeIncludesZero(false);
NumberAxis numberaxis1 = new NumberAxis("Y");
numberaxis1.setAutoRangeIncludesZero(false);
XYSplineRenderer xysplinerenderer = new XYSplineRenderer();
XYPlot xyplot = new XYPlot(createSampleData(), numberaxis, numberaxis1, xysplinerenderer);
xyplot.setBackgroundPaint(new Color(238, 242, 250));//
xyplot.setDomainGridlinePaint(new Color(238, 242, 250));
xyplot.setRangeGridlinePaint(new Color(238, 242, 250));
xyplot.getRenderer().setSeriesPaint(0, Color.BLUE);
xyplot.setAxisOffset(new RectangleInsets(4D, 4D, 4D, 4D));
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) xyplot.getRenderer();
renderer.setSeriesShapesVisible(0, true);//FIXME Dots
xyplot.getDomainAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits());
JFreeChart jfreechart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, xyplot, true);
jfreechart.setBackgroundPaint(Color.white);
return jfreechart;
}
The link provided by Richard describes the problem well; but, ultimately, it looks like you need to manually set the upper bound of your range axis to account for the upper curve of the spline produced by XYSplineRenderer. For your example above, this might be:
xyplot.getRangeAxis().setUpperBound(22.5);
For practical purposes, you would probably want to calculate the maximum Y value, and either add a percentage to it, or more complicated, calculate a ceiling based on its surrounding points. I would start by adding 10% and see how that goes:
// Iterate data values; use Math.max() to determine maxYValue; then:
xyplot.getRangeAxis().setUpperBound( maxYValue + maxYValue * 0.1);
It's at patch, but it should provide the result you want, depending on the nature of your data and the curves produced connecting data points.
i have two sets of data
int[] x1 = {1,2,3,4,5,6,7,8,9,10};
int[] y1 = {1,2,3,5,6,8,9,10,14,11};
int[] x2 = {1,2,3,4,5,6,7,8,9,10};
int[] y2 = {0,2,3,5,0,8,9,8,14,11};
int[] z2 = {1,2,3,1,2,3,1,2,3,1};
I want to plot the x1,y1 as an XYLineChart and then plot x2,y2 as a scatter on the same plot without a line.
I also need each scatter point of xy,y2 to be a different color depending on the value of z2 (1=Color.red, 2=Color.green, 3=Color.blue)
How can i do this?
So far i have:
JPanel panel_1 = new JPanel();
panel_1.setLayout(new BorderLayout(0, 0));
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series1 = new XYSeries("series1");
for(int i=0; i<x1.length; i++){
series1.add(x1[i],y1[i]);
}
dataset.add(series1);
JFreeChart chart = ChartFactory.createXYLineChart("Title", "x", "y", dataset, PlotOrientation.VERTICAL, false, false, false);
ChartPanel cp = new ChartPanel(chart);
panel_1.add(cp, BorderLayout.CENTER);
This gets the line graph sorted. I now need to code the scatter plot for x2,y2 (with colors described above) which is where im stuck.
The createXYLineChart() method will create a chart that uses an XYLineAndShapeRenderer. So fetch the renderer from the plot and cast it to XYLineAndShapeRenderer. Then you can call the methods setSeriesLinesVisible() and setSeriesShapesVisible() to control, for each series, whether shapes and/or lines are drawn for the data items. That way you can use a single renderer and dataset, which makes things simpler.
Your requirement to change the colors depending on another data value requires a little more work. You should subclass the XYLineAndShapeRenderer class and override the getItemPaint(int, int) method. Here you can return any color you want for a data item. The default implementation looks at the series index and returns the color for the series. You need to look at the item index as well, then do a lookup in your table of z-values and decide what color to return.
i'm trying to make an overlaid plot,
And my problem is that i can't bring the second plot to fit the second one.
Here is my first plot :
And here the second one :
And when i try to fit both, here is what i get :
So basically, i would like to fit the whole second plot between 0 and 30, how can i do this without losing any data?
First I tried using plot.mapDatasetToRangeAxis()
Then i tried with :
domain.setRange(0.00, 30.0);
domain.setTickUnit(new NumberTickUnit(1));
But i couldn't bring neither the first, nor the second one to work as i wish.
Do you have any other ideas? (except buying this - which i can't afford right now as a student).
Any help will be greatly appreciated :)
Oh and by the way the x-axis is a speed (forgot to draw it on the plot).
So here a very ugly photomontage of the kind of result i wish to have (with fitting units on the x and y axis) :
Sorry for my Gimp skills, which are beyond bad.
Here is what i did :
private JFreeChart createOverlaidChart()
{
final NumberAxis domainAxis = new NumberAxis("Speed (m / s)");
final ValueAxis rangeAxis = new NumberAxis("Power (kw)");
// create plot ...
final IntervalXYDataset data0 = createDataset0();
final XYItemRenderer renderer0 = new XYBarRenderer(0.20);
// change "new XYBarRenderer(0.20)" to "StandardXYItemRenderer()" if you want to change type of graph
final XYPlot plot = new XYPlot(data0, domainAxis, rangeAxis, renderer0);
// add a second dataset and renderer...
final IntervalXYDataset data1 = createDataset1();
final XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer(false, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(1, data1);
plot.setRenderer(1, renderer1);
// add a third dataset and renderer...
final IntervalXYDataset data2 = createDataset2();
final XYLineAndShapeRenderer renderer2 = new XYLineAndShapeRenderer(true, true);
// arguments of new XYLineAndShapeRenderer are to activate or deactivate the display of points or line. Set first argument to true if you want to draw lines between the points for e.g.
plot.setDataset(2, data2);
plot.setRenderer(2, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
// return a new chart containing the overlaid plot...
return new JFreeChart("Test", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
The Range Axis is the Vertical/Y Axis, you need to add a second Domain Axis (Horizontal/X Axis) to your chart.
I did something similar -- although using same X axis vales but differing Y axis. For this, I use single Domain (you'd want single Range). I convert for you (there may be typos due to my edits):
priceXYPlot.setRangeAxis( new new NumberAxis( "Y" ) );
priceXYPlot.setDomainAxis( 0, new NumberAxis( "X1" ) );
priceXYPlot.setDomainAxis( 1, new NumberAxis("X2") );
and mapDatasetToRangeAxis so that you had two diff X axis along top & bottom, something like:
priceXYPlot.setDataset( 0, data0);
priceXYPlot.mapDatasetToDomainAxis( 0, 0 ); //1st dataset to 1st x-axis
priceXYPlot.setDataset( 1, data1 );
priceXYPlot.mapDatasetToDomainAxis( 1, 1 ); //2nd dataset to 2nd x-axis
How could I add to a plot an OHLCSeriesCollection and a TimeSeriesCollection , in order to represent their values in the same chart ?
Both OHLCSeriesCollection and TimeSeriesCollection are based on XYDataset so you should be able to add them both to an XYPlot with something like the following:
JFreeChart chart = // create your XY chart here.
XYPlot plot = chart.getXYPlot();
OHLCSeriesCollection ohlsSeriesDataset = // create you ohlc dataset here.
TimeSeriesCollection timeSeriesDataset = // create you time dataset here.
AbstractXYItemRenderer olhsSeriesRenderer = // create your ohlc renderer here.
AbstractXYItemRenderer timeSeriesRenderer = // create your time renderer here.
plot.setDataset(0, ohlsSeriesDataset);
plot.setDataset(1, timeSeriesDataset);
plot.setRenderer(0, olhsSeriesRenderer);
plot.setRenderer(1, timeSeriesRenderer);
The type of renderer to use for olhsSeriesRenderer and timeSeriesRenderer really depends on the type of chart you want to generate so I cannot give you specifics here.
I have not tried this myself with XY datasets, but I have been able to do combine CategoryDatasets using this.