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

net.maizegenetics.analysis.association.WeightedMLMPlugin Maven / Gradle / Ivy

Go to download

TASSEL is a software package to evaluate traits associations, evolutionary patterns, and linkage disequilibrium.

The newest version!
package net.maizegenetics.analysis.association;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import net.maizegenetics.dna.snp.GenotypeTable;
import net.maizegenetics.gui.ReportDestinationDialog;
import net.maizegenetics.phenotype.GenotypePhenotype;
import net.maizegenetics.phenotype.Phenotype;
import net.maizegenetics.plugindef.DataSet;
import net.maizegenetics.plugindef.Datum;
import net.maizegenetics.taxa.distance.DistanceMatrix;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class WeightedMLMPlugin extends MLMPlugin{
    
    public boolean isUseP3D() {
        return useP3D;
    }

    public void setUseP3D(boolean useP3D) {
        this.useP3D = useP3D;
    }

    public boolean isUseGenotype() {
        return useGenotype;
    }

    public void setUseGenotype(boolean useGenotype) {
        this.useGenotype = useGenotype;
    }

    public boolean isUseRefProb() {
        return useRefProb;
    }

    public void setUseRefProb(boolean useRefProb) {
        this.useRefProb = useRefProb;
    }

    private static final Logger myLogger = LogManager.getLogger(WeightedMLMPlugin.class);
    protected DistanceMatrix kinshipMatrix;
    protected boolean analyzeByColumn;
    protected boolean useP3D = true;
    protected CompressionType compressionType = CompressionType.None;
    protected double compression = 1;
    protected List weightList;
    private boolean writeOutputToFile = false;
    private String outputName = null;
    private boolean filterOutput = false;
    private double maxp = 1;
    private boolean useGenotype = true;
    private boolean useRefProb = false;
    private boolean useAlleleProb = false;

    public enum CompressionType {
        Optimum, Custom, None
    };

    public WeightedMLMPlugin(Frame parentFrame, boolean isInteractive) {
        super(parentFrame, isInteractive);

    }

    @Override
    public DataSet processData(DataSet input) {
        try {

            java.util.List alignInList = input.getDataOfType(GenotypePhenotype.class);
            if (alignInList.size() == 0) {
                String message = "Invalid selection. Please select a GenotypePhenotype file";
                if (isInteractive()) {
                    JOptionPane.showMessageDialog(getParentFrame(), message);
                } else {
                    myLogger.error("performFunction: " + message);
                }
                return null;
                //alignInList = input.getDataOfType(Phenotype.class);
            }
            this.weightList =  input.getDataOfType(Phenotype.class);
            
            java.util.List kinshipList = input.getDataOfType(DistanceMatrix.class);

            if (alignInList.size() != 1) {
                String message = "Invalid selection. Please select one dataset with marker and trait data.";
                if (isInteractive()) {
                    JOptionPane.showMessageDialog(getParentFrame(), message);
                } else {
                    myLogger.error("performFunction: " + message);
                }
                return null;
            }
            
            if (kinshipList.size() != 1) {
                String message = "Please select exactly one kinship matrix.";
                if (isInteractive()) {
                    JOptionPane.showMessageDialog(getParentFrame(), message);
                } else {
                    myLogger.error("performFunction: " + message);
                }
                return null;
            }
            
            if(weightList.size()!= 1 && weightList.size()!=0) {
                String message = "Please select exactly one weight matrix.";
                if (isInteractive()) {
                    JOptionPane.showMessageDialog(getParentFrame(), message);
                } else {
                    myLogger.error("performFunction: " + message);
                }
                return null;
            }
            if(weightList.size()!=0&&isUseP3D()==false) {
                String message = "If You are using a Weight Matrix, you must use P3D.";
                if (isInteractive()) {
                    JOptionPane.showMessageDialog(getParentFrame(), message);
                } else {
                    myLogger.error("performFunction: " + message);
                }
                return null;
            }
            

            kinshipMatrix = (DistanceMatrix) kinshipList.get(0).getData();
            Iterator itr = alignInList.iterator();

            if (isInteractive()) {
                GenotypePhenotype gp = (GenotypePhenotype) alignInList.get(0).getData();
                WeightedMLMOptionDialog theOptions = new WeightedMLMOptionDialog(getParentFrame(), hasDataTypes(gp),weightList.size());

                if (theOptions.runClicked) {
                    useP3D = theOptions.useP3D();
                    compressionType = theOptions.getCompressionType();
                    compression = theOptions.getCompressionLevel();
                    theOptions.dispose();

                    // give the user the option of sending the output to a file
                    ReportDestinationDialog rdd = new ReportDestinationDialog();
                    rdd.setLocationRelativeTo(getParentFrame());
                    rdd.setVisible(true);
                    if (!rdd.isOkayChecked()) {
                        return null;
                    }
                    writeOutputToFile = rdd.wasUseFileChecked();
                    if (writeOutputToFile) {
                        outputName = rdd.getOutputFileName();
                    }
                    filterOutput = rdd.wasRestrictOutputChecked();
                    if (filterOutput) {
                        maxp = rdd.getMaxP();
                    }

                } else {
                    theOptions.dispose();
                    return null;
                }

            } else {         //non-interactive stuff
            }

            List myResults = new ArrayList();
            while (itr.hasNext()) {

                Datum current = itr.next();
                CompressedMLMusingDoubleMatrix theAnalysis;
                
                GenotypeTable myGenotype = ((GenotypePhenotype) current.getData()).genotypeTable();
                useGenotype = myGenotype.hasGenotype();
                if (!useGenotype) useRefProb = myGenotype.hasReferenceProbablity();

                if (useP3D) {
                        if (compressionType.equals(CompressionType.Optimum)) {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,true, true, Double.NaN);
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, weightList.get(0),true, true, Double.NaN);
                            }
                        } else if (compressionType.equals(CompressionType.Custom)) {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, true, true, compression);
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,  weightList.get(0),true, true, compression);  
                            }
                        } else {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, false, true, Double.NaN);
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,  weightList.get(0),false, true, Double.NaN);
                            }
                        }
                        theAnalysis.useGenotypeCalls(useGenotype);
                        theAnalysis.useReferenceProbability(useRefProb);
                        theAnalysis.useAlleleProbabilities(useAlleleProb);

                } else {
                        if (compressionType.equals(CompressionType.Optimum)) {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, true, false, Double.NaN);   
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,  weightList.get(0),true, false, Double.NaN);
                            }
                        } else if (compressionType.equals(CompressionType.Custom)) {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, true, false, compression);                                
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,  weightList.get(0),true, false, compression); 
                            }
                        } else {
                            if(weightList.size()==0) {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix, false, false, Double.NaN);
                            }
                            else {
                                theAnalysis = new CompressedMLMusingDoubleMatrix(this, current, kinshipMatrix,  weightList.get(0),false, false, Double.NaN);
                            }
                        }

                        theAnalysis.useGenotypeCalls(useGenotype);
                        theAnalysis.useReferenceProbability(useRefProb);
                        theAnalysis.useAlleleProbabilities(useAlleleProb);
                        
                }

                myResults.addAll(theAnalysis.solve());
           }

            if (myResults.size() > 0) {
                return new DataSet(myResults, this);
            }
            else return null;

        } finally {
            fireProgress(100);
        }

    }

    private boolean[] hasDataTypes(GenotypePhenotype gp) {
        boolean[] hasTypes = new boolean[]{false, false, false};
        if (gp.genotypeTable().hasGenotype()) hasTypes[0] = true;
        if (gp.genotypeTable().hasReference()) hasTypes[1] = true;
        if (gp.genotypeTable().hasAlleleProbabilities()) hasTypes[2] = true;
        return hasTypes;
    }
    
    public ImageIcon getIcon() {
        URL imageURL = WeightedMLMPlugin.class.getResource("/net/maizegenetics/analysis/images/Mix.gif");
        if (imageURL == null) {
            return null;
        } else {
            return new ImageIcon(imageURL);
        }
    }

    public String getButtonName() {
        return "WeightedMLM";
    }

    public String getToolTipText() {
        return "Association analysis using mixed model";
    }

    //a few stub functions to avoid producing errors in existing pipeline code
    public void setAnalyzeByColumn(boolean analyzeByColumn) {
        this.analyzeByColumn = analyzeByColumn;
    }

    public void setMaximumNumOfIteration(int max) {/*does nothing*/

    }

    public void setFinalIterMarker(boolean myFinalIterMarker) {/*does nothing*/

    }

    public void addFactors(int[] factors) {/*does nothing*/

    }

    public void setColumnTypes(String[] types) {/*does nothing*/

    }

    public void addFactors(String[] names) {/*does nothing*/

    }

    public void updateProgress(int progress) {
        if (progress < 0) {
            progress = 0;
        } else if (progress > 100) {
            progress = 100;
        }
        fireProgress(progress);
    }

    public void setVarCompEst(String value) {
        if (value.equalsIgnoreCase("P3D")) {
            useP3D = true;
        } else if (value.equalsIgnoreCase("EachMarker")) {
            useP3D = false;
        } else {
            throw new IllegalArgumentException("MLMPlugin: setVarCompEst: don't know how to handle value: " + value);
        }
    }

    public void setCompressionType(CompressionType type) {
        compressionType = type;
    }

    public boolean isWriteOutputToFile() {
        return writeOutputToFile;
    }

    public void setWriteOutputToFile(boolean writeOutputToFile) {
        this.writeOutputToFile = writeOutputToFile;
    }

    public String getOutputName() {
        return outputName;
    }

    public void setOutputName(String outputName) {
        this.outputName = outputName;
        this.writeOutputToFile = true;
    }

    public boolean isFilterOutput() {
        return filterOutput;
    }

    public void setFilterOutput(boolean filterOutput) {
        this.filterOutput = filterOutput;
    }

    public double getMaxp() {
        return maxp;
    }

    public void setMaxp(double maxp) {
        this.maxp = maxp;
        this.filterOutput = true;
    }

    public double getCustomCompression() {
        return compression;
    }

    public void setCustomCompression(double value) {
        compression = value;
    }
    
    public void useGenotypeCalls() {
        useGenotype = true;
        useRefProb = false;
        useAlleleProb = false;
    }
    
    public void useReferenceProbability() {
        useGenotype = false;
        useRefProb = true;
        useAlleleProb = false;
    }
    
    public void useAlleleProbabilities() {
        useGenotype = false;
        useRefProb = false;
        useAlleleProb = true;
    }

    @Override
    public String getCitation() {
        return "Shang Xue, Zachary Miller, Janu Verma, " +
                " First Annual Tassel Hackathon";
    }
}

class WeightedMLMOptionDialog extends JDialog implements ActionListener {

    JRadioButton btnOptimum, btnCustom, btnNoCompression, btnEachMarker, btnP3D;
    ButtonGroup bgCompress, bgVariance, bgType;
    JTextField txtCustom;
    boolean runClicked = false;
    boolean useP3D = true;
    WeightedMLMPlugin.CompressionType compressionType = WeightedMLMPlugin.CompressionType.None;
    boolean useDiscrete = true;
    boolean useRefprob = false;
    boolean useAlleleprob = false;
    int weightedSize;
    
    WeightedMLMOptionDialog(Frame parentFrame, boolean[] hasTypes,int weightedSize) {
        super(parentFrame, true);
        this.weightedSize = weightedSize;
        final Frame pframe = parentFrame;
        setTitle("MLM Options");
        setSize(new Dimension(350, 300));
        setLocationRelativeTo(pframe);
        Container theContentPane = getContentPane();
        theContentPane.setLayout(new BorderLayout());
        JPanel compressionPanel = new JPanel(new GridBagLayout());
        compressionPanel.setBorder(BorderFactory.createTitledBorder("Compression Level"));

        //the method radio buttons
        btnOptimum = new JRadioButton("Optimum Level", false);
        btnOptimum.setActionCommand("Optimum");
        btnOptimum.addActionListener(this);
        btnCustom = new JRadioButton("Custom Level:", false);
        btnCustom.setActionCommand("Custom");
        btnCustom.addActionListener(this);
        btnNoCompression = new JRadioButton("No Compression", true);
        btnNoCompression.setActionCommand("None");
        btnNoCompression.addActionListener(this);
        if(weightedSize==0) {
        btnEachMarker = new JRadioButton("Re-estimate after each marker", false);
        btnEachMarker.setActionCommand("Eachmarker");
        btnEachMarker.addActionListener(this);
        }
        btnP3D = new JRadioButton("P3D (estimate once)", true);
        btnP3D.setActionCommand("P3D");
        btnP3D.addActionListener(this);

        bgCompress = new ButtonGroup();
        bgCompress.add(btnOptimum);
        bgCompress.add(btnCustom);
        bgCompress.add(btnNoCompression);
        bgVariance = new ButtonGroup();
        if(weightedSize==0) {
        bgVariance.add(btnEachMarker);
        }
        bgVariance.add(btnP3D);

        txtCustom = new JTextField(5);
        Insets inset1 = new Insets(5, 15, 5, 5);
        Insets inset2 = new Insets(5, 5, 5, 5);
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.weighty = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = inset1; //top, left, bottom, right
        compressionPanel.add(btnOptimum, gbc);

        gbc.gridy++;
        gbc.gridwidth = 1;
        compressionPanel.add(btnCustom, gbc);
        gbc.gridx++;
        gbc.insets = inset2;
        compressionPanel.add(txtCustom, gbc);

        gbc.gridy++;
        gbc.gridx = 0;
        gbc.gridwidth = 2;
        gbc.insets = inset1;
        compressionPanel.add(btnNoCompression, gbc);

        theContentPane.add(compressionPanel, BorderLayout.NORTH);

        JPanel variancePanel = new JPanel(new GridBagLayout());
        variancePanel.setBorder(BorderFactory.createTitledBorder("Variance Component Estimation"));
        gbc.gridy = 0;
        variancePanel.add(btnP3D, gbc);
        gbc.gridy++;
        if(weightedSize==0) {
        variancePanel.add(btnEachMarker, gbc);
        }
        theContentPane.add(variancePanel, BorderLayout.CENTER);

        //panel for choosing a data type, if there is more than one
        int numberOfTypes = 0;
        for (boolean b : hasTypes) if (b) numberOfTypes++;
        if (numberOfTypes > 1) {
                bgType = new ButtonGroup();
                JPanel typePanel = new JPanel(new GridBagLayout());
                typePanel.setBorder(BorderFactory.createTitledBorder("Choose genotype data"));
                gbc.gridy = 0;
                boolean initialValue = true;
                
                if (hasTypes[0]) {
                        JRadioButton btnDiscrete = new JRadioButton("Discrete type, e.g. SNP", initialValue);
                btnDiscrete.setActionCommand("discrete");
                btnDiscrete.addActionListener(this);
                initialValue = false;
                bgType.add(btnDiscrete);
                typePanel.add(btnDiscrete);
                gbc.gridy++;
                }
                if (hasTypes[1]) {
                        JRadioButton btnRef = new JRadioButton("Numeric genotype", initialValue);
                        btnRef.setActionCommand("reference");
                        btnRef.addActionListener(this);
                initialValue = false;
                bgType.add(btnRef);
                typePanel.add(btnRef);
                gbc.gridy++;
                }
                if (hasTypes[2]) {
                        JRadioButton btnAllele = new JRadioButton("Allele probabilities", initialValue);
                        btnAllele.setActionCommand("allele");
                        btnAllele.addActionListener(this);
                initialValue = false;
                bgType.add(btnAllele);
                typePanel.add(btnAllele);
                gbc.gridy++;
                }
 
                
        }
        
        
        //the help me button
        JButton btnHelpme = new JButton("Help Me Choose");
        final String msg = "For faster analysis, impute marker values before running MLM and use P3D.\n"
                + "With imputed marker values (no missing data), P3D will be very fast but compression will actually increase execution time somewhat.\n"
                + "However, because compression will improve the overall model fit, it should still be used.\n"
                + "If there is missing marker data, compression with P3D will probably be faster than P3D alone.\n"
                + "With small to moderate sized data sets any of the methods should give reasonable performance. \n"
                + "With large data sets consider imputing marker data then using EMMA with both compression and P3D";
        btnHelpme.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                JOptionPane.showMessageDialog(pframe, msg, "EMMA methods", JOptionPane.INFORMATION_MESSAGE);
            }
        });


        //the run and cancel buttons
        JButton btnRun = new JButton("Run");
        JButton btnCancel = new JButton("Cancel");
        btnRun.setActionCommand("run");
        btnRun.addActionListener(this);
        btnCancel.setActionCommand("cancel");
        btnCancel.addActionListener(this);

        Box buttonBox = Box.createHorizontalBox();
        buttonBox.add(Box.createGlue());
        buttonBox.add(btnRun);
        buttonBox.add(Box.createHorizontalStrut(50));
        buttonBox.add(btnCancel);
        buttonBox.add(Box.createHorizontalStrut(50));
        buttonBox.add(btnHelpme);
        buttonBox.add(Box.createGlue());
        theContentPane.add(buttonBox, BorderLayout.SOUTH);
        this.pack();
        setLocationRelativeTo(getParent());
        this.setVisible(true);

    }

    public boolean useP3D() {
        return useP3D;
    }

    public WeightedMLMPlugin.CompressionType getCompressionType() {
        return compressionType;
    }

    public boolean useDiscrete() { return useDiscrete; }
    public boolean useRefProb() { return useRefprob; }
    public boolean useAlleleProb() { return useAlleleprob; }
    
    double getCompressionLevel() {
        double comp;
        try {
            comp = Double.parseDouble(txtCustom.getText());
        } catch (Exception e) {
            comp = Double.NaN;
        }
        return comp;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("run")) {
            runClicked = true;
            this.setVisible(false);
        } else if (e.getActionCommand().equals("cancel")) {
            this.setVisible(false);
        } else if (e.getActionCommand().equals("Optimum")) {
            compressionType = WeightedMLMPlugin.CompressionType.Optimum;
        } else if (e.getActionCommand().equals("Custom")) {
            compressionType = WeightedMLMPlugin.CompressionType.Custom;
        } else if (e.getActionCommand().equals("None")) {
            compressionType = WeightedMLMPlugin.CompressionType.None;
        } else if (e.getActionCommand().equals("Eachmarker")) {
            useP3D = false;
        } else if (e.getActionCommand().equals("P3D")) {
            useP3D = true;
        } else if (e.getActionCommand().equals("discrete")) {
            useDiscrete = true;
            useRefprob = false;
            useAlleleprob = false;
        } else if (e.getActionCommand().equals("reference")) {
            useDiscrete = false;
            useRefprob = true;
            useAlleleprob = false;
        } else if (e.getActionCommand().equals("allele")) {
            useDiscrete = false;
            useRefprob = false;
            useAlleleprob = true;
        }
    }
    
    public static void main(String[] args) {
        WeightedMLMOptionDialog mod = new WeightedMLMOptionDialog(null, new boolean[]{true, true, true},0);
        mod.dispose();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy