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

org.datacleaner.widgets.result.NumberAnalyzerResultSwingRenderer Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Free Software Foundation, Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.datacleaner.widgets.result;

import java.awt.BasicStroke;
import java.awt.event.ActionListener;

import org.apache.metamodel.schema.Table;
import org.datacleaner.api.InputColumn;
import org.datacleaner.api.RendererBean;
import org.datacleaner.beans.NumberAnalyzer;
import org.datacleaner.beans.NumberAnalyzerResult;
import org.datacleaner.connection.Datastore;
import org.datacleaner.connection.DatastoreCatalog;
import org.datacleaner.connection.DatastoreConnection;
import org.datacleaner.guice.DCModuleImpl;
import org.datacleaner.job.builder.AnalysisJobBuilder;
import org.datacleaner.panels.DCPanel;
import org.datacleaner.result.Crosstab;
import org.datacleaner.result.CrosstabNavigator;
import org.datacleaner.result.renderer.SwingRenderingFormat;
import org.datacleaner.util.ChartUtils;
import org.datacleaner.util.IconUtils;
import org.datacleaner.util.LookAndFeelManager;
import org.datacleaner.util.VFSUtils;
import org.datacleaner.util.WidgetUtils;
import org.datacleaner.widgets.Alignment;
import org.datacleaner.widgets.table.DCTable;
import org.datacleaner.windows.ResultWindow;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.data.function.NormalDistributionFunction2D;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;

import com.google.inject.Guice;
import com.google.inject.Injector;

@RendererBean(SwingRenderingFormat.class)
public class NumberAnalyzerResultSwingRenderer extends AbstractCrosstabResultSwingRenderer {

    @Override
    protected void decorate(final NumberAnalyzerResult result, final DCTable table,
            final DisplayChartCallback displayChartCallback) {
        // find the std. deviation row number.
        int rowNumber = -1;
        {
            for (int i = 0; i < table.getRowCount(); i++) {
                final Object value = table.getValueAt(i, 0);
                if (NumberAnalyzer.MEASURE_STANDARD_DEVIATION.equals(value)) {
                    rowNumber = i;
                    break;
                }
            }
            if (rowNumber == -1) {
                throw new IllegalStateException("Could not determine Std. deviation row number!");
            }
        }

        final Crosstab crosstab = result.getCrosstab();

        final InputColumn[] columns = result.getColumns();
        int columnNumber = 1;
        for (final InputColumn column : columns) {
            final CrosstabNavigator nav = crosstab.where(NumberAnalyzer.DIMENSION_COLUMN, column.getName());

            final Number numRows =
                    (Number) nav.where(NumberAnalyzer.DIMENSION_MEASURE, NumberAnalyzer.MEASURE_ROW_COUNT).get();
            if (numRows.intValue() > 0) {
                final Number standardDeviation =
                        (Number) nav.where(NumberAnalyzer.DIMENSION_MEASURE, NumberAnalyzer.MEASURE_STANDARD_DEVIATION)
                                .get();
                if (standardDeviation != null) {

                    final ActionListener action = e -> {
                        final Number mean =
                                (Number) nav.where(NumberAnalyzer.DIMENSION_MEASURE, NumberAnalyzer.MEASURE_MEAN).get();
                        final Number min = (Number) nav
                                .where(NumberAnalyzer.DIMENSION_MEASURE, NumberAnalyzer.MEASURE_LOWEST_VALUE).get();
                        final Number max = (Number) nav
                                .where(NumberAnalyzer.DIMENSION_MEASURE, NumberAnalyzer.MEASURE_HIGHEST_VALUE).get();

                        final NormalDistributionFunction2D normalDistributionFunction =
                                new NormalDistributionFunction2D(mean.doubleValue(), standardDeviation.doubleValue());
                        final XYDataset dataset = DatasetUtilities
                                .sampleFunction2D(normalDistributionFunction, min.doubleValue(), max.doubleValue(), 100,
                                        "Normal");

                        final JFreeChart chart = ChartFactory
                                .createXYLineChart("Normal distribution of " + column.getName(), column.getName(), "",
                                        dataset, PlotOrientation.VERTICAL, false, true, false);
                        ChartUtils.applyStyles(chart);
                        final Marker meanMarker = new ValueMarker(mean.doubleValue(), WidgetUtils.BG_COLOR_BLUE_DARK,
                                new BasicStroke(2f));
                        meanMarker.setLabel("Mean");
                        meanMarker.setLabelOffset(new RectangleInsets(70d, 25d, 0d, 0d));
                        meanMarker.setLabelFont(WidgetUtils.FONT_SMALL);
                        chart.getXYPlot().addDomainMarker(meanMarker);

                        final ChartPanel chartPanel = ChartUtils.createPanel(chart, true);
                        displayChartCallback.displayChart(chartPanel);
                    };

                    final DCPanel panel = AbstractCrosstabResultSwingRenderer
                            .createActionableValuePanel(standardDeviation, Alignment.RIGHT, action,
                                    IconUtils.CHART_LINE);
                    table.setValueAt(panel, rowNumber, columnNumber);
                }
            }

            columnNumber++;
        }

        super.decorate(result, table, displayChartCallback);
    }

    /**
     * A main method that will display the results of a few example number
     * analyzers. Useful for tweaking the charts and UI.
     *
     * @param args
     */
    public static void main(final String[] args) throws Exception {
        LookAndFeelManager.get().init();

        final Injector injector =
                Guice.createInjector(new DCModuleImpl(VFSUtils.getFileSystemManager().resolveFile("."), null));

        // run a small job
        final AnalysisJobBuilder ajb = injector.getInstance(AnalysisJobBuilder.class);
        final Datastore ds = injector.getInstance(DatastoreCatalog.class).getDatastore("orderdb");
        final DatastoreConnection con = ds.openConnection();
        final Table table = con.getSchemaNavigator().convertToTable("PUBLIC.CUSTOMERS");
        ajb.setDatastore(ds);
        ajb.addSourceColumns(table.getNumberColumns());
        ajb.addAnalyzer(NumberAnalyzer.class).addInputColumns(ajb.getSourceColumns());

        final ResultWindow resultWindow = injector.getInstance(ResultWindow.class);
        resultWindow.setVisible(true);
        resultWindow.startAnalysis();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy