`fasstr`

, the Flow Analysis Summary Statistics Tool for R,
is a set of R functions to
tidy, summarize, analyze, trend, and visualize streamflow data. This
package summarizes continuous daily mean streamflow data into various
daily, monthly, annual, and long-term statistics, completes trending and
frequency analyses, with outputs in both table and plot formats.

This vignette guide contains a look at the steps and internal
functions used within the various `fasstr`

functions. It
includes descriptions of the function and steps on data importing,
tidying and wrangling, filtering, analyzing, and plotting. It also
describes some of the functions in the internal utils.R
file and the packages required to use the `fasstr`

package.

`fasstr`

utilizes tidy coding to utilize many efficient
and useful packages and functions; the tidyverse packages
`tidy`

, `dplyr`

, `ggplot2`

are used
frequently, amongst others for specific functions. Because of this,
`fasstr`

also exports the pipe `%>%`

to assist
in using `fasstr`

in a tidy code routine.

This vignette is broken into the following sections that describe
some of the workflows involved in the `fasstr`

functions:

- Data Importing and Checking
- Tidying Functions (
`add_`

and`fill_`

) - Analysis Functions (
`calc_`

and`compute_`

) - Plotting Functions (
`plot_`

) - Internal Functions (utils.R file)
- Package Dependencies

The `fasstr`

functions primarily require daily mean
streamflow data in cubic metres per second. As such, columns of dates
and values are required. Many `fasstr`

functions can analyze
multiple stations (using grouping functions) so a column to group data
by (typically station numbers) can be provided. Other types of data can
be used (climate, water level, etc), but plots and some conversions are
based on the units of discharge. As there are two ways to provide daily
data to the `fasstr`

functions, the `data`

and the
`station_number`

arguments, there are several internal
functions stored in the utils.R
file that checks the data and formats the columns to ensure the data
is prepared for the analysis. The following describes the steps to
ensure data is consistently set up for analysis.

The first step is to import daily data. The internal
`flowdata_import()`

function provides checks on the
`data`

and `station_number`

arguments, and either
extracts daily data from HYDAT (returns an error if the number isn’t in
HYDAT) using the `tidyhydat`

package, or makes sure that
`data`

is in fact a data frame.

At this point in a `fasstr`

function, all the column names
of the data are saved as in a vector and any grouping (tidy grouping) is
removed. The column names are saved as they may be changed in the
following steps and the original names will be returned at the end of
the analysis. Any grouping is removed to allow for the appropriate
grouping of the analysis. For the tidying functions (`add_`

and `fill_`

) any grouping will be returned.

The next step is to ensure the column names of dates, values, and
groups are consistent as ‘Date’, ‘Value’, and ‘STATION_NUMBER’ (to match
the HYDAT outputs), respectively, for the analysis. This is required as
grouping and summarizing functions in the following steps use these
specific column names, and provided data may not use the same names. The
facilitate the column renaming and checking, there are several internal
functions in the utils.R. For each of the three columns there is a
function that checks if it exists, the proper formatting, and renames
the columns to the appropriate name. These functions are
`format_dates_col()`

, `format_values_col()`

, and
`format_groups_col()`

. If no grouping is provided, a fake
‘STATION_NUMBER’ of ‘XXXXXXX’ is provided (and removed at the end of the
`fasstr`

function). As all three columns are required for
many `fasstr`

functions, there is a
`formal_all_cols()`

that uses all three functions, with an
option to remove all other columns.

At this point in a function there is now a data frame of data, usually called ‘flow_data’ that has three columns of ‘Date’, ‘Value’, and ‘STATION_NUMBER’, that is ready to be tidied for analysis.

Note: some functions use different data sources than daily data. The
`compute_HYDAT_peaks_frequencies()`

does not permit the
`data`

argument and just extracts data from HYDAT (and sets
it up appropriately) and the `compute_frequency_analysis()`

function requires a unique dataset (see
`?compute_frequency_analysis`

for more information on the
function).

The following is an example of these first steps (from
`calc_annual_stats()`

):

```
# Check if data is provided and import it
<- flowdata_import(data = data,
flow_data station_number = station_number)
# Save the original columns (to check for STATION_NUMBER col at end) and ungroup if necessary
<- names(flow_data)
orig_cols <- dplyr::ungroup(flow_data)
flow_data
# Check and rename columns
<- format_all_cols(data = flow_data,
flow_data dates = as.character(substitute(dates)),
values = as.character(substitute(values)),
groups = as.character(substitute(groups)),
rm_other_cols = TRUE)
```

`add_`

and `fill_`

)The `fasstr`

tidying functions (start with
`add_`

or `fill_`

) just add rows or columns of
data so there are fewer steps than the other `fasstr`

functions.

After the data has been prepped with the appropriate columns, the columns are added with their equations or other functions, or dates are filled with NA if they are missing. Then if any of the column names were changed in the formatting, they are returned to their original names, and if there was a grouping beforehand, that grouping is returned.

The following is an example of remaining steps of a tidying function
(from `add_daily_yield()`

):

```
## SET UP BASIN AREA
suppressWarnings(flow_data <- add_basin_area(flow_data, basin_area = basin_area))
$Basin_Area_sqkm_temp <- flow_data$Basin_Area_sqkm
flow_data
## ADD YIELD COLUMN
<- dplyr::mutate(flow_data, Yield_mm = Value * 86400 / (Basin_Area_sqkm_temp * 1000))
flow_data
# Return the original names of the Date and Value columns
names(flow_data)[names(flow_data) == 'Value'] <- as.character(substitute(values))
names(flow_data)[names(flow_data) == 'STATION_NUMBER'] <- as.character(substitute(groups))
## Reformat to original names and groups
## -------------------------------------
# Return columns to original order plus new column
if('Yield_mm' %in% orig_cols){
<- flow_data[, c(orig_cols)]
flow_data else {
} <- flow_data[, c(orig_cols, paste('Yield_mm'))]
flow_data
}
::as_tibble(flow_data) dplyr
```

`calc_`

and
`compute_`

)The `fasstr`

analysis functions (start with
`calc_`

or `compute_`

or `screen_`

)
require steps of tidying (adding appropriate columns), filtering,
analyzing and any final data wrangling.

After the data has been prepped with the appropriate columns,
additional columns of dates (years, months, days), rolling days, basin
areas, yields or volumes may be added, depending on the analysis. Dates
with no data are also filled with NA values so that complete years can
be analyzed (and appropriate warnings made if NA’s are produced). To
facilitate these steps there is an internal function in the utils.R file
called `analysis_prep()`

. This function will fill the missing
dates and add columns of ‘CalendarYear’, ‘Month’, ‘MonthName’,
‘WaterYear’, and ‘DayofYear’ to the data frame. It also creates a column
of ‘AnalysisDate’ if necessary, that extracts the dates and converts
them into a single year for columns or plotting. This is to provide
consistency to the analysis functions (as the Wateryear can change based
on the `water_year_start`

argument choice). Any other columns
(rolling means, yield, etc.) are added as necessary using the necessary
tidying functions.

For some functions a ‘RollingValue’ column is created for the statistics calculations so that a roll_day value of other than 1 can be used. For this, the add_rolling_days() function creates an additional column based on the users selection and is renamed to ‘RollingValue’.

At this point in a function the data frame of data, flow_data, has three columns of ‘Date’, ‘Value’ or ‘RollingValue’, and ‘STATION_NUMBER’, and any other date and necessary column required to be filtered for analysis.

The following is an example of the tidying steps (from
`calc_annual_stats()`

):

```
# Fill missing dates, add date variables
<- analysis_prep(data = flow_data,
flow_data water_year_start = water_year_start)
# Add rolling means to end of dataframe
<- add_rolling_means(data = flow_data, roll_days = roll_days, roll_align = roll_align)
flow_data colnames(flow_data)[ncol(flow_data)] <- 'RollingValue'
```

With all the necessary columns of data for analysis, the data can be
filtered for the years, months, dates, etc. as specified in the
`fasstr`

function arguments. These are mostly completed with
simple tidy filtering functions. However when using the
`complete_years`

argument in some of the `fasstr`

functions, there is an internal function in the utils.R file called
`filter_complete_yrs()`

that removes data from years with
incomplete data.

At this point in a function the data frame of data, flow_data, has three columns of ‘Date’, ‘Value’, and ‘STATION_NUMBER’, and any other date and necessary column, and is filtered for the analysis.

The following is an example of the filtering steps (from
`calc_annual_stats()`

):

```
# Filter for the selected year (remove excluded years after)
<- dplyr::filter(flow_data, WaterYear >= start_year & WaterYear <= end_year)
flow_data <- dplyr::filter(flow_data, Month %in% months) flow_data
```

Now that the data contains all the necessary data to summarize, using
the tidy methods of the tidyverse (predominately `tidyr`

and
`dplyr`

packages), data is grouped by the necessary
variables. Data is usually grouped by ‘STATION_NUMBER’ and then whatever
time-frame variable the function calls for (years, months, days,
etc).

Then the data is typically analyzed using the
`dplyr::summarize()`

function (for means, median, minimums,
etc). If an analysis considers if missing data is available or not, then
the `na.rm`

argument is set to the
`ignore_missing`

function provided in the `fasstr`

functions. If `NAN`

or `Inf`

values are produced
in the results, then they are replaced with `NA`

for
consistency. If percentiles are being calculated, another code chunk
will loop through each percentile selected and attach to the data.

Data is then ungrouped to allow for further data wrangling and outputting.

The following is an example of the calculation steps (from
`calc_annual_stats()`

):

```
# Calculate basic stats
<- dplyr::summarize(dplyr::group_by(flow_data, STATION_NUMBER, WaterYear),
annual_stats Mean = mean(RollingValue, na.rm = ignore_missing),
Median = stats::median(RollingValue, na.rm = ignore_missing),
Maximum = max (RollingValue, na.rm = ignore_missing),
Minimum = min (RollingValue, na.rm = ignore_missing))
<- dplyr::ungroup(annual_stats)
annual_stats
#Remove Nans and Infs
$Mean[is.nan(annual_stats$Mean)] <- NA
annual_stats$Maximum[is.infinite(annual_stats$Maximum)] <- NA
annual_stats$Minimum[is.infinite(annual_stats$Minimum)] <- NA
annual_stats
# Calculate annual percentiles
if(!all(is.na(percentiles))) {
for (ptile in percentiles) {
# Calculate percentiles
<- dplyr::summarise(dplyr::group_by(flow_data, STATION_NUMBER, WaterYear),
annual_stats_ptile Percentile = stats::quantile(RollingValue, ptile / 100, na.rm = TRUE))
<- dplyr::ungroup(annual_stats_ptile)
annual_stats_ptile names(annual_stats_ptile)[names(annual_stats_ptile) == 'Percentile'] <- paste0('P', ptile)
# Merge with stats
<- merge(annual_stats, annual_stats_ptile, by = c('STATION_NUMBER', 'WaterYear'))
annual_stats
# Remove percentile if mean is NA (workaround for na.rm=FALSE in quantile)
ncol(annual_stats)] <- ifelse(is.na(annual_stats$Mean), NA, annual_stats[, ncol(annual_stats)])
annual_stats[,
} }
```

To finalize the data results there are usually some final data
filtering or wrangling steps. Some of these include some additional
filtering (usually when using the `exclude_years`

argument;
replaces data with NA), providing warnings if NA’s are produced in the
data, renaming the analysis date columns, and returning the names of the
groups (i.e. ‘STATION_NUMBER’ column) if different, or removing it if it
wasn’t provided (as listed in the original column names vector described
above).

If the option to transpose the results data was set to
`TRUE`

with the `transpose`

argument, then the
data is gathered and spread such that each statistics is a single row as
opposed to a column in the original results.

After all wrangling, the final results are returned from the function as a tibble.

The following is an example of the final wrangling steps (from
`calc_annual_stats()`

):

```
# Rename year column
<- dplyr::rename(annual_stats, Year = WaterYear)
annual_stats
# Remove selected excluded years
$Year %in% exclude_years, -(1:2)] <- NA
annual_stats[annual_stats
# If transpose if selected
if (transpose) {
# Get list of columns to order the Statistic column after transposing
<- names(annual_stats[-(1:2)])
stat_levels
# Transpose the columns for rows
<- tidyr::gather(annual_stats, Statistic, Value, -STATION_NUMBER, -Year)
annual_stats <- tidyr::spread(annual_stats, Year, Value)
annual_stats
# Order the columns
$Statistic <- factor(annual_stats$Statistic, levels = stat_levels)
annual_stats<- dplyr::arrange(annual_stats, STATION_NUMBER, Statistic)
annual_stats
}
# Give warning if any NA values
missing_values_warning(annual_stats[, 3:ncol(annual_stats)])
# Recheck if station_number/grouping was in original data and rename or remove as necessary
if(as.character(substitute(groups)) %in% orig_cols) {
names(annual_stats)[names(annual_stats) == 'STATION_NUMBER'] <- as.character(substitute(groups))
else {
} <- dplyr::select(annual_stats, -STATION_NUMBER)
annual_stats
}
::as_tibble(annual_stats) dplyr
```

`plot_`

)The `fasstr`

plotting functions (start with
`plot_`

) take the data calculated in the analysis functions
and then plot the data with set or custom plotting templates.

For the plotting functions data is typically calculated from the
other `calc_`

`fasstr`

functions and then wrangled
into proper formatting. Before calculating the data, various checks are
performed on the arguments and then the `flowdata_import()`

is first used to check the `data`

or
`station_data`

selections. Then the values, dates, and groups
columns are formatted properly and all other columns removed using the
`format_all_cols()`

internal function. This data frame and
the function arguments are then passed onto the `fasstr`

`calc_`

function. Any final data wrangling is also then
completed to set it up for the plotting functions. Some NA values may be
replaced with substitute values to allow the plot to be produced along
with the appropriate data warnings.

Before plotting, some variables are created based on the custom options provided in the arguments (axis labels etc).

As there is the potential for many plots to be produced in the
`fasstr`

functions, a tidy method was used to create multiple
plots simultaneously in an efficient process using `dplyr`

,
`tidyr`

, `purrr`

, and `ggplot2`

packages to create a tibble of plots. See this webpage
for more information on the method. For `fasstr`

plotting
functions, this entails creating a single tibble of groups
(‘STATION_NUMBER’s), data, and plots. First the data is grouped by the
grouping (typically ’STATION_NUMBER’s) using the
`dplyr::group()`

function; this will create a single plot for
each grouping. Then using `tidyr::nest()`

a tibble is created
with two columns, the first being the ’STATION_NUMBER’ and the second
being a tibble of data for each ‘STATION_NUMBER’ (a tibble of tibbles).
Then using `dplyr::mutate()`

function a column of ggplots is
created; and using `purrr::map2()`

all of the plots can be
created simultaneously (thus saving time in the function). As this type
of table isn’t entirely user-friendly, each plot is extracted into a
list and named appropriately (typically by each grouping and then the
statistic).

The following is an example of the process of the creating the plots (with simplified plotting).

```
# Calculate the statistics
<- calc_annual_stats(station_number = c('08NM116', '08NM240'),
annual_stats start_year = 1985, end_year = 2015)
# Wrangle statistics for plotting
<- tidyr::gather(annual_stats, Statistic, Value, -Year, -STATION_NUMBER)
annual_stats
# Group data by grouping
<- dplyr::group_by(annual_stats, STATION_NUMBER)
tidy_plots
# Create a tibble with a column of STATION_NUMBERs and a column of data for each STATION_NUMBER
<- tidyr::nest(tidy_plots)
tidy_plots
# Create a new column of plots using mutate and purrr::map2
<- dplyr::mutate(tidy_plots,
tidy_plots plot = purrr::map2(data, STATION_NUMBER,
~ggplot2::ggplot(data = ., ggplot2::aes(x = Year, y = Value, color = Statistic)) +
::theme(plot.title = ggplot2::element_text(hjust = 0.5)) +
ggplot2::geom_line(alpha = 0.5, na.rm = TRUE) +
ggplot2::geom_point(na.rm = TRUE) +
ggplot2::ylab('Discharge (cms)')
ggplot2
))
# Create a list of named plots extracted from the tibble
<- tidy_plots$plot
plots if (nrow(tidy_plots) == 1) {
names(plots) <- 'Annual_Statistics'
else {
} names(plots) <- paste0(tidy_plots$STATION_NUMBER, '_Annual_Statistics')
}
# Return the plots
plots
```

`$`08NM116_Annual_Statistics``

```
$`08NM240_Annual_Statistics`
```

Within the package there is an R file called utils.R
that contains a list of functions that are used repeatedly throughout
the various `fasstr`

functions to minimize repetition. These
functions are used internally and are not exported from the package.

At the top of the file are several data formatting and wrangling functions:

`flowdata_import()`

- checks if either`station_number`

or`data`

arguments are provided; extracts HYDAT data or sets up data for next steps.`format_dates_col()`

- checks for proper dates formats in column; renames columns to ‘Date’ if not.`format_values_col()`

- checks for proper numeric formats in column; renames columns to ‘Value’ if not.`format_groups_col()`

- checks for proper formats in column; renames columns to ‘STATION_NUMBER’ if not; if no groups provided, a temporary ‘STATION_NUMBER’ of ‘XXXXXXX’ is created for analysis.`format_all_cols()`

- checks for proper formats of all dates, values, and groups columns; uses all three functions listed above; option to remove all other columns if`rm_other_cols = TRUE`

.`analysis_prep()`

- fills missing dates with NA; adds dates columns of Years, day of years, and dates; formatted to calendar or water year as specified.`filter_complete_yrs()`

- filters data for years with which there is only complete annual data; required for some analyses.

Below these formatting and data wrangling functions are many functions used to check arguments and provide warnings when certain data is present. See the file for examples of these internal functions.

The following list contains the packages required to complete many of
the `fasstr`

functions:

`dplyr`

- used for many tidy functions (grouping, summarizing, etc)`e1071`

- used in the frequency analyses for determining skewness for the fitting distributions`fitdistrplus`

- used in the frequency analyses for fitting data to the distributions`ggplot2`

- used for plotting the data`PearsonDS`

- used in the frequency analyses for fitting data to the distributions`plyr`

- used in the frequency analyses to handle data`purrr`

- used in the plotting functions to plot many plots simultaneously`RcppRoll`

- used to add rolling means`scales`

- used in the plotting functions to customize plots`tidyhydat`

- used to extract data from a HYDAT database`tidyr`

- used for many tidy functions (gather, spread, etc)`openxlsx`

- used to write data as Excel files in the write_ functions`zyp`

- used in the trending function to calculate the trends