Search code examples
javajfreechart

How to create a gauge chart using JFreeChart


I want to create a gauge chart using a combination of pie chart and half donut chart. The expected image is attached. Can someone please help me to modify the attached code to get the expected result? Attaching the sample code, adapted from here:

import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.plot.dial.DialPlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;

public class RingChartTest {

    private static final String INVISIBLE = "have_a_look_on_me_if_you_can_xD";
    private static java.awt.Color whiteColorAlphaChannel = new java.awt.Color(255, 255, 255, 0);
    
    private static PieDataset createDataset() {
        DefaultPieDataset dataset = new DefaultPieDataset();
        dataset.setValue("Safari", 40);
        dataset.setValue("Safari1", 50);
        dataset.setValue("Safari2", 90);
        dataset.setValue(INVISIBLE, 180);
        return dataset;
    }

    private static JFreeChart createChart(PieDataset dataset) {
        JFreeChart chart = ChartFactory.createRingChart("Overall Performance", dataset, false, false, false);
        
        RingPlot plot = (RingPlot) chart.getPlot();
        
        plot.setStartAngle(180);
        plot.setCircular(true);
        plot.setSimpleLabels(true);
        plot.setSectionDepth(0.2);
        plot.setBackgroundPaint(Color.WHITE);
        plot.setSeparatorsVisible(false);
        Color invisible = new Color(0xffffff, true);
        plot.setSectionPaint(INVISIBLE, whiteColorAlphaChannel); // 180° alpha invisible
        plot.setSectionOutlinePaint(INVISIBLE, whiteColorAlphaChannel); // 180° alpha invisible
        plot.setShadowPaint(null);
        plot.setLabelGenerator(null);
         plot.setSectionOutlinesVisible(false);
        return chart;
    }

    public JPanel createDemoPanel() {
        JFreeChart jfreechart = createChart(createDataset());
        ChartPanel chartPanel = new ChartPanel(jfreechart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(500, 400);
            }
        };
        chartPanel.setLayout(new OverlayLayout(chartPanel));
        JLabel label = new JLabel("BrowserShare");
        label.setFont(label.getFont().deriveFont(48.0f));
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setVerticalAlignment(JLabel.CENTER);
        label.setAlignmentX(0.5f);
        label.setAlignmentY(0.75f);
        label.setOpaque(false);
        label.setBackground(Color.LIGHT_GRAY);
        chartPanel.add(label);
        return chartPanel;
    }

    public static void main(String args[]) {
        PieDataset pieDataSet = createDataset();
        JFreeChart jFreeChart = createChart(pieDataSet);
        String filename1 = "C://Users//136965//Desktop//gauge_nut.jpg";

        try {
            ChartUtils.saveChartAsJPEG(new File(filename1), jFreeChart, 500, 400);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

The graph created by the above code is enter image description here

The graph that I am trying to create using JFreeChart library is as follows:

enter image description here


Solution

  • Also consider using org.jfree.chart.plot.dial. The example below use a DialPlot having an ArcDialFrame and a StandardDialScale. Three instances of StandardDialRange provide the colors.

    image

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.plot.dial.ArcDialFrame;
    import org.jfree.chart.plot.dial.DialPlot;
    import org.jfree.chart.plot.dial.DialPointer;
    import org.jfree.chart.plot.dial.StandardDialRange;
    import org.jfree.chart.plot.dial.StandardDialScale;
    import org.jfree.data.general.DefaultValueDataset;
    
    /**
     * @see https://stackoverflow.com/a/70648615/230513
     * @see https://stackoverflow.com/a/10353270/230513
     */
    public class DialTest {
    
        private static final Color LT_GRAY = new Color(0xe0e0e0);
    
        private void display() {
            DefaultValueDataset data = new DefaultValueDataset(70);
            DialPlot plot = new DialPlot(data);
            plot.setView(0, -0.25, 1, 1);
            ArcDialFrame arcDialFrame = new ArcDialFrame();
            arcDialFrame.setInnerRadius(0.42);
            arcDialFrame.setOuterRadius(0.95);
            arcDialFrame.setForegroundPaint(Color.darkGray);
            plot.setDialFrame(arcDialFrame);
            StandardDialScale scale = new StandardDialScale(0, 100, 180, -180, 10, 0);
            scale.setTickRadius(0.95);
            scale.setTickLabelOffset(0.15);
            scale.setMajorTickIncrement(10);
            plot.addScale(0, scale);
            DialPointer.Pin pin = new DialPointer.Pin();
            pin.setPaint(Color.black);
            pin.setRadius(0.8);
            plot.addLayer(pin);
            plot.addLayer(new StandardDialRange(0, 40, Color.red));
            plot.addLayer(new StandardDialRange(40, 60, Color.yellow));
            plot.addLayer(new StandardDialRange(60, 100, Color.green));
    
            JFreeChart chart = new JFreeChart("Overall Performance", plot);
            chart.setBackgroundPaint(LT_GRAY);
    
            JFrame f = new JFrame("Meter Test");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(new ChartPanel(chart) {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(300, 300);
                }
            });
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new DialTest()::display);
        }
    }