be.ugent.maf.cellmissy.gui.controller.TracksWriterController.java Source code

Java tutorial

Introduction

Here is the source code for be.ugent.maf.cellmissy.gui.controller.TracksWriterController.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;

import be.ugent.maf.cellmissy.analysis.singlecell.preprocessing.SingleCellConditionPreProcessor;
import be.ugent.maf.cellmissy.analysis.singlecell.processing.SingleCellConditionOperator;
import be.ugent.maf.cellmissy.entity.*;
import be.ugent.maf.cellmissy.entity.result.singlecell.CellCentricDataHolder;
import be.ugent.maf.cellmissy.entity.result.singlecell.SingleCellConditionDataHolder;
import be.ugent.maf.cellmissy.entity.result.singlecell.TrackDataHolder;
import be.ugent.maf.cellmissy.gui.project.TracksWriterDialog;
import be.ugent.maf.cellmissy.gui.view.MapDataTreeModel;
import be.ugent.maf.cellmissy.service.ExperimentService;
import be.ugent.maf.cellmissy.service.ProjectService;
import be.ugent.maf.cellmissy.service.WellService;
import be.ugent.maf.cellmissy.utils.GuiUtils;
import be.ugent.maf.cellmissy.utils.JFreeChartUtils;
import java.awt.Color;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * This controller takes care of writing tracks-derived data to file.
 *
 * @author Paola Masuzzo <paola.masuzzo@ugent.be>
 */
@Controller("tracksWriterController")
class TracksWriterController {

    private static final Logger LOG = Logger.getLogger(TracksWriterController.class);
    // model
    private LinkedHashMap<Project, List<Experiment>> projectMap;
    private File directory;
    private LinkedHashMap<Experiment, List<List<TrackDataHolder>>> computationsMap;
    // view
    private TracksWriterDialog tracksWriterDialog;
    // parent controller
    @Autowired
    private CellMissyController cellMissyController;
    // child controllers
    // services
    @Autowired
    private ProjectService projectService;
    @Autowired
    private ExperimentService experimentService;
    @Autowired
    private WellService wellService;
    @Autowired
    private SingleCellConditionPreProcessor singleCellConditionPreProcessor;
    @Autowired
    private SingleCellConditionOperator singleCellConditionOperator;

    /**
     * Initialize controller
     */
    public void init() {
        projectMap = new LinkedHashMap<>();
        computationsMap = new LinkedHashMap<>();
        // initialize main view component
        tracksWriterDialog = new TracksWriterDialog(cellMissyController.getCellMissyFrame(), false);
        initTracksWriterDialog();
    }

    /**
     * Show the dialog in the main controller.
     */
    public void showTracksWriterDialog() {
        tracksWriterDialog.pack();
        GuiUtils.centerDialogOnFrame(cellMissyController.getCellMissyFrame(), tracksWriterDialog);
        tracksWriterDialog.setVisible(true);
    }

    /**
     * Initialize dialog
     */
    private void initTracksWriterDialog() {
        // find and sort all projects
        List<Project> allProjects = projectService.findAll();
        Collections.sort(allProjects);
        // for each project, get the experiments performed, if any
        for (Project project : allProjects) {
            List<Experiment> experiments = experimentService
                    .findExperimentsByProjectIdAndStatus(project.getProjectid(), ExperimentStatus.PERFORMED);
            projectMap.put(project, experiments);
        }
        // initialise the data tree (set some of its properties, etc.)
        initDataTree();

        /**
         * On selecting all the projects.
         */
        tracksWriterDialog.getSelectAllButton().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            }
        });

        /**
         * On deselecting all the projects.
         */
        tracksWriterDialog.getDeselectAllButton().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            }
        });

        /**
         * Choose directory to create data files.
         */
        tracksWriterDialog.getChooseDirectoryButton().addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                chooseDirectory();
            }
        });

        /**
         * Retrieve the selected experiments, and do the computations for them.
         */
        tracksWriterDialog.getComputeAndWriteButton().addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                initComputationsMap();
                computeAndWriteToFile();
            }
        });
    }

    /**
     * Initialise the data tree (JTree).
     */
    private void initDataTree() {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("cellmissy");
        JTree dataTree = tracksWriterDialog.getDataTree();
        MapDataTreeModel mapDataTreeModel = new MapDataTreeModel(root, projectMap);
        dataTree.setModel(mapDataTreeModel);
        dataTree.setEditable(true);
    }

    /**
     * Choose Directory
     */
    private void chooseDirectory() {
        // Open a JFile Chooser
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("Select directory to save the files");
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fileChooser.setAcceptAllFileFilterUsed(false);
        // in response to the button click, show open dialog
        int returnVal = fileChooser.showOpenDialog(tracksWriterDialog);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            directory = fileChooser.getSelectedFile();
        }
        tracksWriterDialog.getDirectoryTextField().setText(directory.getAbsolutePath());
    }

    /**
     * Write data for a specific experiment.
     *
     * @param experiment
     */
    private void writeDataForExperiment(Experiment experiment) {
        directory = new File("E:\\");
        // get the data out of the map
        List<List<TrackDataHolder>> list = computationsMap.get(experiment);
        // name for the file
        String fileName = "cellmissy" + new SimpleDateFormat("yyyy-MM-dd hh-mm-ss").format(new Date()) + "_"
                + experiment + " [" + experiment.getProject() + "]" + ".csv";
        appendInfo("writing file: " + fileName + " to directory: " + directory);
        // use a BufferedWriter
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(directory, fileName)))) {

            String header = "projid" + " expid" + " condid" + " wellid" + " trackid" + " length" + " xmin" + " xmax"
                    + " ymin" + " ymax" + " xnd" + " ynd" + " cd" + " ed" + " diratio" + " medir" + " medspeed"
                    + " medta" + " maxdisp" + " dr" + " or" + " perim" + " area" + " acirc" + " dir" + " v";
            bufferedWriter.append(header);
            bufferedWriter.newLine();
            for (List<TrackDataHolder> trackDataHolders : list) {

                // iterate through the data
                for (TrackDataHolder trackDataHolder : trackDataHolders) {
                    CellCentricDataHolder cellCentricDataHolder = trackDataHolder.getCellCentricDataHolder();
                    Track track = trackDataHolder.getTrack();
                    Well well = track.getWellHasImagingType().getWell();
                    PlateCondition condition = well.getPlateCondition();

                    //                    String data = experiment.getProject().getProjectid() + " " + experiment.getExperimentid() + " " + condition.getPlateConditionid() + " " + well.getWellid() + " " + track.getTrackid() + " " + track.getTrackPointList().size() + " " + cellCentricDataHolder.getxMin() + " " + cellCentricDataHolder.getxMax() + " " + cellCentricDataHolder.getyMin() + " " + cellCentricDataHolder.getyMax() + " " + cellCentricDataHolder.getxNetDisplacement() + " " + cellCentricDataHolder.getyNetDisplacement() + " " + cellCentricDataHolder.getCumulativeDistance() + " " + cellCentricDataHolder.getEuclideanDistance() + " " + cellCentricDataHolder.getEndPointDirectionalityRatio() + " " + cellCentricDataHolder.getMedianDirectionalityRatio() + " " + cellCentricDataHolder.getMedianSpeed() + " " + cellCentricDataHolder.getMedianTurningAngle() + " " + cellCentricDataHolder.getConvexHull().getMostDistantPointsPair().getMaxSpan() + " " + cellCentricDataHolder.getDisplacementRatio() + " " + cellCentricDataHolder.getOutreachRatio() + " " + cellCentricDataHolder.getConvexHull().getPerimeter() + " " + cellCentricDataHolder.getConvexHull().getArea() + " " + cellCentricDataHolder.getConvexHull().getAcircularity() + " " + cellCentricDataHolder.getConvexHull().getDirectionality() + " " + cellCentricDataHolder.getConvexHull().getHullSize();

                    //                    bufferedWriter.append(data);
                    bufferedWriter.newLine();
                }
            }
        } catch (IOException ex) {
            LOG.error(ex.getMessage(), ex);
            appendInfo("ERROR WRITING DATA TO FILE !!!");
        }
    }

    /**
     * Get the selected List of Experiments, to start the computations on.
     *
     * @return
     */
    private void initComputationsMap() {
        for (Project project : projectMap.keySet()) {
            if (project.getProjectNumber() == 16) { // ************************
                List<Experiment> exps = projectMap.get(project);
                if (exps != null && !exps.isEmpty()) {
                    for (Experiment exp : exps) {
                        computationsMap.put(exp, new ArrayList());
                    }
                }
            }
        }
    }

    /**
     *
     */
    private class ComputationsSwingWorker extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() throws Exception {
            Iterator<Experiment> iterator = computationsMap.keySet().iterator();
            while (iterator.hasNext()) {
                List<List<TrackDataHolder>> list = new ArrayList();
                Experiment experiment = iterator.next();
                if (experiment.getExperimentNumber() == 17) {
                    String info = "Starting querying data from EXPERIMENT: " + experiment + " ["
                            + experiment.getProject() + "]";
                    appendInfo(info);
                    // compute the conversion factor
                    double conversionFactor = experiment.getInstrument().getConversionFactor()
                            * experiment.getMagnification().getMagnificationValue() / 10;
                    // fetch the migration data
                    for (PlateCondition plateCondition : experiment.getPlateConditionList()) {
                        info = "Starting querying data from CONDITION: " + plateCondition;
                        appendInfo(info);
                        List<Well> wells = new ArrayList<>();
                        for (Well well : plateCondition.getWellList()) {
                            Well fetchedWell = wellService.fetchMigrationData(well.getWellid());
                            wells.add(fetchedWell);
                            info = "Starting querying data from WELL: " + fetchedWell;
                            appendInfo(info);
                        }
                        plateCondition.setWellList(wells);
                        info = "Data fully queried for CONDITION: " + plateCondition;
                        appendInfo(info);

                        info = "... COMPUTING stuff now ...";
                        appendInfo(info);
                        // now do the computations
                        int totTracks = 0;
                        info = "Starting computations for CONDITION: " + plateCondition;
                        appendInfo(info);
                        // create a new object to hold pre-processing results
                        SingleCellConditionDataHolder singleCellConditionDataHolder = new SingleCellConditionDataHolder();
                        // do the computations
                        singleCellConditionPreProcessor.generateDataHolders(singleCellConditionDataHolder);
                        info = "track data holders generated...";
                        appendInfo(info);
                        List<TrackDataHolder> trackDataHolders = singleCellConditionDataHolder
                                .getTrackDataHolders();
                        if (!trackDataHolders.isEmpty()) {
                            singleCellConditionPreProcessor.generateDataStructure(singleCellConditionDataHolder);
                            info = "data structure generated ...\n*****";
                            appendInfo(info);
                            singleCellConditionPreProcessor.preProcessStepsAndCells(singleCellConditionDataHolder,
                                    conversionFactor, experiment.getExperimentInterval());
                            info = "step-centric and cell-centric operations performed ...";
                            appendInfo(info);
                            singleCellConditionPreProcessor
                                    .generateRawTrackCoordinatesMatrix(singleCellConditionDataHolder);
                            singleCellConditionPreProcessor
                                    .generateShiftedTrackCoordinatesMatrix(singleCellConditionDataHolder);
                            info = "tracks coordinates computed...";
                            appendInfo(info);
                            singleCellConditionOperator
                                    .generateInstantaneousDisplacementsVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateDirectionalityRatiosVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateMedianDirectionalityRatiosVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateTrackDisplacementsVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateCumulativeDistancesVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateEuclideanDistancesVector(singleCellConditionDataHolder);
                            singleCellConditionOperator.generateTrackSpeedsVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateEndPointDirectionalityRatiosVector(singleCellConditionDataHolder);
                            info = "displacements, speeds and directionalities computed...";
                            appendInfo(info);
                            singleCellConditionOperator.generateConvexHullsVector(singleCellConditionDataHolder);
                            info = "convex hulls computed...";
                            appendInfo(info);
                            singleCellConditionOperator
                                    .generateDisplacementRatiosVector(singleCellConditionDataHolder);
                            singleCellConditionOperator.generateOutreachRatiosVector(singleCellConditionDataHolder);
                            singleCellConditionOperator.generateTurningAnglesVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateMedianTurningAnglesVector(singleCellConditionDataHolder);
                            singleCellConditionOperator
                                    .generateMedianTurningAnglesVector(singleCellConditionDataHolder);
                            info = "angles data computed...";
                            appendInfo(info);
                            totTracks += trackDataHolders.size();
                            list.add(trackDataHolders);
                            appendInfo("$$$ nr. tracks for CONDITION: " + trackDataHolders.size());
                            appendInfo("*-*-* CONDITION " + plateCondition + " processed!");
                            appendInfo("TOTAL nr. of cell tracks: " + totTracks);
                        } else {
                            tracksWriterDialog.getLogTextArea().setForeground(Color.red);
                            info = "No Tracks... skipping computations, moving to next!";
                            appendInfo(info);
                            tracksWriterDialog.getLogTextArea().setForeground(Color.black);
                        }
                    }
                    computationsMap.get(experiment).addAll(list);
                    appendInfo("WRITING data for: " + experiment);
                    writeDataForExperiment(experiment);
                    iterator.remove();
                }

            }
            appendInfo("DONE !!!");
            return null;
        }

        @Override
        protected void done() {
            try {
                get();
            } catch (InterruptedException | ExecutionException | CancellationException ex) {
                LOG.error(ex.getMessage(), ex);
            }
        }
    }

    /**
     * Append the info in the log text area.
     *
     * @param info
     */
    private void appendInfo(String info) {
        String newLine = JFreeChartUtils.getNewLine();
        tracksWriterDialog.getLogTextArea().append(info + newLine);
        tracksWriterDialog.getLogTextArea()
                .setCaretPosition(tracksWriterDialog.getLogTextArea().getDocument().getLength());
    }

    /**
     * For a specific list of selected experiments, compute the track data. This
     * basically calls a SwingWorker and execute it. For each experiment, write
     * the data to a single file in the chosen directory.
     */
    private void computeAndWriteToFile() {
        ComputationsSwingWorker computationsSwingWorker = new ComputationsSwingWorker();
        computationsSwingWorker.execute();
    }
}