JFreeChart - XYBarChart Show Separate Bars for Each Series

bar-chart, java, jfreechart

Solution

EDIT Use `ClusteredXYBarRenderer` instead of `XYBarRenderer`. This draws adjacent bars (instead of StackedBars) and provides zooming capabilities.

There is no factory method in `ChartFactory` to create `ClusteredXYBarRenderer`.

Use the below method to create the Bar Chart.

private static JFreeChart createClusteredChart(String title, String categoryAxisLabel, String valueAxisLabel, IntervalXYDataset dataset) {

  NumberAxis domainAxis = new NumberAxis(categoryAxisLabel);
  domainAxis.setAutoRangeIncludesZero(false);

  ValueAxis valueAxis = new NumberAxis(valueAxisLabel);

  XYBarRenderer renderer = new ClusteredXYBarRenderer();

  XYPlot plot = new XYPlot(dataset, domainAxis, valueAxis, renderer);
  plot.setOrientation(PlotOrientation.VERTICAL);

  JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);

  return chart;
}

`XYBarRenderer` that you are using is correct. But I think you should use `CategoryDataSet` instead of `XYSeriesCollection`. Try using below dataset instead of `XYSeriesCollection`. This will produce adjacent bars instead of stacked bars.

private static CategoryDataset createDataset() {
  String series1 = "First";
  String series2 = "Second";
  String series3 = "Third";

  String category1 = "Category 1";
  String category2 = "Category 2";
  String category3 = "Category 3";
  String category4 = "Category 4";
  String category5 = "Category 5";

  DefaultCategoryDataset dataset = new DefaultCategoryDataset();

  dataset.addValue(1.0D, series1, category1);
  dataset.addValue(4.0D, series1, category2);
  dataset.addValue(3.0D, series1, category3);
  dataset.addValue(5.0D, series1, category4);
  dataset.addValue(5.0D, series1, category5);

  dataset.addValue(5.0D, series2, category1);
  dataset.addValue(7.0D, series2, category2);
  dataset.addValue(6.0D, series2, category3);
  dataset.addValue(8.0D, series2, category4);
  dataset.addValue(4.0D, series2, category5);

  dataset.addValue(4.0D, series3, category1);
  dataset.addValue(3.0D, series3, category2);
  dataset.addValue(2.0D, series3, category3);
  dataset.addValue(3.0D, series3, category4);
  dataset.addValue(6.0D, series3, category5);

  return dataset;
}

Problem

I'm creating a XYBarChart using JFreeChart and adding multiple series to it. Currently for a given x-value and different Y-values from the series, all of them are getting stacked on top of each other. Would be possible to show each series as a different bar for a given x-value? Edit: I'm posting the relevant section of my code that is used to create the chart for your reference. Note that I cannot use CategoryDataset because this does not provide zooming capabilities on the Domain Axis. This is an essential requirement for my implementation. ``` XYSeriesCollection intervalXYDataSet = new XYSeriesCollection(); int countPlotPoints = populateBandData(intervalXYDataSet, optionList); //optionList is a HashMap<Integer,ArrayList<Integer>> where key = seriesKey, and ArrayList<Integer> builds up the value for each series if (countPlotPoints == 0) { print("No options selected.\n"); JOptionPane.showMessageDialog(this, "No Plot Points Were Selected!", "Warning", JOptionPane.WARNING_MESSAGE); return; } /** * Chart Creation Section */ JFreeChart chart = ChartFactory.createXYBarChart(tabTitle, "Frequency Bands", false, "rxlev", intervalXYDataSet, PlotOrientation.VERTICAL, true, true, false); XYPlot plot = (XYPlot) chart.getPlot(); plot.getRangeAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits()); plot.getDomainAxis().setAutoRange(true); // final XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer(); renderer.setDrawBarOutline(false); renderer.setShadowVisible(false); renderer.setMargin(0.2); renderer.setDefaultShadowsVisible(false); ChartPanel chartpanel = new ChartPanel(chart); chartpanel.setDefaultDirectoryForSaveAs(new File(lastAnalyzedPath)); JFrame frame = new JFrame(); frame.setTitle(plotTitle); frame.add(new JScrollPane(chartpanel)); frame.pack(); frame.setVisible(true); frame.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent evt) { try { System.out.println(":: Clearning Memory ::"); System.out.println("\tFree Memory (Before cleanup): "+Runtime.getRuntime().freeMemory()); Component component = getComponent(0); if(component instanceof ChartPanel){ JFreeChart chart = ((ChartPanel) component).getChart(); XYPlot plot = (XYPlot) chart.getPlot(); plot = null; chart = null; component = null; } } finally { System.runFinalization(); System.gc(); System.out.println("\tFree Memory (Post cleanup): "+Runtime.getRuntime().freeMemory()); } } }); ``` Here's a screenshot of how it's currently appearing

Original source