JFreeChart array as dataset - java

I am using JFreeChart to plot a line graph. I would like to load arrays as the data set... one array for the x-axis and another array for the y-axis.
I am having a problem when trying to pass the array as the data to use in the dataset.
The following is what I've tried;
public DefaultCategoryDataset createDataset(int[] epochNo, int[] BFacts)
{
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 0; i<epochNo.length(); i++)
{
dataset.addValue(epochNo[i], BFacts[i]);
}
return dataset;
}
Thanks in advance!

There are two solutions; with a normal line chart, you use a DefaultCategoryDataset. The addValue method has three arguments, the second being the name of the dataset. And the third is the column label:
dataset.addValue(BFacts[i], "myline", String.valueOf(epochNo[i]));
There other solution is to see this as an XY line chart (using ChartFactory.createXYLineChart). In that case your dataset is an XYDataset instead of a CategoryDataset:
private XYDataset createDataset(int[] epochNo, int[] bFacts) {
final XYSeries myline = new XYSeries( "myline" );
for (int i = 0; i < epochNo.length; i++) {
myline.add(epochNo[i], bFacts[i]);
}
final XYSeriesCollection dataset = new XYSeriesCollection( );
dataset.addSeries(myline);
return dataset;
}
See more in this example

Related

JFreeChart: How to plot a line graph and a scatter on same chart

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.

Built class to create a JFreeChart, how do I add it to a JPanel in my main interface?

Have just come across JFreeChart and am trying it out for my project... I created a class, called "CountryVsCountryChart", that I want to use to create a new chart, according to the options parsed through. What I want to know is how can I add an object of this class to a JPanel in my main interface? I want to be able to do this via selecting an option in a JComboBox, but I think I would be able to handle that...
Here is the the code for the class (minus the appropriate import statements) below:
public class CountryVsCountryChart extends JPanel
{
private static final long serialVersionUID = 1L;
private ArrayList<Player> players;
private StatUtilities stats;
public CountryVsCountryChart(String applicationTitle, String chartTitle, ArrayList<Player> players, int option) {
//super(applicationTitle);
this.players = players;
stats = new StatUtilities();
// This will create the dataset
PieDataset dataset = createDataset(option);
// based on the dataset we create the chart
JFreeChart chart = createChart(dataset, chartTitle);
// we put the chart into a panel
ChartPanel chartPanel = new ChartPanel(chart);
// default size
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
}
/** * Creates a sample dataset */
private PieDataset createDataset(int graphDisplayOption) {
ArrayList<String> countries = new ArrayList<String>();
for (Player p : players) {
countries.add(p.getCountryName());
}
//Get unique country names
Set<String> countryNames = new HashSet<String>(countries);
DefaultPieDataset result = new DefaultPieDataset();
/*
* The below code block uses a switch statement to determine
* which type of stats to display in the graph (country by country).
*
* Options for the switch statement are as follows:
*
* 1 = Average Balls Bowled
* 2 = Average of Bowling Averages
* 3 = Average Career Lengths
* 4 = Average Economy Rates
* 5 = Average Number of 5 Wicket Innings
* 6 = Average Innings Played
* 7 = Average Matches Played
* 8 = Average Runs Conceded
* 9 = Average Strike Rates
* 10 = Average WicketsTaken
*/
for(String c: countryNames)
{
switch(graphDisplayOption)
{
case 1:
result.setValue(c, stats.aveBallsBowled(players, c));
break;
case 2:
result.setValue(c, stats.aveBowlingAverage(players, c));
break;
case 3:
result.setValue(c, stats.aveCareerLength(players, c));
break;
case 4:
result.setValue(c, stats.aveEconRate(players, c));
break;
case 5:
result.setValue(c, stats.aveFiveWicketsInns(players, c));
break;
case 6:
result.setValue(c, stats.aveInningsPerCountry(players, c));
break;
case 7:
result.setValue(c, stats.aveMatchesPerPlayer(players, c));
break;
case 8:
result.setValue(c, stats.aveRunsConceded(players, c));
break;
case 9:
result.setValue(c, stats.aveStrikeRate(players, c));
break;
case 10:
result.setValue(c, stats.aveWickets(players, c));
break;
}
}
return result;
}
/** * Creates a chart */
private JFreeChart createChart(PieDataset dataset, String title) {
JFreeChart chart = ChartFactory.createPieChart3D(
title, // chart title
dataset, // data
true, // include legend
true,
false
);
PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setStartAngle(290);
plot.setDirection(Rotation.CLOCKWISE);
plot.setForegroundAlpha(0.5f);
return chart;
}
}
The next bit of code is for a button listener - for a button I click to display the chart in the jpanel. At the moment it is only two lines of code for testing purposes. The code is in my main interface class called "AppInterface":
private void comparePlayerStatsBtnActionPerformed(java.awt.event.ActionEvent evt) {
/*
* Include below information in a loop to generate chart, based on option selected.
*/
CountryVsCountryChart chart = new CountryVsCountryChart("Test Chart", "A Test Chart", players, 1);
/**/
graphDisplayPanel.add(chart);
}
Also, not sure if this will help, but here is a screen dump of the part of my interface I'm referring to. The white panel is where I want the graph to show up, the JComboBox contains numerous options for what chart to (create) then display, and the button is self explanatory...
As for posting SSCCE's - I wasnt sure whether to include the whole chart class or not. Since I am new to JFreeChart, I thought someone might need to analyse the whole class - as the structure of it may be a problem (as well). If you want to run the project, you can clone it from GitHub here - https://github.com/rattfieldnz/Java_Projects/tree/master/PCricketStats.
In your CountryVsCountryChart, you've not actually added anything to it...
public class CountryVsCountryChart extends JPanel
{
private static final long serialVersionUID = 1L;
private ArrayList<Player> players;
private StatUtilities stats;
public CountryVsCountryChart(String applicationTitle, String chartTitle, ArrayList<Player> players, int option) {
//super(applicationTitle);
this.players = players;
stats = new StatUtilities();
// This will create the dataset
PieDataset dataset = createDataset(option);
// based on the dataset we create the chart
JFreeChart chart = createChart(dataset, chartTitle);
// we put the chart into a panel
ChartPanel chartPanel = new ChartPanel(chart);
// Don't forget me...
setLayout(new BorderLayout());
add(chartPanel);
}
Baiscally, I changed the layout manager for graphDisplayPanel to BorderLayout, via the form desinger and added a call to repaint to try and force the repaint manager to update the UI.
private void comparePlayerStatsBtnActionPerformed(java.awt.event.ActionEvent evt)
{
/*
* Include below information in a loop to generate chart, based on option selected.
*/
CountryVsCountryChart chart = new CountryVsCountryChart("Test Chart", "A Test Chart", players, 1);
/**/
graphDisplayPanel.add(chart);
repaint();
}

AChartEngine Y-Axis custom labels area margins and chart values as String?

I have created a Chart shows Questions (X) / Time (Y) answered during a test.
You can see the first question here for details.
But now I need to show the chart bullet values correctly, at the moment shows the milliseconds value but i need to show the custom hh:mm:ss value like I've done with the Y-Axis label and somehow customize the Y-Axis area to show the full values correctly.
Below is a screenshot of how the chart looks like now.
[EDIT]
With Dan's help I almost got what I want. It's just a little problem.
Check in the screenshot below where the chart values now appearing.
I updated to 1.1.0 from the AChartEngine repository.
addNotations is on the TimeSeries objects. I copy paste my code below where adding data to my TimeSeries instance.
myQuestionsTimeSeries.add(i, DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()));
xyMultipleSeriesRenderer.addYTextLabel(DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()),
String.valueOf(answer.getEstimatedAnswerTime()));
myQuestionsTimeSeries.addAnnotation(String.valueOf(answer.getEstimatedAnswerTime()), i,
DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()));
The code results to this Chart:
[EDIT]
This is basically the whole class:
private void initQuestionsTimeChart() {
xyMultipleSeriesDataset = new XYMultipleSeriesDataset();
xyMultipleSeriesRenderer = new XYMultipleSeriesRenderer();
questionsTimeChart = ChartFactory.getLineChartView(getActivity(), xyMultipleSeriesDataset, xyMultipleSeriesRenderer);
rootView.addView(questionsTimeChart);
initSeriesData();
}
private void initSeriesData() {
createMyQuestionsSeries();
addSeriesAndRenderer(myQuestionsTimeSeries, myQuestionsRenderer);
xyMultipleSeriesRenderer.setYTitle("Questions Time");
xyMultipleSeriesRenderer.setXTitle("Questions Number");
xyMultipleSeriesRenderer.setMarginsColor(Color.argb(0, 255, 255, 255));
xyMultipleSeriesRenderer.setAxesColor(Color.BLACK);
xyMultipleSeriesRenderer.setLabelsColor(Color.BLACK);
xyMultipleSeriesRenderer.setXLabelsColor(Color.BLACK);
xyMultipleSeriesRenderer.setYLabelsColor(0, Color.BLACK);
xyMultipleSeriesRenderer.setAxisTitleTextSize(16);
xyMultipleSeriesRenderer.setLabelsTextSize(15);
xyMultipleSeriesRenderer.setYLabelsAlign(Paint.Align.RIGHT);
xyMultipleSeriesRenderer.setSelectableBuffer(20);
xyMultipleSeriesRenderer.setYLabels(0);
xyMultipleSeriesRenderer.setMargins(new int[]{ 80, 80, 80, 80 });
}
private void addSeriesAndRenderer(XYSeries series, XYSeriesRenderer renderer) {
xyMultipleSeriesDataset.addSeries(series);
xyMultipleSeriesRenderer.addSeriesRenderer(renderer);
}
private void createMyQuestionsSeries() {
myQuestionsTimeSeries = new TimeSeries("My Questions/Time");
myQuestionsRenderer = new XYSeriesRenderer();
myQuestionsRenderer.setColor(Color.BLUE);
myQuestionsRenderer.setLineWidth(3f);
myQuestionsRenderer.setPointStyle(PointStyle.CIRCLE);
myQuestionsRenderer.setFillPoints(true);
myQuestionsRenderer.setChartValuesSpacing(10f);
}
private void fillData() {
int i = 0;
for (Answer answer : getAnswers()) {
i++;
if (answer.getEstimatedAnswerTime() != null) {
myQuestionsTimeSeries.add(i, DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()));
xyMultipleSeriesRenderer.addYTextLabel(DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()),
String.valueOf(answer.getEstimatedAnswerTime()));
myQuestionsTimeSeries.addAnnotation(String.valueOf(answer.getEstimatedAnswerTime()), i,
DateTimeHelper.getMillisFromTime(answer.getEstimatedAnswerTime()));
}
}
}
Thank you in advance!
First of all, hide the chart values:
renderer.setDisplayChartValues(false);
Then, for each chart value, add an annotation:
renderer.addAnnotation("text", x, y);
For the Y axis labels to be visible, just align them to LEFT:
renderer.setYLabelsAlign(Align.LEFT);
Or you can increase the margins:
renderer.setMargins(margins);
Make sure you are using the latest ACE build available here.

How to display the total in a StackedXYBarChart

I create and pass a TimeTableXYDataset to display a StackedBarChart, quite similar to the StackedXYBarChartDemo2 from the demo package. In addition to the values displayed as ItemLabels, I would like to display the sum of all values above every bar. Does anyone know if this is doable, and how ?
You can define a custom XYItemLabelGenerator which will sum the two series.
For example :
DateAxis domainAxis = new DateAxis("Date");
domainAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
NumberAxis rangeAxis = new NumberAxis("Y");
// Set a margin so that the label above the bar has a place to display
rangeAxis.setUpperMargin(0.15);
StackedXYBarRenderer renderer = new StackedXYBarRenderer(0.10);
renderer.setDrawBarOutline(false);
XYPlot plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
// Custom LabelGenerator, which displays the sum of the two series.
XYItemLabelGenerator generator = new XYItemLabelGenerator() {
#Override
public String generateLabel(XYDataset dataset, int series, int item) {
// Sum values for the two series of data
double sum = dataset.getYValue(0, item) + dataset.getYValue(1, item);
return "" + sum;
}
};
// The LabelGenerator is linked to series 1 (top part of the bar)
renderer.setSeriesItemLabelGenerator(1, generator);
renderer.setSeriesItemLabelsVisible(1, true);
renderer.setSeriesPositiveItemLabelPosition(1, new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12,
TextAnchor.BASELINE_CENTER));
renderer.setItemLabelAnchorOffset(10);
JFreeChart chart = new JFreeChart("Stacked XY Bar Chart Demo 2", plot);
return chart;

JFreeChart to represent 3D data in a 2D graph using colourmaps

I'm currently trying to use JFreeChart to represent 3D data in a 2D graph.
Essentially, I have a 2d array called data[i][j]. The i and j represent the y and x coordinates where I want to plot. The value of data[i][j] represents a frequency value, which I want to represent in the graph as a colour.
I'm not entirely sure what something like this is called, but it would look something like this:
Now I have been trying to do this using XYBlockRenderer, however I am having issues with defining the dataset. I am trying to use DefaultXYZDataset, but I'm really confused at how to even define the data here.
Can someone explain how to use the DefaultXYZDataset to accomplish such a task?
DefaultXYZDataset dataset = new DefaultXYZDataset();
Concentration.dataoutHeight = Concentration.dataout[0].length;
System.out.println(Concentration.dataoutHeight);
System.out.println(ImageProcessor.MAXCBVINT);
double[][] data = new double[3][ImageProcessor.MAXCBVINT];
for (int i = 0; i < Concentration.dataoutHeight; i++) {
for (int j = 0; j < ImageProcessor.MAXCBVINT; j++) {
data[0][j] = j;//x value
data[1][j] = i;//y value
data[2][j] = Concentration.dataout[j][i][0];//Colour
}
dataset.addSeries(i, data);
}
NumberAxis xAxis = new NumberAxis("Intensity");
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
xAxis.setLowerMargin(0.0);
xAxis.setUpperMargin(0.0);
NumberAxis yAxis = new NumberAxis("Distance to Closest Blood Vessel (um)");
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setLowerMargin(0.0);
yAxis.setUpperMargin(0.0);
XYBlockRenderer renderer = new XYBlockRenderer();
PaintScale scale = new GrayPaintScale(0, 10000.0);
renderer.setPaintScale(scale);
renderer.setBlockHeight(1);
renderer.setBlockWidth(1);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinesVisible(false);
plot.setRangeGridlinePaint(Color.white);
JFreeChart chart = new JFreeChart("Surface Plot", plot);
chart.removeLegend();
chart.setBackgroundPaint(Color.white);
ChartFrame frame = new ChartFrame("Surface Map - "
+ (Concentration.testing ? "TESTING using "
+ Concentration.testfile : currentFile.getName()), chart);
frame.pack();
frame.setVisible(true);
You have two options:
Represent them as 3d
3D Lib for JFreeChart
You need to use the class : XYBlockRenderer which does exactly what you are asking. You can download the JFreeChart demo collection where the code for this is given.
(source code of class here)
There is also this full code example with 4D very similar.

Categories