be.ugent.maf.cellmissy.gui.controller.analysis.singlecell.SingleCellStatisticsController.java Source code

Java tutorial

Introduction

Here is the source code for be.ugent.maf.cellmissy.gui.controller.analysis.singlecell.SingleCellStatisticsController.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package be.ugent.maf.cellmissy.gui.controller.analysis.singlecell;

import be.ugent.maf.cellmissy.analysis.SignificanceLevel;
import be.ugent.maf.cellmissy.analysis.factory.MultipleComparisonsCorrectionFactory;
import be.ugent.maf.cellmissy.analysis.factory.StatisticsTestFactory;
import be.ugent.maf.cellmissy.analysis.singlecell.processing.SingleCellStatisticsAnalyzer;
import be.ugent.maf.cellmissy.entity.result.singlecell.SingleCellAnalysisGroup;
import be.ugent.maf.cellmissy.entity.result.singlecell.SingleCellConditionDataHolder;
import be.ugent.maf.cellmissy.gui.experiment.analysis.singlecell.AnalysisPanel;
import be.ugent.maf.cellmissy.gui.view.renderer.table.FormatRenderer;
import be.ugent.maf.cellmissy.gui.view.renderer.table.PValuesTableRenderer;
import be.ugent.maf.cellmissy.gui.view.renderer.table.TableHeaderRenderer;
import be.ugent.maf.cellmissy.gui.view.table.model.SingleCellPValuesTableModel;
import be.ugent.maf.cellmissy.gui.view.table.model.SingleCellStatSummaryTableModel;
import java.awt.event.ActionEvent;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import org.apache.log4j.Logger;
import org.jdesktop.beansbinding.AutoBinding;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.observablecollections.ObservableCollections;
import org.jdesktop.observablecollections.ObservableList;
import org.jdesktop.swingbinding.JComboBoxBinding;
import org.jdesktop.swingbinding.JListBinding;
import org.jdesktop.swingbinding.SwingBindings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * A controller to take care of the logic for the single cell statistics.
 *
 * @author Paola
 */
@Controller("singleCellStatisticsController")
public class SingleCellStatisticsController {

    private static final Logger LOG = Logger.getLogger(SingleCellStatisticsController.class);
    // model
    private BindingGroup bindingGroup;
    private ObservableList<SingleCellAnalysisGroup> groupsBindingList;
    // view
    // parent controller
    @Autowired
    private SingleCellAnalysisController singleCellAnalysisController;
    // child controllers
    // services
    @Autowired
    private SingleCellStatisticsAnalyzer singleCellStatisticsAnalyzer;

    /**
     * Initialize controller
     */
    public void init() {
        bindingGroup = new BindingGroup();
        // initialize the main view
        initMainView();
    }

    /**
     * Update the list with conditions.
     */
    public void updateConditionList() {
        JList conditionList = singleCellAnalysisController.getAnalysisPanel().getConditionList();
        DefaultListModel model = (DefaultListModel) conditionList.getModel();
        if (singleCellAnalysisController.isFilteredData()) {
            singleCellAnalysisController.getFilteringMap().keySet().stream().forEach((conditionDataHolder) -> {
                model.addElement(conditionDataHolder.getPlateCondition());
            });
        } else {
            singleCellAnalysisController.getPreProcessingMap().values().stream().forEach((conditionDataHolder) -> {
                model.addElement(conditionDataHolder.getPlateCondition());
            });
        }
    }

    /**
     * Initialize main view.
     */
    private void initMainView() {
        // the view is kept in the parent controllers
        AnalysisPanel analysisPanel = singleCellAnalysisController.getAnalysisPanel();
        analysisPanel.getConditionList().setModel(new DefaultListModel());
        // customize tables
        analysisPanel.getStatTable().getTableHeader().setReorderingAllowed(false);
        analysisPanel.getStatTable().getTableHeader().setReorderingAllowed(false);
        analysisPanel.getComparisonTable().setFillsViewportHeight(true);
        analysisPanel.getComparisonTable().setFillsViewportHeight(true);

        // init binding
        groupsBindingList = ObservableCollections.observableList(new ArrayList<SingleCellAnalysisGroup>());
        JListBinding jListBinding = SwingBindings.createJListBinding(AutoBinding.UpdateStrategy.READ_WRITE,
                groupsBindingList, analysisPanel.getAnalysisGroupList());
        bindingGroup.addBinding(jListBinding);

        // fill in combo box
        List<Double> significanceLevels = new ArrayList<>();
        for (SignificanceLevel significanceLevel : SignificanceLevel.values()) {
            significanceLevels.add(significanceLevel.getValue());
        }
        ObservableList<Double> significanceLevelsBindingList = ObservableCollections
                .observableList(significanceLevels);
        JComboBoxBinding jComboBoxBinding = SwingBindings.createJComboBoxBinding(
                AutoBinding.UpdateStrategy.READ_WRITE, significanceLevelsBindingList,
                analysisPanel.getSignLevelComboBox());
        bindingGroup.addBinding(jComboBoxBinding);
        bindingGroup.bind();
        // add the NONE (default) correction method
        // when the none is selected, CellMissy does not correct for multiple hypotheses
        analysisPanel.getCorrectionComboBox().addItem("none");
        // fill in combo box: get all the correction methods from the factory
        Set<String> correctionBeanNames = MultipleComparisonsCorrectionFactory.getInstance()
                .getCorrectionBeanNames();
        correctionBeanNames.stream().forEach((correctionBeanName) -> {
            analysisPanel.getCorrectionComboBox().addItem(correctionBeanName);
        });
        // do the same for the statistical tests
        Set<String> statisticsCalculatorBeanNames = StatisticsTestFactory.getInstance()
                .getStatisticsCalculatorBeanNames();
        statisticsCalculatorBeanNames.stream().forEach((testName) -> {
            analysisPanel.getStatTestComboBox().addItem(testName);
        });
        //significance level to 0.05
        analysisPanel.getSignLevelComboBox().setSelectedIndex(1);
        // add parameters to perform analysis on
        analysisPanel.getParameterComboBox().addItem("cell speed");
        analysisPanel.getParameterComboBox().addItem("cell direct");

        /**
         * Add a group to analysis
         */
        analysisPanel.getAddGroupButton().addActionListener((ActionEvent e) -> {
            // from selected conditions make a new group and add it to the list
            addGroupToAnalysis();
        });

        /**
         * Remove a Group from analysis
         */
        analysisPanel.getRemoveGroupButton().addActionListener((ActionEvent e) -> {
            // remove the selected group from list
            removeGroupFromAnalysis();
        });
        /**
         * Execute a Mann Whitney Test on selected Analysis Group
         */
        analysisPanel.getPerformStatButton().addActionListener((ActionEvent e) -> {
            int selectedIndex = analysisPanel.getAnalysisGroupList().getSelectedIndex();
            String statisticalTestName = analysisPanel.getStatTestComboBox().getSelectedItem().toString();
            String param = analysisPanel.getParameterComboBox().getSelectedItem().toString();
            // check that an analysis group is being selected
            if (selectedIndex != -1) {
                SingleCellAnalysisGroup selectedGroup = groupsBindingList.get(selectedIndex);
                // compute statistics
                computeStatistics(selectedGroup, statisticalTestName, param);
                // show statistics in tables
                showSummary(selectedGroup);
                // set the correction combobox to the one already chosen
                analysisPanel.getCorrectionComboBox().setSelectedItem(selectedGroup.getCorrectionMethodName());
                if (selectedGroup.getCorrectionMethodName().equals("none")) {
                    // by default show p-values without adjustment
                    showPValues(selectedGroup, false);
                } else {
                    // show p values with adjustement
                    showPValues(selectedGroup, true);
                }
            } else {
                // ask user to select a group
                singleCellAnalysisController.showMessage("Please select a group to perform analysis on.",
                        "You must select a group first", JOptionPane.INFORMATION_MESSAGE);
            }
        });

        /**
         * Refresh p value table with current selected significance of level
         */
        analysisPanel.getSignLevelComboBox().addActionListener((ActionEvent e) -> {
            if (analysisPanel.getSignLevelComboBox().getSelectedIndex() != -1) {
                String statisticalTest = analysisPanel.getStatTestComboBox().getSelectedItem().toString();
                Double selectedSignLevel = (Double) analysisPanel.getSignLevelComboBox().getSelectedItem();
                SingleCellAnalysisGroup selectedGroup = groupsBindingList
                        .get(analysisPanel.getAnalysisGroupList().getSelectedIndex());
                boolean isAdjusted = !selectedGroup.getCorrectionMethodName().equals("none");
                singleCellStatisticsAnalyzer.detectSignificance(selectedGroup, statisticalTest, selectedSignLevel,
                        isAdjusted);
                boolean[][] significances = selectedGroup.getSignificances();
                JTable pValuesTable = analysisPanel.getComparisonTable();
                for (int i = 1; i < pValuesTable.getColumnCount(); i++) {
                    pValuesTable.getColumnModel().getColumn(i)
                            .setCellRenderer(new PValuesTableRenderer(new DecimalFormat("#.####"), significances));
                }
                pValuesTable.repaint();
            }
        });

        /**
         * Apply correction for multiple comparisons: choose the algorithm!
         */
        analysisPanel.getCorrectionComboBox().addActionListener((ActionEvent e) -> {
            int selectedIndex = analysisPanel.getAnalysisGroupList().getSelectedIndex();
            if (selectedIndex != -1) {
                SingleCellAnalysisGroup selectedGroup = groupsBindingList.get(selectedIndex);
                String correctionMethod = analysisPanel.getCorrectionComboBox().getSelectedItem().toString();

                // if the correction method is not "NONE"
                if (!correctionMethod.equals("none")) {
                    // adjust p values
                    singleCellStatisticsAnalyzer.correctForMultipleComparisons(selectedGroup, correctionMethod);
                    // show p - values with the applied correction
                    showPValues(selectedGroup, true);
                } else {
                    // if selected correction method is "NONE", do not apply correction and only show normal p-values
                    showPValues(selectedGroup, false);
                }
            }
        });

        /**
         * Perform statistical test: choose the test!!
         */
        analysisPanel.getPerformStatButton().addActionListener((ActionEvent e) -> {
            // get the selected test to be executed
            String selectedTest = analysisPanel.getStatTestComboBox().getSelectedItem().toString();
            String param = analysisPanel.getParameterComboBox().getSelectedItem().toString();
            // analysis group
            int selectedIndex = analysisPanel.getAnalysisGroupList().getSelectedIndex();
            if (selectedIndex != -1) {
                SingleCellAnalysisGroup selectedGroup = groupsBindingList.get(selectedIndex);
                computeStatistics(selectedGroup, selectedTest, param);
            }
        });

        //multiple comparison correction: set the default correction to none
        analysisPanel.getCorrectionComboBox().setSelectedIndex(0);
        analysisPanel.getStatTestComboBox().setSelectedIndex(0);
        analysisPanel.getParameterComboBox().setSelectedIndex(0);
    }

    /**
     * Show Summary Statistics in correspondent table
     *
     * @param analysisGroup
     */
    private void showSummary(SingleCellAnalysisGroup singleCellAnalysisGroup) {
        singleCellAnalysisController.getAnalysisPanel().getCurrentGroupName()
                .setText(singleCellAnalysisGroup.getGroupName());
        // set model and cell renderer for statistics summary table
        SingleCellStatSummaryTableModel statisticalSummaryTableModel = new SingleCellStatSummaryTableModel(
                singleCellAnalysisGroup);
        JTable statisticalSummaryTable = singleCellAnalysisController.getAnalysisPanel().getStatTable();
        statisticalSummaryTable.setModel(statisticalSummaryTableModel);
        for (int i = 1; i < statisticalSummaryTable.getColumnCount(); i++) {
            statisticalSummaryTable.getColumnModel().getColumn(i)
                    .setCellRenderer(new FormatRenderer(new DecimalFormat("#.####"), SwingConstants.CENTER));
        }
        statisticalSummaryTable.getTableHeader().setDefaultRenderer(new TableHeaderRenderer(SwingConstants.RIGHT));
    }

    /**
     * Show p-values in correspondent table
     *
     * @param analysisGroup
     */
    private void showPValues(SingleCellAnalysisGroup singleCellAnalysisGroup, boolean isAdjusted) {
        String statisticalTestName = singleCellAnalysisController.getAnalysisPanel().getStatTestComboBox()
                .getSelectedItem().toString();
        SingleCellPValuesTableModel pValuesTableModel = new SingleCellPValuesTableModel(singleCellAnalysisGroup,
                isAdjusted);
        JTable pValuesTable = singleCellAnalysisController.getAnalysisPanel().getComparisonTable();
        pValuesTable.setModel(pValuesTableModel);
        Double selectedSignLevel = (Double) singleCellAnalysisController.getAnalysisPanel().getSignLevelComboBox()
                .getSelectedItem();
        // detect significances with selected alpha level
        singleCellStatisticsAnalyzer.detectSignificance(singleCellAnalysisGroup, statisticalTestName,
                selectedSignLevel, isAdjusted);
        boolean[][] significances = singleCellAnalysisGroup.getSignificances();
        for (int i = 1; i < pValuesTable.getColumnCount(); i++) {
            pValuesTable.getColumnModel().getColumn(i)
                    .setCellRenderer(new PValuesTableRenderer(new DecimalFormat("#.####"), significances));
        }
        pValuesTable.getTableHeader().setDefaultRenderer(new TableHeaderRenderer(SwingConstants.RIGHT));
    }

    /**
     * Compute Statistics for the selected Group
     *
     * @param analysisGroup
     */
    private void computeStatistics(SingleCellAnalysisGroup analysisGroup, String statisticalTestName,
            String parameter) {
        // generate summary statistics
        singleCellStatisticsAnalyzer.generateSummaryStatistics(analysisGroup, statisticalTestName, parameter);
        // execute mann whitney test --- set p values matrix (no adjustment)
        singleCellStatisticsAnalyzer.executePairwiseComparisons(analysisGroup, statisticalTestName, parameter);
    }

    /**
     * Get conditions according to selected rows and add them to the Analysis
     * Group
     */
    private void addGroupToAnalysis() {
        List<SingleCellConditionDataHolder> conditionDataHolders = new ArrayList<>();

        Boolean filteredData = singleCellAnalysisController.isFilteredData();
        AnalysisPanel analysisPanel = singleCellAnalysisController.getAnalysisPanel();
        int[] selectedIndices = analysisPanel.getConditionList().getSelectedIndices();

        // we check here that at least two conditions have been selected to be part of the analysis group
        // else, the analysis does not really make sense
        if (selectedIndices.length > 1) {

            if (filteredData) {
                conditionDataHolders.addAll(singleCellAnalysisController.getFilteringMap().keySet());
            } else {
                conditionDataHolders.addAll(singleCellAnalysisController.getPreProcessingMap().values());
            }

            // make a new analysis group, with those conditions and those results
            SingleCellAnalysisGroup singleCellAnalysisGroup = new SingleCellAnalysisGroup(conditionDataHolders);

            //set name for the group
            if (!analysisPanel.getGroupNameTextField().getText().isEmpty()) {
                singleCellAnalysisGroup.setGroupName(analysisPanel.getGroupNameTextField().getText());
                // set correction method to NONE by default
                singleCellAnalysisGroup.setCorrectionMethodName("none");
                analysisPanel.getGroupNameTextField().setText("");
                // actually add the group to the analysis list
                if (!groupsBindingList.contains(singleCellAnalysisGroup)) {
                    groupsBindingList.add(singleCellAnalysisGroup);
                }
            } else {
                // ask the user to type a name for the group
                singleCellAnalysisController.showMessage("Please type a name for the analysis group.",
                        "no name typed for the analysis group", JOptionPane.INFORMATION_MESSAGE);
            }
        } else {
            // we tell the user that statistics cannot be performed on only one condition !!
            // the selection is basically ignored
            singleCellAnalysisController.showMessage(
                    "Sorry! It is not possible to perform analysis on one condition only!\nPlease select at least two conditions.",
                    "at least two conditions need to be chosen for analysis", JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * Remove a Group of Conditions
     */
    private void removeGroupFromAnalysis() {
        // selected group
        int selectedIndex = singleCellAnalysisController.getAnalysisPanel().getAnalysisGroupList()
                .getSelectedIndex();
        // check if an element is selected first
        if (selectedIndex != -1) {
            groupsBindingList.remove(selectedIndex);
        } else {
            singleCellAnalysisController.showMessage("Select a group to remove from current analysis!",
                    "remove group error", JOptionPane.INFORMATION_MESSAGE);
        }
    }

}