ubic.gemma.web.controller.diff.DifferentialExpressionSearchController.java Source code

Java tutorial

Introduction

Here is the source code for ubic.gemma.web.controller.diff.DifferentialExpressionSearchController.java

Source

/*
 * The Gemma project
 * 
 * Copyright (c) 2006-2011 University of British Columbia
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package ubic.gemma.web.controller.diff;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import ubic.gemma.core.analysis.expression.diff.DiffExpressionSelectedFactorCommand;
import ubic.gemma.core.analysis.expression.diff.DifferentialExpressionMetaAnalysisValueObject;
import ubic.gemma.core.analysis.expression.diff.GeneDifferentialExpressionService;
import ubic.gemma.core.analysis.util.ExperimentalDesignUtils;
import ubic.gemma.core.genome.gene.service.GeneService;
import ubic.gemma.core.genome.gene.service.GeneSetService;
import ubic.gemma.core.job.executor.webapp.TaskRunningService;
import ubic.gemma.core.tasks.visualization.DifferentialExpressionSearchTaskCommand;
import ubic.gemma.model.analysis.expression.ExpressionExperimentSet;
import ubic.gemma.model.analysis.expression.FactorAssociatedAnalysisResultSet;
import ubic.gemma.model.analysis.expression.diff.DifferentialExpressionAnalysis;
import ubic.gemma.model.analysis.expression.diff.DifferentialExpressionValueObject;
import ubic.gemma.model.expression.experiment.*;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.gene.GeneSetValueObject;
import ubic.gemma.model.genome.gene.GeneValueObject;
import ubic.gemma.persistence.service.analysis.expression.diff.DifferentialExpressionAnalysisService;
import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService;
import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentSetService;
import ubic.gemma.web.controller.expression.experiment.ExpressionExperimentExperimentalFactorValueObject;
import ubic.gemma.web.util.EntityNotFoundException;

import java.util.*;

/**
 * A controller used to get differential expression analysis and meta analysis results.
 *
 * @author keshav
 */
@Controller
public class DifferentialExpressionSearchController {

    private static final Log log = LogFactory.getLog(DifferentialExpressionSearchController.class.getName());

    @Autowired
    private DifferentialExpressionAnalysisService differentialExpressionAnalysisService;
    @Autowired
    private GeneDifferentialExpressionService geneDifferentialExpressionService;
    @Autowired
    private GeneService geneService;
    @Autowired
    private GeneSetService geneSetService;
    @Autowired
    private ExpressionExperimentService expressionExperimentService;
    @Autowired
    private ExpressionExperimentSetService expressionExperimentSetService;
    @Autowired
    private TaskRunningService taskRunningService;

    /**
     * AJAX entry which returns results on a non-meta analysis basis. That is, the differential expression results for
     * the gene with the id, geneId, are returned.
     */
    public Collection<DifferentialExpressionValueObject> getDifferentialExpression(Long geneId, double threshold) {

        return this.getDifferentialExpression(geneId, threshold, null);
    }

    /**
     * AJAX entry which returns results on a non-meta analysis basis. That is, the differential expression results for
     * the gene with the id, geneId, are returned.
     */
    public Collection<DifferentialExpressionValueObject> getDifferentialExpression(Long geneId, double threshold,
            Integer limit) {

        Gene g = geneService.load(geneId);
        g = geneService.thaw(g);

        if (g == null) {
            return new ArrayList<>();
        }

        return geneDifferentialExpressionService.getDifferentialExpression(g, threshold, limit);
    }

    /**
     * AJAX entry which returns results on a non-meta analysis basis. That is, the differential expression results for
     * the gene with the id, geneId, are returned. This method is just like getDifferentialExpression but any analyses
     * with the 'batch' factor are filtered out because they are not biologically relevant
     */
    public Collection<DifferentialExpressionValueObject> getDifferentialExpressionWithoutBatch(Long geneId,
            double threshold, Integer limit) {

        Collection<DifferentialExpressionValueObject> analyses = getDifferentialExpression(geneId, threshold,
                limit);

        // for each DifferentialExpressionValueObject, check if its factors includes a batch factor and if so, remove
        // the batch factor
        Collection<DifferentialExpressionValueObject> toRemove = new ArrayList<>();
        for (DifferentialExpressionValueObject analysis : analyses) {
            for (ExperimentalFactorValueObject factor : analysis.getExperimentalFactors()) {
                if (ExperimentalDesignUtils.isBatch(factor)) {
                    toRemove.add(analysis);
                }
            }
        }
        analyses.removeAll(toRemove);

        return analyses;
    }

    /**
     * AJAX entry.
     * Value objects returned contain experiments that have 2 factors and have had the diff analysis run on it.
     */
    public Collection<ExpressionExperimentExperimentalFactorValueObject> getFactors(final Collection<Long> eeIds) {

        Collection<ExpressionExperimentExperimentalFactorValueObject> result = new HashSet<>();

        final Collection<Long> securityFilteredIds = securityFilterExpressionExperimentIds(eeIds);

        if (securityFilteredIds.size() == 0) {
            return result;
        }

        log.debug("Getting factors for experiments with ids: "
                + StringUtils.abbreviate(securityFilteredIds.toString(), 100));

        Collection<Long> filteredEeIds = new HashSet<>();

        Map<Long, Collection<DifferentialExpressionAnalysis>> diffAnalyses = differentialExpressionAnalysisService
                .findByInvestigationIds(securityFilteredIds);

        if (diffAnalyses.isEmpty()) {
            log.debug("No differential expression analyses for given ids: " + StringUtils.join(filteredEeIds, ','));
            return result;
        }

        Collection<ExpressionExperimentValueObject> eevos = this.expressionExperimentService
                .loadValueObjects(diffAnalyses.keySet(), false);

        Map<Long, ExpressionExperimentValueObject> eevoMap = new HashMap<>();
        for (ExpressionExperimentValueObject eevo : eevos) {
            eevoMap.put(eevo.getId(), eevo);
        }

        for (Long id : diffAnalyses.keySet()) {

            Collection<DifferentialExpressionAnalysis> analyses = diffAnalyses.get(id);

            for (DifferentialExpressionAnalysis analysis : analyses) {
                differentialExpressionAnalysisService.thaw(analysis);

                Collection<ExperimentalFactor> factors = new HashSet<>();
                for (FactorAssociatedAnalysisResultSet fars : analysis.getResultSets()) {
                    // FIXME includes factors making up interaction terms, but shouldn't
                    // matter, because they will be included as main effects too. If not, this will be wrong!
                    factors.addAll(fars.getExperimentalFactors());
                }

                filteredEeIds.add(id);
                ExpressionExperimentValueObject eevo = eevoMap.get(id);
                ExpressionExperimentExperimentalFactorValueObject eeefvo = new ExpressionExperimentExperimentalFactorValueObject();
                eeefvo.setExpressionExperiment(eevo);
                eeefvo.setNumFactors(factors.size());
                for (ExperimentalFactor ef : factors) {
                    ExperimentalFactorValueObject efvo = geneDifferentialExpressionService
                            .configExperimentalFactorValueObject(ef);
                    eeefvo.getExperimentalFactors().add(efvo);
                }

                result.add(eeefvo);
            }
        }
        log.info("Filtered experiments.  Returning factors for experiments with ids: "
                + StringUtils.abbreviate(filteredEeIds.toString(), 100));
        return result;
    }

    /**
     * AJAX - method used for main display metaheatmap.
     */
    @SuppressWarnings("unused") //used in js DiffExSearchAndVisualize
    public String scheduleDiffExpSearchTask(Long taxonId, ExpressionExperimentSetValueObject eevo,
            GeneSetValueObject gsvo) {

        log.info("Starting gene x condition search...");
        // Load experiments
        Collection<ExpressionExperimentDetailsValueObject> experiments;
        List<String> datasetGroupNames = new ArrayList<>();
        if (eevo.getExpressionExperimentIds().isEmpty()) {
            if (eevo.getId() != null) {
                experiments = expressionExperimentSetService.getExperimentValueObjectsInSet(eevo.getId());
            } else if (eevo.getName() != null) {
                Collection<ExpressionExperimentSet> eesets = expressionExperimentSetService
                        .findByName(eevo.getName());
                if (eesets.isEmpty() || eesets.size() > 1) {
                    throw new IllegalArgumentException("Experiment set not found by name=" + eevo.getName());
                }
                experiments = expressionExperimentSetService
                        .getExperimentValueObjectsInSet(eesets.iterator().next().getId());

            } else {
                throw new IllegalArgumentException(
                        "Experiment group should either have an id or a list of ee ids, or a unique name");
            }
        } else {
            experiments = loadExperimentsByIds(eevo.getExpressionExperimentIds());
        }

        datasetGroupNames.add(eevo.getName());

        // Load genes
        Collection<GeneValueObject> genes;
        if (gsvo.getGeneIds().isEmpty()) {
            genes = geneSetService.getGenesInGroup(gsvo);
        } else {
            genes = geneService.loadValueObjectsByIds(gsvo.getGeneIds());
        }

        log.info("Got genes");
        // FIXME why not just pass in the eeset and geneset (security filtering could happen there)
        final DifferentialExpressionSearchTaskCommand taskCommand = new DifferentialExpressionSearchTaskCommand(
                genes, experiments, gsvo.getName(), eevo.getName());

        String taskId = taskRunningService.submitLocalTask(taskCommand);

        log.info("Scheduled search with task=" + taskId);

        return taskId;
    }

    /**
     * Returns the results of the meta-analysis.
     */
    private DifferentialExpressionMetaAnalysisValueObject getDifferentialExpressionMetaAnalysis(Long geneId,
            Collection<DiffExpressionSelectedFactorCommand> selectedFactors, double threshold) {

        Gene g = geneService.load(geneId);

        if (g == null) {
            log.warn("No Gene with id=" + geneId);
            return null;
        }

        /* find experiments that have had the diff cli run on it and have the gene g (analyzed) - security filtered. */
        Collection<BioAssaySet> experimentsAnalyzed = differentialExpressionAnalysisService
                .findExperimentsWithAnalyses(g);

        if (experimentsAnalyzed.size() == 0) {
            throw new EntityNotFoundException("No results were found: no experiment analyzed those genes");
        }

        /* the 'chosen' factors (and their associated experiments) */
        Map<Long, Long> eeFactorsMap = new HashMap<>();
        for (DiffExpressionSelectedFactorCommand selectedFactor : selectedFactors) {
            Long eeId = selectedFactor.getEeId();
            eeFactorsMap.put(eeId, selectedFactor.getEfId());
            if (log.isDebugEnabled())
                log.debug(eeId + " --> " + selectedFactor.getEfId());
        }

        /*
         * filter experiments that had the diff cli run on it and are in the scope of eeFactorsMap eeIds
         * (active/available to the user).
         */
        Collection<BioAssaySet> activeExperiments;
        if (eeFactorsMap.keySet() == null || eeFactorsMap.isEmpty()) {
            activeExperiments = experimentsAnalyzed;
        } else {
            activeExperiments = new ArrayList<>();
            for (BioAssaySet ee : experimentsAnalyzed) {
                if (eeFactorsMap.keySet().contains(ee.getId())) {
                    activeExperiments.add(ee);
                }
            }
        }

        if (activeExperiments.isEmpty()) {
            throw new EntityNotFoundException(
                    "No results were found: none of the experiments selected analyzed those genes");
        }

        return geneDifferentialExpressionService.getDifferentialExpressionMetaAnalysis(threshold, g, eeFactorsMap,
                activeExperiments);
    }

    private Collection<ExpressionExperimentDetailsValueObject> loadExperimentsByIds(Collection<Long> ids) {
        if (ids.isEmpty()) {
            throw new IllegalArgumentException("No ids were provided");
        }

        Collection<ExpressionExperimentDetailsValueObject> experiments = expressionExperimentService
                .loadDetailsValueObjects(null, false, ids, null, 0, 0);

        if (experiments.isEmpty()) {
            throw new EntityNotFoundException("Could not access any experiments for " + ids.size() + " ids");
        }

        return experiments;
    }

    private Collection<Long> securityFilterExpressionExperimentIds(Collection<Long> ids) {
        /*
         * Because this method returns the results, we have to screen.
         */
        Collection<ExpressionExperiment> securityScreened = expressionExperimentService.load(ids);

        Collection<Long> filteredIds = new HashSet<>();
        for (ExpressionExperiment ee : securityScreened) {
            filteredIds.add(ee.getId());
        }
        return filteredIds;
    }
}