adams.gui.menu.AppendDatasets.java Source code

Java tutorial

Introduction

Here is the source code for adams.gui.menu.AppendDatasets.java

Source

/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * AppendDatasets.java
 * Copyright (C) 2015-2017 University of Waikato, Hamilton, New Zealand
 *
 */

package adams.gui.menu;

import adams.core.Properties;
import adams.core.Utils;
import adams.core.option.OptionUtils;
import adams.gui.application.AbstractApplicationFrame;
import adams.gui.application.AbstractBasicMenuItemDefinition;
import adams.gui.application.ChildFrame;
import adams.gui.application.UserMode;
import adams.gui.core.GUIHelper;
import adams.gui.wizard.AbstractWizardPage;
import adams.gui.wizard.FinalPage;
import adams.gui.wizard.PageCheck;
import adams.gui.wizard.WekaSelectDatasetPage;
import adams.gui.wizard.WekaSelectMultipleDatasetsPage;
import adams.gui.wizard.WizardPane;
import gnu.trove.list.array.TIntArrayList;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.AbstractFileLoader;
import weka.core.converters.ConverterUtils;
import weka.core.converters.ConverterUtils.DataSink;
import weka.core.converters.ConverterUtils.DataSource;

import java.awt.event.ActionEvent;
import java.io.File;
import java.util.logging.Level;

/**
 * For appending datasets into single dataset.
 *
 * @author  fracpete (fracpete at waikato dot ac dot nz)
 * @version $Revision$
 */
public class AppendDatasets extends AbstractBasicMenuItemDefinition {

    /** for serialization. */
    private static final long serialVersionUID = 7586443345167287461L;

    /**
     * Initializes the menu item with no owner.
     */
    public AppendDatasets() {
        this(null);
    }

    /**
     * Initializes the menu item.
     *
     * @param owner   the owning application
     */
    public AppendDatasets(AbstractApplicationFrame owner) {
        super(owner);
    }

    /**
     * Returns the file name of the icon.
     *
     * @return      the filename or null if no icon available
     */
    @Override
    public String getIconName() {
        return "append.png";
    }

    /**
     * Launches the functionality of the menu item.
     */
    @Override
    public void launch() {
        final WizardPane wizard;
        WekaSelectMultipleDatasetsPage infiles;
        WekaSelectDatasetPage outfile;
        FinalPage finalpage;
        final ChildFrame frame;

        // wizard
        wizard = new WizardPane();
        wizard.setCustomFinishText("Append");
        infiles = new WekaSelectMultipleDatasetsPage("Input");
        infiles.setDescription(
                "Select the Weka datasets to append (one-after-the-other).\nYou have to choose at least two.");
        infiles.setPageCheck(new PageCheck() {
            @Override
            public boolean checkPage(AbstractWizardPage page) {
                Properties props = page.getProperties();
                try {
                    String[] files = OptionUtils
                            .splitOptions(props.getProperty(WekaSelectMultipleDatasetsPage.KEY_FILES));
                    return (files.length >= 2);
                } catch (Exception e) {
                    getLogger().log(Level.SEVERE, "Failed to obtain files:", e);
                }
                return false;
            }
        });
        wizard.addPage(infiles);
        outfile = new WekaSelectDatasetPage("Output");
        outfile.setDescription("Select the file to save the combined data to.");
        outfile.setUseSaveDialog(true);
        wizard.addPage(outfile);
        finalpage = new FinalPage();
        finalpage.setLogo(null);
        finalpage.setDescription("<html><h2>Ready</h2>Please click on <b>Append</b> to start the process.</html>");
        wizard.addPage(finalpage);
        frame = createChildFrame(wizard, GUIHelper.getDefaultDialogDimension());
        wizard.addActionListener((ActionEvent e) -> {
            if (!e.getActionCommand().equals(WizardPane.ACTION_FINISH)) {
                frame.dispose();
                return;
            }
            Properties props = wizard.getProperties(false);
            File[] input = null;
            File output = null;
            try {
                String[] files = OptionUtils
                        .splitOptions(props.getProperty(WekaSelectMultipleDatasetsPage.KEY_FILES));
                input = new File[files.length];
                for (int i = 0; i < files.length; i++)
                    input[i] = new File(files[i]);
                output = new File(props.getProperty(WekaSelectDatasetPage.KEY_FILE));
            } catch (Exception ex) {
                GUIHelper.showErrorMessage(getOwner(),
                        "Failed to get setup from wizard!\n" + Utils.throwableToString(ex));
                return;
            }
            doAppend(frame, input, output);
        });
    }

    /**
     * Performs the append.
     *
     * @param frame       the frame to close
     * @param input       the files to merge
     * @param output      the output file
     */
    protected void doAppend(ChildFrame frame, File[] input, File output) {
        Instances[] data;
        Instances full;
        int i;
        int n;
        AbstractFileLoader loader;
        DataSink sink;
        int count;
        TIntArrayList transferAtt;
        int index;

        if (input.length < 2) {
            GUIHelper.showErrorMessage(getOwner(), "At least two files are required!");
            return;
        }

        // load and check compatibility
        loader = ConverterUtils.getLoaderForFile(input[0]);
        data = new Instances[input.length];
        count = 0;
        transferAtt = new TIntArrayList();
        for (i = 0; i < input.length; i++) {
            try {
                loader.setFile(input[i]);
                data[i] = DataSource.read(loader);
                if (i > 0) {
                    if (!data[0].equalHeaders(data[i])) {
                        GUIHelper.showErrorMessage(getOwner(), "Datasets '" + input[0] + "' and '" + input[i]
                                + "' are not compatible!\n" + data[0].equalHeadersMsg(data[i]));
                        return;
                    }
                } else {
                    for (n = 0; n < data[0].numAttributes(); n++) {
                        if (data[0].attribute(n).isString() || data[0].attribute(n).isRelationValued())
                            transferAtt.add(n);
                    }
                }
                count += data[i].numInstances();
            } catch (Exception e) {
                GUIHelper.showErrorMessage(getOwner(),
                        "Failed to read '" + input[i] + "'!\n" + Utils.throwableToString(e));
                return;
            }
        }

        // combine
        full = new Instances(data[0], count);
        for (i = 0; i < data.length; i++) {
            for (Instance inst : data[i]) {
                if (transferAtt.size() > 0) {
                    for (n = 0; n < transferAtt.size(); n++) {
                        index = transferAtt.get(n);
                        if (inst.attribute(index).isString())
                            full.attribute(index).addStringValue(inst.stringValue(index));
                        else if (inst.attribute(n).isRelationValued())
                            full.attribute(index).addRelation(inst.relationalValue(index));
                        else
                            throw new IllegalStateException(
                                    "Unhandled attribute type: " + Attribute.typeToString(inst.attribute(index)));
                    }
                }
                full.add(inst);
            }
        }

        // save
        try {
            sink = new DataSink(output.getAbsolutePath());
            sink.write(full);
        } catch (Exception e) {
            GUIHelper.showErrorMessage(getOwner(),
                    "Failed to save data to '" + output + "'!\n" + Utils.throwableToString(e));
            return;
        }

        GUIHelper.showInformationMessage(null, "Successfully appended!\n" + output);
        frame.dispose();
    }

    /**
     * Returns the title of the window (and text of menuitem).
     *
     * @return       the title
     */
    @Override
    public String getTitle() {
        return "WEKA Append datasets";
    }

    /**
     * Whether the panel can only be displayed once.
     *
     * @return      true if the panel can only be displayed once
     */
    @Override
    public boolean isSingleton() {
        return false;
    }

    /**
     * Returns the user mode, which determines visibility as well.
     *
     * @return      the user mode
     */
    @Override
    public UserMode getUserMode() {
        return UserMode.BASIC;
    }

    /**
     * Returns the category of the menu item in which it should appear, i.e.,
     * the name of the menu.
     *
     * @return      the category/menu name
     */
    @Override
    public String getCategory() {
        return CATEGORY_TOOLS;
    }
}