I have to implement an histogram using JFreeChart API. This histogram has to represent the datas of this JTable:
So I have a JTable with three columns: "thea", "type", "Number of occurrences". My histogram has two targets: the first is to count the number of occurrences of each thea field; the second is to mark with different colors the bars corresponding to JTable records with different types.
To implement my histogram I used a DefaultCategoryDataset:
private DefaultCategoryDataset createDataset(ArrayList<String>fieldsOccs) {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for(int i = 0; i<this.fieldsOccs.size() && i<end; i++) {
String thea = fieldsOccs.get(i).getFieldName();
String type = fieldsOccs.get(i).getType();
int occurrences = fieldsOccs.get(i).getOccurrences();
dataset.setValue(occurrences, type, thea);
}
return dataset;
}
Anf then I create my chart using a createChart method:
private JFreeChart createChart(DefaultCategoryDataset dataset) {
JFreeChart chart = ChartFactory.createBarChart(
"",
"", //X-axis title
"", //Y-axis title
dataset, //dataset
PlotOrientation.HORIZONTAL, //plot orientation
true, //show legends
true, //use tooltips
false //generate URLs
);
return chart;
}
This is what I get:
As you can see in the picture it is not nice to see. The values on x axes are not formatted correctly.
How can I solve this rendering problem?
--edit
I have this problem just in case of more types in the JTable. For example if my JTable is:
and there is just String, the correspondig histogram is nice:
--edit1
What dou you think about StackedBarChart3D? I get this output:
My histogram has two targets:
You may get a more appealing result with ChartFactory.createHistogram() and a SimpleHistogramDataset, seen here.
To get diverse colors, override the getItemPaint() method in a custom XYBarRenderer, as suggested here.
Related
I'm facing the below issue while using JFreeChart for creating bar chart with relatively large dataset:
Bar chart generated with overlapping X-axis labels. I have tried positioning the labels vertical, still no help. Please provide the best possible way to solve this issue. Code snipped below:
CategoryDataset categoryDataSet = getBarDataset();
JFreeChart barChart = ChartFactory.createBarChart("TITLE", "X-LABEL","Y-LABEL", categoryDataSet, PlotOrientation.VERTICAL, true, true, false);
barChart.getCategoryPlot().getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
barChart.getCategoryPlot().getDomainAxis().setMaximumCategoryLabelLines(4);
jpg = Image.getInstance(im, null);
document.add(jpg);
Update:
As per the suggestion from #trashgod, I've used SlidingCategoryDataset indexing from 0 to the column count. When the column count is large(50 here), the X-Label's are overlapping. When the column count is set to a lower number, it's working fine. I want to find a solution for large column size. Importantly, I need to export the chart image to pdf. Please help me in arriving to a feasible solution. Thanks!
private static void createBarChart() throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(FILE_LOCN));
writer.setStrictImageSequence(true);
document.open();
CategoryDataset categoryDataset = createDataset();
int colCount = categoryDataset.getColumnCount();
SlidingCategoryDataset slidingCategoryDataSet = new SlidingCategoryDataset(categoryDataset, 0, colCount);
JFreeChart barChart = ChartFactory.createBarChart("TITLE", "X-LABEL","Y-LABEL", slidingCategoryDataSet,
PlotOrientation.VERTICAL, true, true, false);
barChart.getCategoryPlot().getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_90);
barChart.getCategoryPlot().getDomainAxis().setMaximumCategoryLabelLines(4);
java.awt.Image im = barChart.createBufferedImage(400, 400);
Image jpg = Image.getInstance(im, null);
jpg.scaleToFit(400, 400);
document.add(jpg);
document.close();
writer.close();
}
private static CategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (int i = 0; i <= 50; i++) {
dataset.addValue(i, "R", "C" + i);
}
return dataset;
}
With a large number of categories, specifying vertical labels via setCategoryLabelPositions() is a good choice for maximizing legibility. Arbitrary CategoryLabelPositions are supported.
In an interactive chart, SlidingCategoryDataset, mentioned here, allows your application to set the count and starting index of visible categories as desired, perhaps using a slider or spinner, as shown here.
How can I achieve this in a PDF?…More pixels seems a good idea, but how can we implement that here?
In a fixed size context with a given number of categories, you can optimize the size of the chart image via createBufferedImage(), as shown here, or Image.scaleToFit(). For yet larger datasets, it may be possible to create multiple linked charts in a domain specific way, e.g. by year or subsidiary.
Hi im trying to create a chart that is a combination of a bar chart and a line chart in JFree chart. The bar chart is vs time and for each hour it will compare two (or more) different values.
The line chart uses the same scale as the bar chart and shows the overall trend of the data set.
You can plot each dataset on the same Plot, and use a different renderer for each dataset (for instance a BarRenderer and LineAndShapeRenderer). Below is a simplified example that generates some mock data values (1-9) and renders the same data as both bars and lines on the same ChartPanel.
//Mock data
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
int[] times = new int[]{1,2,3,4,5,6,7,8,9};
for ( int i = 0; i < times.length; i++ ){
dataset.addValue(times[i], "Time", "Hour" + String.valueOf(i+1));
}
//create the plot
CategoryPlot plot = new CategoryPlot();
//add the first dataset, and render as bar values
CategoryItemRenderer renderer = new BarRenderer();
plot.setDataset(0,dataset);
plot.setRenderer(0,renderer);
//add the second dataset, render as lines
CategoryItemRenderer renderer2 = new LineAndShapeRenderer();
plot.setDataset(1, dataset);
plot.setRenderer(1, renderer2);
//set axis
plot.setDomainAxis(new CategoryAxis("Time"));
plot.setRangeAxis(new NumberAxis("Value"));
And the resulting Chart:
I am working with java, I want to draw a line chart which includes at least two lines at the same time. I can only pass one DefaultCategoryDataset each time as a parameter, and this DefaultCategoryDataset represent one line. so how can I do that?
ChartFactory.createLineChart("String", "String", "String", "DefaultCategoryDataset", "PlotOrientation.HORIZONTAL", "boolean", "boolean", "boolean");
You have to "feed" data with more than one series.
Here it is how i handle this with XYLineChart:
1) I have a private object
private XYSeriesCollection data =null;
2) It is initialised into a method and then another method that "feeds" data is called.
data = new XYSeriesCollection();
fillXYSeries();
3) Here is this method:
private void fillXYSeries(){
data.removeAllSeries();
for(int i=0;i<tables.size();i++){
final XYSeries series = new XYSeries(tables.get(i).getName());
for(int j=0;j<mostIntensiveTables.get(i).getChangesForChart().size();j++){
series.add(j,mostIntensiveTables.get(i).getChangesForChart().get(j));
}
int found=0;
for(int k=0;k<data.getSeriesCount();k++){
if(data.getSeries(k)==series){
found=1;
break;
}
}
if(found==0){
data.addSeries(series);
}
}
}
and finally i construct my chart with data object as parameter:
final JFreeChart chart = ChartFactory.createXYLineChart(
"Most Updated Tables",
"Version ID",
"Number of Changes",
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
The spider web plot of JFreeChart does not display values close to the marked points, as default:
what must be done to display the numbers?
That's what I have now, in a method returning StreamedContent (for PrimeFaces' p:graphicImage:
CategoryDataset categorydataset = createCategoryDataset(displayBy, configuration, null);
SpiderWebPlot plot = new SpiderWebPlot(categorydataset);
plot.setInteriorGap(0.40);
plot.setNoDataMessage("No data available");
plot.setStartAngle(0);
plot.setLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", NumberFormat.getInstance()));
plot.setWebFilled(true);
JFreeChart chart = new JFreeChart(title, TextTitle.DEFAULT_FONT, plot, true);
File chartFile = new File(String.valueOf(new Random().nextLong()));
ChartUtilities.saveChartAsPNG(chartFile, chart, 375, 300);
return new DefaultStreamedContent(new FileInputStream(chartFile), "image/png");
EDIT: After #trashgod's suggestion, some values appeared but no in the expected place. I want the columnKey values, not the `rowKey' values (addValue method in DefaultCategoryDataset class):
What must be done to display the numbers?
You can label points on the plot using a CategoryItemLabelGenerator, as shown here.
What matters are the three other [points].
It looks like you might be able to add a second series, one with a second rowKey, in order to get labels associated with those points.
I have a data source in which there are three departments and each department has equal employees that are 8.
I want to make a pie chart using jFreeChart such that first we partition the pie into 3 equal parts for departments that is 120' for each department. Then in these partitions I want to show the sales of each employee. How can I do this in jFreeChart.
public class PieChart extends JFrame {
private PieDataset createDataset() {
DefaultPieDataset result = new DefaultPieDataset();
result.setValue("department1", 33.33);
result.setValue("department2", 33.33);
result.setValue("department3", 33.33);
return result;
}
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;
}
}
public static void main(String[] args) {
PieChart demo = new PieChart("Comparison", "Which operating system are you using?");
demo.pack();
demo.setVisible(true);
}
PieChartDemo1 is a good starting point; focus on createDataset(); the full source is included in the distribution.
Addendum: How to further create partitions?
Ah, you want to sub-divide each 120° partition. DefaultPieDataset doesn't support a hierarchical structure directly, but you can use color in the PiePlot to highlight the grouping. Create related colors using Color.getHSBColor(), as shown here, and use setSectionPaint() to apply the colors accordingly.