The myrwaR package includes functions for loading and analyzing precipitation data. First, load the packages.

library(myrwaR)
library(dplyr)
library(lubridate)
library(ggplot2)
theme_set(theme_bw())

Loading Precipitation Data

Loading Precipitation Data from Excel File

To load a precipitation dataset from an Excel file, use the load_precip_from_xls() function. This function takes a number of additional arguments such as the name of the workbook sheet, the timezone of the datetimes, and the names of the datetime and precipitation value columns. The defaults for these arguments are based on MyRWA’s current LocationPrecip.xlsx file. See ?load_precip_from_xls for details.

# get path to example precip file provided within myrwaR package
# this is a truncated version of the official MyRWA precipitation file
xls_path <- system.file("extdata", "LoganPrecip.xlsx", package = "myrwaR")
prcp <- load_precip_from_xls(path = xls_path, as.type = "dataframe")
str(prcp)
#> Classes 'tbl_df' and 'data.frame':   170928 obs. of  2 variables:
#>  $ Datetime: POSIXct, format: "1996-07-02 00:00:00" "1996-07-02 01:00:00" ...
#>  $ Precip  : num  0 0 0 0 0 0 0 0 0 0 ...

Returning a zoo Object

The precipitation timeseries can also be returned as a zoo object (see the zoo package for details). A zoo object is designed to handle timeseries data better than a dataframe. However, it does take some time to learn how to use the package effectively.

prcp_zoo <- load_precip_from_xls(path = xls_path, as.type = "zoo")
str(prcp_zoo)
#> 'zoo' series from 1996-07-02 to 2015-12-31 23:00:00
#>   Data: num [1:170928] 0 0 0 0 0 0 0 0 0 0 ...
#>   Index:  POSIXct[1:170928], format: "1996-07-02 00:00:00" "1996-07-02 01:00:00" ...

Loading Precipitation Data from USGS NWIS

Precipitation data can also be loaded from the USGS NWIS system using the load_precip_from_usgs() function. The default station for this function is the Aberjona River gage (01102500).

prcp_usgs <- load_precip_from_usgs(start_date="2015-01-01", end_date="2015-01-10", station_id="01102500")
str(prcp_usgs)
#> 'data.frame':    240 obs. of  2 variables:
#>  $ Datetime: POSIXct, format: "2015-01-01 00:00:00" "2015-01-01 01:00:00" ...
#>  $ Precip  : num  0 0 0 0 0 0 0 0 0 0 ...
mutate(prcp_usgs, PrecipCumsum = cumsum(Precip)) %>%
  ggplot(aes(Datetime)) +
  geom_line(aes(y=Precip, color="Precip")) +
  geom_line(aes(y=PrecipCumsum, color="PrecipCumsum")) +
  scale_color_manual('', values=c(Precip="steelblue", PrecipCumsum="orangered"),
                     labels=c(Precip="Hourly Precip", PrecipCumsum="Cumulative Precip")) +
  theme(legend.position=c(0, 1),
        legend.justification=c(0, 1))

Antecedent Precipitation

Antecedent precipitation is a useful variable for analyzing water quality data. The antecedent_precip() function computes antecedent precipitation based on an hourly timeseries and a specified duration (e.g. 48-hour). The function returns a numeric vector of the same length as the original precipitation. Note that the first n-1 elements will be NA, since there are insufficient values available to compute the full antecedent precipitation.

ante_prcp <- antecedent_precip(prcp, period = 48)
summary(ante_prcp)
#>    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
#>   0.000   0.000   0.010   0.245   0.250  50.050      47

The function also checks that the input timeseries is continuous and at an hourly timestep. If there are any gaps, duplicated datetimes, or NA values, then the function will throw and error. For example, if the 100th row of prcp is removed`:

antecedent_precip(prcp[-100, ], period = 48)
#> Timeseries is not regular, check timesteps around 1996-07-06 02:00:00 (index 99)
#> Error in antecedent_precip(prcp[-100, ], period = 48): Timeseries is not regular

To create a data frame containing multiple antecedent precipitation columns, just save the result antecedent_precip() to new columns in the original data frame.

prcp$Precip24 <- antecedent_precip(prcp, period = 24)
prcp$Precip48 <- antecedent_precip(prcp, period = 48)

A delay can also be set for the antecedent precipitation, which shifts the period by some number of hours. For example, to get the 48 hours with a delay of 6 hours:

prcp$Precip48.6 <- antecedent_precip(prcp, period = 48, delay = 6)

And finally, we can change the aggregation function to view other statistics of antecedent precipitation. For exmple, to see the maximum intensity over the previous 24 hours:

prcp$Precip24.max <- antecedent_precip(prcp, period = 24, fun = max)

This figure shows the historical hourly (black), 24-hour antecedent sum (solid red) and maximum intensity (dashed red), 48-hour antecedent sum (blue), and 48-hour antecedent sum with 6 hour delay (green) precipitation over 30 days of the timeseries.

ggplot(prcp[(24*15):(24*30), ], aes(Datetime)) +
  geom_line(aes(y=Precip, color="Precip")) +
  geom_line(aes(y=Precip24, color="Precip24")) +
  geom_line(aes(y=Precip24.max, color="Precip24.max")) +
  geom_line(aes(y=Precip48, color="Precip48")) +
  geom_line(aes(y=Precip48.6, color="Precip48.6")) +
  scale_color_manual(NULL,
                     labels=c(Precip="Hourly Precip",
                              Precip24="24-hr Total Precip", 
                              Precip24.max="24-hr Max Precip",
                              Precip48="48-hr Total Precip", 
                              Precip48.6="48-hour Total Precip (6-hr Delay)"),
                     values=c(Precip="black",
                              Precip24="red", 
                              Precip24.max="orange",
                              Precip48="deepskyblue", 
                              Precip48.6="olivedrab3")) +
  theme(legend.position=c(0, 1),
        legend.justification=c(0, 1),
        legend.background=element_blank())

Adding Antecedent Precip to WQ Data

The append_weather() function can be used to add columns of antecedent precipitation and weather condition (dry/wet) to a water quality data frame. The following code loads the baseline wq samples for 2010-2011, and the hourly Logan precip dataset. The 48-hour antecedent precipitation is then added to the wq dataframe (column name “Precip.48”), and the weather condition (column name “Weather”) assigned to “Wet”" or “Dry” based on a threshold of 0.25 inches over 48 hours.

wq <- load_wq("D:/Dropbox/Work/mystic/db/MysticDB_20160208.accdb", projects="BASE", sample_types="S", exclude_flags=FALSE)
wq <- filter(wq, year(Datetime) %in% 2010:2011)
xls_path <- system.file("extdata", "LoganPrecip.xlsx", package = "myrwaR")
prcp <- load_precip_from_xls(path = xls_path, as.type = "dataframe")

wq_prcp <- append_weather(wq, prcp, period = 48, precip.threshold = 0.25, precip.name = "Precip")
#> Computing antecedent precip...done
#> Computing DateHour column in wq dataframe...done
#> Merging wq and precip...done
str(wq_prcp)
#> 'data.frame':    2651 obs. of  36 variables:
#>  $ DateHour           : POSIXct, format: "2010-01-20 06:00:00" "2010-01-20 06:00:00" ...
#>  $ LocationID         : Factor w/ 16 levels "ABR006","ABR028",..: 10 10 2 2 3 10 10 3 2 3 ...
#>  $ VisitID            : int  1649 1649 1650 1650 1651 1649 1649 1651 1650 1651 ...
#>  $ ID                 : int  14171 14173 14175 14179 14187 14167 14169 14184 14180 14183 ...
#>  $ CharacteristicID   : Factor w/ 17 levels "DO","DO_SAT",..: 12 15 3 15 15 1 3 8 16 3 ...
#>  $ ResultValue        : num  3.83e+03 8.39e-02 9.33e+02 6.16e-02 6.49e-02 ...
#>  $ Units              : Factor w/ 8 levels "%","CFU/100ml",..: 8 4 5 4 4 4 5 4 4 5 ...
#>  $ Qualifier          : Factor w/ 3 levels "","<",">": NA NA NA NA NA NA NA NA 2 NA ...
#>  $ FlagID             : Factor w/ 7 levels "E","F","k","K",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ MethodID           : int  32 50 5 50 50 23 5 36 27 5 ...
#>  $ ResultComment      : Factor w/ 72 levels ""," ","(bacteria) perservative (blue pill) fell out of one of bottles",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ SampleDepth        : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ UniqueID           : Factor w/ 2204 levels "200007120603_UPL001_BASE_S",..: 1166 1166 1167 1167 1168 1166 1166 1168 1167 1168 ...
#>  $ Datetime           : POSIXct, format: "2010-01-20 06:08:00" "2010-01-20 06:08:00" ...
#>  $ ProjectID          : Factor w/ 1 level "BASE": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleTypeID       : Factor w/ 1 level "S": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ HasFlow            : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleDepthType    : Factor w/ 0 levels: NA NA NA NA NA NA NA NA NA NA ...
#>  $ Comment            : Factor w/ 1261 levels ""," "," cooler temp - cold, had snow in it",..: 1022 1022 954 954 287 1022 1022 287 954 287 ...
#>  $ LocationDescription: Factor w/ 16 levels "","Aberjona River at Salem Street in Woburn; downstream side of the bridge",..: 10 10 4 4 2 10 10 2 4 2 ...
#>  $ WaterBodyID        : Factor w/ 12 levels "Aberjona River",..: 7 7 1 1 1 7 7 1 1 1 ...
#>  $ MunicipalityID     : Factor w/ 11 levels "Arlington","Belmont",..: 1 1 10 10 11 1 1 11 10 11 ...
#>  $ Latitude           : num  42.4 42.4 42.5 42.5 42.5 ...
#>  $ Longitude          : num  -71.1 -71.1 -71.1 -71.1 -71.1 ...
#>  $ LocationTypeID     : int  22 22 22 22 22 22 22 22 22 22 ...
#>  $ LocationMethod     : Factor w/ 1 level "GPS-Unspecified": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CoordinateSystem   : Factor w/ 1 level "WGS84": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ InWatershed        : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ RegionalID         : Factor w/ 2 levels "Lower Mystic River",..: 2 2 2 2 2 2 2 2 2 2 ...
#>  $ WaterType          : Factor w/ 2 levels "Fresh","Saline": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ Owner              : Factor w/ 1 level "": NA NA NA NA NA NA NA NA NA NA ...
#>  $ StaffGage          : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ County             : Factor w/ 2 levels "Middlesex","Suffolk": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CatchmentArea_Sqmi : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ Precip.48          : num  0.44 0.44 0.44 0.44 0.44 0.44 0.44 0.44 0.44 0.44 ...
#>  $ Weather            : Factor w/ 2 levels "Dry","Wet": 2 2 2 2 2 2 2 2 2 2 ...

Note that the last two columns are Precip.48 and Weather, which were created by the append_weather() function. The antecedent precipitation column named according to the scheme: <precip.name>.<period> where precip.name and period are defined as arguments to the function.

Storm Events

It can also be useful when analyzing water quality data to identify and summarize discrete storm events. The myrwaR package includes two functions related to storm events. The first function, assign_precip_events(), takes an hour precipitation timeseries and assigns a unique ID to each dry and wet event. The second function, precip_event_summary() takes the result of assign_precip_events() and generates a summary table listing the properties of each event (e.g. duration, total depth, max intensity, etc.).

Identifyng Storm Events

For this example, we’ll start with the hourly precipitation for March 2010. The plot below shows some small and some large events.

prcp_032010 <- dplyr::filter(prcp, lubridate::year(Datetime)==2010, month(Datetime)==3)
ggplot(prcp_032010, aes(Datetime, Precip)) +
  geom_line() +
  labs(y="Precip (in/hr)")

The assign_precip_events() function can then identify and assign unique IDs to each event.

prcp_032010_evt <- assign_precip_events(x = prcp_032010)
str(prcp_032010_evt)
#> Classes 'tbl_df', 'tbl' and 'data.frame':    744 obs. of  4 variables:
#>  $ Datetime : POSIXct, format: "2010-03-01 00:00:00" "2010-03-01 01:00:00" ...
#>  $ Precip   : num  0 0.01 0.03 0.05 0.05 0.05 0.03 0.03 0.03 0.02 ...
#>  $ EventID  : num  1 1 1 1 1 1 1 1 1 1 ...
#>  $ EventType: chr  "Wet" "Wet" "Wet" "Wet" ...

The result from this function is a copy of the original timeseries with additional columns for:

ggplot(prcp_032010_evt, aes(Datetime, Precip, group=EventID, color=interaction(EventType, EventID))) +
  geom_line() +
  scale_color_discrete("EventType.EventID") +
  labs(y="Precip (in/hr)")

This figure shows the hourly and cumulative precipitation during each wet event.

filter(prcp_032010_evt, EventType == "Wet") %>%
  group_by(EventID) %>%
  mutate(PrecipCumsum=cumsum(Precip)) %>%
  ggplot(aes(Datetime)) +
  geom_line(aes(y=Precip, color="Precip")) +
  geom_line(aes(y=PrecipCumsum, color="PrecipCumsum")) +
  scale_color_manual(NULL, labels=c(Precip="Hourly Precip", PrecipCumsum="Cumulative Precip"),
                     values=c(Precip="steelblue", PrecipCumsum="orangered")) +
  scale_x_datetime(labels=scales::date_format("%b %d %H:%M")) +
  ylim(0, NA) +
  labs(x="", y="Precip (in/hr) / Cumul Precip (in)") +
  facet_wrap(~EventID, scales="free", labeller = "label_both", ncol = 2) +
  theme(axis.text.x=element_text(angle=90, hjust=1, vjust=0.5))

Summarize Events

After assigning unique EventIDs to the hourly precipitation timeseries, the precip_event_summary() function can be used to create a summary of these events and list various characteristics such as the start/end times, duration, total precipitation depth, peak precipitation rate, etc.

prcp_032010_evt_summary <- precip_event_summary(prcp_032010_evt)
str(prcp_032010_evt_summary)
#> 'data.frame':    10 obs. of  9 variables:
#>  $ EventID            : num  1 2 3 4 5 6 7 8 9 10
#>  $ EventType          : chr  "Wet" "Dry" "Wet" "Dry" ...
#>  $ StartDatetime      : POSIXct, format: "2010-03-01 00:00:00" "2010-03-01 11:00:00" ...
#>  $ EndDatetime        : POSIXct, format: "2010-03-01 10:00:00" "2010-03-13 10:00:00" ...
#>  $ TotalDuration      : int  11 288 58 160 32 55 5 66 53 16
#>  $ PeakIntensity      : num  0.05 0.04 0.4 0 0.43 0.01 0.05 0 0.34 0
#>  $ MeanIntensity      : num  0.028182 0.000556 0.120345 0 0.071875 ...
#>  $ TotalDepth         : num  0.31 0.16 6.98 0 2.3 0.02 0.17 0 4.88 0
#>  $ AntecedentDryPeriod: num  NA NA 288 NA 160 NA 55 NA 66 NA

Note that the data frame returned from this function includes both the dry and wet events. To summarize only the wet events, simply filter on the EventType column.

filter(prcp_032010_evt_summary, EventType=="Wet") %>%
  summary
#>     EventID   EventType         StartDatetime                
#>  Min.   :1   Length:5           Min.   :2010-03-01 00:00:00  
#>  1st Qu.:3   Class :character   1st Qu.:2010-03-13 11:00:00  
#>  Median :5   Mode  :character   Median :2010-03-22 13:00:00  
#>  Mean   :5                      Mean   :2010-03-18 11:00:00  
#>  3rd Qu.:7                      3rd Qu.:2010-03-26 04:00:00  
#>  Max.   :9                      Max.   :2010-03-29 03:00:00  
#>                                                              
#>   EndDatetime                  TotalDuration  PeakIntensity  
#>  Min.   :2010-03-01 10:00:00   Min.   : 5.0   Min.   :0.050  
#>  1st Qu.:2010-03-15 20:00:00   1st Qu.:11.0   1st Qu.:0.050  
#>  Median :2010-03-23 20:00:00   Median :32.0   Median :0.340  
#>  Mean   :2010-03-19 17:48:00   Mean   :31.8   Mean   :0.254  
#>  3rd Qu.:2010-03-26 08:00:00   3rd Qu.:53.0   3rd Qu.:0.400  
#>  Max.   :2010-03-31 07:00:00   Max.   :58.0   Max.   :0.430  
#>                                                              
#>  MeanIntensity       TotalDepth    AntecedentDryPeriod
#>  Min.   :0.02818   Min.   :0.170   Min.   : 55.00     
#>  1st Qu.:0.03400   1st Qu.:0.310   1st Qu.: 63.25     
#>  Median :0.07187   Median :2.300   Median :113.00     
#>  Mean   :0.06930   Mean   :2.928   Mean   :142.25     
#>  3rd Qu.:0.09208   3rd Qu.:4.880   3rd Qu.:192.00     
#>  Max.   :0.12034   Max.   :6.980   Max.   :288.00     
#>                                    NA's   :1

Adding Events to a WQ Dataset

The precipitation events dataframe can be joined to the water quality dataset using the date/time stamp of each water quality result, and the date/time of the precipitation timeseries. However, to perform this join, the date/time stamp in the water quality dataset must first be rounded to the nearest hour. For example, the following code loads the baseline wq and precipitation datasets for 2010-2011, identifies the precipitation events, and then joins this information with the wq dataset:

wq <- load_wq("D:/Dropbox/Work/mystic/db/MysticDB_20160208.accdb", projects="BASE", sample_types="S", exclude_flags=FALSE)
wq <- filter(wq, year(Datetime) %in% 2010:2011)

xls_path <- system.file("extdata", "LoganPrecip.xlsx", package = "myrwaR")
prcp <- load_precip_from_xls(path = xls_path, as.type = "dataframe")
prcp <- dplyr::filter(prcp, year(Datetime) %in% 2010:2010)

We then assign the events to the hourly precipitation dataset:

prcp_evt <- assign_precip_events(x = prcp)

summary(prcp_evt)
#>     Datetime                       Precip            EventID     
#>  Min.   :2010-01-01 00:00:00   Min.   :0.000000   Min.   : 0.00  
#>  1st Qu.:2010-04-02 05:45:00   1st Qu.:0.000000   1st Qu.:22.00  
#>  Median :2010-07-02 11:30:00   Median :0.000000   Median :50.00  
#>  Mean   :2010-07-02 11:30:00   Mean   :0.005271   Mean   :47.81  
#>  3rd Qu.:2010-10-01 17:15:00   3rd Qu.:0.000000   3rd Qu.:73.00  
#>  Max.   :2010-12-31 23:00:00   Max.   :1.600000   Max.   :98.00  
#>   EventType        
#>  Length:8760       
#>  Class :character  
#>  Mode  :character  
#>                    
#>                    
#> 

Finally, add a new column Datehour to the wq data frame which is the Datetime column rounded to the nearest hour, and then use that column to join the prcp_evt data frame.

wq <- mutate(wq, Datehour = floor_date(Datetime, unit = "hour"))
wq_prcp_evt <- left_join(wq, prcp_evt, by=c("Datehour"="Datetime"))
str(wq_prcp_evt)
#> 'data.frame':    2651 obs. of  37 variables:
#>  $ LocationID         : Factor w/ 16 levels "ABR006","ABR028",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ VisitID            : int  1748 1656 1748 1748 1748 1656 1656 1748 1890 1748 ...
#>  $ ID                 : int  15019 14221 15020 15022 15021 14220 14224 15018 16115 15017 ...
#>  $ CharacteristicID   : Factor w/ 17 levels "DO","DO_SAT",..: 12 12 13 16 15 8 16 8 1 3 ...
#>  $ ResultValue        : num  9.41e+02 2.59e+03 1.50e+01 5.00 3.18e-02 ...
#>  $ Units              : Factor w/ 8 levels "%","CFU/100ml",..: 8 8 3 4 4 4 4 4 4 5 ...
#>  $ Qualifier          : Factor w/ 3 levels "","<",">": NA NA NA 2 NA NA NA NA NA NA ...
#>  $ FlagID             : Factor w/ 7 levels "E","F","k","K",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ MethodID           : int  32 32 67 27 50 36 27 36 23 5 ...
#>  $ ResultComment      : Factor w/ 72 levels ""," ","(bacteria) perservative (blue pill) fell out of one of bottles",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ SampleDepth        : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ UniqueID           : Factor w/ 2204 levels "200007120603_UPL001_BASE_S",..: 1294 1172 1294 1294 1294 1172 1172 1294 1469 1294 ...
#>  $ Datetime           : POSIXct, format: "2010-09-15 06:19:00" "2010-01-20 07:19:00" ...
#>  $ ProjectID          : Factor w/ 1 level "BASE": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleTypeID       : Factor w/ 1 level "S": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ HasFlow            : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleDepthType    : Factor w/ 0 levels: NA NA NA NA NA NA NA NA NA NA ...
#>  $ Comment            : Factor w/ 1261 levels ""," "," cooler temp - cold, had snow in it",..: 270 856 270 270 270 856 856 270 604 270 ...
#>  $ LocationDescription: Factor w/ 16 levels "","Aberjona River at Salem Street in Woburn; downstream side of the bridge",..: 3 3 3 3 3 3 3 3 3 3 ...
#>  $ WaterBodyID        : Factor w/ 12 levels "Aberjona River",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ MunicipalityID     : Factor w/ 11 levels "Arlington","Belmont",..: 10 10 10 10 10 10 10 10 10 10 ...
#>  $ Latitude           : num  42.4 42.4 42.4 42.4 42.4 ...
#>  $ Longitude          : num  -71.1 -71.1 -71.1 -71.1 -71.1 ...
#>  $ LocationTypeID     : int  22 22 22 22 22 22 22 22 22 22 ...
#>  $ LocationMethod     : Factor w/ 1 level "GPS-Unspecified": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CoordinateSystem   : Factor w/ 1 level "WGS84": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ InWatershed        : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ RegionalID         : Factor w/ 2 levels "Lower Mystic River",..: 2 2 2 2 2 2 2 2 2 2 ...
#>  $ WaterType          : Factor w/ 2 levels "Fresh","Saline": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ Owner              : Factor w/ 1 level "": NA NA NA NA NA NA NA NA NA NA ...
#>  $ StaffGage          : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ County             : Factor w/ 2 levels "Middlesex","Suffolk": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CatchmentArea_Sqmi : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ Datehour           : POSIXct, format: "2010-09-15 06:00:00" "2010-01-20 07:00:00" ...
#>  $ Precip             : num  0 0 0 0 0 0 0 0 NA 0 ...
#>  $ EventID            : num  68 4 68 68 68 4 4 68 NA 68 ...
#>  $ EventType          : chr  "Dry" "Dry" "Dry" "Dry" ...

We can also add the event summary data to the wq data frame by joining on the EventID and EventType columns:

prcp_evt_summary <- precip_event_summary(prcp_evt)
wq_prcp_evt <- left_join(wq_prcp_evt, prcp_evt_summary, by=c("EventID", "EventType"))
str(wq_prcp_evt)
#> 'data.frame':    2651 obs. of  44 variables:
#>  $ LocationID         : Factor w/ 16 levels "ABR006","ABR028",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ VisitID            : int  1748 1656 1748 1748 1748 1656 1656 1748 1890 1748 ...
#>  $ ID                 : int  15019 14221 15020 15022 15021 14220 14224 15018 16115 15017 ...
#>  $ CharacteristicID   : Factor w/ 17 levels "DO","DO_SAT",..: 12 12 13 16 15 8 16 8 1 3 ...
#>  $ ResultValue        : num  9.41e+02 2.59e+03 1.50e+01 5.00 3.18e-02 ...
#>  $ Units              : Factor w/ 8 levels "%","CFU/100ml",..: 8 8 3 4 4 4 4 4 4 5 ...
#>  $ Qualifier          : Factor w/ 3 levels "","<",">": NA NA NA 2 NA NA NA NA NA NA ...
#>  $ FlagID             : Factor w/ 7 levels "E","F","k","K",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ MethodID           : int  32 32 67 27 50 36 27 36 23 5 ...
#>  $ ResultComment      : Factor w/ 72 levels ""," ","(bacteria) perservative (blue pill) fell out of one of bottles",..: NA NA NA NA NA NA NA NA NA NA ...
#>  $ SampleDepth        : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ UniqueID           : Factor w/ 2204 levels "200007120603_UPL001_BASE_S",..: 1294 1172 1294 1294 1294 1172 1172 1294 1469 1294 ...
#>  $ Datetime           : POSIXct, format: "2010-09-15 06:19:00" "2010-01-20 07:19:00" ...
#>  $ ProjectID          : Factor w/ 1 level "BASE": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleTypeID       : Factor w/ 1 level "S": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ HasFlow            : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ SampleDepthType    : Factor w/ 0 levels: NA NA NA NA NA NA NA NA NA NA ...
#>  $ Comment            : Factor w/ 1261 levels ""," "," cooler temp - cold, had snow in it",..: 270 856 270 270 270 856 856 270 604 270 ...
#>  $ LocationDescription: Factor w/ 16 levels "","Aberjona River at Salem Street in Woburn; downstream side of the bridge",..: 3 3 3 3 3 3 3 3 3 3 ...
#>  $ WaterBodyID        : Factor w/ 12 levels "Aberjona River",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ MunicipalityID     : Factor w/ 11 levels "Arlington","Belmont",..: 10 10 10 10 10 10 10 10 10 10 ...
#>  $ Latitude           : num  42.4 42.4 42.4 42.4 42.4 ...
#>  $ Longitude          : num  -71.1 -71.1 -71.1 -71.1 -71.1 ...
#>  $ LocationTypeID     : int  22 22 22 22 22 22 22 22 22 22 ...
#>  $ LocationMethod     : Factor w/ 1 level "GPS-Unspecified": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CoordinateSystem   : Factor w/ 1 level "WGS84": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ InWatershed        : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ RegionalID         : Factor w/ 2 levels "Lower Mystic River",..: 2 2 2 2 2 2 2 2 2 2 ...
#>  $ WaterType          : Factor w/ 2 levels "Fresh","Saline": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ Owner              : Factor w/ 1 level "": NA NA NA NA NA NA NA NA NA NA ...
#>  $ StaffGage          : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ County             : Factor w/ 2 levels "Middlesex","Suffolk": 1 1 1 1 1 1 1 1 1 1 ...
#>  $ CatchmentArea_Sqmi : num  NA NA NA NA NA NA NA NA NA NA ...
#>  $ Datehour           : POSIXct, format: "2010-09-15 06:00:00" "2010-01-20 07:00:00" ...
#>  $ Precip             : num  0 0 0 0 0 0 0 0 NA 0 ...
#>  $ EventID            : num  68 4 68 68 68 4 4 68 NA 68 ...
#>  $ EventType          : chr  "Dry" "Dry" "Dry" "Dry" ...
#>  $ StartDatetime      : POSIXct, format: "2010-09-13 20:00:00" "2010-01-19 19:00:00" ...
#>  $ EndDatetime        : POSIXct, format: "2010-09-16 19:00:00" "2010-01-25 09:00:00" ...
#>  $ TotalDuration      : int  72 135 72 72 72 135 135 72 NA 72 ...
#>  $ PeakIntensity      : num  0.05 0 0.05 0.05 0.05 0 0 0.05 NA 0.05 ...
#>  $ MeanIntensity      : num  0.000694 0 0.000694 0.000694 0.000694 ...
#>  $ TotalDepth         : num  0.05 0 0.05 0.05 0.05 0 0 0.05 NA 0.05 ...
#>  $ AntecedentDryPeriod: num  NA NA NA NA NA NA NA NA NA NA ...