<commit_before>package org.intermine.web.logic.widget;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.intermine.api.profile.InterMineBag;
import org.intermine.objectstore.ObjectStore;
import org.intermine.util.TypeUtil;
import org.intermine.web.logic.widget.config.GraphWidgetConfig;
import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.imagemap.ImageMapUtilities;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYSplineRenderer;
import org.jfree.chart.servlet.ServletUtilities;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.urls.CategoryURLGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

/*
 * Copyright (C) 2002-2011 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */


/**
 * @author "<NAME>"
 *
 */
public class GraphWidget extends Widget
{
    private static final Logger LOG = Logger.getLogger(GraphWidget.class);
    private int notAnalysed = 0;
    private DataSetLdr dataSetLdr;
    private InterMineBag bag;
    private ObjectStore os;
    private String fileName = null;
    private String imageMap = null;
    private String selectedExtraAttribute;
    private static final ChartColor BLUE = new ChartColor(47, 114, 255);
    private static final ChartColor LIGHT_BLUE = new ChartColor(159, 192, 255);
    private static final ChartColor DARK_BLUE = new ChartColor(39, 77, 216);
    private Dataset graphDataSet;

    /**
     * @param config config for widget
     * @param interMineBag bag for widget
     * @param os objectstore
     * @param selectedExtraAttribute extra attribute
     */
    public GraphWidget(GraphWidgetConfig config, InterMineBag interMineBag, ObjectStore os,
                       String selectedExtraAttribute) {
        super(config);
        this.bag = interMineBag;
        this.os = os;
        this.selectedExtraAttribute = selectedExtraAttribute;
        process();
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public List getElementInList() {
        return new Vector();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void process() {

        String dataSetLoader = config.getDataSetLoader();
        Class<?> clazz = TypeUtil.instantiate(dataSetLoader);
        try {
            Constructor<?> constr = clazz.getConstructor(new Class[] {InterMineBag.class,
                ObjectStore.class, String.class});
            dataSetLdr = (DataSetLdr) constr.newInstance(new Object[] {bag, os,
                selectedExtraAttribute});
            notAnalysed = bag.getSize() - dataSetLdr.getWidgetTotal();
        } catch (Exception err) {
            LOG.warn("Error rendering graph widget.", err);
            return;
        }

        if (dataSetLdr == null || dataSetLdr.getDataSet() == null) {
            LOG.warn("No data found for graph widget");
            return;
        }
        BarRenderer.setDefaultShadowsVisible(false);
        JFreeChart chart = null;
        graphDataSet = dataSetLdr.getDataSet();
        String graphType = ((GraphWidgetConfig) config).getGraphType();
        ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());

        if (StringUtils.isNotEmpty(graphType) && "ScatterPlot".equals(graphType)) {
            chart = ChartFactory.createScatterPlot(
                    config.getTitle(),
                    ((GraphWidgetConfig) config).getDomainLabel(),
                    ((GraphWidgetConfig) config).getRangeLabel(),
                    (XYDataset) graphDataSet,
                    PlotOrientation.VERTICAL,
                    true, true, false);
            XYPlot plot = chart.getXYPlot();

            XYItemRenderer xyrenderer = plot.getRenderer();
            StandardXYItemRenderer regressionRenderer
                = new StandardXYItemRenderer();
            regressionRenderer.setBaseSeriesVisibleInLegend(false);
            plot.setDataset(1, regress((XYDataset) graphDataSet));
            plot.setRenderer(1, regressionRenderer);
            xyrenderer.setSeriesStroke(0, new BasicStroke(3.0f));
            xyrenderer.setSeriesStroke(1, new BasicStroke(3.0f));

            xyrenderer.setSeriesPaint(0, BLUE);
            xyrenderer.setSeriesPaint(1, LIGHT_BLUE);

            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
            plot.setDomainGridlinesVisible(true);
            plot.setRangeGridlinePaint(Color.LIGHT_GRAY);

            DivNumberFormat formatter = new DivNumberFormat(1000);
            NumberAxis axis = (NumberAxis) plot.getRangeAxis();
            axis.setNumberFormatOverride(formatter);

        } else if (StringUtils.isNotEmpty(graphType) && "XYLineChart".equals(graphType)) {

            chart = ChartFactory.createXYLineChart(config.getTitle(),
                    ((GraphWidgetConfig) config).getDomainLabel(),
                    ((GraphWidgetConfig) config).getRangeLabel(), (XYDataset) graphDataSet,
                    PlotOrientation.VERTICAL, true, true, false);

            XYPlot plot = chart.getXYPlot();

            XYItemRenderer xyrenderer = plot.getRenderer();
            xyrenderer.setSeriesStroke(0, new BasicStroke(3.0f));
            xyrenderer.setSeriesStroke(1, new BasicStroke(3.0f));

            xyrenderer.setSeriesPaint(0, BLUE);
            xyrenderer.setSeriesPaint(1, LIGHT_BLUE);

            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
            plot.setDomainGridlinesVisible(true);
            plot.setRangeGridlinePaint(Color.LIGHT_GRAY);

            DivNumberFormat formatter = new DivNumberFormat(1000);
            NumberAxis axis = (NumberAxis) plot.getRangeAxis();
            axis.setNumberFormatOverride(formatter);
        } else if (StringUtils.isNotEmpty(graphType) && "PieChart".equals(graphType)) {
            chart = ChartFactory.createPieChart(
                    config.getTitle(), (PieDataset) graphDataSet,
                    true, true, false);
            PiePlot plot = (PiePlot) chart.getPlot();
            plot.setNoDataMessage("No data available");
            plot.setCircular(true);
            plot.setLabelGap(0.02);
            plot.setBackgroundPaint(Color.white);
            Font labelFont = new Font("SansSerif", Font.BOLD, 12);
            plot.setLabelFont(labelFont);
            plot.setMaximumLabelWidth(0.20d);
            @SuppressWarnings("rawtypes")
            List keys = ((PieDataset) graphDataSet).getKeys();
            int mod = (keys.size() % 3 == 1) ? 2 : 3;
            int i = 0;
            for (Object key: keys) {
                Color paint;
                switch (i++ % mod) {
                    case 0: paint = BLUE; break;
                    case 1: paint = LIGHT_BLUE; break;
                    case 2: paint = DARK_BLUE; break;
                    default: paint = BLUE;
                }
                plot.setSectionPaint((Comparable<?>) key, paint);
            }
        } else if (StringUtils.isNotEmpty(graphType) && "StackedBarChart".equals(graphType)) {
            chart = ChartFactory.createStackedBarChart(config.getTitle(), // chart title
                    ((GraphWidgetConfig) config).getDomainLabel(), // domain axis label
                    ((GraphWidgetConfig) config).getRangeLabel(), // range axis label
                    (CategoryDataset) graphDataSet, // data
                    PlotOrientation.HORIZONTAL, true, true, // include legend,tooltips?
                    false // URLs?
            );
            CategoryPlot categoryPlot = chart.getCategoryPlot();
            CategoryItemRenderer categoryRenderer = categoryPlot.getRenderer();
            categoryRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT));
            categoryRenderer.setBaseNegativeItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE9, TextAnchor.CENTER_RIGHT));

            ((GraphWidgetConfig) config).setHeight(400);
            formatBarCharts(categoryPlot);
            setURLGen(categoryRenderer);
        /* regular bar chart */
        } else {
            chart = ChartFactory.createBarChart(config.getTitle(), // chart title
                                                ((GraphWidgetConfig) config).getDomainLabel(),
                                                ((GraphWidgetConfig) config).getRangeLabel(),
                                                (CategoryDataset) graphDataSet, // data
                                                PlotOrientation.VERTICAL, true, true, // tooltips?
                                                false // URLs?
            );

            if (selectedExtraAttribute != null
                            && !selectedExtraAttribute.startsWith("any")) {
                TextTitle subtitleText = new TextTitle(selectedExtraAttribute);
                subtitleText.setFont(new Font("SansSerif", Font.ITALIC, 10));
                chart.addSubtitle(subtitleText);
            }
            CategoryPlot categoryPlot = chart.getCategoryPlot();
            CategoryItemRenderer categoryRenderer = new BarRenderer();
            ((BarRenderer) categoryRenderer).setItemMargin(0);
            categoryRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER));
            categoryRenderer.setBaseNegativeItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER));
            categoryPlot.setRenderer(categoryRenderer);

            // rotate the category labels
            categoryPlot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions
                    .createUpRotationLabelPositions(Math.PI / 6.0));

            setURLGen(categoryRenderer);

            ((BarRenderer) categoryRenderer).setNegativeItemLabelPositionFallback(
                new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.BASELINE_LEFT));

            formatBarCharts(categoryPlot);
        }

        if (chart.getTitle() != null) {
            chart.getTitle().setFont(new Font("SansSerif", Font.BOLD, 12));
        }

        chart.setPadding(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
// this would speed up chart rendering, but it wouldn't look as nice.
//        chart.setAntiAlias(false);
        ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());

        // generate the image and imagemap
        try {
            fileName = ServletUtilities.saveChartAsPNG(chart,
                    ((GraphWidgetConfig) config).getWidth(),
                    ((GraphWidgetConfig) config).getHeight(), info,
                    ((GraphWidgetConfig) config).getSession());
        } catch (IOException e) {
            throw new RuntimeException("error rendering html", e);
        }

        imageMap = ImageMapUtilities.getImageMap("chart" + fileName, info);
    }

    private void setURLGen(CategoryItemRenderer categoryRenderer) {
        if (config.getLink() == null) {
            return;
        }
        CategoryURLGenerator categoryUrlGen = null;

        // set series 0 to have URLgenerator specified in config file
        // set series 1 to have no URL generator.
        try {
            Class<?> clazz2 = TypeUtil.instantiate(config.getLink());<commit_msg>TEMPORARILY change to save JPEGs instead of PNGs<commit_after>package org.intermine.web.logic.widget;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.intermine.api.profile.InterMineBag;
import org.intermine.objectstore.ObjectStore;
import org.intermine.util.TypeUtil;
import org.intermine.web.logic.widget.config.GraphWidgetConfig;
import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.imagemap.ImageMapUtilities;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYSplineRenderer;
import org.jfree.chart.servlet.ServletUtilities;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.urls.CategoryURLGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

/*
 * Copyright (C) 2002-2011 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */


/**
 * @author "<NAME>"
 *
 */
public class GraphWidget extends Widget
{
    private static final Logger LOG = Logger.getLogger(GraphWidget.class);
    private int notAnalysed = 0;
    private DataSetLdr dataSetLdr;
    private InterMineBag bag;
    private ObjectStore os;
    private String fileName = null;
    private String imageMap = null;
    private String selectedExtraAttribute;
    private static final ChartColor BLUE = new ChartColor(47, 114, 255);
    private static final ChartColor LIGHT_BLUE = new ChartColor(159, 192, 255);
    private static final ChartColor DARK_BLUE = new ChartColor(39, 77, 216);
    private Dataset graphDataSet;

    /**
     * @param config config for widget
     * @param interMineBag bag for widget
     * @param os objectstore
     * @param selectedExtraAttribute extra attribute
     */
    public GraphWidget(GraphWidgetConfig config, InterMineBag interMineBag, ObjectStore os,
                       String selectedExtraAttribute) {
        super(config);
        this.bag = interMineBag;
        this.os = os;
        this.selectedExtraAttribute = selectedExtraAttribute;
        process();
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public List getElementInList() {
        return new Vector();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void process() {

        String dataSetLoader = config.getDataSetLoader();
        Class<?> clazz = TypeUtil.instantiate(dataSetLoader);
        try {
            Constructor<?> constr = clazz.getConstructor(new Class[] {InterMineBag.class,
                ObjectStore.class, String.class});
            dataSetLdr = (DataSetLdr) constr.newInstance(new Object[] {bag, os,
                selectedExtraAttribute});
            notAnalysed = bag.getSize() - dataSetLdr.getWidgetTotal();
        } catch (Exception err) {
            LOG.warn("Error rendering graph widget.", err);
            return;
        }

        if (dataSetLdr == null || dataSetLdr.getDataSet() == null) {
            LOG.warn("No data found for graph widget");
            return;
        }
        BarRenderer.setDefaultShadowsVisible(false);
        JFreeChart chart = null;
        graphDataSet = dataSetLdr.getDataSet();
        String graphType = ((GraphWidgetConfig) config).getGraphType();
        ChartFactory.setChartTheme(StandardChartTheme.createLegacyTheme());

        if (StringUtils.isNotEmpty(graphType) && "ScatterPlot".equals(graphType)) {
            chart = ChartFactory.createScatterPlot(
                    config.getTitle(),
                    ((GraphWidgetConfig) config).getDomainLabel(),
                    ((GraphWidgetConfig) config).getRangeLabel(),
                    (XYDataset) graphDataSet,
                    PlotOrientation.VERTICAL,
                    true, true, false);
            XYPlot plot = chart.getXYPlot();

            XYItemRenderer xyrenderer = plot.getRenderer();
            StandardXYItemRenderer regressionRenderer
                = new StandardXYItemRenderer();
            regressionRenderer.setBaseSeriesVisibleInLegend(false);
            plot.setDataset(1, regress((XYDataset) graphDataSet));
            plot.setRenderer(1, regressionRenderer);
            xyrenderer.setSeriesStroke(0, new BasicStroke(3.0f));
            xyrenderer.setSeriesStroke(1, new BasicStroke(3.0f));

            xyrenderer.setSeriesPaint(0, BLUE);
            xyrenderer.setSeriesPaint(1, LIGHT_BLUE);

            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
            plot.setDomainGridlinesVisible(true);
            plot.setRangeGridlinePaint(Color.LIGHT_GRAY);

            DivNumberFormat formatter = new DivNumberFormat(1000);
            NumberAxis axis = (NumberAxis) plot.getRangeAxis();
            axis.setNumberFormatOverride(formatter);

        } else if (StringUtils.isNotEmpty(graphType) && "XYLineChart".equals(graphType)) {

            chart = ChartFactory.createXYLineChart(config.getTitle(),
                    ((GraphWidgetConfig) config).getDomainLabel(),
                    ((GraphWidgetConfig) config).getRangeLabel(), (XYDataset) graphDataSet,
                    PlotOrientation.VERTICAL, true, true, false);

            XYPlot plot = chart.getXYPlot();

            XYItemRenderer xyrenderer = plot.getRenderer();
            xyrenderer.setSeriesStroke(0, new BasicStroke(3.0f));
            xyrenderer.setSeriesStroke(1, new BasicStroke(3.0f));

            xyrenderer.setSeriesPaint(0, BLUE);
            xyrenderer.setSeriesPaint(1, LIGHT_BLUE);

            plot.setBackgroundPaint(Color.white);
            plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
            plot.setDomainGridlinesVisible(true);
            plot.setRangeGridlinePaint(Color.LIGHT_GRAY);

            DivNumberFormat formatter = new DivNumberFormat(1000);
            NumberAxis axis = (NumberAxis) plot.getRangeAxis();
            axis.setNumberFormatOverride(formatter);
        } else if (StringUtils.isNotEmpty(graphType) && "PieChart".equals(graphType)) {
            chart = ChartFactory.createPieChart(
                    config.getTitle(), (PieDataset) graphDataSet,
                    true, true, false);
            PiePlot plot = (PiePlot) chart.getPlot();
            plot.setNoDataMessage("No data available");
            plot.setCircular(true);
            plot.setLabelGap(0.02);
            plot.setBackgroundPaint(Color.white);
            Font labelFont = new Font("SansSerif", Font.BOLD, 12);
            plot.setLabelFont(labelFont);
            plot.setMaximumLabelWidth(0.20d);
            @SuppressWarnings("rawtypes")
            List keys = ((PieDataset) graphDataSet).getKeys();
            int mod = (keys.size() % 3 == 1) ? 2 : 3;
            int i = 0;
            for (Object key: keys) {
                Color paint;
                switch (i++ % mod) {
                    case 0: paint = BLUE; break;
                    case 1: paint = LIGHT_BLUE; break;
                    case 2: paint = DARK_BLUE; break;
                    default: paint = BLUE;
                }
                plot.setSectionPaint((Comparable<?>) key, paint);
            }
        } else if (StringUtils.isNotEmpty(graphType) && "StackedBarChart".equals(graphType)) {
            chart = ChartFactory.createStackedBarChart(config.getTitle(), // chart title
                    ((GraphWidgetConfig) config).getDomainLabel(), // domain axis label
                    ((GraphWidgetConfig) config).getRangeLabel(), // range axis label
                    (CategoryDataset) graphDataSet, // data
                    PlotOrientation.HORIZONTAL, true, true, // include legend,tooltips?
                    false // URLs?
            );
            CategoryPlot categoryPlot = chart.getCategoryPlot();
            CategoryItemRenderer categoryRenderer = categoryPlot.getRenderer();
            categoryRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT));
            categoryRenderer.setBaseNegativeItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE9, TextAnchor.CENTER_RIGHT));

            ((GraphWidgetConfig) config).setHeight(400);
            formatBarCharts(categoryPlot);
            setURLGen(categoryRenderer);
        /* regular bar chart */
        } else {
            chart = ChartFactory.createBarChart(config.getTitle(), // chart title
                                                ((GraphWidgetConfig) config).getDomainLabel(),
                                                ((GraphWidgetConfig) config).getRangeLabel(),
                                                (CategoryDataset) graphDataSet, // data
                                                PlotOrientation.VERTICAL, true, true, // tooltips?
                                                false // URLs?
            );

            if (selectedExtraAttribute != null
                            && !selectedExtraAttribute.startsWith("any")) {
                TextTitle subtitleText = new TextTitle(selectedExtraAttribute);
                subtitleText.setFont(new Font("SansSerif", Font.ITALIC, 10));
                chart.addSubtitle(subtitleText);
            }
            CategoryPlot categoryPlot = chart.getCategoryPlot();
            CategoryItemRenderer categoryRenderer = new BarRenderer();
            ((BarRenderer) categoryRenderer).setItemMargin(0);
            categoryRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER));
            categoryRenderer.setBaseNegativeItemLabelPosition(new ItemLabelPosition(
                        ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER));
            categoryPlot.setRenderer(categoryRenderer);

            // rotate the category labels
            categoryPlot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions
                    .createUpRotationLabelPositions(Math.PI / 6.0));

            setURLGen(categoryRenderer);

            ((BarRenderer) categoryRenderer).setNegativeItemLabelPositionFallback(
                new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.BASELINE_LEFT));

            formatBarCharts(categoryPlot);
        }

        if (chart.getTitle() != null) {
            chart.getTitle().setFont(new Font("SansSerif", Font.BOLD, 12));
        }

        chart.setPadding(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
// this would speed up chart rendering, but it wouldn't look as nice.
//        chart.setAntiAlias(false);
        ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());

        // generate the image and imagemap
//        try {
//            fileName = ServletUtilities.saveChartAsPNG(chart,
//                    ((GraphWidgetConfig) config).getWidth(),
//                    ((GraphWidgetConfig) config).getHeight(), info,
//                    ((GraphWidgetConfig) config).getSession());
//        } catch (IOException e) {
//            throw new RuntimeException("error rendering html", e);
//        }
        try {
            fileName = ServletUtilities.saveChartAsJPEG(chart,
                    ((GraphWidgetConfig) config).getWidth(),
                    ((GraphWidgetConfig) config).getHeight(), info,
                    ((GraphWidgetConfig) config).getSession());
        } catch (IOException e) {
            throw new RuntimeException("error rendering html", e);
        }
        imageMap = ImageMapUtilities.getImageMap("chart" + fileName, info);
    }

    private void setURLGen(CategoryItemRenderer categoryRenderer) {
        if (config.getLink() == null) {
            return;
        }
        CategoryURLGenerator categoryUrlGen = null;

        // set series 0 to have URLgenerator specified in config file
        // set series 1 to have no URL generator.
        try {
            Class<?> clazz2 = TypeUtil.instantiate(config.getLink());
{'fraction_non_alphanumeric': 0.0983643373133211, 'fraction_numerical': 0.007710446532170528, 'mean_word_length': 2.4488188976377954, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7151837', 'n_tokens_mistral': 7243, 'n_tokens_neox': 6982, 'n_words': 1407}