2

I'm trying to work with ClusteredXYBarRenderer while creating a XYBarChart. This chart in itself has multiple data series added to it. My requirement is to allow the users to zoom in on the domain axis whilst preventing zoom on the range axis. This I could easily implement in my code.

However what I getting stuck at is the following requirement:

  • The ability to zoom only to a specific level on the domain axis. i.e. I do NOT want users to zoom on fractional values. If the domain contains value {3, 4, 5....}, the users can maximum zoom in to see {3, 4}, etc but not {3, 3.5, 3.75....}

  • Add spacing between the start/end of domain data points, for example: bar1, bar2, bar3 (x-value= 1) [gap] bar1, bar2, bar3 (x-value= 2), This way, it would be easier for the user to differentiate where one set of values start and where do they end.

Here's an SSCCE for your reference:

import javax.swing.JFrame;
import javax.swing.JScrollPane;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.ClusteredXYBarRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class ClusteredBarChart {

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

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


        ValueAxis valueAxis = new NumberAxis(valueAxisLabel);

        XYBarRenderer renderer = new ClusteredXYBarRenderer();
        renderer.setShadowVisible(false);

        XYPlot plot = new XYPlot(dataset, domainAxis, valueAxis, renderer);
        plot.setOrientation(PlotOrientation.VERTICAL);
        plot.setNoDataMessage("=== No Datapoints Detected ====");

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

        return chart;
    }   

    private void createDummyData(XYSeriesCollection intervalDataset){

        XYSeries series1 = new XYSeries("series1");
        XYSeries series2 = new XYSeries("series2");
        XYSeries series3 = new XYSeries("series3");
        XYSeries series4 = new XYSeries("series4");
        XYSeries series5 = new XYSeries("series5");

        series1.add(6, 10);
        series1.add(7, 11);
        series1.add(10, 11);
        series1.add(17, 17);
        series1.add(21, 15);

        series2.add(6, 18);
        series2.add(7, 10);
        series2.add(10, 14);
        series2.add(17, 12);
        series2.add(21, 6);

        series3.add(6, 12);
        series3.add(7, 13);
        series3.add(10, 14);
        series3.add(17, 16);
        series3.add(21, 9);

        series4.add(6, 8);
        series4.add(7, 22);
        series4.add(10, 21);
        series4.add(17, 26);
        series4.add(21, 24);

        series5.add(6, 14);
        series5.add(7, 11);
        series5.add(10, 31);
        series5.add(17, 12);
        series5.add(21, 11);    

        intervalDataset.addSeries(series1);
        intervalDataset.addSeries(series2);
        intervalDataset.addSeries(series3);
        intervalDataset.addSeries(series4);
        intervalDataset.addSeries(series5);
    }


    public  void doPlot(String plotTitle) {
        XYSeriesCollection intervalXYDataSet  = new XYSeriesCollection();

        createDummyData(intervalXYDataSet);

        JFreeChart chart = createClusteredChart(plotTitle, "Category", "Value", intervalXYDataSet);
        ChartPanel chartpanel = new ChartPanel(chart);
        chartpanel.setDomainZoomable(true);
        chartpanel.setRangeZoomable(false);

        JFrame frame = new JFrame();
        frame.setTitle(plotTitle);
        frame.add(new JScrollPane(chartpanel));
        frame.pack();
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        new ClusteredBarChart().doPlot("Test Plot");
    }
}

If you run the example, you would see that the points for value #6 and #7 appears real close. I want to add space in between them. Also, I want to prevent users to zoom in to 6.5 or 6.75, etc....in other words, the max zoom-able range should be the values present in the actual data set.

Note that this questions has a reference to this one that I had asked earlier.

Any help would be really appreciated. Thanks!

Community
  • 1
  • 1
Sujay
  • 6,753
  • 2
  • 30
  • 49

1 Answers1

2

I can see two approaches:

  • Use the zoom() method of ChartPanel method with a suitable Rectangle2D. You'll need to iterate over the model to find the desired cluster's bounds in data space, and you can use the valueToJava2D() of NumberAxis to convert to Java 2D space. You can get the plot's data area from the ChartPanel:

    Rectangle2D r = panel.getChartRenderingInfo().getPlotInfo().getDataArea();
    
  • Add control(s) to your ChartPanel to display only the cluster of interest, excluding the others from the model. This related example that pages through multiple Box & Whisker plots may be helpful.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • i like the 1st approach but am unsure of how to go about implementing it. do you've any sample code up or any online link that can give me some idea regarding this? thanks! – Sujay Jul 10 '12 at 02:40
  • Sadly, no; I've always avoided it. I usually just enable all the zooming features and maybe add a convenience control, as shown [here](http://stackoverflow.com/a/5522583/230513). Both `setMouseZoomable()` and `setMouseWheelEnabled()` may be useful. – trashgod Jul 10 '12 at 02:50
  • A `JToolBar` of zoom controls is shown [here](https://stackoverflow.com/a/41544007/230513). – trashgod Oct 16 '20 at 11:58