guiTimeseries_Model.java [src/java/m/cfa/timeseries] Revision: dcd7855a1c5c790e25d21d768e7dc4b21435f39d  Date: Wed Dec 15 12:56:29 MST 2021
package m.cfa.timeseries;

import WaterData.WaterData;
import WaterData.WaterDataInterface;
import WaterData.WaterQualityInfo;
import csip.Executable;
import m.cfa.FlowStatistics;
import m.cfa.DoubleArray;
import m.cfa.DoubleMath;
import m.cfa.Graphing;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
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.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.LogarithmicAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.xy.AbstractXYZDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;

/**
* Last Updated: 9-April-2019
* @author Tyler Wible
* @since 24-June-2011
*/
public class guiTimeseries_Model {
    //Inputs
    String directory = "E:/Projects/TylerWible_repos/NetBeans/data/CFA/Timeseries";
    String database = "USGS";//"CDWR";//"STORET";//"CDSN";//"UserData";//
    String orgId = "n/a";//"n/a";//"21COL001";//"CITYFTCO_WQX";//"n/a";//
    String stationId = "06764880";//"CLAGRECO";//"000028";//"1EFF";//"n/a";//
    String stationName = "South Platte River at Roscoe, Nebr.";//"Cache La Poudre Near Greeley";//"BIG THOMPSON R NEAR MOUTH";//"n/a";//"n/a";//
    String wqTest = "flow";//"00600 Total nitrogen, water, unfiltered, milligrams per liter -- mg/L";//"00625 Ammonia-nitrogen as N -- mg/L";//
    String startDate = "";
    String endDate = "";
    String timeStep = "Daily";//"Yearly";//"Monthly";//
    String method = "Max";//"Min";//"Average";//"Total";//
    int numBins = 10;
    boolean logarithmicBinsTF = true;
    String seasonBegin = "06-01";//"MM-dd"
    String seasonEnd = "09-30";//"MM-dd"
    String period1Begin = "";
    String period1End = "";
    String period2Begin = "";
    String period2End = "";
    String period3Begin = "";
    String period3End = "";
    boolean medianTF = false;
    boolean envelopeTF = true;
    boolean rasterTF = true;
    boolean rasterLogarithmicBinsTF = true;
    double highPercentile = 0.75;
    double lowPercentile = 0.25;
    boolean showMonthlyStatsTF = false;
    boolean calcFlowStatisticsFileTF = true;
    boolean waterYearTF = false;
    boolean calcCDPHElowflowTF = true;
    String CDPHE_lowFlowType = "dflow-all";//"extreme-value";//"biological";//"human-health";//"reg31";//
    int CDPHE_m = 4;//m-day average                          //only used if CDPHE_lowFlowType == "all" or "extreme-value" or "biological"
    int CDPHE_R = 10;//R-year return period for cdphe flows  //only used if CDPHE_lowFlowType == "all" or "extreme-value" or "biological"
    String CDPHE_waterYearBegin = "04-01";//"MM-dd"          //only used if CDPHE_lowFlowType == "all" or "extreme-value"
    int CDPHE_clusterLength = 120;                           //only used if CDPHE_lowFlowType == "all" or "biological"
    int CDPHE_clusterCountMax = 5;                           //only used if CDPHE_lowFlowType == "all" or "biological"
    boolean mergeDatasets = false;//true;// 
    String mergeMethod = "user";//"public";//"max";//"average";//"min";//
    String userData = "";//"Date\tFlow\n1999-04-29\t8.3\n1999-05-09\t60.2\n1999-05-29\t20.1";//
    
    //Outputs
    String len = "-1";
    String start = "?";
    String end = "?";
    String units = "?";
    String dataSource = "?";
    double extremeValueDFLOW = -1;
    double biologicalDFLOW_all = -1;
    double biologicalDFLOW_jan = -1;
    double biologicalDFLOW_feb = -1;
    double biologicalDFLOW_mar = -1;
    double biologicalDFLOW_apr = -1;
    double biologicalDFLOW_may = -1;
    double biologicalDFLOW_jun = -1;
    double biologicalDFLOW_jul = -1;
    double biologicalDFLOW_aug = -1;
    double biologicalDFLOW_sep = -1;
    double biologicalDFLOW_oct = -1;
    double biologicalDFLOW_nov = -1;
    double biologicalDFLOW_dec = -1;
    int biologicalYear_jan = -1;
    int biologicalYear_feb = -1;
    int biologicalYear_mar = -1;
    int biologicalYear_apr = -1;
    int biologicalYear_may = -1;
    int biologicalYear_jun = -1;
    int biologicalYear_jul = -1;
    int biologicalYear_aug = -1;
    int biologicalYear_sep = -1;
    int biologicalYear_oct = -1;
    int biologicalYear_nov = -1;
    int biologicalYear_dec = -1;
    double humanHealthDFLOW = -1;
    String reg31DFLOWsummary = "?";
    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_seasonal = "-1";
    double max_seasonal = -1;
    double min_seasonal = -1;
    double upperQuartile_seasonal = -1;
    double lowerQuartile_seasonal = -1;
    double median_seasonal = -1;
    double mean_seasonal = -1;
    double standardDeviation_seasonal = -1;
    double variance_seasonal = -1;
    double skew_seasonal = -1;
    double coeffvar_seasonal = -1;
    double kendallCorlCoeff_seasonal = -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 getParagraph(){ return new File(directory, "timeseries_summary.txt"); }
    public File getFlowStatistics_summary() {
        FlowStatistics flowStats = new FlowStatistics();
        return new File(directory, flowStats.getFlowStatistics_summary());
    }
    public File getTimeseriesOutput(){ return new File(directory, "timeseries_graph.out"); }//for use with JSHighCharts
    public File getBoxplotOutput(){ return new File(directory, "timeseries_boxplot.out"); }//for use with JSHighCharts
    public File getMonthlyTimeseriesOutput(){ return new File(directory, "timeseries_monthlygraph.out"); }//for use with JSHighCharts
//    public File getMonthlyBoxplotOutput(){ return new File(directory, "timeseries_monthlyboxplot.out"); }//for use with JSHighCharts
    public File getTimeseriesEnvelopeOutput(){ return new File(directory, "timeseries_envelope.out"); }//for use with JSHighCharts
    public File getHistogramOutput(){ return new File(directory, "timeseries_histogram.outt"); }//for use with JSHighCharts
    public File getCDFoutput(){ return new File(directory, "timeseries_cdf.out"); }//for use with JSHighCharts
    public String getGraph(){ return "timeseries_graph.jpg"; }
    public String getBoxplot(){ return "timeseries_boxplot.jpg"; }
    public String getTimeseriesEnvelope(){ return "timeseries_envelope.jpg"; }
    public String getTimeseriesRaster(){ return "timeseries_raster.jpg"; }
    public String getMonthlyGraph(){ return "timeseries_monthlygraph.jpg"; }
    public String getHistogram(){ return "timeseries_histogram.jpg"; }
    public String getCDF(){ return "timeseries_cdf.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 getCDPHE_ExtremeValueDFLOW(){ return String.valueOf(extremeValueDFLOW); }
    public String getCDPHE_BiologicalDFLOW_all(){ return String.valueOf(biologicalDFLOW_all); }
    public String getCDPHE_BiologicalDFLOW_jan(){ return String.valueOf(biologicalDFLOW_jan); }
    public String getCDPHE_BiologicalDFLOW_feb(){ return String.valueOf(biologicalDFLOW_feb); }
    public String getCDPHE_BiologicalDFLOW_mar(){ return String.valueOf(biologicalDFLOW_mar); }
    public String getCDPHE_BiologicalDFLOW_apr(){ return String.valueOf(biologicalDFLOW_apr); }
    public String getCDPHE_BiologicalDFLOW_may(){ return String.valueOf(biologicalDFLOW_may); }
    public String getCDPHE_BiologicalDFLOW_jun(){ return String.valueOf(biologicalDFLOW_jun); }
    public String getCDPHE_BiologicalDFLOW_jul(){ return String.valueOf(biologicalDFLOW_jul); }
    public String getCDPHE_BiologicalDFLOW_aug(){ return String.valueOf(biologicalDFLOW_aug); }
    public String getCDPHE_BiologicalDFLOW_sep(){ return String.valueOf(biologicalDFLOW_sep); }
    public String getCDPHE_BiologicalDFLOW_oct(){ return String.valueOf(biologicalDFLOW_oct); }
    public String getCDPHE_BiologicalDFLOW_nov(){ return String.valueOf(biologicalDFLOW_nov); }
    public String getCDPHE_BiologicalDFLOW_dec(){ return String.valueOf(biologicalDFLOW_dec); }
    public String getCDPHE_BiologicalYear_jan(){ return String.valueOf(biologicalYear_jan); }
    public String getCDPHE_BiologicalYear_feb(){ return String.valueOf(biologicalYear_feb); }
    public String getCDPHE_BiologicalYear_mar(){ return String.valueOf(biologicalYear_mar); }
    public String getCDPHE_BiologicalYear_apr(){ return String.valueOf(biologicalYear_apr); }
    public String getCDPHE_BiologicalYear_may(){ return String.valueOf(biologicalYear_may); }
    public String getCDPHE_BiologicalYear_jun(){ return String.valueOf(biologicalYear_jun); }
    public String getCDPHE_BiologicalYear_jul(){ return String.valueOf(biologicalYear_jul); }
    public String getCDPHE_BiologicalYear_aug(){ return String.valueOf(biologicalYear_aug); }
    public String getCDPHE_BiologicalYear_sep(){ return String.valueOf(biologicalYear_sep); }
    public String getCDPHE_BiologicalYear_oct(){ return String.valueOf(biologicalYear_oct); }
    public String getCDPHE_BiologicalYear_nov(){ return String.valueOf(biologicalYear_nov); }
    public String getCDPHE_BiologicalYear_dec(){ return String.valueOf(biologicalYear_dec); }
    public String getCDPHE_HumanHealthDFLOW(){ return String.valueOf(humanHealthDFLOW); }
    public String getCDPHE_Reg31DFLOWsummary(){ return String.valueOf(reg31DFLOWsummary); }
    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_seasonal(){ return len_seasonal; }
    public String getMax_seasonal(){ return String.valueOf(max_seasonal); }
    public String getMin_seasonal(){ return String.valueOf(min_seasonal); }
    public String getUpperQuartile_seasonal(){ return String.valueOf(upperQuartile_seasonal); }
    public String getLowerQuartile_seasonal(){ return String.valueOf(lowerQuartile_seasonal); }
    public String getMedian_seasonal(){ return String.valueOf(median_seasonal); }
    public String getMean_seasonal(){ return String.valueOf(mean_seasonal); }
    public String getStandardDeviation_seasonal(){ return String.valueOf(standardDeviation_seasonal); }
    public String getVariance_seasonal(){ return String.valueOf(variance_seasonal); }
    public String getSkewness_seasonal(){ return String.valueOf(skew_seasonal); }
    public String getCoefficientOfVariation_seasonal(){ return String.valueOf(coeffvar_seasonal); }
    public String getKendallCorrelationCoefficient_seasonal(){ return String.valueOf(kendallCorlCoeff_seasonal); }
    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 setDirectory(String directory_str){ directory = directory_str; }
    public void setDatabase(String database_str){ database = database_str; }
    public void setOrganizationID(String orgId_str){ orgId = orgId_str; }
    public void setStartDate(String startDate_str){ startDate = startDate_str; }
    public void setEndDate(String endDate_str){ endDate = endDate_str; }
    public void setStationName(String stationName_str){ stationName = stationName_str; }
    public void setStationId(String stationId_str){ stationId = stationId_str; }
    public void setWQtest(String wqTest_str){ wqTest = wqTest_str; }
    public void setTimeStep(String timeStep_str){ timeStep = timeStep_str; }
    public void setMethod(String method_str){ method = method_str; }
    public void setNumberOfBins(int numBins_int){ numBins = numBins_int; }
    public void setLogarithmicHistogramBins(boolean logarithmicBins_TF){ logarithmicBinsTF = logarithmicBins_TF; }
    public void setSeasonBegin(String seasonBegin_str){ seasonBegin = seasonBegin_str; }
    public void setSeasonEnd(String seasonEnd_str){ seasonEnd = seasonEnd_str; }
    public void setPeriod1Begin(String period1Begin_str){ period1Begin = period1Begin_str; }
    public void setPeriod1End(String period1End_str){ period1End = period1End_str; }
    public void setPeriod2Begin(String period2Begin_str){ period2Begin = period2Begin_str; }
    public void setPeriod2End(String period2End_str){ period2End = period2End_str; }
    public void setPeriod3Begin(String period3Begin_str){ period3Begin = period3Begin_str; }
    public void setPeriod3End(String period3End_str){ period3End = period3End_str; }
    public void setMedianTF(boolean median_TF){ medianTF = median_TF; }
    public void setEnvelopeTF(boolean envelope_TF){ envelopeTF = envelope_TF; }
    public void setRasterTF(boolean raster_TF){ rasterTF = raster_TF; }
    public void setRasterLogarithmicBinsTF(boolean rasterLogarithmicBins_TF){ rasterLogarithmicBinsTF = rasterLogarithmicBins_TF; }
    public void setHighPercentile(double highPercentile_dbl){ highPercentile = highPercentile_dbl; }
    public void setLowPercentile(double lowPercentile_dbl){ lowPercentile = lowPercentile_dbl; }
    public void setShowMonthlyStatsTF(boolean showMonthlyStats_TF){ showMonthlyStatsTF = showMonthlyStats_TF; }
    public void setCalcFlowStatisticsFileTF(boolean calcFlowStatisticsFile_TF){ calcFlowStatisticsFileTF = calcFlowStatisticsFile_TF; }
    public void setWaterYear_TF(boolean waterYear_TF){ waterYearTF = waterYear_TF; }
    public void setCalcCDPHElowflowTF(boolean calcCDPHElowflow_TF){ calcCDPHElowflowTF = calcCDPHElowflow_TF; }
    public void setCDPHE_lowFlowType(String CDPHE_lowFlowType_str){ CDPHE_lowFlowType = CDPHE_lowFlowType_str; }
    public void setCDPHE_m(int CDPHE_m_int){ CDPHE_m = CDPHE_m_int; }
    public void setCDPHE_R(int CDPHE_R_int){ CDPHE_R = CDPHE_R_int; }
    public void setCDPHE_waterYearBegin(String CDPHE_waterYearBegin_str){ CDPHE_waterYearBegin = CDPHE_waterYearBegin_str; }
    public void setCDPHE_clusterLength(int CDPHE_clusterLength_int){ CDPHE_clusterLength = CDPHE_clusterLength_int; }
    public void setCDPHE_clusterCountMax(int CDPHE_clusterCountMax_int){ CDPHE_clusterCountMax = CDPHE_clusterCountMax_int; }
    public void setMergeDatasets(boolean mergeDatasets_TF){ mergeDatasets = mergeDatasets_TF; }
    public void setMergeMethod(String mergeMethod_str){ mergeMethod = mergeMethod_str; }
    public void setUserData(String userData_str){ userData = userData_str; }
    /**
     * 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<>();
        for(int i=0; i<data.length; i++){
            dataList.add(Double.parseDouble(data[i][1]));
        }

        //Calculate statistics
        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("seasonal")){
            len_seasonal = String.valueOf(data.length);
            max_seasonal = temp1;
            min_seasonal = temp2;
            upperQuartile_seasonal = temp3;
            lowerQuartile_seasonal = temp4;
            median_seasonal = temp5;
            mean_seasonal = temp6;
            standardDeviation_seasonal = temp7;
            variance_seasonal = temp8;
            skew_seasonal = temp9;
            coeffvar_seasonal = temp10;
            kendallCorlCoeff_seasonal = 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
     */
    private void createTimeseriesGraph(String[][] sortedData,
                                       String[][] sortedData_user,
                                       String[][] period1Data,
                                       String[][] period2Data,
                                       String[][] period3Data,
                                       Color color,
                                       Color color2,
                                       boolean showLine,
                                       String yAxisTitle) throws ParseException, IOException {
        DateFormat periodDateFormat = DoubleArray.getDateFormat("daily",  false);
        Date jfreeChartDateLimit = periodDateFormat.parse("1900-01-01");
        
        //Re-Format graphing data for output for use with JHighChart
        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 = periodDateFormat.parse(period1Begin);
            period1End_date = periodDateFormat.parse(period1End);
        }
        if(!period2Begin.isEmpty() && !period2End.isEmpty()){
            period2Begin_date = periodDateFormat.parse(period2Begin);
            period2End_date = periodDateFormat.parse(period2End);
        }
        if(!period3Begin.isEmpty() && !period3End.isEmpty()){
            period3Begin_date = periodDateFormat.parse(period3Begin);
            period3End_date = periodDateFormat.parse(period3End);
        }
        
        String[][] graphData = new String[sortedData.length][5];
        DateFormat desiredDateFormat = DoubleArray.getDateFormat(timeStep, false);
        for(int i=0; i<sortedData.length; i++){
            Date newDate = desiredDateFormat.parse(sortedData[i][0]);
            graphData[i][0] = sortedData[i][0];
            graphData[i][1] = sortedData[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 m.cfa.DateComparator());
        DoubleArray.writeTimeSeries(directory, graphData, timeStep, getTimeseriesOutput().getName(), false);
        
        //Create TimeSeries graph of merged data
        XYPlot plotTime = new XYPlot();
        boolean showLegend = false;
        TimeSeries series = Graphing.createTimeSeriesFromData(sortedData, stationId + ": Data", timeStep);
        TimeSeries series2 = Graphing.createTimeSeriesFromData(sortedData_user, stationId + ": User Data", timeStep);
        
        //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){
            len_period1 = String.valueOf(period1Data.length);
            double value = mean_period1;
            String label = "Mean";
            if(medianTF){
                value = median_period1;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 1 " + label + ": " + value + " " + units);
            
            //artificial limit for JFreeCharts' "Day" class
            Date period1Begin_Date = desiredDateFormat.parse(period1Begin);
            if(period1Begin_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period1Begin_Date), value);
            }
            Date period1End_Date = desiredDateFormat.parse(period1End);
            if(period1End_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period1End_Date), value);
            }
            
            plotTime = Graphing.addTimeseriesData(plotTime, periodSeries, true, Color.red, false, false, true, true, 2);
            showLegend = true;
        }
        if(period2Data.length > 0){
            len_period2 = String.valueOf(period2Data.length);
            double value = mean_period2;
            String label = "Mean";
            if(medianTF){
                value = median_period2;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 2 " + label + ": " + value + " " + units);
            
            //artificial limit for JFreeCharts' "Day" class
            Date period2Begin_Date = desiredDateFormat.parse(period2Begin);
            if(period2Begin_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period2Begin_Date), value);
            }
            Date period2End_Date = desiredDateFormat.parse(period2End);
            if(period2End_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period2End_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){
            len_period3 = String.valueOf(period3Data.length);
            double value = mean_period3;
            String label = "Mean";
            if(medianTF){
                value = median_period3;
                label = "Median";
            }
            TimeSeries periodSeries = new TimeSeries("Period 3 " + label + ": " + value + " " + units);
            
            //artificial limit for JFreeCharts' "Day" class
            Date period3Begin_Date = desiredDateFormat.parse(period3Begin);
            if(period3Begin_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period3Begin_Date), value);
            }
            Date period3End_Date = desiredDateFormat.parse(period3End);
            if(period3End_Date.compareTo(jfreeChartDateLimit) >= 0){
                periodSeries.add(new Day(period3End_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 = directory + 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.");
        }
    }
    /**
     * Creates a boxplot of the timeseries data to be displayed next to a summary of the statistics of the timeseries data
     * @param yAxisTitle  a String of the title for the Y axis of the boxplot
     */
    private void createTimeseriesBoxplot(String[][] data, String yAxisTitle) throws IOException{    	
        //Prep. boxplot data for output function
        ArrayList<ArrayList<Double>> boxplotOutliers = new ArrayList<>();
        ArrayList<Double> outliers = new ArrayList<>();// Get daily outliers
        double IQR = upperQuartile - lowerQuartile;// Find IQR
    	for (int i = 0; i < data.length; i++){
            double value = Double.parseDouble(data[i][1]);
            if(value < (lowerQuartile - 1.5 * IQR) || value > (upperQuartile + 1.5 * IQR)){		
                outliers.add(value);
            }
    	}
        boxplotOutliers.add(outliers);
        double[][] boxplotData = {{max},{upperQuartile},{median},{lowerQuartile},{min}};
        
        //Write output for JHighChart boxplot for use on eRAMS
        DoubleArray.writeBoxplot(directory, boxplotOutliers, boxplotData, getBoxplotOutput().getName());
        
        
        //Create boxplot of the timeseries data
        XYPlot plot = new XYPlot();

        //Create X Axis
        ValueAxis xAxis = new NumberAxis("");
        xAxis.setRange(0, 10);
        xAxis.setLabelFont(Graphing.masterFont);
        xAxis.setTickLabelFont(Graphing.masterFont);
        xAxis.setTickLabelsVisible(false);
        plot.setDomainAxis(0, xAxis);
        
    	ValueAxis yAxis = new NumberAxis(yAxisTitle);
        yAxis.setLabelFont(Graphing.masterFont);
        yAxis.setTickLabelFont(Graphing.masterFont);
        plot.setRangeAxis(0, yAxis);

    	//Calculate and add Median to dataset
        XYSeries median_series = new XYSeries("Median");
        median_series.add(5, median);

        //Create median Line
        XYDataset median_scatter = new XYSeriesCollection(median_series);
        XYItemRenderer renderer_median = new XYLineAndShapeRenderer(false, true);
        renderer_median.setSeriesShape(0, new Rectangle2D.Double(-4.0, 0.0, 8.0, 1));//new Ellipse2D.Double(-4, -4, 8, 8));
        renderer_median.setSeriesPaint(0, Color.red);
        renderer_median.setSeriesVisibleInLegend(0, false);
        plot.setDataset(0, median_scatter);
        plot.setRenderer(0, renderer_median);


        //Create quartile Box shapes for the box plot
        //Create XYSeries for the box shape
        XYSeries shapeSeries = new XYSeries("Shape");
        shapeSeries.add(5, lowerQuartile);
        shapeSeries.add(5, upperQuartile);

        //Create the quartile rectangle shape
        XYDataset shapeDataset = new XYSeriesCollection(shapeSeries);
        XYItemRenderer renderer_shape = new XYLineAndShapeRenderer(true, false);
        Stroke thickness = new BasicStroke(10, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
        renderer_shape.setSeriesStroke(0, thickness);
        renderer_shape.setSeriesPaint(0, Color.blue);
        renderer_shape.setSeriesVisibleInLegend(0, false);
        plot.setDataset(1, shapeDataset);
        plot.setRenderer(1, renderer_shape);

        
        //Creates 1.5 * Interquartile Range (IQR) lines
        //Create XYSeries for the min-max lines
        double lowerLimit = lowerQuartile - 1.5*IQR;
        double upperLimit = upperQuartile + 1.5*IQR;
        if(lowerLimit < min){
            lowerLimit = min;
        }
        if(upperLimit > max){
            upperLimit = max;
        }
        XYSeries lineSeries = new XYSeries("Line");
        lineSeries.add(5, lowerLimit);
        lineSeries.add(5, upperLimit);

        //Create the 1.5*IQR lines
        XYDataset lineDataset = new XYSeriesCollection(lineSeries);
        XYItemRenderer lineRenderer = new XYLineAndShapeRenderer(true, true);
        Stroke thickness2 = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
        lineRenderer.setSeriesStroke(0, thickness2);
        lineRenderer.setSeriesShape(0, new Rectangle2D.Double(-10.0, 0.0, 20.0, 1));
        lineRenderer.setSeriesPaint(0, Color.black);
        lineRenderer.setSeriesVisibleInLegend(0, false);
        plot.setDataset(2, lineDataset);
        plot.setRenderer(2, lineRenderer);
        
        //Calculate and create Outliers (# < lowerQuartile - 1.5*IQR or # > upperQuartile + 1.5*IQR)
        //Calculate and create Extreme Outliers (# < lowerQuartile - 3*IQR or # > upperQuartile + 3*IQR)
        XYSeries outliers_XY = new XYSeries("Outliers");
        XYSeries extremeOutliers = new XYSeries("Extreme Outliers");
        for(int i=0; i<data.length; i++){
            double value = Double.parseDouble(data[i][1]);
            //Lower outliers
            if(value < (lowerQuartile - 1.5*IQR) && value > (lowerQuartile - 3*IQR)){
                outliers_XY.add(5, value);
            }
            //Upper outliers
            if(value > (upperQuartile + 1.5*IQR) && value < (lowerQuartile + 3*IQR)){
                outliers_XY.add(5, value);
            }

            //Extreme Lower outliers
            if(value < (lowerQuartile - 3*IQR)){
                extremeOutliers.add(5, value);
            }
            //Extreme Upper outliers
            if(value > (lowerQuartile + 3*IQR)){
                extremeOutliers.add(5, value);
            }
        }

        //Create outlier scatter
        XYDataset outlier_scatter = new XYSeriesCollection(outliers_XY);
        XYItemRenderer renderer_outlier = new XYLineAndShapeRenderer(false, true);
        renderer_outlier.setSeriesShape(0, new Ellipse2D.Double(-2.0, 2.0, 4.0, 4.0));
        renderer_outlier.setSeriesPaint(0, Color.darkGray);
        if(outliers_XY.isEmpty()){
            renderer_outlier.setSeriesVisibleInLegend(0, false);        	
        }
        plot.setDataset(3, outlier_scatter);
        plot.setRenderer(3, renderer_outlier);
        
        //Create extreme outlier scatter
        XYDataset extremeOutlier_scatter = new XYSeriesCollection(extremeOutliers);
        XYItemRenderer renderer_ExtremeOutlier = new XYLineAndShapeRenderer(false, true);
        renderer_ExtremeOutlier.setSeriesShape(0, new Ellipse2D.Double(-2.0, 2.0, 4.0, 4.0));
        renderer_ExtremeOutlier.setSeriesPaint(0, Color.red);
        if(extremeOutliers.isEmpty()){
            renderer_ExtremeOutlier.setSeriesVisibleInLegend(0, false);        	
        }
        plot.setDataset(4, extremeOutlier_scatter);
        plot.setRenderer(4, renderer_ExtremeOutlier);

        //Put the line on the first Domain and first Range
        plot.mapDatasetToDomainAxis(0, 0);
        plot.mapDatasetToRangeAxis(0, 0);

        //Set extra plot preferences
        plot.setOutlinePaint(Color.black);
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.black);
        
        
        //Create the chart with the plot and a legend
        JFreeChart chart = new JFreeChart("Boxplot of Timeseries Data", Graphing.titleFont, plot, true);

        //Save resulting graph for use later
        try{
            String path = directory + File.separator + getBoxplot();
            ChartUtilities.saveChartAsJPEG(new File(path), chart, 200, 400);
            System.out.println("JFreeChart created properly at: " + path);

        }catch(IOException e){
            System.err.println("A problem occurred while trying to creating the chart.");
        }
    }
    /**
     * Graph the quantile plot CDF of the time series 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 xAxisTitle  the String label for the x axis of the graph
     */
    private void createTimeseriesCDF(String[][] sortedData,
                                     String[][] sortedData_user,
                                     String[][] period1Data,
                                     String[][] period2Data,
                                     String[][] period3Data,
                                     Color color,
                                     Color color2,
                                     String xAxisTitle) throws ParseException, IOException {
        double[][] xyRanks = DoubleArray.weibullPlottingPosition(sortedData);
        double[][] xyRanks_user = DoubleArray.weibullPlottingPosition(sortedData_user);
        double[][] xyRanks_period1 = DoubleArray.weibullPlottingPosition(period1Data);
        double[][] xyRanks_period2 = DoubleArray.weibullPlottingPosition(period2Data);
        double[][] xyRanks_period3 = DoubleArray.weibullPlottingPosition(period3Data);
        
        //Calculate cdf for the entire dataset
        XYSeries series = new XYSeries(stationId + ": Data");
        XYSeries series_user = new XYSeries(stationId + ": User Data");
        XYSeries period1_series = new XYSeries(stationId + ": Period 1");
        XYSeries period2_series = new XYSeries(stationId + ": Period 2");
        XYSeries period3_series = new XYSeries(stationId + ": Period 3");
        String[][] cdfData = new String[xyRanks.length][8];
        for(int i=0; i<xyRanks.length; i++){
            double x = xyRanks[i][1]; //flow
            double y = 1 - (xyRanks[i][0]/100); //rank
            series.add(x, y);
            cdfData[i][0] = String.valueOf(x);
            cdfData[i][1] = String.valueOf(y);
            //Add user data (if any)
            if(i < xyRanks_user.length){
                x = xyRanks_user[i][1]; //flow
                y = 1 - (xyRanks_user[i][0]/100); //rank
                series_user.add(x, y);
            }
            //Add period 1 data (if any)
            if(i < xyRanks_period1.length){
                x = xyRanks_period1[i][1]; //flow
                y = 1 - (xyRanks_period1[i][0]/100); //rank
                period1_series.add(x, y);
                cdfData[i][2] = String.valueOf(x);
                cdfData[i][3] = String.valueOf(y);
            }else{
                cdfData[i][2] = "-1";
                cdfData[i][3] = "-1";
            }
            //Add period 2 data (if any)
            if(i < xyRanks_period2.length){
                x = xyRanks_period2[i][1]; //flow
                y = 1 - (xyRanks_period2[i][0]/100); //rank
                period2_series.add(x, y);
                cdfData[i][4] = String.valueOf(x);
                cdfData[i][5] = String.valueOf(y);
            }else{
                cdfData[i][4] = "-1";
                cdfData[i][5] = "-1";
            }
            //Add period 3 data (if any)
            if(i < xyRanks_period3.length){
                x = xyRanks_period3[i][1]; //flow
                y = 1 - (xyRanks_period3[i][0]/100); //rank
                period3_series.add(x, y);
                cdfData[i][6] = String.valueOf(x);
                cdfData[i][7] = String.valueOf(y);
            }else{
                cdfData[i][6] = "-1";
                cdfData[i][7] = "-1";
            }
        }
        //Save cdf data for JHighCharts
        DoubleArray.writeXYseries(directory, cdfData, getCDFoutput().getName());
		
        //Create renderer, and axis for timeseries graph
        XYPlot plot = new XYPlot();
        XYDataset xyDataset = new XYSeriesCollection(series);
        XYDataset xyDataset_user = new XYSeriesCollection(series_user);
        XYDataset xyDataset_period1 = new XYSeriesCollection(period1_series);
        XYDataset xyDataset_period2 = new XYSeriesCollection(period2_series);
        XYDataset xyDataset_period3 = new XYSeriesCollection(period3_series);
        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
        renderer.setSeriesPaint(0, color);
        
        //Set the line data, renderer, and axis into plot
        plot.setDataset(0, xyDataset);
        plot.setRenderer(0, renderer);
        boolean legendTF = false;
        
        if(sortedData_user.length > 0){
            XYItemRenderer renderer_user = new XYLineAndShapeRenderer(true, false);
            renderer_user.setSeriesPaint(0, color2);
            plot.setDataset(1, xyDataset_user);
            plot.setRenderer(1, renderer_user);
            legendTF = true;
        }
        if(period1Data.length > 0){
            XYItemRenderer renderer_period1 = new XYLineAndShapeRenderer(true, false);
            renderer_period1.setSeriesPaint(0, Color.red);
            plot.setDataset(2, xyDataset_period1);
            plot.setRenderer(2, renderer_period1);
            legendTF = true;
        }
        if(period2Data.length > 0){
            XYItemRenderer renderer_period2 = new XYLineAndShapeRenderer(true, false);
            renderer_period2.setSeriesPaint(0, new Color(255, 135, 0));//gold
            plot.setDataset(3, xyDataset_period2);
            plot.setRenderer(3, renderer_period2);
            legendTF = true;
        }
        if(period3Data.length > 0){
            XYItemRenderer renderer_period3 = new XYLineAndShapeRenderer(true, false);
            renderer_period3.setSeriesPaint(0, Color.green);
            plot.setDataset(4, xyDataset_period3);
            plot.setRenderer(4, renderer_period3);
            legendTF = true;
        }

        //Map the line to the first Domain and first Range
        plot.mapDatasetToDomainAxis(0, 0);
        plot.mapDatasetToRangeAxis(0, 0);
        
        //Create Y Axis
        ValueAxis rangeAxis = new NumberAxis("Non-Exceedance");
        rangeAxis.setRange(0, 1);
        plot.setRangeAxis(0, rangeAxis);
        
        //Create X Axis
        LogarithmicAxis xAxis = new LogarithmicAxis(xAxisTitle);
        xAxis.setAllowNegativesFlag(true); 
        plot.setDomainAxis(0, xAxis);
        
        //Set extra plot preferences
        plot = Graphing.setLogXaxisPreferences(plot);

        //Create the charts out of the plots
        String graphTitle = "CDF for " + database + " Station: " + stationId + "; " + stationName;
        JFreeChart chart = new JFreeChart(graphTitle, Graphing.titleFont, plot, legendTF);
        
        //Set legend Font
        if(legendTF){
            LegendTitle legendTitle = chart.getLegend();
            legendTitle.setItemFont(Graphing.masterFont);
        }
        
        //Save monthly timeseries graph for use later
        try{
            String path = directory + File.separator + getCDF();
            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.");
        }
    }
    /**
     * Graph the time series verses the month/day for each year (calender or water year depends on waterYearTF)
     * and long term average/median 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), column 2 = value
     * @param period1Data  the String[][] containing sorted data for the time series 
     * contained by period1 (column 1 = dates (yyyy-mm-dd), column 2 = value
     * @param period2Data  the String[][] containing sorted data for the time series 
     * contained by period1 (column 1 = dates (yyyy-mm-dd), column 2 = value
     * @param period3Data  the String[][] containing sorted data for the time series 
     * contained by period1 (column 1 = dates (yyyy-mm-dd), column 2 = value
     * @param yAxisTitle  the String label for the y axis of the graph
     */
    private void createTimeseriesEnvelopeGraph(String[][] sortedData,
                                               String[][] period1Data,
                                               String[][] period2Data,
                                               String[][] period3Data,
                                               String yAxisTitle,
                                               boolean logYaxis_TF) throws IOException, ParseException {
        //Initialize variables
        DateFormat desiredDateFormat = DoubleArray.getDateFormat("daily", false);
        String[][] graphData = new String[366][6];
        String[] dayList = new String[366];
        int seriesIndex = 0;
        String periodTitle = "Mean";
        if(medianTF){ periodTitle = "Median"; }
        
        //Plot each year and the long term average and the most recent year
        XYPlot plot = new XYPlot();
        TimeSeries median_TS = new TimeSeries("All Data: Median");
        TimeSeries mean_TS = new TimeSeries("All Data: Mean");
        TimeSeries period1_TS = new TimeSeries("Period 1: " + periodTitle);
        TimeSeries period2_TS = new TimeSeries("Period 2: " + periodTitle);
        TimeSeries period3_TS = new TimeSeries("Period 3: " + periodTitle);
        String currentDate_str = "2000-01-01";
        if(waterYearTF) currentDate_str = "1999-10-01";
        for(int j=1; j<=366; j++){
            ArrayList<Double> dateData = new ArrayList<>();
            ArrayList<Double> dateData_period1 = new ArrayList<>();
            ArrayList<Double> dateData_period2 = new ArrayList<>();
            ArrayList<Double> dateData_period3 = new ArrayList<>();
            dayList[j-1] = String.valueOf(j);
            
            for(int i=0; i<sortedData.length; i++){
                String month_day = sortedData[i][0].substring(5);
                if(month_day.equalsIgnoreCase(currentDate_str.substring(5))){
                    dateData.add(Double.parseDouble(sortedData[i][1]));
                }
            }
            for(int i=0; i<period1Data.length; i++){
                String month_day = period1Data[i][0].substring(5);
                if(month_day.equalsIgnoreCase(currentDate_str.substring(5))){
                    dateData_period1.add(Double.parseDouble(period1Data[i][1]));
                }
            }
            for(int i=0; i<period2Data.length; i++){
                String month_day = period2Data[i][0].substring(5);
                if(month_day.equalsIgnoreCase(currentDate_str.substring(5))){
                    dateData_period2.add(Double.parseDouble(period2Data[i][1]));
                }
            }
            for(int i=0; i<period3Data.length; i++){
                String month_day = period3Data[i][0].substring(5);
                if(month_day.equalsIgnoreCase(currentDate_str.substring(5))){
                    dateData_period3.add(Double.parseDouble(period3Data[i][1]));
                }
            }
            
            //Calculate average/median
            double dayValue_median = DoubleMath.median(dateData);
            double dayValue_mean = DoubleMath.meanArithmetic(dateData);
            Day currentDay = new Day(desiredDateFormat.parse(currentDate_str));
            median_TS.add(currentDay, dayValue_median);
            mean_TS.add(currentDay, dayValue_mean);
            graphData[j-1][0] = currentDate_str;
            graphData[j-1][1] = String.valueOf(dayValue_median);
            graphData[j-1][2] = String.valueOf(dayValue_mean);
            
            //Check for period 1 data
            double dayValue_period1 = -1;
            if(!dateData_period1.isEmpty()){
                if(medianTF){
                    dayValue_period1 = DoubleMath.median(dateData_period1);
                }else{
                    dayValue_period1 = DoubleMath.meanArithmetic(dateData_period1);
                }
                period1_TS.add(currentDay, dayValue_period1);
            }
            graphData[j-1][3] = String.valueOf(dayValue_period1);
            
            //Check for period 2 data
            double dayValue_period2 = -1;
            if(!dateData_period2.isEmpty()){
                if(medianTF){
                    dayValue_period2 = DoubleMath.median(dateData_period2);
                }else{
                    dayValue_period2 = DoubleMath.meanArithmetic(dateData_period2);
                }
                period2_TS.add(currentDay, dayValue_period2);
            }
            graphData[j-1][4] = String.valueOf(dayValue_period2);
            
            //Check for period 3 data
            double dayValue_period3 = -1;
            if(!dateData_period3.isEmpty()){
                if(medianTF){
                    dayValue_period3 = DoubleMath.median(dateData_period3);
                }else{
                    dayValue_period3 = DoubleMath.meanArithmetic(dateData_period3);
                }
                period3_TS.add(currentDay, dayValue_period3);
            }
            graphData[j-1][5] = String.valueOf(dayValue_period3);
            
            //Move to the next day
            currentDate_str = DoubleArray.getDay(currentDate_str, 1);
        }

        //Create renderer, and axis for timeseries graph
        plot = Graphing.addTimeseriesData(plot, median_TS, true, Color.gray, false, false, true, true, seriesIndex);
        seriesIndex++;
        plot = Graphing.addTimeseriesData(plot, mean_TS, true, Color.black, false, false, true, true, seriesIndex);
        seriesIndex++;
        if(!period1_TS.isEmpty()){
            plot = Graphing.addTimeseriesData(plot, period1_TS, true, Color.red, false, false, true, true, seriesIndex);
            seriesIndex++;
        }
        if(!period2_TS.isEmpty()){
            plot = Graphing.addTimeseriesData(plot, period2_TS, true, new Color(255, 135, 0), false, false, true, true, seriesIndex);
            seriesIndex++;
        }
        if(!period3_TS.isEmpty()){
            plot = Graphing.addTimeseriesData(plot, period3_TS, true, Color.green, false, false, true, true, seriesIndex);
            seriesIndex++;
        }
        int recentYear = seriesIndex;
        seriesIndex++;//Increase series so the most recent month can be plotted second
        
        //Calculate Flow statistics for each year in time period
        boolean moreYears = sortedData.length > 0;
        String firstYear = sortedData[0][0].substring(0,4);
        String finalYear = sortedData[sortedData.length - 1][0].substring(0,4);
        String currentYear = sortedData[sortedData.length - 1][0].substring(0,4);
        if(waterYearTF){
            Date firstDate = desiredDateFormat.parse(sortedData[0][0]);
            Date firstWaterYear = desiredDateFormat.parse(firstYear + "-10-01");
            if(firstDate.before(firstWaterYear)){
                firstYear = String.valueOf(Integer.parseInt(firstYear) - 1);
            }
            
            Date lastDate = desiredDateFormat.parse(sortedData[sortedData.length - 1][0]);
            Date lastWaterYear = desiredDateFormat.parse(finalYear + "-09-30");
            if(lastDate.after(lastWaterYear)){
                finalYear = String.valueOf(Integer.parseInt(finalYear) + 1);
            }
        }
        
        //Graph a line for each year of data in analysis period
        String[][] mostRecentYearData = new String[0][2];
        while(moreYears){
            String[][] partialData = new String[0][2];
            if(waterYearTF){
                //Get current water year's data
                String previousYear = String.valueOf(Integer.parseInt(currentYear) - 1);
                partialData = DoubleArray.getPeriodData(sortedData, previousYear + "-10-01", currentYear + "-09-30");
            }else{
                //Get current calendar year's data
                partialData = DoubleArray.getYearsData(sortedData, currentYear);
            }
            //Get current year's data and graph it
            for(int i=0; i<partialData.length; i++){
                String month_day = partialData[i][0].substring(5);
                if(waterYearTF){
                    Date currentDate = desiredDateFormat.parse("2000-" + month_day);
                    Date waterYearEndDate = desiredDateFormat.parse("2000-09-30");
                    if(currentDate.after(waterYearEndDate)){
                        partialData[i][0] = "1999-" + month_day;
                    }else{
                        partialData[i][0] = "2000-" + month_day;
                    }
                }else{
                    partialData[i][0] = "2000-" + month_day;
                }
            }
            TimeSeries currentYear_TS = Graphing.createTimeSeriesFromData(partialData, "temp", "daily");
            plot = Graphing.addTimeseriesData(plot, currentYear_TS, true, Color.lightGray, false, false, false, false, seriesIndex);
            seriesIndex++;
            
            if(waterYearTF){
                Date currentStartDate = desiredDateFormat.parse(currentYear + "-10-01");
                Date finalWaterYear = desiredDateFormat.parse(finalYear + "-10-01");
                if(currentStartDate.equals(finalWaterYear)){
                    mostRecentYearData = partialData;
                }
            }else {
                if(currentYear.equalsIgnoreCase(finalYear)){
                    mostRecentYearData = partialData;
                }
            }
            
            //Save results for output for JHighCharts
            String[] partialDayData = new String[dayList.length];
            int ctr = 0;
            currentDate_str = "2000-01-01";
            if(waterYearTF) currentDate_str = "1999-10-01";
            for(int i=0; i<dayList.length; i++){
                partialDayData[i] = "-1";//value
                try{
                    String month_day = partialData[ctr][0].substring(5);
                    if(month_day.equalsIgnoreCase(currentDate_str.substring(5))){
                        partialDayData[i] = partialData[ctr][1];//value
                        ctr++;
                    }
                }catch(IndexOutOfBoundsException e){
                    //do nothing as it already has a -1 value
                }
                currentDate_str = DoubleArray.getDay(currentDate_str, 1);
            }
            graphData = DoubleArray.appendcolumn_Matrix(graphData, partialDayData);//Add day values (aka y points)
            
            //Check to stop looping
            if(waterYearTF){
                //For water year comparison
                String previousYear = String.valueOf(Integer.parseInt(currentYear) - 1);
                Date currentStartDate = desiredDateFormat.parse(previousYear + "-10-01");
                Date firstWaterYear = desiredDateFormat.parse(firstYear + "-10-01");
                if(currentStartDate.after(firstWaterYear)){
                    currentYear = String.valueOf(previousYear);
                }else{
                    moreYears = false;
                }
            }else{
                //For calendar year comparison
                int previousYear = Integer.parseInt(currentYear) - 1;
                if(firstYear.compareToIgnoreCase(String.valueOf(previousYear)) <= 0){
                    currentYear = String.valueOf(previousYear);
                }else{
                    moreYears = false;
                }
            }
        }
        
        //Re-add the most recent year to the graph so it renders on top
        TimeSeries finalYear_TS = Graphing.createTimeSeriesFromData(mostRecentYearData, String.valueOf(finalYear), "daily");
        plot = Graphing.addTimeseriesData(plot, finalYear_TS, true, Color.cyan, false, false, true, true, recentYear);
        
        //Output monthly boxplot and timeseries data for use with JHighCharts
        if(rasterTF || envelopeTF){
            DoubleArray.writeTimeSeries(directory, graphData, "daily", getTimeseriesEnvelopeOutput().getName(), false);
        }
        
        //Check if the user desires a raster graph
        if(rasterTF){
            createTimeseriesRasterGraph(graphData, yAxisTitle);
        }
        
        //Check if the user desires an envelope graph
        if(envelopeTF){
            //Create Y Axis
            if(logYaxis_TF){
                LogarithmicAxis rangeAxis = new LogarithmicAxis(yAxisTitle);
                rangeAxis.setAllowNegativesFlag(true); 
                plot.setRangeAxis(0, rangeAxis);
            }else{
                ValueAxis rangeAxis = new NumberAxis(yAxisTitle);
                plot.setRangeAxis(0, rangeAxis);
            }

            //Create X Axis
            String xAxisTitle = "Calendar Year";
            if(waterYearTF) xAxisTitle = "Water Year (10-01 to 9-30)";
            DateAxis domainTime = new DateAxis(xAxisTitle);
            domainTime.setLowerMargin(0.05);
            domainTime.setUpperMargin(0.05);
            SimpleDateFormat xlabelDateFormat = new SimpleDateFormat("MMM");
            domainTime.setDateFormatOverride(xlabelDateFormat);
            plot.setDomainAxis(0, domainTime);

            //Set extra plot preferences
            plot = Graphing.setAxisPreferences(plot);

            //Create the charts out of the plots
            String graphTitle = "Time Series Range for " + database + " Station: " + stationId + "; " + stationName;
            JFreeChart chart = new JFreeChart(graphTitle, Graphing.titleFont, plot, true);

            //Set legend Font
            LegendTitle legendTitle = chart.getLegend();
            legendTitle.setItemFont(Graphing.masterFont);

            //Save monthly timeseries graph for use later
            try{
                String path = directory + File.separator + getTimeseriesEnvelope();
                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.");
            }
        }
    }
    /**
     * Graph the time series (z) verses the month/day (x) per each year (y)
     * and save the resulting graph to the specified location.
     */
    private void createTimeseriesRasterGraph(String[][] envelopePlotData, String zAxisTitle) throws IOException {
        //Manipulate envelope plot data into raster plot data format
        ArrayList<Double> tempData_dayOfYear = new ArrayList<>();
        ArrayList<Double> tempData_year = new ArrayList<>();
        ArrayList<Double> tempData_value = new ArrayList<>();
        ArrayList<Double> tempData_noZeros = new ArrayList<>();
        double currentYear = Double.parseDouble(end.substring(0,4));
        for(int j=6; j< envelopePlotData[0].length; j++){//skip data columns 0=date, 1=median, 2=average, 3=period1, 4=period2, 5=period3 to get to the individual year(s) data
            for(int i=0; i<366; i++){//day loop
                double value = Double.parseDouble(envelopePlotData[i][j]);
                if(value > -1){
                    tempData_dayOfYear.add((double) i+1);
                    tempData_year.add(currentYear);
                    tempData_value.add(value);
                    if(value > 0){
                        tempData_noZeros.add(value);
                    }
                }
            }
            currentYear--;
        }
        double[][] rasterData = new double[tempData_dayOfYear.size()][3];
        for(int i=0; i<tempData_dayOfYear.size(); i++){
            rasterData[i][0] = tempData_dayOfYear.get(i);
            rasterData[i][1] = tempData_year.get(i);
            rasterData[i][2] = tempData_value.get(i);
        }
        double tempMin = DoubleMath.min(tempData_value);
        double tempMax = DoubleMath.max(tempData_value);
        
        //Renderer
        XYZDataset xyzRasterData = new XYZArrayDataset(rasterData);
        XYBlockRenderer renderer = new XYBlockRenderer();
        LookupPaintScale paintScale = new LookupPaintScale(tempMin, tempMax, Color.lightGray);
        Paint[] contourColors = getFullRainBowScale(170);
        
        //Color Scale
        double value = tempMax;
        double delta = (tempMax - tempMin)/(contourColors.length -1);
        if(rasterLogarithmicBinsTF){
            value = Math.log(tempMax);
            delta = (Math.log(tempMax) - Math.log(tempMin))/(contourColors.length -1);
            if(tempMin == 0){
                delta = (Math.log(tempMax) - Math.log(DoubleMath.min(tempData_noZeros)))/(contourColors.length -1);
            }
        }
        for(int i=0; i<contourColors.length; i++){
            if(rasterLogarithmicBinsTF){
                paintScale.add(Math.exp(value), contourColors[i]);
            }else{
                paintScale.add(value, contourColors[i]);
            }
            value = value - delta;
        }
        paintScale.add(0, Color.blue);
        renderer.setPaintScale(paintScale);
        
        //Put the line data, renderer, and axis into plot
        XYPlot plot = new XYPlot();
        plot.setDataset(0, xyzRasterData);
        plot.setRenderer(0, renderer);

        //Put the line on the first Domain and first Range
        plot.mapDatasetToDomainAxis(0, 0);
        plot.mapDatasetToRangeAxis(0, 0);
        
        //Create Y Axis
        ValueAxis rangeAxis = new NumberAxis("Year");
        rangeAxis.setRange(Double.parseDouble(start.substring(0,4)), Double.parseDouble(end.substring(0,4)));
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        plot.setRangeAxis(0, rangeAxis);
        
        //Create X Axis
        String xAxisTitle = "Day of Calendar Year";
        if(waterYearTF) xAxisTitle = "Day of Water Year (10-01 to 9-30)";
        ValueAxis domainAxis = new NumberAxis(xAxisTitle);
        domainAxis.setLowerMargin(0.0);
        domainAxis.setUpperMargin(0.0);
        plot.setDomainAxis(0, domainAxis);
        
        //Set extra plot preferences
        plot = Graphing.setAxisPreferences(plot);

        //Create the charts out of the plots
        String graphTitle = "Raster Graph for " + database + " Station: " + stationId + "; " + stationName;
        JFreeChart chart = new JFreeChart(graphTitle, Graphing.titleFont, plot, false);
        
        //Add scale/legend
        NumberAxis scaleAxis = new NumberAxis(zAxisTitle);
        if(rasterLogarithmicBinsTF){
            scaleAxis = new LogarithmicAxis(zAxisTitle);
        }
        scaleAxis.setAxisLinePaint(Color.white);
        scaleAxis.setTickMarkPaint(Color.white);
        scaleAxis.setTickLabelFont(Graphing.masterFont);
        scaleAxis.setLabelFont(Graphing.masterFont);
        PaintScaleLegend legend = new PaintScaleLegend(paintScale, scaleAxis);
        legend.setAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
        legend.setAxisOffset(5.0);
        legend.setMargin(new RectangleInsets(5, 5, 5, 5));
        legend.setFrame(new BlockBorder(Color.black));
        legend.setPadding(new RectangleInsets(10, 10, 10, 10));
        legend.setPosition(RectangleEdge.RIGHT);
        chart.addSubtitle(legend);
        
        //Save monthly timeseries graph for use later
        try{
            String path = directory + File.separator + getTimeseriesRaster();
            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.");
        }
    }
    private static class XYZArrayDataset extends AbstractXYZDataset{
        double[][] data; //{{x1, y1, z1}, {x2, y2, z2}, ...{xN, yN, zN}}
        int rowCount = 0;
        int columnCount = 0;

        XYZArrayDataset(double[][] data){
           this.data = data;
           rowCount = data.length;
           columnCount = data[0].length;
        }
        @Override
        public int getSeriesCount(){
           return 1;
        }
        @Override
        public Comparable getSeriesKey(int series){
           return "serie";
        }
        @Override
        public int getItemCount(int series){
           return rowCount;
        }
        @Override
        public double getXValue(int series,int item){
            return data[item][0];
        }
        @Override
        public double getYValue(int series,int item){
            return data[item][1];
        }
        @Override
        public double getZValue(int series,int item){
            return data[item][2];
        }
        @Override
        public Number getX(int series,int item){
            return data[item][0];
        }
        @Override
        public Number getY(int series,int item){
            return data[item][1];
        }
        @Override
        public Number getZ(int series,int item){
            return data[item][2];
        }
   }
    private static Paint[] getFullRainBowScale(double colorValue){
        // minimum of about 200 to not have perceptible steps in color scale
        // whether or not perceptible color gradients show depend upon the
        // legend size and the monitor settings
        int ncolor = 360;
        Color [] rainbow = new Color[ncolor];
        // divide the color wheel up into more than ncolor pieces
        // but don't go all of the way around the wheel, or the first color
        // will repeat.  The 60 value is about a minimum of 40, or the
        // red color will repeat.  Too large a value, and there will be no magenta.
//        float x = (float) (1./(ncolor + 170.));
        float x = (float) (1./(ncolor + colorValue));
        for (int i=0; i < rainbow.length; i++){
            rainbow[i] = new Color( Color.HSBtoRGB((i)*x,1.0F,1.0F));
        }
        return rainbow;
   }
    /**
     * Graph a histogram of 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 graph for flow (blue) or water quality (magenta)
     * @param xAxisTitle  the String label for the y axis of the graph
     */
    private void createTimeseriesHistogram(String[][] sortedData,
                                           String[][] sortedData_user,
                                           String[][] period1Data,
                                           String[][] period2Data,
                                           String[][] period3Data,
                                           Color color,
                                           String xAxisTitle) throws IOException{
        //Determine bin type (arithmetic/logarithmic) and then range
        double[] lowerLimit = new double[numBins];
        double[] upperLimit = new double[numBins];
        if(logarithmicBinsTF){
            if(min != 0){
                double exponent = (Math.log10(max) - Math.log10(min)) / numBins;
                for(int i=0; i<numBins; i++){
                    if(i == 0){
                        lowerLimit[i] = 0;
                    }else{
                        lowerLimit[i] = upperLimit[i-1];
                    }
                    upperLimit[i] =  min * Math.pow(10, exponent * (i+1));
                }
            }else{
                double exponent = Math.log10(max) / numBins;
                for(int i=0; i<numBins; i++){
                    if(i == 0){
                        lowerLimit[i] = 0;
                    }else{
                        lowerLimit[i] = upperLimit[i-1];
                    }
                    upperLimit[i] =  Math.pow(10, exponent * (i+1));
                }
            }
        }else{
            double interval = (max - min) / numBins;
            for(int i=0; i<numBins; i++){
                lowerLimit[i] = min + i*interval;
                upperLimit[i] = min + (i+1)*interval;
            }
        }
        
        //Create TimeSeries graph
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        String[][] histogramData = new String[numBins][5];
        boolean legendTF = false;
        for(int j=0; j<numBins; j++){
            //Count data within the bin range
            int count = 0;
            for(int i=0; i < sortedData.length; i++) {
                double value = Double.parseDouble(sortedData[i][1]);
                if(value > lowerLimit[j] && value <= upperLimit[j]){
                    count++;
                }
            }
            String categoryTitle = String.valueOf(DoubleMath.round(lowerLimit[j],1)) + " to " + String.valueOf(DoubleMath.round(upperLimit[j],1));
            dataset.addValue(count, "All Data", categoryTitle);
            histogramData[j][0] = categoryTitle;
            histogramData[j][1] = String.valueOf(count);
            
            //Count user data within the bin range
            if(sortedData_user.length > 0){
                count = 0;
                for(int i=0; i < sortedData_user.length; i++) {
                    double value = Double.parseDouble(sortedData_user[i][1]);
                    if(value > lowerLimit[j] && value <= upperLimit[j]){
                        count++;
                    }
                }
                dataset.addValue(count, "User Data", categoryTitle);
            }
            //Count period 1 data within the bin range
            if(period1Data.length > 0){
                count = 0;
                for(int i=0; i < period1Data.length; i++) {
                    double value = Double.parseDouble(period1Data[i][1]);
                    if(value > lowerLimit[j] && value <= upperLimit[j]){
                        count++;
                    }
                }
                dataset.addValue(count, "Period 1 Data", categoryTitle);
                histogramData[j][2] = String.valueOf(count);
                legendTF = true;
            }else{
                histogramData[j][2] = "-1";
            }
            //Count period 2 data within the bin range
            if(period2Data.length > 0){
                count = 0;
                for(int i=0; i < period2Data.length; i++) {
                    double value = Double.parseDouble(period2Data[i][1]);
                    if(value > lowerLimit[j] && value <= upperLimit[j]){
                        count++;
                    }
                }
                dataset.addValue(count, "Period 2 Data", categoryTitle);
                histogramData[j][3] = String.valueOf(count);
                legendTF = true;
            }else{
                histogramData[j][3] = "-1";
            }
            //Count period 3 data within the bin range
            if (period3Data.length > 0) {
                count = 0;
                for (int i = 0; i < period3Data.length; i++) {
                    double value = Double.parseDouble(period3Data[i][1]);
                    if (value > lowerLimit[j] && value <= upperLimit[j]) {
                        count++;
                    }
                }
                dataset.addValue(count, "Period 3 Data", categoryTitle);
                histogramData[j][4] = String.valueOf(count);
                legendTF = true;
            }else{
                histogramData[j][4] = "-1";
            }
        }
        //Save histogram data for JHighCharts
        DoubleArray.writeXYseries(directory, histogramData, getHistogramOutput().getName());
        
        //Define renderer properties for bar graph
        int seriesIndex = 0;
        BarRenderer renderer = new BarRenderer();
        renderer.setDrawBarOutline(false);
        renderer.setSeriesPaint(seriesIndex, color);
        seriesIndex++;
        if(sortedData_user.length > 0){
            renderer.setSeriesPaint(seriesIndex, Color.gray);
            seriesIndex++;
        }
        if(period1Data.length > 0){
            renderer.setSeriesPaint(seriesIndex, Color.red);
            seriesIndex++;
        }
        if(period2Data.length > 0){
            renderer.setSeriesPaint(seriesIndex, new Color(255, 135, 0));//gold
            seriesIndex++;
        }
        if(period3Data.length > 0){
            renderer.setSeriesPaint(seriesIndex, Color.green);
            seriesIndex++;
        }
        
        //Define axis and properties
        NumberAxis yAxis = new NumberAxis("Count");
        CategoryAxis xAxis = new CategoryAxis(xAxisTitle);
        xAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45);
        
        //Graph the dataset using the renderer and create a chart
        CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
        
        //Set extra plot preferences
        plot = Graphing.setCategoryAxisPreferences(plot);
        
        //Create the chart with the plot
        String graphTitle = "Histogram for " + database + " Station: " + stationId + "; " + stationName;
        JFreeChart chart = new JFreeChart(graphTitle, Graphing.titleFont, plot, legendTF);
        
        //Set legend Font
        if(legendTF){
            LegendTitle legendTitle = chart.getLegend();
            legendTitle.setItemFont(Graphing.masterFont);
        }
        
        //Save resulting graph for use later
        try{
            String path = directory + File.separator + getHistogram();
            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.");
        }
    }
    /**
     * Graph the monthly average time series and user data and save the resulting graph to the specified location.
     * Also creates a boxplot for each month's data in a new graph
     * @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 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 yAxisTitle  the String label for the y axis of the graph
     */
    private void createTimeseriesMonthlyGraph(String[][] sortedData,
                                              String[][] period1Data,
                                              String[][] period2Data,
                                              String[][] period3Data,
                                              String yAxisTitle) throws IOException {
        //Convert sortedData to monthly data
        sortedData = DoubleArray.computeFlowMethod(sortedData, "Monthly", "Average", false);
        period1Data = DoubleArray.computeFlowMethod(period1Data, "Monthly", "Average", false);
        period2Data = DoubleArray.computeFlowMethod(period2Data, "Monthly", "Average", false);
        period3Data = DoubleArray.computeFlowMethod(period3Data, "Monthly", "Average", false);
        
        //Calculate monthly averages for the entire dataset
        XYPlot plot = new XYPlot();
        XYSeries series = new XYSeries(stationId + ": Data");
        XYSeries period1_series = new XYSeries(stationId + ": Period 1 Data");
        XYSeries period2_series = new XYSeries(stationId + ": Period 2 Data");
        XYSeries period3_series = new XYSeries(stationId + ": Period 3 Data");
//        ArrayList<ArrayList<Double>> boxplotOutliers = new ArrayList<>();
//        double[][] boxplotData = new double[5][12];
        String[][] monthXYdata = new String[12][8];
        boolean showOutliers = false, showExtremeOutliers = false;
        int seriesIndex = 0;
        
        for(int j=1; j<=12; j++){
            ArrayList<Double> monthlyData = new ArrayList<>();
            double flow = 0, flow1 = 0, flow2 = 0, flow3 = 0;
            double ctr = 0, ctr1 = 0, ctr2 = 0, ctr3 = 0;
            
            for(int i=0; i<sortedData.length; i++){
                double month = Double.parseDouble(sortedData[i][0].substring(5));
                double value = Double.parseDouble(sortedData[i][1]);
                int month_int = (int) month;
                if(month_int == j){
                    monthlyData.add(value);
                    flow = flow + value;
                    ctr = ctr + 1;
                }
                if(i < period1Data.length){
                    month_int = (int) Double.parseDouble(period1Data[i][0].substring(5));
                    value = Double.parseDouble(period1Data[i][1]);
                    if(month_int == j){
                        flow1 = flow1 + value;
                        ctr1 = ctr1 + 1;
                    }
                }
                if(i < period2Data.length){
                    month_int = (int) Double.parseDouble(period2Data[i][0].substring(5));
                    value = Double.parseDouble(period2Data[i][1]);
                    if(month_int == j){
                        flow2 = flow2 + value;
                        ctr2 = ctr2 + 1;
                    }
                }
                if(i < period3Data.length){
                    month_int = (int) Double.parseDouble(period3Data[i][0].substring(5));
                    value = Double.parseDouble(period3Data[i][1]);
                    if(month_int == j){
                        flow3 = flow3 + value;
                        ctr3 = ctr3 + 1;
                    }
                }
            }
            //Calculate monthly average
            if(ctr == 0){ctr = 1;}   //prevent divide by zero problems
            series.add(j, flow/ctr);
            monthXYdata[j-1][0] = String.valueOf(j);
            monthXYdata[j-1][1] = String.valueOf(flow/ctr);
            monthXYdata[j-1][2] = String.valueOf(j);
            monthXYdata[j-1][3] = "-1";
            monthXYdata[j-1][4] = String.valueOf(j);
            monthXYdata[j-1][5] = "-1";
            monthXYdata[j-1][6] = String.valueOf(j);
            monthXYdata[j-1][7] = "-1";
            
            //Check for period data
            if(period1Data.length > 0){
                if(ctr1 == 0){ctr1 = 1;} //prevent divide by zero problems
                period1_series.add(j, flow1/ctr1);
                monthXYdata[j-1][3] = String.valueOf(flow1/ctr1);
            }
            if(period2Data.length > 0){
                if(ctr2 == 0){ctr2 = 1;} //prevent divide by zero problems
                period2_series.add(j, flow2/ctr2);
                monthXYdata[j-1][5] = String.valueOf(flow2/ctr2);
            }
            if(period3Data.length > 0){
                if(ctr3 == 0){ctr3 = 1;} //prevent divide by zero problems
                period3_series.add(j, flow3/ctr3);
                monthXYdata[j-1][7] = String.valueOf(flow3/ctr3);
            }
            
            //Create Monthly boxplot
            if(monthlyData.size() > 4){
                //Create quartile rectangle, min-max line, and median line
                Object[] returnArray = Graphing.boxplot_shapes(plot, j, monthlyData, seriesIndex, showOutliers, showExtremeOutliers);
                plot = (XYPlot) returnArray[0];
                showOutliers = (boolean) returnArray[1];
                showExtremeOutliers = (boolean) returnArray[2];
                seriesIndex = (int) returnArray[3];
//                ArrayList<Double> outliers = (ArrayList<Double>) returnArray[4];
//                double[] currentBoxplotData = (double[]) returnArray[5];
//                
//                //Store additional results for use with JHighCharts
//                boxplotOutliers.add(outliers);
//                boxplotData[0][j-1] = currentBoxplotData[0];
//                boxplotData[1][j-1] = currentBoxplotData[1];
//                boxplotData[2][j-1] = currentBoxplotData[2];
//                boxplotData[3][j-1] = currentBoxplotData[3];
//                boxplotData[4][j-1] = currentBoxplotData[4];
            }
        }
        
//        //Check to show legend on boxplot graph
//        boolean showBoxplotLegend = false;
//        if(showOutliers || showExtremeOutliers){
//            showBoxplotLegend = true;
//        }
		
        //Create renderer, and axis for timeseries graph
        XYDataset xyDataset = new XYSeriesCollection(series);
        XYDataset xyDataset_period1 = new XYSeriesCollection(period1_series);
        XYDataset xyDataset_period2 = new XYSeriesCollection(period2_series);
        XYDataset xyDataset_period3 = new XYSeriesCollection(period3_series);
        XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
        renderer.setSeriesPaint(0, Color.black);
        renderer.setSeriesStroke(0, 
                new BasicStroke(
                    3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                    1.0f, new float[] {6.0f, 0.0f}, 0.0f
                ));
        
        //Set the line data, renderer, and axis into plot
        plot.setDataset(seriesIndex, xyDataset);
        plot.setRenderer(seriesIndex, renderer);
        boolean legendTF = false;
        seriesIndex++;
        
        //Add period data (if any)
        if(period1Data.length > 0){
            XYItemRenderer renderer_period1 = new XYLineAndShapeRenderer(true, false);
            renderer_period1.setSeriesPaint(0, Color.red);
            plot.setDataset(seriesIndex, xyDataset_period1);
            plot.setRenderer(seriesIndex, renderer_period1);
            legendTF = true;
            seriesIndex++;
        }
        if(period2Data.length > 0){
            XYItemRenderer renderer_period2 = new XYLineAndShapeRenderer(true, false);
            renderer_period2.setSeriesPaint(0, new Color(255, 135, 0));//gold
            plot.setDataset(seriesIndex, xyDataset_period2);
            plot.setRenderer(seriesIndex, renderer_period2);
            legendTF = true;
            seriesIndex++;
        }
        if(period3Data.length > 0){
            XYItemRenderer renderer_period3 = new XYLineAndShapeRenderer(true, false);
            renderer_period3.setSeriesPaint(0, Color.green);
            plot.setDataset(seriesIndex, xyDataset_period3);
            plot.setRenderer(seriesIndex, renderer_period3);
            legendTF = true;
            seriesIndex++;
        }
        
        //Map the line to the first Domain and first Range
        plot.mapDatasetToDomainAxis(0, 0);
        plot.mapDatasetToRangeAxis(0, 0);
        
        //Graph a line for each year of monthly data in time period
        String[] monthList = {"1","2","3","4","5","6","7","8","9","10","11","12"};
        String currentYear = start.substring(0,4);
        String finalYear = end.substring(0,4);
        boolean moreYears = sortedData.length > 0;
        while(moreYears){
            //Get current year's data and graph it
            String[][] partialData = DoubleArray.getYearsData(sortedData, currentYear);
            double[][] currentYearData = new double[partialData.length][2];
            for(int i=0; i<partialData.length; i++){
                currentYearData[i][0] = Double.parseDouble(partialData[i][0].substring(5));//month
                currentYearData[i][1] = Double.parseDouble(partialData[i][1]);//value
            }
            Graphing.addXYSeries(plot, currentYearData, Color.lightGray, seriesIndex);
            seriesIndex++;
            
            //Save results for output for JHighCharts
            String[] partialMonthData = new String[12];
            int ctr = 0;
            for(int i=0; i<12; i++){
                partialMonthData[i] = "-1";//value
                try{
                    double month = Double.parseDouble(partialData[ctr][0].substring(5));//month
                    int month_int = (int) month;
                    if(month_int == (i+1)){
                        partialMonthData[i] = partialData[ctr][1];//value
                        ctr++;
                    }
                }catch(IndexOutOfBoundsException e){
                    //do nothing as it already has a -1 value
                }
            }
            monthXYdata = DoubleArray.appendcolumn_Matrix(monthXYdata, monthList);//Add list of months (aka x points)
            monthXYdata = DoubleArray.appendcolumn_Matrix(monthXYdata, partialMonthData);//Add month values (aka y points)
            
            //Determine the next data year to continue looping over
            int nextYear = Integer.parseInt(currentYear) + 1;
            if(finalYear.compareToIgnoreCase(String.valueOf(nextYear)) >= 0){
                currentYear = String.valueOf(nextYear);
            }else{
                moreYears = false;
            }
        }
        
        //Output monthly boxplot and timeseries data for use with JHighCharts
        DoubleArray.writeXYseries(directory, monthXYdata, getMonthlyTimeseriesOutput().getName());
//        DoubleArray.writeBoxplot(directory, boxplotOutliers, boxplotData, getMonthlyBoxplotOutput().getName());
        
        //Create Y Axis
        ValueAxis rangeAxis = new NumberAxis(yAxisTitle);
        plot.setRangeAxis(0, rangeAxis);
        
        //Create X Axis
        NumberTickUnit temp = new NumberTickUnit(1);
        NumberAxis domainAxis = new NumberAxis("Calendar Month");
        domainAxis.setRange(0.75, 12.25);
        domainAxis.setTickUnit(temp);
        plot.setDomainAxis(0, domainAxis);
        
        //Set extra plot preferences
        plot = Graphing.setAxisPreferences(plot);

        //Create the charts out of the plots
        String graphTitle = "Monthly Averages for " + database + " Station: " + stationId + "; " + stationName;
        JFreeChart chart = new JFreeChart(graphTitle, Graphing.titleFont, plot, legendTF);
        
        //Set legend Font
        if(legendTF){
            LegendTitle legendTitle = chart.getLegend();
            legendTitle.setItemFont(Graphing.masterFont);
        }
        
        //Save monthly timeseries graph for use later
        try{
            String path = directory + File.separator + getMonthlyGraph();
            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.");
        }
    }
    /**
     * 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);
    }
    /**
     * Primary TimeSeries
     * It calls the subfunctions based on user selection/inputs.
     * Calls STORET or USGS database queries and their respective subfunctions
     * @param e  DFLOW executable file
     * @throws IOException 
     * @throws InterruptedException 
     * @throws java.text.ParseException 
     */
    public void run(Executable e) throws IOException, InterruptedException, ParseException, Exception {
        //If no date input, make it the maximum of available data
        if(startDate == null || startDate.equalsIgnoreCase("")){
            startDate = "1850-01-01";
        }
        if(endDate == null || endDate.equalsIgnoreCase("")){
            // Pull current date for upper limit of data search
            DateFormat desiredDateFormat = DoubleArray.getDateFormat("daily", false);
            Date currentDate = new Date();
            endDate = desiredDateFormat.format(currentDate);
        }
        
        //Initialize graph variables
        String yAxisTitle = "y axis";
        String monthlyYaxisTitle = "y axis";
        Color color = Color.black, color2 = Color.black;
        boolean showLine = true;
        
        String[][] sortableData = new String[0][2];
        if(wqTest.equalsIgnoreCase("flow")){
            //Check if any flow data exists
            WaterDataInterface waterLib = WaterData.getNewWaterDataInterface(database, userData);
            sortableData = waterLib.extractFlowData_formatted(directory, orgId, stationId, startDate, endDate);
            dataSource = waterLib.getDataSourceCitation();

            //Define other graph information
            units = "cfs";
            if(timeStep.equalsIgnoreCase("Daily")){
                yAxisTitle = timeStep + " Flow [cfs]";
            }else{
                yAxisTitle = timeStep + " " + method + " Flow [cfs]";
            }
            monthlyYaxisTitle = "Monthly Average Flow [cfs]";
            color = Color.blue;
            color2 = Color.darkGray;
            showLine = true;
        }else{
            //Search for WQ data
            WaterDataInterface waterLib = WaterData.getNewWaterDataInterface(database, userData);
            sortableData = waterLib.extractWaterQualityData_formatted(directory, orgId, stationId, startDate, endDate, wqTest);
            dataSource = waterLib.getDataSourceCitation();
            
            //Get Units and conversion for current WQ test
            String[] resultArray = WaterQualityInfo.getWqTestDataInfo(wqTest, database);
            //String wqCode = resultArray[0];
            String wqLabel = resultArray[1];
            units = resultArray[2];
            //double ldcConversion = Double.parseDouble(resultArray[3]);
            //String ldcEndUnits = resultArray[4];

            //Define other graph information
            if(timeStep.equalsIgnoreCase("Daily")){
                yAxisTitle = timeStep + " " + wqLabel + " [" + units + "]";
            }else{
                yAxisTitle = timeStep + " " + method + " " + wqLabel + " [" + units + "]";
            }
            monthlyYaxisTitle = "Monthly Average " + wqLabel + " [" + units + "]";
            color = Color.magenta;
            color2 = Color.blue;
            showLine = false;
        }
        
        //Check if merging the datasets is desired, if so get the user data
        String[][] sortableData_user = new String[0][0];
        if(mergeDatasets){
            WaterDataInterface waterLibUser = WaterData.getNewWaterDataInterface("UserData", userData);
            if(wqTest.equalsIgnoreCase("flow")){
                sortableData = waterLibUser.extractFlowData_formatted(directory, orgId, stationId, startDate, endDate);
            }else{
                sortableData = waterLibUser.extractWaterQualityData_formatted(directory, orgId, stationId, startDate, endDate, wqTest);
            }
        }
        
        //Sort the Data by date to remove duplicate date entries
        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<>();
            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
        start = sortedData_combined[0][0];
        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);
        String[][] seasonalData = DoubleArray.getSeasonalData(sortedData_combined, seasonBegin, seasonEnd);
        
        //Perform operations on daily data before it is converted to the user desired timeStep
        createTimeseriesMonthlyGraph(sortedData_combined, period1Data, period2Data, period3Data, monthlyYaxisTitle);
        
        FlowStatistics flowStats = new FlowStatistics();
        if(wqTest.equalsIgnoreCase("flow")){
            //Create Envelope Graph
            if(envelopeTF || rasterTF){
                createTimeseriesEnvelopeGraph(sortedData_combined, period1Data, period2Data, period3Data, yAxisTitle, true);
            }
            
            //Calculate Hydrologic Indicators of Alteration
            if(calcFlowStatisticsFileTF){
                flowStats.calculateAllStatisticsSummaries(directory, stationId, stationName, sortedData_combined, highPercentile, lowPercentile, 0, 0, showMonthlyStatsTF,
                        seasonBegin, seasonEnd, period1Begin, period1End, period2Begin, period2End, period3Begin, period3End, waterYearTF);
            }
            
            //Calculate CDPHE design low flow
            if(calcCDPHElowflowTF){
                CDPHE_lowFlowStats cdphe_lowflow = new CDPHE_lowFlowStats();
                DFLOW_lowFlowStats dflow_lowflow = new DFLOW_lowFlowStats();
                if(CDPHE_lowFlowType.equalsIgnoreCase("extreme-value")){
                    //Calculate the Extreme-value based design flow:
                    extremeValueDFLOW = cdphe_lowflow.CDPHE_ExtremeValue(sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_waterYearBegin);
                    
                }if(CDPHE_lowFlowType.equalsIgnoreCase("dflow-extreme-value")){
                    //Calculate the Extreme-value based design flow:
                    extremeValueDFLOW = dflow_lowflow.DFLOW_ExtremeValue(e, directory, sortedData_combined, CDPHE_m, CDPHE_R);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("biological")){
                    //Calculate the Biologically based design flow:
                    double[] biologial_flows = cdphe_lowflow.CDPHE_Biological(sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_clusterLength, CDPHE_clusterCountMax);
                    biologicalDFLOW_all = biologial_flows[0];
                    biologicalDFLOW_jan = biologial_flows[1];
                    biologicalDFLOW_feb = biologial_flows[2];
                    biologicalDFLOW_mar = biologial_flows[3];
                    biologicalDFLOW_apr = biologial_flows[4];
                    biologicalDFLOW_may = biologial_flows[5];
                    biologicalDFLOW_jun = biologial_flows[6];
                    biologicalDFLOW_jul = biologial_flows[7];
                    biologicalDFLOW_aug = biologial_flows[8];
                    biologicalDFLOW_sep = biologial_flows[9];
                    biologicalDFLOW_oct = biologial_flows[10];
                    biologicalDFLOW_nov = biologial_flows[11];
                    biologicalDFLOW_dec = biologial_flows[12];
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("dflow-biological")){
                    //Calculate the Biologically based design flow:
                    double[][] biologial_flows = dflow_lowflow.DFLOW_Biological(e, directory, sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_clusterLength, CDPHE_clusterCountMax);
                    biologicalDFLOW_all = biologial_flows[0][0];
                    biologicalDFLOW_jan = biologial_flows[0][1];
                    biologicalDFLOW_feb = biologial_flows[0][2];
                    biologicalDFLOW_mar = biologial_flows[0][3];
                    biologicalDFLOW_apr = biologial_flows[0][4];
                    biologicalDFLOW_may = biologial_flows[0][5];
                    biologicalDFLOW_jun = biologial_flows[0][6];
                    biologicalDFLOW_jul = biologial_flows[0][7];
                    biologicalDFLOW_aug = biologial_flows[0][8];
                    biologicalDFLOW_sep = biologial_flows[0][9];
                    biologicalDFLOW_oct = biologial_flows[0][10];
                    biologicalDFLOW_nov = biologial_flows[0][11];
                    biologicalDFLOW_dec = biologial_flows[0][12];
                    biologicalYear_jan = (int) biologial_flows[1][1];
                    biologicalYear_feb = (int) biologial_flows[1][2];
                    biologicalYear_mar = (int) biologial_flows[1][3];
                    biologicalYear_apr = (int) biologial_flows[1][4];
                    biologicalYear_may = (int) biologial_flows[1][5];
                    biologicalYear_jun = (int) biologial_flows[1][6];
                    biologicalYear_jul = (int) biologial_flows[1][7];
                    biologicalYear_aug = (int) biologial_flows[1][8];
                    biologicalYear_sep = (int) biologial_flows[1][9];
                    biologicalYear_oct = (int) biologial_flows[1][10];
                    biologicalYear_nov = (int) biologial_flows[1][11];
                    biologicalYear_dec = (int) biologial_flows[1][12];
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("human-health")){
                    //Calculate the Human-health based design flow:
                    humanHealthDFLOW = cdphe_lowflow.CDPHE_HumanHealth(sortedData_combined);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("dflow-human-health")){
                    //Calculate the Human-health based design flow:
                    humanHealthDFLOW = dflow_lowflow.DFLOW_HumanHealth(e, directory, sortedData_combined);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("reg31")){
                    //Calcualte the Regulation 31 summary of design flows:
                    reg31DFLOWsummary = cdphe_lowflow.CDPHE_REG31(sortedData_combined);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("dflow-reg31")){
                    //Calcualte the Regulation 31 summary of design flows:
                    reg31DFLOWsummary = dflow_lowflow.DFLOW_REG31(e, directory, sortedData_combined);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("all")){
                    //Calculate all design flows
                    extremeValueDFLOW = cdphe_lowflow.CDPHE_ExtremeValue(sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_waterYearBegin);
                    double[] biologial_flows = cdphe_lowflow.CDPHE_Biological(sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_clusterLength, CDPHE_clusterCountMax);
                    biologicalDFLOW_all = biologial_flows[0];
                    biologicalDFLOW_jan = biologial_flows[1];
                    biologicalDFLOW_feb = biologial_flows[2];
                    biologicalDFLOW_mar = biologial_flows[3];
                    biologicalDFLOW_apr = biologial_flows[4];
                    biologicalDFLOW_may = biologial_flows[5];
                    biologicalDFLOW_jun = biologial_flows[6];
                    biologicalDFLOW_jul = biologial_flows[7];
                    biologicalDFLOW_aug = biologial_flows[8];
                    biologicalDFLOW_sep = biologial_flows[9];
                    biologicalDFLOW_oct = biologial_flows[10];
                    biologicalDFLOW_nov = biologial_flows[11];
                    biologicalDFLOW_dec = biologial_flows[12];
                    humanHealthDFLOW = cdphe_lowflow.CDPHE_HumanHealth(sortedData_combined);
                    reg31DFLOWsummary = cdphe_lowflow.CDPHE_REG31(sortedData_combined);
                    
                }else if(CDPHE_lowFlowType.equalsIgnoreCase("dflow-all")){
                    //Calculate all design flows
                    extremeValueDFLOW = dflow_lowflow.DFLOW_ExtremeValue(e, directory, sortedData_combined, CDPHE_m, CDPHE_R);
                    double[][] biologial_flows = dflow_lowflow.DFLOW_Biological(e, directory, sortedData_combined, CDPHE_m, CDPHE_R, CDPHE_clusterLength, CDPHE_clusterCountMax);
                    biologicalDFLOW_all = biologial_flows[0][0];
                    biologicalDFLOW_jan = biologial_flows[0][1];
                    biologicalDFLOW_feb = biologial_flows[0][2];
                    biologicalDFLOW_mar = biologial_flows[0][3];
                    biologicalDFLOW_apr = biologial_flows[0][4];
                    biologicalDFLOW_may = biologial_flows[0][5];
                    biologicalDFLOW_jun = biologial_flows[0][6];
                    biologicalDFLOW_jul = biologial_flows[0][7];
                    biologicalDFLOW_aug = biologial_flows[0][8];
                    biologicalDFLOW_sep = biologial_flows[0][9];
                    biologicalDFLOW_oct = biologial_flows[0][10];
                    biologicalDFLOW_nov = biologial_flows[0][11];
                    biologicalDFLOW_dec = biologial_flows[0][12];
                    biologicalYear_jan = (int) biologial_flows[1][1];
                    biologicalYear_feb = (int) biologial_flows[1][2];
                    biologicalYear_mar = (int) biologial_flows[1][3];
                    biologicalYear_apr = (int) biologial_flows[1][4];
                    biologicalYear_may = (int) biologial_flows[1][5];
                    biologicalYear_jun = (int) biologial_flows[1][6];
                    biologicalYear_jul = (int) biologial_flows[1][7];
                    biologicalYear_aug = (int) biologial_flows[1][8];
                    biologicalYear_sep = (int) biologial_flows[1][9];
                    biologicalYear_oct = (int) biologial_flows[1][10];
                    biologicalYear_nov = (int) biologial_flows[1][11];
                    biologicalYear_dec = (int) biologial_flows[1][12];
                    humanHealthDFLOW = dflow_lowflow.DFLOW_HumanHealth(e, directory, sortedData_combined);
                    reg31DFLOWsummary = dflow_lowflow.DFLOW_REG31(e, directory, sortedData_combined);
                }
            }
        }else{
            //Report that there cannot be flow statistics for water quality data
            String[][] errorMessage = {{"Error"," Cannot compute flow statistics as indicators of hydrologic alteration using water quality data."},{"This output is only applicable for flow analysis.",""}};
            flowStats.writeStatsSummaryFile(directory, errorMessage);
        }
        
        //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);
        seasonalData = DoubleArray.computeFlowMethod(seasonalData, timeStep, method, false);
        
        //CalculateStatistics
        CalculateStatistics(sortedData_combined, "all");
        CalculateStatistics(period1Data, "period1");
        CalculateStatistics(period2Data, "period2");
        CalculateStatistics(period3Data, "period3");
        CalculateStatistics(seasonalData, "seasonal");
        
        //Graph the timeseries data
        createTimeseriesGraph(sortedData_combined, sortedData_user, period1Data, period2Data, period3Data, color, color2, showLine, yAxisTitle);
        createTimeseriesBoxplot(sortedData_combined, yAxisTitle);
        createTimeseriesHistogram(sortedData_combined, sortedData_user, period1Data, period2Data, period3Data, color, yAxisTitle);
        createTimeseriesCDF(sortedData_combined, sortedData_user, period1Data, period2Data, period3Data, color, color2, yAxisTitle);
        len = String.valueOf(sortedData_combined.length);
    }
    public static void main(String[] args) throws IOException, InterruptedException, Exception {
        //Run model
        guiTimeseries_Model timeseries_Model = new guiTimeseries_Model();
        timeseries_Model.run(null);
    }
}