I'm currently using JFreeChart to create a line chart. This line chart gets updated every second with a new value (currently a random value). This way you can see how your data has changed over a certain time period. However after I've added over ten values they don't fit on the line anymore turning into dots. I would like to only have 5 values shown at a time which are spread across the entire timings. This is how it looks now:
Notice the dots at the bottom of the chart. I would like it to be changed to this:
Note that I want to keep all points which are created between these points in time. So data from 11:31:00, 11:31:01, 11:31:02 etc. should be still there.
This is what I currently have:
LocalDateTime date = LocalDateTime.now();
category = new DefaultCategoryDataset();
category.addValue(new Random().nextInt(10), "Data", date.getHour() + ":" + date.getMinute() + ":" + date.getSecond());
chart = ChartFactory.createLineChart("Values", "Time", "Data", category, PlotOrientation.VERTICAL, false, true, false);
((NumberAxis) ((CategoryPlot) chart.getPlot()).getRangeAxis()).setStandardTickUnits(NumberAxis.createIntegerTickUnits());
I got it by using a TimeSeriesChart. This is what I ended up with:
TimeSeriesCollection collection = new TimeSeriesCollection();
TimeSeries serie = new TimeSeries("Data");
collection.addSeries(serie);
JFreeChart chart = ChartFactory.createTimeSeriesChart("Data", "Time", "Data", collection, false, true, false);
Related
I am monitoring CPU, RAM and disk IO for a computational pipeline that consists of multiple steps to process the input data. I would like to visualize the hardware consumption for the entire pipeline but also per step of the pipeline.
In order to render hardware consumptions, I'd like to draw a combined plot with jFreeChart with four vertically aligned subplots that all have the same x-axis - time. The top plot is supposed to be a gantt plot to indicate the step of the pipeline. In the second plot I'd like to render the CPU consumption over time. In the third plot the RAM consumption, the bottom plot is for disk IO. The aim is to visually slide horizontally over the plot and see, which step of the pipeline uses how much CPU, RAM and disk.
I'm all set up in eclipse, jFreeChart library installed and all my data is imported and ready to render. All I need is some guidance for how to set up the combined chart up, cause my code blows up, when I try to combine the Gantt plot (which is a category plot) and the CPU plot (which is XY plot):
public JFreeChart createChart() {
final JFreeChart ganttChart = ChartFactory.createGanttChart(
"Gantt of Tasks", // chart title
"Task", // domain axis label
"Time", // range axis label
createGanttDataset(), // data
true, // include legend
true, // tooltips
false // urls
);
JFreeChart cpuChart = ChartFactory.createTimeSeriesChart(
"CPU load", // title
"Time", // x-axis label
"CPU Load", // y-axis label
createCpuDataset(), // data
true, // create legend?
true, // generate tooltips?
false // generate URLs?
);
// parent plot...
final CombinedRangeCategoryPlot plot = new CombinedRangeCategoryPlot();
plot.setGap(10.0);
// add the subplots...
plot.add(ganttChart.getCategoryPlot(), 1);
plot.add(cpuChart.getCategoryPlot(), 1);
plot.setOrientation(PlotOrientation.VERTICAL);
// return a new chart containing the overlaid plot...
return new JFreeChart("Combined GANTT/CPU plot",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
}
private IntervalCategoryDataset createGanttDataset() {
final TaskSeries taskSeries = new TaskSeries("Tasks");
for (Map.Entry<DoubleLong, String> entry : algoStartEndDates.entrySet()) {
final String taskTitle = entry.getValue();
final long startDate = entry.getKey().n1;
final long endDate = entry.getKey().n2;
taskSeries.add(new Task(taskTitle, new SimpleTimePeriod(startDate, endDate)));
}
final TaskSeriesCollection collection = new TaskSeriesCollection();
collection.add(taskSeries);
return collection;
}
private XYDataset createCpuDataset() {
final TimeSeries timeSeries = new TimeSeries("CPU load");
for (CollectlData data : collectlData) {
final RegularTimePeriod t = new Millisecond(new Date(data.getUtcTime()));
timeSeries.add(t, data.getCpuData().getTotal());
}
final TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(timeSeries);
dataset.setDomainIsPointsInTime(true);
return dataset;
}
I would expect this to create a combined plot, but I'm receiving the error message:
Caused by: java.lang.ClassCastException: class org.jfree.chart.plot.XYPlot cannot be cast to class org.jfree.chart.plot.CategoryPlot (org.jfree.chart.plot.XYPlot and org.jfree.chart.plot.CategoryPlot are in unnamed module of loader 'app')
at org.jfree.chart.JFreeChart.getCategoryPlot(JFreeChart.java:824) ~[jfreechart-1.0.15.jar:1.0.15]
I want to create a chart using mysql database with Jfreechart, this is the code i used :
try {
String query =
"Select id,Prop_menages_Urbains_Proprietaires from fes";
JDBCCategoryDataset dataset =
new JDBCCategoryDataset(
DBConnection.DBConnection(),
query
);
JFreeChart chart =
ChartFactory.createBarChart(
"test",
"id",
"Prop_menages_Urbains_Proprietaires",
dataset,
PlotOrientation.VERTICAL,
false,
true,
true
);
BarRenderer render = null;
CategoryPlot plot = null;
render = new BarRenderer();
ChartFrame fram =
new ChartFrame("test", chart);
fram.setVisible(true);
fram.setSize(600,650);
}
catch(Exception ex) {
System.out.println("Erreur: " + ex);
}
after the execution the barchart doesn't show up although there are no errors in the code syntax
any help please ?
UPDATE: i tried the same code but this time i used other columns from the database and it worked , what's the issues with the other one knowing that they're all numbers
The JDBCCategoryDataset API specifies:
The SQL query must return at least two columns. The first column will be the category name and remaining columns values (each column represents a series).
This complete example, which you have successfully adapted, illustrates the effect. The question then becomes,
What's the issues with the other one knowing that they're all numbers?
The executeQuery() source shows how each of the java.sql.Types is mapped to a numeric value: a numeric type becomes a Number directly, a date type becomes a Number representing milliseconds from the Java epoch, and a character type is converted using Double.valueOf(); the default is null.
In this case, verify that Prop_menages_Urbains_Proprietaires has a SQL type that is suitable for conversion to a numeric value.
I am trying to create a interconnect between multiple points in a XY chart with jfreechart. This chart.add( 1.0 , 4.0 );chart.add( 2.0 , 5.0 ); chart.add( 2.5 , 7.0 ); sort of connects them in a line. Like this - wrong image. But I want to return back to the 1st point and create a chart like this -correct image. And I want to repeat it for multiple base nodes. Something like this -
for(int i=0;i<=1000;i++){
for(int j=0;j<=30;j++){
chart.add(arr1[i], arr2[j]);
}
}
How can I go about this ?
Try using multiple XYSeries:
In the XYSeries constructor set autosort to false to allow the lines to go backwards if needed, and set allowDuplicates to true if you may need to navigate a series through a point that has already been plotted.
final XYSeries series1 = new XYSeries("Data 1", false, true);
series1.add( 1.0 , 4.0 );
series1.add( 2.0 , 5.0 );
final XYSeries series2 = new XYSeries("Data 2", false, true);
series2.add( 1.0 , 4.0 );
series2.add( 2.5 , 7.0 );
final XYSeriesCollection data = new XYSeriesCollection();
data.addSeries(series1);
data.addSeries(series2);
final JFreeChart chart = ChartFactory.createXYLineChart(
"XY Chart",
"X",
"Y",
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
To add further data series, use more invocations of XYSeriesCollection.addSeries(series).
I am learning java and I am trying to build an app. I'm stuck with this one last part of the application and was hoping some of you may be able to help me. The application stores values in a database and, upon the users request, it will retrieve the data and plot this data on a line graph. The application is producing a line graph, but my issue is that it is producing one line graph for each piece of data that it retrieves from the database. So if the query returns 15 results, the application produces 15 graphs with one plot each. I want all of the data retrieved and plotted onto one graph. Below is my code. Can someone point me in the right direction?
try
{
Connection con = new DataConnection().connect();
ResultSet rs;
PreparedStatement retrieve = con.prepareStatement("SELECT row FROM table");
rs = retrieve.executeQuery();
while (rs.next())
{
String string = rs.getString(1);
double double = Double.parseDouble(string);
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(double, "Chart", "Data");
JFreeChart chart = ChartFactory.createLineChart("Graph", "Data", "Data", dataset, PlotOrientation.VERTICAL, true, false, false);
CategoryPlot p = chart.getCategoryPlot();
p.setRangeGridlinePaint(Color.black);
ChartFrame frame = new ChartFrame("Line Chart", chart);
frame.setVisible(true);
frame.setSize(450, 350);
}
}
So if the query returns 15 results, the application produces 15 graphs
with one plot each. I want all of the data retrieved and plotted onto
one graph.
Your code creates a new JFreeChart instance for each row in your database query result set and that's why you get too many frames with charts opened. You have to create just a single JFreeChart instance and add the data to its model as a series.
See this related Q&A: Multiple graphs in multiple figures using jFreeChart. There are also plenty of examples under jfreechart tag.
I need to draw hysteresis loops and then calculate the area closed within the loop. I am using jFreeChart.
consider the following data:
hyst[0]=0;
hyst[1]=0;
hyst[2]=0.0098;
hyst[3]=0.0196;
hyst[4]=0.0489;
hyst[5]=0.0879;
hyst[6]=0.0684;
hyst[7]=0.0489;
hyst[8]=0.0196;
hyst[9]=0.0098;
hyst[10]=0;
hyst[11]=0;
hyst[12]=0;
hyst[13]=0;
hyst[14]=0;
hyst[15]=-0.0195;
hyst[16]=-0.0488;
hyst[17]=-0.0391;
hyst[18]=-0.0195;
hyst[19]=0;
hyst[20]=0;
When I try :
public void plotHysteresis()
{
int j=0;
int i=0;
XYSeries series1 = new XYSeries("Before Treatment");
// DefaultCategoryDataset series1 = new DefaultCategoryDataset();
for(i=0;i<6;i++)
{
series1.add(j,hyst[i]);
logTextArea.append(Integer.toString(j) +" : " +Double.toString(hyst[i])+"\n");
j=j+5;
}
j=j-5;
for(;i<11;i++)
{
j=j-5;
series1.add(j,hyst[i]);
logTextArea.append(Integer.toString(j) +" : " +Double.toString(hyst[i])+"\n");
}
for(;i<16;i++)
{
j=j-5;
series1.add(j,hyst[i]);
logTextArea.append(Integer.toString(j) +" : " +Double.toString(hyst[i])+"\n");
}
for(;i<21;i++)
{
j=j+5;
series1.add(j,hyst[i]);
logTextArea.append(Integer.toString(j) +" : " +Double.toString(hyst[i])+"\n");
}
XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);
JFreeChart chart = ChartFactory.createXYAreaChart(
"Hysteresis Plot", // chart title
"Pounds (lb)", // x axis label
"Distance (inches)", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
chart.setBackgroundPaint(Color.white);
ChartPanel frame = new ChartPanel(chart);
frame.setVisible(true);
frame.setSize(plotPanel.getWidth(),plotPanel.getHeight());
plotPanel.add(frame);
plotPanel.repaint();
}
It gives me below result:
If I use :
JFreeChart chart = ChartFactory.createXYLineChart(
"Hysteresis Plot", // chart title
"Pounds (lb)", // x axis label
"Distance (inches)", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
I gives:
I need a hysteresis plot that looks like:
I guess the difference is the way points are being connected. Please guide how to obtained the desired hysteresis loop with jFreeChart and then how to calculate area enclosed.
Thanks
How can I change the line color as well the symbols representing the data points. I want all of them to be uniform.
It appears you've settled on JFreeChart for your view. Synthesizing a few other comments,
You can make the colors and shapes of your several series homogeneous by providing a DrawingSupplier, as suggested here and shown here.
You can combine the series into a GeneralPath and estimate the area as outlined here.