guiGroundwater_Model.java [src/java/m/groundwater] Revision: 87d1785a457caf03ed52dccdce3c74db5108caaa  Date: Fri Feb 05 09:59:57 MST 2016
package m.groundwater;

import groundwater.DateComparator;
import groundwater.DoubleArray;
import groundwater.DoubleMath;
import groundwater.Graphing;
import groundwater.USGSwell_Data;
import groundwater.User_Data;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.time.Day;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.Year;

/**
* Last Updated: 5-February-2016
* @author Tyler Wible
* @since 3-November-2014
*/
public class guiGroundwater_Model {
    String mainFolder = "C:/Projects/TylerWible/CodeDirectories/NetBeans/data/GW";//The output location of the graph
    String database = "USGS";
    String stationID = "402955103163501";//"404915077500801";//
    String stationName = "SB00605311CCC";//"CE 661";//
    String wqTest = "height";//"depth";//"00930 Sodium, water, filtered, milligrams per liter -- mg/L";//
    String beginDate = "";
    String endDate = "";
    String timeStep = "Daily";//"Yearly";//"Monthly";//
    String method = "Max";//"Min";//"Average";//"Total";//
    String period1Begin = "";
    String period1End = "";
    String period2Begin = "";
    String period2End = "";
    String period3Begin = "";
    String period3End = "";
    boolean medianTF = false;
    boolean mergeDatasets = false;//true;//
    String mergeMethod = "user";//"public";//"max";//"average";//"min";//
    String userData  = "";//"Date\tDepth\n1999-04-29\t80.3\n1999-05-09\t60.2\n1999-05-29\t20.1";
    
    //Outputs
    String len = "-1";
    String start = "?";
    String end = "?";
    String units = "?";
    String dataSource = "?";
    double max = -1;
    double min = -1;
    double upperQuartile = -1;
    double lowerQuartile = -1;
    double median = -1;
    double mean = -1;
    double standardDeviation = -1;
    double variance = -1;
    double skew = -1;
    double coeffvar = -1;
    double kendallCorlCoeff = -1;
    
    String len_period1 = "-1";
    double max_period1 = -1;
    double min_period1 = -1;
    double upperQuartile_period1 = -1;
    double lowerQuartile_period1 = -1;
    double median_period1 = -1;
    double mean_period1 = -1;
    double standardDeviation_period1 = -1;
    double variance_period1 = -1;
    double skew_period1 = -1;
    double coeffvar_period1 = -1;
    double kendallCorlCoeff_period1 = -1;
    
    String len_period2 = "-1";
    double max_period2 = -1;
    double min_period2 = -1;
    double upperQuartile_period2 = -1;
    double lowerQuartile_period2 = -1;
    double median_period2 = -1;
    double mean_period2 = -1;
    double standardDeviation_period2 = -1;
    double variance_period2 = -1;
    double skew_period2 = -1;
    double coeffvar_period2 = -1;
    double kendallCorlCoeff_period2 = -1;
    
    String len_period3 = "-1";
    double max_period3 = -1;
    double min_period3 = -1;
    double upperQuartile_period3 = -1;
    double lowerQuartile_period3 = -1;
    double median_period3 = -1;
    double mean_period3 = -1;
    double standardDeviation_period3 = -1;
    double variance_period3 = -1;
    double skew_period3 = -1;
    double coeffvar_period3 = -1;
    double kendallCorlCoeff_period3 = -1;
    
    
    //Gets
    public File getGWgraphOutput(){
        //This output file is for use with JSHighCharts
        return new File(mainFolder, "groundwater_graph.out");
    }
    public String getGraph() {
        return "groundwater_graph.jpg";
    }
    public String getLen() {
        return len;
    }
    public String getStart() {
        return start;
    }
    public String getEnd() {
        return end;
    }
    public String getUnits(){
        return units;
    }
    public String getDataSource() {
        return dataSource;
    }
    public String getMax(){
        return String.valueOf(max);
    }
    public String getMin(){
        return String.valueOf(min);
    }
    public String getUpperQuartile(){
        return String.valueOf(upperQuartile);
    }
    public String getLowerQuartile(){
        return String.valueOf(lowerQuartile);
    }
    public String getMedian(){
        return String.valueOf(median);
    }
    public String getMean(){
        return String.valueOf(mean);
    }
    public String getStandardDeviation(){
        return String.valueOf(standardDeviation);
    }
    public String getVariance(){
        return String.valueOf(variance);
    }
    public String getSkewness(){
        return String.valueOf(skew);
    }
    public String getCoefficientOfVariation(){
        return String.valueOf(coeffvar);
    }
    public String getKendallCorrelationCoefficient(){
        return String.valueOf(kendallCorlCoeff);
    }
    public String getLen_period1(){
        return len_period1;
    }
    public String getMax_period1(){
        return String.valueOf(max_period1);
    }
    public String getMin_period1(){
        return String.valueOf(min_period1);
    }
    public String getUpperQuartile_period1(){
        return String.valueOf(upperQuartile_period1);
    }
    public String getLowerQuartile_period1(){
        return String.valueOf(lowerQuartile_period1);
    }
    public String getMedian_period1(){
        return String.valueOf(median_period1);
    }
    public String getMean_period1(){
        return String.valueOf(mean_period1);
    }
    public String getStandardDeviation_period1(){
        return String.valueOf(standardDeviation_period1);
    }
    public String getVariance_period1(){
        return String.valueOf(variance_period1);
    }
    public String getSkewness_period1(){
        return String.valueOf(skew_period1);
    }
    public String getCoefficientOfVariation_period1(){
        return String.valueOf(coeffvar_period1);
    }
    public String getKendallCorrelationCoefficient_period1(){
        return String.valueOf(kendallCorlCoeff_period1);
    }
    public String getLen_period2(){
        return len_period2;
    }
    public String getMax_period2(){
        return String.valueOf(max_period2);
    }
    public String getMin_period2(){
        return String.valueOf(min_period2);
    }
    public String getUpperQuartile_period2(){
        return String.valueOf(upperQuartile_period2);
    }
    public String getLowerQuartile_period2(){
        return String.valueOf(lowerQuartile_period2);
    }
    public String getMedian_period2(){
        return String.valueOf(median_period2);
    }
    public String getMean_period2(){
        return String.valueOf(mean_period2);
    }
    public String getStandardDeviation_period2(){
        return String.valueOf(standardDeviation_period2);
    }
    public String getVariance_period2(){
        return String.valueOf(variance_period2);
    }
    public String getSkewness_period2(){
        return String.valueOf(skew_period2);
    }
    public String getCoefficientOfVariation_period2(){
        return String.valueOf(coeffvar_period2);
    }
    public String getKendallCorrelationCoefficient_period2(){
        return String.valueOf(kendallCorlCoeff_period2);
    }
    public String getLen_period3(){
        return len_period3;
    }
    public String getMax_period3(){
        return String.valueOf(max_period3);
    }
    public String getMin_period3(){
        return String.valueOf(min_period3);
    }
    public String getUpperQuartile_period3(){
        return String.valueOf(upperQuartile_period3);
    }
    public String getLowerQuartile_period3(){
        return String.valueOf(lowerQuartile_period3);
    }
    public String getMedian_period3(){
        return String.valueOf(median_period3);
    }
    public String getMean_period3(){
        return String.valueOf(mean_period3);
    }
    public String getStandardDeviation_period3(){
        return String.valueOf(standardDeviation_period3);
    }
    public String getVariance_period3(){
        return String.valueOf(variance_period3);
    }
    public String getSkewness_period3(){
        return String.valueOf(skew_period3);
    }
    public String getCoefficientOfVariation_period3(){
        return String.valueOf(coeffvar_period3);
    }
    public String getKendallCorrelationCoefficient_period3(){
        return String.valueOf(kendallCorlCoeff_period3);
    }
    
    
    //Sets
    public void setMainFolder(String mainFolder) {
        this.mainFolder = mainFolder;
    }
    public void setDatabase(String database) {
        this.database = database;
    }
    public void setStationID(String stationID) {
        this.stationID = stationID;
    }
    public void setStationName(String stationName) {
        this.stationName = stationName;
    }
    public void setWQtest(String wqTest) {
        this.wqTest = wqTest;
    }
    public void setBeginDate(String beginDate) {
        this.beginDate = beginDate;
    }
    public void setEndDate(String endDate) {
        this.endDate = endDate;
    }
    public void setTimeStep(String timeStep) {
        this.timeStep = timeStep;
    }
    public void setMethod(String method) {
        this.method = method;
    }
    public void setPeriod1Begin(String period1Begin) {
        this.period1Begin = period1Begin;
    }
    public void setPeriod1End(String period1End) {
        this.period1End = period1End;
    }
    public void setPeriod2Begin(String period2Begin) {
        this.period2Begin = period2Begin;
    }
    public void setPeriod2End(String period2End) {
        this.period2End = period2End;
    }
    public void setPeriod3Begin(String period3Begin) {
        this.period3Begin = period3Begin;
    }
    public void setPeriod3End(String period3End) {
        this.period3End = period3End;
    }
    public void setMedianTF(boolean medianTF) {
        this.medianTF = medianTF;
    }
    public void setUserData(String userData) {
        this.userData = userData;
    }
    public void setMergeDatasets(boolean mergeDatasets) {
        this.mergeDatasets = mergeDatasets;
    }
    public void setMergeMethod(String mergeMethod) {
        this.mergeMethod = mergeMethod;
    }
    
    /**
     * Main statistics function calls other functions to calculate each statistic value then stores the results as global variables
     * @param dataList  data on which statistical values are desired
     * @param flag  a flag for which results the statistics will be stored to, either "all", "period1", "period2", or "period3"
     */
    private void CalculateStatistics(String[][] data, String flag) {
        //Convert into double list
        ArrayList<Double> dataList = new ArrayList<Double>();
        for(int i=0; i<data.length; i++){
            dataList.add(Double.parseDouble(data[i][1]));
        }
        
        //Calculate statistics
        DoubleMath doubleMath = new DoubleMath();
        double temp1 = doubleMath.round(doubleMath.max(dataList),3);//Call Max function
        double temp2 = doubleMath.round(doubleMath.min(dataList),3);//Call Min function
        double temp3 = doubleMath.round(doubleMath.Percentile_function(dataList,0.75),3);//Call Upper Quartile function
        double temp4 = doubleMath.round(doubleMath.Percentile_function(dataList,0.25),3);//Call Lower Quartile function
        double temp5 = doubleMath.round(doubleMath.median(dataList),3);//Call Median function
        double temp6 = doubleMath.round(doubleMath.meanArithmetic(dataList),3);//Call Mean function
        double temp7 = doubleMath.round(doubleMath.StandardDeviationSample(dataList),3);//Call standard deviation function
        double temp8 = doubleMath.round(doubleMath.VarianceSample(dataList),3);//Call variance function
        double temp9 = doubleMath.round(doubleMath.SkewnessSample(dataList),8);//Call skewness function
        double temp10 = doubleMath.round(doubleMath.CoefficientOfVariation(dataList),3);//call coefficient of variation function
        double temp11 = doubleMath.round(doubleMath.KendallCorrelationCoefficient(dataList), 4);
        
        if(flag.equalsIgnoreCase("all")){
            max = temp1;
            min = temp2;
            upperQuartile = temp3;
            lowerQuartile = temp4;
            median = temp5;
            mean = temp6;
            standardDeviation = temp7;
            variance = temp8;
            skew = temp9;
            coeffvar = temp10;
            kendallCorlCoeff = temp11;
        }else if(flag.equalsIgnoreCase("period1")){
            max_period1 = temp1;
            min_period1 = temp2;
            upperQuartile_period1 = temp3;
            lowerQuartile_period1 = temp4;
            median_period1 = temp5;
            mean_period1 = temp6;
            standardDeviation_period1 = temp7;
            variance_period1 = temp8;
            skew_period1 = temp9;
            coeffvar_period1 = temp10;
            kendallCorlCoeff_period1 = temp11;
        }else if(flag.equalsIgnoreCase("period2")){
            max_period2 = temp1;
            min_period2 = temp2;
            upperQuartile_period2 = temp3;
            lowerQuartile_period2 = temp4;
            median_period2 = temp5;
            mean_period2 = temp6;
            standardDeviation_period2 = temp7;
            variance_period2 = temp8;
            skew_period2 = temp9;
            coeffvar_period2 = temp10;
            kendallCorlCoeff_period2 = temp11;
        }else if(flag.equalsIgnoreCase("period3")){
            max_period3 = temp1;
            min_period3 = temp2;
            upperQuartile_period3 = temp3;
            lowerQuartile_period3 = temp4;
            median_period3 = temp5;
            mean_period3 = temp6;
            standardDeviation_period3 = temp7;
            variance_period3 = temp8;
            skew_period3 = temp9;
            coeffvar_period3 = temp10;
            kendallCorlCoeff_period3 = temp11;
        }
    }
    /**
     * Graph the time series and user data and save the resulting graph to the specified location
     * @param sortedData  the String[][] containing sorted data for the time series 
     * (column 1 = dates (yyyy-mm-dd if timeStep = "daily", yyyy-mm if 
     * timeStep = "monthly", yyyy if timeStep = "yearly") column 2 = value
     * @param sortedData_user  the String[][] containing sorted user data for the 
     * time series (column 1 = dates (yyyy-mm-dd if timeStep = "daily", yyyy-mm 
     * if timeStep = "monthly", yyyy if timeStep = "yearly") column 2 = value
     * @param period1Data  the String[][] containing sorted data for the time
     * series contained by period1 (column 1 = dates (yyyy-mm-dd if timeStep = 
     * "daily", yyyy-mm if timeStep = "monthly", yyyy if timeStep = "yearly") 
     * column 2 = value
     * @param period2Data  the String[][] containing sorted data for the time
     * series contained by period2 (column 1 = dates (yyyy-mm-dd if timeStep = 
     * "daily", yyyy-mm if timeStep = "monthly", yyyy if timeStep = "yearly") 
     * column 2 = value
     * @param period3Data  the String[][] containing sorted data for the time
     * series contained by period3 (column 1 = dates (yyyy-mm-dd if timeStep = 
     * "daily", yyyy-mm if timeStep = "monthly", yyyy if timeStep = "yearly") 
     * column 2 = value
     * @param color  the color of the merged dataset (Java.Color)
     * @param color2  the color of the user dataset (Java.Color)
     * @param showLine  a boolean, if true lines will be shown on the graph, if false only shapes for the data
     * @param yAxisTitle  the String label for the y axis of the graph
     * @param units  the units of the current graph to be used in labeling for the legend
     * @param medianTF  if true then the median value will be plotted for period analyses, if false the mean (average) will be used
     */
    private void createTimeseriesGraph(String[][] sortedData,
                                       String[][] sortedData_user,
                                       String[][] period1Data,
                                       String[][] period2Data,
                                       String[][] period3Data,
                                       Color color,
                                       Color color2,
                                       boolean showLine,
                                       String yAxisTitle) throws ParseException {
        //Create TimeSeries graph of merged data
        Graphing graphing = new Graphing();
        XYPlot plotTime = new XYPlot();
        boolean showLegend = false;
        TimeSeries series = createTimeSeriesFromData(sortedData, stationID + ": Data");
        TimeSeries series2 = createTimeSeriesFromData(sortedData_user, stationID + ": User Data");
        
        //Create user data points
        if(sortedData_user.length != 0){//only show user points if it is not zero
            plotTime = graphing.addTimeseriesData(plotTime, series, showLine, color, false, false, false, true, 0);
            plotTime = graphing.addTimeseriesData(plotTime, series2, showLine, color2, false, false, false, true, 1);
            showLegend = true;
        }else{
            plotTime = graphing.addTimeseriesData(plotTime, series, showLine, color, false, false, false, true, 0);
        }
        
        //Create period analysis average lines
        if(period1Data.length > 0){
            this.len_period1 = String.valueOf(period1Data.length);
            double value = mean_period1;
            String label = "Average";
            if(medianTF){
                value = median_period1;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 1 " + label + ": " + value + " ft");
            
            //Set Start Point
            double d = Double.parseDouble(period1Begin.substring(8));
            double m = Double.parseDouble(period1Begin.substring(5,7));
            double y = Double.parseDouble(period1Begin.substring(0,4));
            int day =  (int)d;
            int month = (int)m;
            int year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            //Set End Point
            d = Double.parseDouble(period1End.substring(8));
            m = Double.parseDouble(period1End.substring(5,7));
            y = Double.parseDouble(period1End.substring(0,4));
            day =  (int)d;
            month = (int)m;
            year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            plotTime = graphing.addTimeseriesData(plotTime, periodSeries, true, Color.red, false, false, true, true, 2);
            showLegend = true;
        }
        if(period2Data.length > 0){
            this.len_period2 = String.valueOf(period2Data.length);
            double value = mean_period2;
            String label = "Average";
            if(medianTF){
                value = median_period2;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 2 " + label + ": " + value + " ft");
            
            //Set Start Point
            double d = Double.parseDouble(period2Begin.substring(8));
            double m = Double.parseDouble(period2Begin.substring(5,7));
            double y = Double.parseDouble(period2Begin.substring(0,4));
            int day =  (int)d;
            int month = (int)m;
            int year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            //Set End Point
            d = Double.parseDouble(period2End.substring(8));
            m = Double.parseDouble(period2End.substring(5,7));
            y = Double.parseDouble(period2End.substring(0,4));
            day =  (int)d;
            month = (int)m;
            year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            plotTime = graphing.addTimeseriesData(plotTime, periodSeries, true, new Color(255, 135, 0), false, false, true, true, 3);//gold
            showLegend = true;
        }
        if(period3Data.length > 0){
            this.len_period3 = String.valueOf(period3Data.length);
            double value = mean_period3;
            String label = "Average";
            if(medianTF){
                value = median_period3;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 3 " + label + ": " + value + " ft");
            
            //Set Start Point
            double d = Double.parseDouble(period3Begin.substring(8));
            double m = Double.parseDouble(period3Begin.substring(5,7));
            double y = Double.parseDouble(period3Begin.substring(0,4));
            int day =  (int)d;
            int month = (int)m;
            int year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            //Set End Point
            d = Double.parseDouble(period3End.substring(8));
            m = Double.parseDouble(period3End.substring(5,7));
            y = Double.parseDouble(period3End.substring(0,4));
            day =  (int)d;
            month = (int)m;
            year = (int)y;
            if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                Day date = new Day(day,month,year);//day,month,year
                periodSeries.add(date, value);
            }
            
            plotTime = graphing.addTimeseriesData(plotTime, periodSeries, true, Color.green, false, false, true, true, 4);
            showLegend = true;
        }
      
        //Create Y Axis
        ValueAxis rangeTime = new NumberAxis(yAxisTitle);
        plotTime.setRangeAxis(0, rangeTime);
        
        //Create X Axis
        DateAxis domainTime = new DateAxis("Date");
        domainTime.setLowerMargin(0.05);
        domainTime.setUpperMargin(0.05);
        plotTime.setDomainAxis(0, domainTime);

        //Set extra plot preferences
        plotTime = graphing.setTimeAxisPreferences(plotTime);

        //Create the chart with the plot and a legend
        String graphTitle = "Time Series for " + database + " Station: " + stationID + "; " + stationName;
        JFreeChart chart = new JFreeChart(graphTitle, graphing.titleFont, plotTime, showLegend);
        
        //Set legend Font
        if(showLegend){
            LegendTitle legendTitle = chart.getLegend();
            legendTitle.setItemFont(graphing.masterFont);
        }
        
        //Save resulting graph for use later
        try{
            String path = mainFolder + File.separator + getGraph();
            ChartUtilities.saveChartAsJPEG(new File(path), chart, 1280, 800);
            System.out.println("JFreeChart created properly at: " + path);

        }catch(IOException e){
            System.err.println("A problem occurred while trying to creating the chart.");
        }
    }
    /**
     * Create a JFreeChart TimeSeries out of the provided time series data
     * @param data  the String[][] containing data for the 
     * time series (column 1 = dates (yyyy-mm-dd if timeStep = "daily", yyyy-mm 
     * if timeStep = "monthly", yyyy if timeStep = "yearly") column 2 = value
     * @param title  the title of the TimeSeries to appear in the legend
     * @return a JFreeChart TimeSeries
     */
    private TimeSeries createTimeSeriesFromData(String[][] data, String title){
        //Create TimeSeries graph of merged data
        TimeSeries series = new TimeSeries(title);
        for(int i=0; i < data.length; i++) {
            double value = Double.parseDouble(data[i][1]);
            String tmpStr = data[i][0];

            if(timeStep.equalsIgnoreCase("daily")){
                double d = Double.parseDouble(tmpStr.substring(8));
                double m = Double.parseDouble(tmpStr.substring(5,7));
                double y = Double.parseDouble(tmpStr.substring(0,4));
                int day =  (int)d;
                int month = (int)m;
                int year = (int)y;
                if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                    Day date = new Day(day,month,year);//day,month,year
                    series.add(date, value);
                }
                
            }else if(timeStep.equalsIgnoreCase("monthly")){
                double m = Double.parseDouble(tmpStr.substring(5,7));
                double y = Double.parseDouble(tmpStr.substring(0,4));
                int month = (int)m;
                int year = (int)y;
                if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                    Month date = new Month(month,year);//month,year
                    series.add(date, value);
                }
                
            }else if(timeStep.equalsIgnoreCase("yearly")){
                double y = Double.parseDouble(tmpStr.substring(0,4));
                int year = (int)y;
                if(year >= 1900){//artificial limit for JFreeCharts' "Day" class
                    Year date = new Year(year);//year
                    series.add(date, value);
                }
            }
        }
        return series;
    }
    /**
     * Writes out the error message, if any, for finding the file and then exits the program
     * @param error  string array to be written as each line of an error message
     * @throws IOException
     */
    public void writeError(ArrayList<String> error) throws IOException{
        //Output data to text file
        String errorContents = error.get(0);
        for(int i=1; i<error.size(); i++){
            errorContents = errorContents + "\n" + error.get(i);
        }
        throw new IOException("Error encountered. Please see the following message for details: \n" + errorContents);
    }
    public void run() throws IOException, Exception {
        //If no date input, make it the maximum of available data
        if(beginDate == null || beginDate.equalsIgnoreCase("")){
            beginDate = "1850-01-01";
        }
        if(endDate == null || endDate.equalsIgnoreCase("")){
            // Pull current date for upper limit of data search
            DateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date currentDate = new Date();
            endDate = desiredDateFormat.format(currentDate);
        }
        
        //Initialize graph variables
        String yAxisTitle = "y axis";
        String WQlabel = "??";
        Color color = Color.black, color2 = Color.black;
        boolean showLine = true;
        
        //Get Data
        USGSwell_Data usgsWell_data = new USGSwell_Data();
        String[][] sortableData = new String[0][2];
        if(wqTest.equalsIgnoreCase("height")){
            //Check if any groundwater height data exists
            Object[] returnArray = usgsWell_data.getUSGSwellHeightData(stationID, beginDate, endDate);
            //ArrayList<String> textData = (ArrayList<String>) returnArray[0];
            sortableData = (String[][]) returnArray[1];
            //String start = (String) returnArray[2];
            //String end = (String) returnArray[3];

            //Define other graph information
            if(timeStep.equalsIgnoreCase("Daily")){
                yAxisTitle = "Median Groundwater Height [ft]";
            }else{
                yAxisTitle = timeStep + " " + method + " Groundwater Height [ft]";
            }
            color = Color.blue;
            color2 = Color.darkGray;
            showLine = true;
            this.units = "ft";
        }else if(wqTest.equalsIgnoreCase("depth")){
            //Check if any depth to watertable data exists
            Object[] returnArray = usgsWell_data.getUSGSwatertableDepthData(stationID, beginDate, endDate);
            //ArrayList<String> textData = (ArrayList<String>) returnArray[0];
            sortableData = (String[][]) returnArray[1];
            //String start = (String) returnArray[2];
            //String end = (String) returnArray[3];

            //Define other graph information
            if(timeStep.equalsIgnoreCase("Daily")){
                yAxisTitle = "Distance to Groundwater from Ground Surface [ft]";
            }else{
                yAxisTitle = timeStep + " " + method + " Distance to Groundwater from Ground Surface [ft]";
            }
            color = Color.blue;
            color2 = Color.darkGray;
            showLine = true;
            this.units = "ft";
        }else{
            //Check if any wq data exists
            Object[] returnArray = usgsWell_data.getUSGSwellWQdata(stationID, wqTest, beginDate, endDate);
            //ArrayList<String> textData = (ArrayList<String>) returnArray[0];
            sortableData = (String[][]) returnArray[1];
            //String start = (String) returnArray[2];
            //String end = (String) returnArray[3];

            //Define other graph information
            //Get Units and conversion for current WQ test
            String wqCode = wqTest.substring(0,5);//pull just the 5 digit USGS WQ code
            String wqLabel = wqTest.substring(6,wqTest.lastIndexOf("--")-1);//cut off the "98335" the test name and the "mg/L" units after the name
            String wqUnits = usgsWell_data.getUSGSwqUnits(wqCode);
            if(timeStep.equalsIgnoreCase("Daily")){
                yAxisTitle = wqCode + " " + wqLabel + " [" + wqUnits + "]";
            }else{
                yAxisTitle = timeStep + " " + method + " " + wqCode + " " + wqLabel + " [" + wqUnits + "]";
            }
            color = Color.magenta;
            color2 = Color.blue;
            showLine = false;
            this.units = wqUnits;
        }
        
        //Check if merging the datasets is desired, if so get the user data
        String[][] sortableData_user = new String[0][0];
        if(mergeDatasets){
            User_Data user_Data = new User_Data();
            sortableData_user = user_Data.readUserFile("UserData", stationID, userData, wqTest, beginDate, endDate);
        }
        
        //Sort the Data by date to remove duplicate date entries
        DoubleArray doubleArray = new DoubleArray();
        String[][] sortedData = doubleArray.removeDuplicateDates(sortableData);
        String[][] sortedData_user = doubleArray.removeDuplicateDates(sortableData_user);

        //Merge the two datasets (if user data is empty nothing will be merged)
        String[][] sortedData_combined = doubleArray.mergeData(sortedData, sortedData_user, mergeMethod);
        if(sortedData_combined.length == 0){
            ArrayList<String> errorMessage = new ArrayList<String>();
            if(sortableData.length == 0){
                errorMessage.add("There is no available " + wqTest + " data in the " + database + " database for station '" + stationID + "' and the specified date range.");
                if(database.equalsIgnoreCase("CDWR")){
                    errorMessage.add("The CDWR database is sensitive to the begin date used, try specifying a later begin date");
                }
            }
            if(sortedData_user.length == 0){
                errorMessage.add("There is no available uploaded data for station '" + stationID + "' and the specified date range");
            }
            writeError(errorMessage);
        }
        
        //Save analysis results
        this.start = sortedData_combined[0][0];
        this.end = sortedData_combined[sortedData_combined.length - 1][0];

        //Get period data for analyses
        String[][] period1Data = doubleArray.getPeriodData(sortedData_combined, period1Begin, period1End);
        String[][] period2Data = doubleArray.getPeriodData(sortedData_combined, period2Begin, period2End);
        String[][] period3Data = doubleArray.getPeriodData(sortedData_combined, period3Begin, period3End);
        
        //Perform analysis method on data
        sortedData_combined = doubleArray.computeFlowMethod(sortedData_combined, timeStep, method, false);
        sortedData_user = doubleArray.computeFlowMethod(sortedData_user, timeStep, method, false);
        period1Data = doubleArray.computeFlowMethod(period1Data, timeStep, method, false);
        period2Data = doubleArray.computeFlowMethod(period2Data, timeStep, method, false);
        period3Data = doubleArray.computeFlowMethod(period3Data, timeStep, method, false);
        
        //CalculateStatistics
        CalculateStatistics(sortedData_combined, "all");
        CalculateStatistics(period1Data, "period1");
        CalculateStatistics(period2Data, "period2");
        CalculateStatistics(period3Data, "period3");
        
        //Graph the timeseries data
        createTimeseriesGraph(sortedData_combined, sortedData_user, period1Data, period2Data, period3Data, color, color2, showLine, yAxisTitle);
        
        //Re-Format graphing data for output for use with JHighChart
        SimpleDateFormat desiredDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date period1Begin_date = new Date();
        Date period1End_date = new Date();
        Date period2Begin_date = new Date();
        Date period2End_date = new Date();
        Date period3Begin_date = new Date();
        Date period3End_date = new Date();
        if(!period1Begin.isEmpty() && !period1End.isEmpty()){
            period1Begin_date = desiredDateFormat.parse(period1Begin);
            period1End_date = desiredDateFormat.parse(period1End);
        }
        if(!period2Begin.isEmpty() && !period2End.isEmpty()){
            period2Begin_date = desiredDateFormat.parse(period2Begin);
            period2End_date = desiredDateFormat.parse(period2End);
        }
        if(!period3Begin.isEmpty() && !period3End.isEmpty()){
            period3Begin_date = desiredDateFormat.parse(period3Begin);
            period3End_date = desiredDateFormat.parse(period3End);
        }
        
        String[][] graphData = new String[sortedData_combined.length][5];
        SimpleDateFormat dataDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        if(timeStep.equalsIgnoreCase("Monthly")){
            dataDateFormat = new SimpleDateFormat("yyyy-MM");
        }else if(timeStep.equalsIgnoreCase("Yearly")){
            dataDateFormat = new SimpleDateFormat("yyyy");
        }
        for(int i=0; i<sortedData_combined.length; i++){
            Date newDate = dataDateFormat.parse(sortedData_combined[i][0]);
            graphData[i][0] = sortedData_combined[i][0];
            graphData[i][1] = sortedData_combined[i][1];
            
            //Period1
            if(newDate.compareTo(period1Begin_date) >= 0 && newDate.compareTo(period1End_date) <= 0){
                if(medianTF){
                    graphData[i][2] = String.valueOf(median_period1);
                }else{
                    graphData[i][2] = String.valueOf(mean_period1);
                }
            }else{
                graphData[i][2] = "-1";
            }
            
            //Period2
            if(newDate.compareTo(period2Begin_date) >= 0 && newDate.compareTo(period2End_date) <= 0){
                if(medianTF){
                    graphData[i][3] = String.valueOf(median_period2);
                }else{
                    graphData[i][3] = String.valueOf(mean_period2);
                }
            }else{
                graphData[i][3] = "-1";
            }
            
            //Period3
            if(newDate.compareTo(period3Begin_date) >= 0 && newDate.compareTo(period3End_date) <= 0){
                if(medianTF){
                    graphData[i][4] = String.valueOf(median_period3);
                }else{
                    graphData[i][4] = String.valueOf(mean_period3);
                }
            }else{
                graphData[i][4] = "-1";
            }
        }
        
        //Write output for JHighChart timeseries for use on eRAMS
        Arrays.sort(graphData, new DateComparator());
        doubleArray.writeTimeSeries(mainFolder, graphData, timeStep, getGWgraphOutput().getName(), false);
        
        //Get today's date for the source reference
        Date currentDate = new Date();
        SimpleDateFormat sourceDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String today = sourceDateFormat.format(currentDate);
        if(database.equalsIgnoreCase("USGS")){
            this.dataSource = "Groundwater data and water quality test data courtesy of the U.S. Geological Survey, National Water Information System: Web Interface. http://waterdata.usgs.gov/nwis, accessed: " + today;
        }
        this.len = String.valueOf(sortedData_combined.length);
    }
    public static void main(String[] args) throws IOException, Exception {
        //Define and run model
        guiGroundwater_Model gw_Model = new guiGroundwater_Model();
        gw_Model.run();
    }
}