All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.analysis.utils.JFreeChartUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.artifact.analysis.utils;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.annotations.XYAnnotation;
import org.jfree.chart.annotations.XYTextAnnotation;
import org.jfree.chart.axis.*;
import org.jfree.chart.block.Block;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.LabelBlock;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.AbstractRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.title.*;
import org.jfree.chart.util.Args;
import org.jfree.data.general.DefaultPieDataset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileNotFoundException;
import java.text.DecimalFormat;
import java.util.List;

public abstract class JFreeChartUtils {

    private final static Logger LOG = LoggerFactory.getLogger(JFreeChartUtils.class);

    /**
     * Writes a JFreeChart into a svg file.
     *
     * @param chart  The chart to write.
     * @param file   The file to write the svg into.
     * @param height The height of the svg.
     * @param width  The width of the svg.
     * @throws SVGGraphics2DIOException If the file failed to write.
     * @throws FileNotFoundException    If the parent directory does not exist and cannot be created.
     */
    public static void writeGraphToFile(JFreeChart chart, File file, int width, int height) throws SVGGraphics2DIOException, FileNotFoundException {
        if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
            throw new FileNotFoundException("Parent directory of file [" + file.getAbsolutePath() + "] does not exist and cannot be created for writing chart");
        } else if (file.isDirectory()) {
            throw new IllegalArgumentException("Expected file, got directory for writing chart to [" + file.getAbsolutePath() + "]");
        }

        final DOMImplementation svgDOM = GenericDOMImplementation.getDOMImplementation();
        final Document document = svgDOM.createDocument(null, "svg", null);

        final SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
        svgGenerator.setSVGCanvasSize(new Dimension(width, height));

        // render chart as SVG 2D Graphics object
        chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height), null);

        svgGenerator.stream(file.getAbsolutePath());
    }

    public static void applyDefaultForLineChartAxis(CategoryAxis axis) {
        axis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        axis.setMaximumCategoryLabelWidthRatio(1.3f);
        axis.setLowerMargin(0);
        axis.setUpperMargin(0);
    }

    public static void applyDefaultForPieChartPlot(PiePlot plot) {
        plot.setLabelGenerator(null);
        //plot.setShadowPaint(new Color(0, 0, 0, 0));
        plot.setDefaultSectionOutlinePaint(Color.WHITE);
        plot.setDefaultSectionOutlineStroke(new BasicStroke(1));
    }

    public static > void addPieChartData(DefaultPieDataset dataset, PiePlot plot, T key, Number value, Color color) {
        dataset.setValue(key, value);
        plot.setSectionPaint(key, color);
    }

    public static > void addPieChartDataIfNotZero(DefaultPieDataset dataset, PiePlot plot, T key, Number value, Color color) {
        if (value.doubleValue() == 0) return;
        dataset.setValue(key, value);
        plot.setSectionPaint(key, color);
    }

    public static void setTransparentBackground(JFreeChart chart) {
        if (chart != null) {
            chart.setBackgroundPaint(null);
            if (chart.getPlot() != null) chart.getPlot().setBackgroundPaint(null);
            if (chart.getLegend() != null) chart.getLegend().setBackgroundPaint(null);
            if (chart.getTitle() != null) chart.getTitle().setBackgroundPaint(null);
        }
    }

    public static void removeChartOutline(JFreeChart chart) {
        if (chart != null && chart.getPlot() != null) {
            chart.getPlot().setOutlinePaint(null);
        }
    }

    public static void setPieChartLabelGenerator(JFreeChart chart, boolean pieSectionKey, boolean absoluteValue, boolean percentageValue, Color backgroundPaint, Color foregroundPaint) {
        if (chart != null && chart.getPlot() instanceof PiePlot) {
            PiePlot plot = (PiePlot) chart.getPlot();

            StringBuilder format = new StringBuilder();
            if (pieSectionKey) {
                format.append("{0}");
                if (absoluteValue || percentageValue) {
                    format.append(":");
                }
            }
            if (absoluteValue) {
                format.append(" {1}");
            }
            if (percentageValue) {
                if (absoluteValue) {
                    format.append(" ({2})");
                } else {
                    format.append(" {2}");
                }
            }

            PieSectionLabelGenerator gen = new StandardPieSectionLabelGenerator(format.toString(), new DecimalFormat("0"), new DecimalFormat("0%"));
            plot.setLabelGenerator(gen);

            if (backgroundPaint != null) {
                plot.setLabelBackgroundPaint(backgroundPaint);
            }
            if (foregroundPaint != null) {
                plot.setLabelPaint(foregroundPaint);
            }
        }
    }

    public static void setFont(JFreeChart chart, Font font) {
        setFont(chart, font, -1, -1, -1, -1);
    }

    public static void setFont(JFreeChart chart, Font font, int extraLarge, int large, int regular, int small) {
        StandardChartTheme fontApplierTheme = createFontApplierTheme();

        fontApplierTheme.setExtraLargeFont(font.deriveFont(Font.BOLD, extraLarge == -1 ? 20 : extraLarge));
        fontApplierTheme.setLargeFont(font.deriveFont(Font.BOLD, large == -1 ? 14 : large));
        fontApplierTheme.setRegularFont(font.deriveFont(Font.PLAIN, regular == -1 ? 12 : regular));
        fontApplierTheme.setSmallFont(font.deriveFont(Font.PLAIN, small == -1 ? 10 : small));

        fontApplierTheme.apply(chart);
    }

    private static StandardChartTheme createFontApplierTheme() {
        return new StandardChartTheme("FontApplier") {
            @Override
            public void apply(JFreeChart chart) {
                TextTitle title = chart.getTitle();
                if (title != null) {
                    title.setFont(this.getExtraLargeFont());
                }

                int subtitleCount = chart.getSubtitleCount();
                for (int i = 0; i < subtitleCount; i++) {
                    applyToTitle(chart.getSubtitle(i));
                }

                // now process the plot if there is one
                Plot plot = chart.getPlot();
                if (plot != null) {
                    applyToPlot(plot);
                }
            }

            @Override
            protected void applyToTitle(Title title) {
                if (title instanceof TextTitle) {
                    TextTitle tt = (TextTitle) title;
                    tt.setFont(this.getLargeFont());
                } else if (title instanceof LegendTitle) {
                    LegendTitle lt = (LegendTitle) title;
                    lt.setItemFont(this.getRegularFont());
                    if (lt.getWrapper() != null) {
                        applyToBlockContainer(lt.getWrapper());
                    }
                } else if (title instanceof PaintScaleLegend) {
                    PaintScaleLegend psl = (PaintScaleLegend) title;
                    ValueAxis axis = psl.getAxis();
                    if (axis != null) {
                        applyToValueAxis(axis);
                    }
                } else if (title instanceof CompositeTitle) {
                    CompositeTitle ct = (CompositeTitle) title;
                    BlockContainer bc = ct.getContainer();
                    List blocks = bc.getBlocks();
                    for (Object block : blocks) {
                        Block b = (Block) block;
                        if (b instanceof Title) {
                            applyToTitle((Title) b);
                        }
                    }
                }
            }

            @Override
            protected void applyToBlockContainer(BlockContainer bc) {
                for (Object o : bc.getBlocks()) {
                    Block b = (Block) o;
                    applyToBlock(b);
                }
            }

            @Override
            protected void applyToBlock(Block b) {
                if (b instanceof Title) {
                    applyToTitle((Title) b);
                } else if (b instanceof LabelBlock) {
                    LabelBlock lb = (LabelBlock) b;
                    lb.setFont(this.getRegularFont());
                }
            }

            @Override
            protected void applyToPlot(Plot plot) {
                Args.nullNotPermitted(plot, "plot");
                if (plot instanceof PiePlot) {
                    applyToPiePlot((PiePlot) plot);
                } else if (plot instanceof MultiplePiePlot) {
                    applyToMultiplePiePlot((MultiplePiePlot) plot);
                } else if (plot instanceof CategoryPlot) {
                    applyToCategoryPlot((CategoryPlot) plot);
                } else if (plot instanceof XYPlot) {
                    applyToXYPlot((XYPlot) plot);
                } else if (plot instanceof FastScatterPlot) {
                    applyToFastScatterPlot((FastScatterPlot) plot);
                } else if (plot instanceof MeterPlot) {
                    applyToMeterPlot((MeterPlot) plot);
                } else if (plot instanceof ThermometerPlot) {
                    applyToThermometerPlot((ThermometerPlot) plot);
                } else if (plot instanceof SpiderWebPlot) {
                    applyToSpiderWebPlot((SpiderWebPlot) plot);
                } else if (plot instanceof PolarPlot) {
                    applyToPolarPlot((PolarPlot) plot);
                }
            }

            @Override
            protected void applyToPiePlot(PiePlot plot) {
                plot.setLabelFont(this.getRegularFont());
            }

            @Override
            protected void applyToMultiplePiePlot(MultiplePiePlot plot) {
                apply(plot.getPieChart());
            }

            @Override
            protected void applyToCategoryPlot(CategoryPlot plot) {
                // process all domain axes
                int domainAxisCount = plot.getDomainAxisCount();
                for (int i = 0; i < domainAxisCount; i++) {
                    CategoryAxis axis = plot.getDomainAxis(i);
                    if (axis != null) {
                        applyToCategoryAxis(axis);
                    }
                }

                // process all range axes
                int rangeAxisCount = plot.getRangeAxisCount();
                for (int i = 0; i < rangeAxisCount; i++) {
                    ValueAxis axis = plot.getRangeAxis(i);
                    if (axis != null) {
                        applyToValueAxis(axis);
                    }
                }

                // process all renderers
                int rendererCount = plot.getRendererCount();
                for (int i = 0; i < rendererCount; i++) {
                    CategoryItemRenderer r = plot.getRenderer(i);
                    if (r != null) {
                        applyToCategoryItemRenderer(r);
                    }
                }

                if (plot instanceof CombinedDomainCategoryPlot) {
                    CombinedDomainCategoryPlot cp = (CombinedDomainCategoryPlot) plot;
                    for (Object o : cp.getSubplots()) {
                        CategoryPlot subplot = (CategoryPlot) o;
                        if (subplot != null) {
                            applyToPlot(subplot);
                        }
                    }
                }
                if (plot instanceof CombinedRangeCategoryPlot) {
                    CombinedRangeCategoryPlot cp = (CombinedRangeCategoryPlot) plot;
                    for (Object o : cp.getSubplots()) {
                        CategoryPlot subplot = (CategoryPlot) o;
                        if (subplot != null) {
                            applyToPlot(subplot);
                        }
                    }
                }
            }

            @Override
            protected void applyToXYPlot(XYPlot plot) {
                // process all domain axes
                int domainAxisCount = plot.getDomainAxisCount();
                for (int i = 0; i < domainAxisCount; i++) {
                    ValueAxis axis = plot.getDomainAxis(i);
                    if (axis != null) {
                        applyToValueAxis(axis);
                    }
                }

                // process all range axes
                int rangeAxisCount = plot.getRangeAxisCount();
                for (int i = 0; i < rangeAxisCount; i++) {
                    ValueAxis axis = plot.getRangeAxis(i);
                    if (axis != null) {
                        applyToValueAxis(axis);
                    }
                }

                // process all renderers
                int rendererCount = plot.getRendererCount();
                for (int i = 0; i < rendererCount; i++) {
                    XYItemRenderer r = plot.getRenderer(i);
                    if (r != null) {
                        applyToXYItemRenderer(r);
                    }
                }

                // process all annotations
                for (Object o : plot.getAnnotations()) {
                    XYAnnotation a = (XYAnnotation) o;
                    applyToXYAnnotation(a);
                }

                if (plot instanceof CombinedDomainXYPlot) {
                    CombinedDomainXYPlot cp = (CombinedDomainXYPlot) plot;
                    for (Object o : cp.getSubplots()) {
                        XYPlot subplot = (XYPlot) o;
                        if (subplot != null) {
                            applyToPlot(subplot);
                        }
                    }
                }
                if (plot instanceof CombinedRangeXYPlot) {
                    CombinedRangeXYPlot cp = (CombinedRangeXYPlot) plot;
                    for (Object o : cp.getSubplots()) {
                        XYPlot subplot = (XYPlot) o;
                        if (subplot != null) {
                            applyToPlot(subplot);
                        }
                    }
                }
            }

            @Override
            protected void applyToFastScatterPlot(FastScatterPlot plot) {
                ValueAxis xAxis = plot.getDomainAxis();
                if (xAxis != null) {
                    applyToValueAxis(xAxis);
                }
                ValueAxis yAxis = plot.getRangeAxis();
                if (yAxis != null) {
                    applyToValueAxis(yAxis);
                }

            }

            @Override
            protected void applyToPolarPlot(PolarPlot plot) {
                plot.setAngleLabelFont(this.getRegularFont());
                ValueAxis axis = plot.getAxis();
                if (axis != null) {
                    applyToValueAxis(axis);
                }
            }

            @Override
            protected void applyToSpiderWebPlot(SpiderWebPlot plot) {
                plot.setLabelFont(this.getRegularFont());
            }

            @Override
            protected void applyToMeterPlot(MeterPlot plot) {
                plot.setValueFont(this.getLargeFont());
                plot.setTickLabelFont(this.getRegularFont());
            }

            @Override
            protected void applyToThermometerPlot(ThermometerPlot plot) {
                plot.setValueFont(this.getLargeFont());
                ValueAxis axis = plot.getRangeAxis();
                if (axis != null) {
                    applyToValueAxis(axis);
                }
            }

            @Override
            protected void applyToCategoryAxis(CategoryAxis axis) {
                axis.setLabelFont(this.getLargeFont());
                axis.setTickLabelFont(this.getRegularFont());
                if (axis instanceof SubCategoryAxis) {
                    SubCategoryAxis sca = (SubCategoryAxis) axis;
                    sca.setSubLabelFont(this.getRegularFont());
                }
            }

            @Override
            protected void applyToValueAxis(ValueAxis axis) {
                axis.setLabelFont(this.getLargeFont());
                axis.setTickLabelFont(this.getRegularFont());
                if (axis instanceof SymbolAxis) {
                    applyToSymbolAxis((SymbolAxis) axis);
                }
                if (axis instanceof PeriodAxis) {
                    applyToPeriodAxis((PeriodAxis) axis);
                }
            }

            @Override
            protected void applyToSymbolAxis(SymbolAxis axis) {
            }

            @Override
            protected void applyToPeriodAxis(PeriodAxis axis) {
                PeriodAxisLabelInfo[] info = axis.getLabelInfo();
                for (int i = 0; i < info.length; i++) {
                    PeriodAxisLabelInfo e = info[i];
                    PeriodAxisLabelInfo n = new PeriodAxisLabelInfo(e.getPeriodClass(),
                            e.getDateFormat(), e.getPadding(), this.getRegularFont(),
                            this.getTickLabelPaint(), e.getDrawDividers(),
                            e.getDividerStroke(), e.getDividerPaint());
                    info[i] = n;
                }
                axis.setLabelInfo(info);
            }

            @Override
            protected void applyToAbstractRenderer(AbstractRenderer renderer) {
            }

            @Override
            protected void applyToCategoryItemRenderer(CategoryItemRenderer renderer) {
                Args.nullNotPermitted(renderer, "renderer");

                if (renderer instanceof AbstractRenderer) {
                    applyToAbstractRenderer((AbstractRenderer) renderer);
                }

                renderer.setDefaultItemLabelFont(this.getRegularFont());
            }

            @Override
            protected void applyToXYItemRenderer(XYItemRenderer renderer) {
                Args.nullNotPermitted(renderer, "renderer");
                if (renderer instanceof AbstractRenderer) {
                    applyToAbstractRenderer((AbstractRenderer) renderer);
                }
                renderer.setDefaultItemLabelFont(this.getRegularFont());
            }

            @Override
            protected void applyToXYAnnotation(XYAnnotation annotation) {
                Args.nullNotPermitted(annotation, "annotation");
                if (annotation instanceof XYTextAnnotation) {
                    XYTextAnnotation xyta = (XYTextAnnotation) annotation;
                    xyta.setFont(this.getSmallFont());
                }
            }
        };
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy