com.hmsinc.epicenter.webapp.remoting.AnalysisService.java Source code

Java tutorial

Introduction

Here is the source code for com.hmsinc.epicenter.webapp.remoting.AnalysisService.java

Source

/**
 * Copyright (C) 2008 University of Pittsburgh
 * 
 * 
 * This file is part of Open EpiCenter
 * 
 *     Open EpiCenter 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.
 * 
 *     Open EpiCenter 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 Open EpiCenter.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * 
 *   
 */
package com.hmsinc.epicenter.webapp.remoting;

import static com.hmsinc.epicenter.util.DateTimeUtils.deltaDays;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;
import org.jfree.chart.annotations.XYAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.springframework.security.annotation.Secured;
import org.springframework.transaction.annotation.Transactional;

import com.hmsinc.ts4j.analysis.ResultType;
import com.hmsinc.ts4j.analysis.univariate.DescriptiveUnivariateAnalyzer;
import com.hmsinc.epicenter.model.analysis.AnalysisParameters;
import com.hmsinc.epicenter.model.analysis.DataConditioning;
import com.hmsinc.epicenter.model.analysis.DataRepresentation;
import com.hmsinc.epicenter.model.analysis.classify.Classification;
import com.hmsinc.epicenter.model.geography.Geography;
import com.hmsinc.epicenter.model.geography.GeographyType;
import com.hmsinc.epicenter.model.util.ModelUtils;
import com.hmsinc.epicenter.service.data.DataQueryService;
import com.hmsinc.epicenter.service.discovery.AnalyzerDiscoveryService;
import com.hmsinc.epicenter.spatial.render.SpatialScanResult;
import com.hmsinc.epicenter.spatial.service.SpatialScanService;
import com.hmsinc.epicenter.spatial.util.GoogleProjection;
import com.hmsinc.ts4j.TimeSeries;
import com.hmsinc.ts4j.TimeSeriesCollection;
import com.hmsinc.ts4j.TimeSeriesPeriod;
import com.hmsinc.epicenter.webapp.chart.ChartColor;
import com.hmsinc.epicenter.webapp.chart.ChartService;
import com.hmsinc.epicenter.webapp.chart.ChartType;
import com.hmsinc.epicenter.webapp.chart.LineStyle;
import com.hmsinc.epicenter.webapp.chart.TimeSeriesChart;
import com.hmsinc.epicenter.webapp.data.QueryService;
import com.hmsinc.epicenter.webapp.dto.AnalysisParametersDTO;
import com.hmsinc.epicenter.webapp.dto.KeyValueDTO;
import com.vividsolutions.jts.geom.Envelope;

/**
 * Handles data analysis in the UI.
 * 
 * TODO: Move most of this to a DWR converter instead of using DTOs.
 * 
 * @author <a href="mailto:steve.kondik@hmsinc.com">Steve Kondik</a>
 * @version $Id:AnalysisService.java 205 2007-09-26 16:52:01Z steve.kondik $
 */
@RemoteProxy(name = "AnalysisService")
public class AnalysisService extends AbstractRemoteService {

    @Resource
    private QueryService queryService;

    @Resource
    private DataQueryService dataQueryService;

    @Resource
    private ChartService chartService;

    @Resource
    private AnalyzerDiscoveryService analyzerDiscoveryService;

    @Resource
    private SpatialScanService spatialScanService;

    /**
     * Generates a TimeSeries of total counts for the given geography.
     * 
     * @param <T>
     * @param start
     * @param end
     * @param geoType
     * @param geoId
     * @param patientLocation
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    @SuppressWarnings("unchecked")
    public String getTotalChart(final AnalysisParametersDTO paramsDTO) {

        final AnalysisParameters params = convertParameters(paramsDTO);

        // Set the period based on the date range:
        params.setPeriod(deltaDays(params.getStartDate(), params.getEndDate()) > 0 ? TimeSeriesPeriod.DAY
                : TimeSeriesPeriod.HOUR);

        final Class<? extends Geography> aggregateType = (Class<? extends Geography>) ModelUtils
                .getRealClass(params.getContainer());
        final Map<? extends Geography, TimeSeries> ts = dataQueryService.queryTotals(params, aggregateType);
        Validate.notNull(ts, "Unable to get timeseries data!");

        final TimeSeries totals = ts.get(params.getContainer());

        final TimeSeriesChart chart = new TimeSeriesChart();
        chart.setType(ChartType.TIMESERIES_BAR);
        chart.setYLabel("Number of Visits");

        if (totals != null) {
            chart.add((params.getDataType() == null ? "Total Visits" : params.getDataType().getName()), totals);
        }

        return chartService.getChartURL(chart);
    }

    /**
     * @param paramsDTO
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    @SuppressWarnings("unchecked")
    public String getSummaryChart(final AnalysisParametersDTO paramsDTO) {

        final AnalysisParameters analysisParameters = convertParameters(paramsDTO);
        final Class<? extends Geography> aggregateType = (Class<? extends Geography>) ModelUtils
                .getRealClass(analysisParameters.getContainer());

        final TimeSeriesCollection<? extends Geography, Classification> tsc = dataQueryService
                .query(analysisParameters, aggregateType);

        final TimeSeriesChart chart = new TimeSeriesChart();
        chart.setType(ChartType.MOUNTAIN);
        chart.setYLabel("Number of Visits");

        if (tsc.getPrimaryIndexes().contains(analysisParameters.getContainer())) {

            final Map<Classification, TimeSeries> tsm = tsc.getMaps().get(analysisParameters.getContainer());

            // Sort the map by the max value in the timeseries.
            final ArrayList<Classification> keys = new ArrayList<Classification>();
            keys.addAll(tsm.keySet());

            Collections.sort(keys, new Comparator<Classification>() {
                public int compare(Classification o1, Classification o2) {
                    return new CompareToBuilder().append(tsm.get(o2).getMaxValue(), tsm.get(o1).getMaxValue())
                            .toComparison();
                }
            });

            int i = 0;

            for (Classification c : keys) {
                if (!"Other".equals(c.getName())) {
                    chart.add(c.getName(), tsm.get(c));
                    i++;
                    if (i > 6) {
                        break;
                    }
                }
            }
        }

        return chartService.getChartURL(chart);
    }

    /**
     * Builds a timeseries for the given criteria.
     * 
     * @param classifierId
     * @param classifierCategory
     * @param start
     * @param end
     * @param geoType
     * @param geoId
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    public String getTimeSeriesChart(final AnalysisParametersDTO paramsDTO) {

        final AnalysisParameters params = convertParameters(paramsDTO);
        final Properties analyzerProperties = paramsDTO.getAlgorithmProperties();

        // Set the period based on the date range:
        params.setPeriod(deltaDays(params.getStartDate(), params.getEndDate()) > 0 ? TimeSeriesPeriod.DAY
                : TimeSeriesPeriod.HOUR);

        TimeSeries ts = queryService.queryForTimeSeries(params, paramsDTO.getAlgorithmName(), analyzerProperties);
        TimeSeriesChart chart = new TimeSeriesChart();
        final List<XYAnnotation> events = new ArrayList<XYAnnotation>();

        if (ts != null) {

            chart.setYLabel(params.getDataRepresentation().getDisplayName());

            final String label = getAttributeLabel(params);
            if (!DataConditioning.NONE.equals(params.getDataConditioning())) {

                chart.add(label + " (Conditioned)", ts, ChartColor.VALUE.getColor(), LineStyle.SOLID);
                chart.add("Actual Value", ts, ResultType.RAW, ChartColor.VALUE.getColor(), LineStyle.DASHED);

            } else {

                chart.add(label, ts, ChartColor.VALUE.getColor(), LineStyle.SOLID);
                if (DataRepresentation.ACTUAL.equals(params.getDataRepresentation())) {
                    chart.setRangeTickUnits(NumberAxis.createIntegerTickUnits());
                }
            }

            if (paramsDTO.getAlgorithmName() != null) {
                chart.add(paramsDTO.getAlgorithmName(), ts, ResultType.THRESHOLD, ChartColor.THRESHOLD.getColor(),
                        LineStyle.SOLID);

                /*
                 * for (TimeSeriesEntry entry : ts) { if (entry.getValue() >=
                 * entry.getDoubleProperty(ResultType.THRESHOLD) &&
                 * entry.getValue() > 10) { final String value =
                 * String.valueOf(FormatUtils.round(entry.getValue(), 1)); final
                 * XYPointerAnnotation annotation = new
                 * XYPointerAnnotation(value, entry.getTime().getMillis(),
                 * entry.getValue(), 3.0 * Math.PI / 4.0 );
                 * annotation.setPaint(ChartColor.THRESHOLD.getColor());
                 * events.add(annotation); } }
                 */
            }
        }

        return chartService.getChartURL(chart, events);
    }

    /**
     * @param paramsDTO
     * @param feature
     * @param width
     * @param height
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    public SpatialScanResult spatialScan(final AnalysisParametersDTO paramsDTO, final double minX,
            final double minY, final double maxX, final double maxY, final GeographyType feature, final int width,
            final int height) {

        Validate.notNull(feature, "Feature type is required.");

        final AnalysisParameters analysisParameters = convertParameters(paramsDTO);
        final Envelope bounds = new Envelope(minX, maxX, minY, maxY);
        Validate.notNull(bounds, "Invalid bbox.");

        analysisParameters.setFilter(bounds);

        return spatialScanService.scan(analysisParameters, feature.getGeoClass(), GoogleProjection.GOOGLE_MERCATOR,
                width, height, false, false);

    }

    /**
     * @param analysisParameters
     * @return
     */
    public static String getAttributeLabel(final AnalysisParameters analysisParameters) {

        final String ageLabel;
        final String genderLabel;

        if (analysisParameters.getAgeGroups() == null || analysisParameters.getAgeGroups().size() == 0) {
            ageLabel = "All Ages";
        } else if (analysisParameters.getAgeGroups().size() == 1) {
            ageLabel = analysisParameters.getAgeGroups().iterator().next().getName();
        } else {
            ageLabel = "Custom Age";
        }

        if (analysisParameters.getGenders() == null || analysisParameters.getGenders().size() == 0) {
            genderLabel = "All Genders";
        } else if (analysisParameters.getGenders().size() == 1) {
            genderLabel = analysisParameters.getGenders().iterator().next().getName();
        } else {
            genderLabel = "Custom Gender";
        }

        return StringUtils.join(new String[] { ageLabel, genderLabel }, "+");
    }

    /**
     * Gets all available algorithms.
     * 
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    public Collection<KeyValueDTO> getAlgorithms() {
        final Set<KeyValueDTO> ret = new TreeSet<KeyValueDTO>();
        for (String name : analyzerDiscoveryService.getUnivariateAnalyzers()) {
            ret.add(new KeyValueDTO(name, name));
        }
        return prependNoneCategory(ret, "No Analysis");
    }

    /**
     * Gets all available algorithms.
     * 
     * @return
     */
    @Secured("ROLE_USER")
    @Transactional(readOnly = true)
    @RemoteMethod
    public Collection<KeyValueDTO> getPosteriorAlgorithms() {
        final Set<KeyValueDTO> ret = new TreeSet<KeyValueDTO>();
        for (String name : analyzerDiscoveryService.getUnivariateProbabilityAnalyzers()) {
            ret.add(new KeyValueDTO(name, name));
        }
        return ret;
    }

    /**
     * @param name
     * @return
     */
    @Secured("ROLE_USER")
    @RemoteMethod
    public DescriptiveUnivariateAnalyzer getAnalyzerDetails(final String name) {

        Validate.notNull(name, "Analyzer name is required.");

        final DescriptiveUnivariateAnalyzer analyzer;
        if (analyzerDiscoveryService.getUnivariateAnalyzers().contains(name)) {
            analyzer = analyzerDiscoveryService.getUnivariateAnalyzer(name);
        } else if (analyzerDiscoveryService.getUnivariateProbabilityAnalyzers().contains(name)) {
            analyzer = analyzerDiscoveryService.getUnivariateProbabilityAnalyzer(name);
        } else {
            throw new IllegalArgumentException("No such analyzer: " + name);
        }
        return analyzer;
    }

    /**
     * @param name
     * @param parameters
     * @return
     */
    @Secured("ROLE_USER")
    @RemoteMethod
    public List<Integer> getEffectiveTrainingPeriods(final String name, final Properties parameters) {

        Validate.notNull(name, "Analyzer name is required.");

        final DescriptiveUnivariateAnalyzer analyzer;
        if (analyzerDiscoveryService.getUnivariateAnalyzers().contains(name)) {
            analyzer = analyzerDiscoveryService.getUnivariateAnalyzer(name);
        } else if (analyzerDiscoveryService.getUnivariateProbabilityAnalyzers().contains(name)) {
            analyzer = analyzerDiscoveryService.getUnivariateProbabilityAnalyzer(name);
        } else {
            throw new IllegalArgumentException("No such analyzer: " + name);
        }

        return analyzer.getEffectiveTrainingPeriods(parameters);
    }
}