6.0) Beyond the three main analyses

Hugo Flávio



  1. Preparing your data
    1. Structuring the study area
    2. Creating a distances matrix
    3. The preload() function
  2. explore()
    1. Processes behind explore()
    2. Inspecting the explore() results
  3. migration()
    1. Processes behind migration()
    2. Inspecting the migration() results
    3. One-way efficiency estimations
  4. residency()
    1. Processes behind residency()
    2. Inspecting the residency() results
    3. Multi-way efficiency estimations
  5. Manual mode
  6. Beyond the three main analyses

Expanding on what actel can give you

First of all, congratulations! If you are reading this page, you must have successfully ran an actel analysis on your data. I hope you have found the results useful :)

Here you will find some additional examples of things you can do using the output of your analysis. As actel connects to other packages and expands its capacities, so will this page. Because the page is getting a bit long already, here is a list of the subsections you will find here:

  1. Utilization distribution areas
  2. Calculating efficiency ranges
  3. Plotting personalised circular plots
  4. Plotting personalised detection plots
  5. Plotting sensor data for individual tags
  6. Plotting movements for multiple tags at the same time
  7. Extracting detailed array-level movement speeds
  8. Simultaneous and cumulative presence at one or more arrays
  9. Plotting individual residency for individual tags
  10. Plotting global (and group) residency!
  11. Plotting array live times
  12. What would you like to see here?

Calculating utilization distribution areas and space-use overlaps

The R package RSP (available here) allows you to run spatial analyses on the habitat use of your animals using the output of your actel analysis. With the RSP toolkit you can analyse the fine scale movements of aquatic animals while accounting for the surrounding land masses. The animal movements between detections are recreated to have occurred exclusively in water and the utilization distribution areas are limited by the land contours, providing realistic estimations of space use.

Depending on the research questions being addressed the utilization distribution areas can be calculated for the entire monitoring periods, or in fine-scale according to fixed temporal intervals in hours (timeframes). This approach allows spatial ecologists to use the outputs from such fine scale space use models (areas of use, or between-group overlap frequencies) as input for further statistical analysis.

This is a great R package, so make sure to go check it out!

Calculating efficiency ranges

Both the migration and the residency analyses include efficiency calculations. However, these calculations can sometimes be somewhat limited. To get a better idea of your array efficiencies, you can run the function advEfficiency on the efficiency outputs of your actel analysis.

Let us assume that you have stored the results of your analysis in an object called results (i.e. you ran results <- migration(...) or results <- residency(...)).

You can run advEfficiency on three different contexts:

  1. On the progression results from the migration analysis:
# Run estimation on the overall detections

# Run estimation on the detections for a specific group
# Replace "name" with the actual name of the group.

# Run estimation on the detections for a specific group from a specific release site
# Replace "A" with the group name and "B" with the name of the release site.
  1. On the efficiency results from the residency analysis:
# advEfficiency will estimate both the maximum and minimum efficiency.

# additionally, you can choose how these are plotted by manipulating 
# the 'paired' and 'force.grid' arguments, e.g.:
advEfficiency(results$efficiency, paired = TRUE, force.grid = c(1, 4))
  1. On the efficiency results from an intra-array estimation:
# Replace "name" with the name of the array for which the intra-array efficiency was calculated.

Bonus case: If you want to know intra-array estimations for a specific group, you can adapt and run the code below:

# Fetch the detection matrix for the intra array estimate 
# (replace "name" with the actual name of the array)
m <- results$intra.array.matrices$name

# Fetch the signals of the tags of the group you are interest in 
# (replace "group_name" with the name of the group)
tags <- results$status.df$Signal[results$status.df$Group == "group_name"]

# Extract only the matrix rows that match the target group
m <- x[match(tags, stripCodeSpaces(rownames(m))), ]

# Remove any NA leftovers
m <- m[complete.cases(m), ]

# Re-calculate the intra-array CJS
x <- dualArrayCJS(m)

# Run advEfficiency on the new results

advEfficiency comes with some additional parameters that will help you get the results exactly as you need them. Find more by running ?advEfficiency. The advEfficiency manual page also includes additional information on how the calculations are made, and how you could explain them in a paper, if you need to!

Plotting personalised circular plots

Circular plots are a great way to display your results in a publication. Examples include differences between groups or between arrival points at different places. Although actel provides circular plots with its analyses, these default plots may not be exactly what you are looking for. As such, I created the function plotTimes, to help you get your plot just right.

You can prepare the input for plotTimes by using two other functions (which may also be useful on their own): getTimes and timesToCircular.

For example, if you want to plot the arrival times for all your tags at two arrays:

# Assuming you saved the output of an actel analysis as 'results',
# you can use getTimes to extract the times you want. You can specify
# which locations you are interested in with the argument locations.
x <- getTimes(results, locations = c("A", "B"))

# Then, convert the times to a circular object
x <- timesToCircular(x)

# and plot it!

# You can include a night period by using the night argument, e.g.:
plotTimes(x, night = c("20:00", "06:00"))

This will plot two data series (one for array “A” and one for array “B”), with all the tags pooled together.

However, if you want to plot the arrival times at a specific array per group, you could do the following:

x <- getTimes(results, locations = "A")
x <- timesToCircular(x, by.group = TRUE)

# You can change the names on the legend by changing the
# names of object 'x' (run 'names(x)' to see them).

This will plot each group that arrived at array “A” in a different colour.

You can then choose the combination that makes more sense for the point you are trying to prove. Additionally, plotTimes allows you to shade a portion of the graphic to highlight the night period, and comes with a series of other arguments that allow you to personalise your plot until it is on point (see ?plotTimes for more details).

Bonus case: You can combine time data from multiple analyses. For example, if you ran your study during two years, you can plot the arrival times at a given array for both years and see if there is any variation.

# Load the results from both years:
y1 <- dataToList("actel_migration_results_year1.RData")
y2 <- dataToList("actel_migration_results_year2.RData")

# extract the time data for a specific array:
x1 <- getTimes(y1, locations = "A")
x2 <- getTimes(y2, locations = "A")

# Convert the times to circular, and combine them in a single list
x <- list(
  year.1 = timesToCircular(x1)[[1]],
  year.2 = timesToCircular(x2)[[1]])
# The names you choose for each object above will be used in the plot legend,
# for example, in this plot, the legend would read "year.1" and "year.2".

# plot both years together!

# You can also choose your own colours, and even give it a title:
plotTimes(x, col = c("blue", "orange"), title = "A plot of two datasets!")

You can expand on the example above to plot different groups too. Once you have finished your plot, you can save it to an svg file by adding a name to the ‘file’ argument.

Plotting personalised detection plots

Detection plots provide a lot of information. However, the default plots printed in the reports may be to small to analyse, or perhaps you would like to edit them to use in a presentation or paper. plotDetections() is the function you are looking for.

# Assuming you saved the output of an actel analysis as 'results',
# you can then plot the detections for single individuals. Imagine
# you want to see tag 'R64K-1995'. You can run:
plotDetections(results, tag = "R64K-1995")

# plotMoves comes with some additional personalisation arguments,
# such as title, or array.alias. array.alias allows you to replace
# default name of an array with a name of your choosing, e.g.:
plotDetections(results, tag = "R64K-1995", array.alias = c("River1" = "My_first_array"))

# additionally, if you give the same name to multiple arrays, they
# will be combined automatically! e.g.:
plotDetections(results, tag = "R64K-1995", array.alias = c("River1" = "River", "River2" = "River"))

# You can find all the details about plotDetections arguments by running

# plotDetections returns a ggplot object, which means you can edit it further!
# Very simple example:
p <- plotDetections(results, tag = "R64K-1995")
p <- p + xlab("changing the label after running plotDetections is possible!")

# Of course, you can also save your new plots using ggsave.

Plotting sensor data for individual tags

When your tags have sensor data, these data will be automatically plotted in the report (just like the detections). However, similarly to plotDetections(), you can use plotSensors() to plot the sensor data for a specific tag.

# Assuming you saved the output of an actel analysis as 'results',
# you can then plot the sensor data for single individuals. For example:
plotSensors(results, tag = "R64K-1995")

# You can also choose to plot only some of the sensors by selecting
# a specific unit with the 'sensor' argument!

Plotting movements for multiple tags at the same time

Sometimes it can be useful to compare the movements of multiple tags at the same time. Comparing individual detection plots works, but being able to overlap plots would be much nicer! That’s exactly why I created the plotMoves() function. This function allows you to overlap the movements of multiple tags.

# Assuming you saved the output of an actel analysis as 'results',
# you can then plot the moves of multiple tags by running:
plotMoves(results, tags = c("R64K-1995", "R64K-2001"))

# If you get any tag number wrong, actel will let you know.

Extracting detailed array-level movement speeds

If you have included a valid distances matrix in your analysis, then there is a lot of valuable information scattered throughout the tag movements. While this information is summarised at the section level in the status.df object (for migration() and residency() analyses), maybe you would like to have a look at the event-to-event values. To avoid having to go through each movement table individually, you can use the function getSpeeds():

# As usual, lets assume you saved the output of an actel analysis as 'results'.

# Running getSpeeds on the results will return all the recorded speeds, for
# every animal.

# However, you can trim this output by using the remaining arguments in getSpeeds().

# For example, return only the speeds between neighbouring arrays by using:
getSpeeds(results, direct = TRUE)

# This will only return speeds when the respective movement did not imply
# skipping an ALS array.

# You can further trim these results by choosing only events in a specific direction:

# To display only speeds in a forward direction (as specified by the study area structure)
getSpeeds(results, direct = TRUE, type = "forward")

# Or only in the backwards direction
getSpeeds(results, direct = TRUE, type = "backward")

# The default is "all"
getSpeeds(results, direct = TRUE, type = "all")

# A little side note on directions: 
# If you stated in the spatial.txt file that "A -- B", then A is considered to 
# come before B, and thus a movement from A to B is a forward movement.
# Consequently a movement from B to A is considered a backwards movement.
# Note that movements between parallel arrays are not forward nor backward,
# and the respective speeds will only be displayed if type = "all".

# Finally, you can choose how many events per tag you want to see:
getSpeeds(results, direct = TRUE, type = "all", n.events = "first") # default
getSpeeds(results, direct = TRUE, type = "all", n.events = "all")
getSpeeds(results, direct = TRUE, type = "all", n.events = "last")

# The n.events controls how many instances of a specific movement event you would like to see.
# If a tag moved twice from A to B, "first" will return only the first speed, "last" will
# return only the last speed, and "all" will return both.
# Note that moving from A to B is not the same as moving from B to A, and both will be treated
# separately by getSpeeds.

Because speeds have many underlying variables (from where, to where, which tag, etc.), there is no pre-made plot function for speeds. However, the output of getSpeeds() is structured in a way that should make it easy for you to jump to ggplot2 and start drawing your plots, your way :)

Simultaneous and cumulative presence at one or more arrays

A classic plot in migration analyses is one showing the cumulative arrival of tags at a specific array. The function plotArray() allows you to obtain both the simultaneous presence at an array (if cumulative = FALSE, the default), or the cumulative arrivals at an array (yes, you guessed it, with cumulative = TRUE).

# Assuming you saved the output of an actel analysis as 'results',
# you can then use plotArray to see the simultaneous or cumulative
# presence at one or more arrays:
plotArray(results, arrays = "A1", cumulative = FALSE) # will give you the simultaneous presence
plotArray(results, arrays = "A1", cumulative = TRUE) # will give you the cumulative arrivals

# additionally, you can adjust the time resolution:
plotArray(results, arrays = "A1", timestep = "days") # The default; will aggregate the results by day
plotArray(results, arrays = "A1", timestep = "hours") # Will aggregate the results by hour (takes longer to calculate)
plotArray(results, arrays = "A1", timestep = "mins") # Will aggregate the results by minute (takes way longer to calculate!)

# Finally, although plotArrays will automatically choose between
# plotting lines or bars depending on whether the plot is cumulative
# or not (respectively), you can set a specific plot style with the
# argument 'type'.

One additional feature of this function is that it allows you to group multiple arrays to obtain combined results! Imagine you had two success arrays: A8 and A9. You can get an aggregated result by running:

plotArray(results, arrays = c("A8", "A9"))

Plotting individual residency for individual tags

When you run a residency analysis, one of the outputs is the individual places where your animal spent most of its time. Like the individual detection plots, these are also drawn automatically for each tag in your report. And like the detection plots, you can also get these ones directly in R! Just use plotResidency():

# Assuming you saved the output of an actel residency analysis as 'results',
# you can then plot the residency for single individuals. Imagine you want 
# to see tag 'R64K-1995'. You can run:
plotResidency(results, tag = "R64K-1995")

# As usual, you can save the output of plotResidency as an object, and edit
# it as needed using ggplot commands.

Remember, you can always access the numerical data behind these plots by inspecting the object time.ratios.

Plotting global (and group) residency!

Another great output from the residency analysis is the global and group residency ratios (through the objects global.ratios and group.ratios). The function plotRatios() allows you to plot either of these metrics! This function comes with an argument ‘group’. If you do not set a ‘group’, the global ratios will be printed, but if you set a group, then only that group will be plotted. Additionally, you can choose between absolute values (number of animals at each section) and percentage values (proportion of animals at each section), using the argument type.

# Assuming you saved the output of an actel residency analysis as 'results',
# you can then plot the global ratios:
plotRatios(results) # this prints the absolute values
plotRatios(results, type = "percentages") # this prints the percentage values

# You can then make these plots only for a specific group, using the group
# argument, e.g.:
plotRatios(results, group = "A")
plotRatios(results, group = "B", type = "percentages")

# As usual, you can save the output of plotRatios as an object, and edit
# it as needed using ggplot commands.

You can also plot the multiple groups simultaneously for a subset of sections using the ‘sections’ argument!

# For example, if I wanted to know how many animals were in section "River"
# during the study period, I could run:
plotRatios(results, sections = "River")

# or, for the percentage of tags from each group, run:
plotRatios(results, sections = "River", type = "percentages")

# Keep in mind that you cannot use the arguments 'group' and 'sections' at the same time!
# But you can see aggregated results for multiple sections, e.g.:
plotRatios(results, sections = c("River", "River-Fjord", "Fjord"), type = "percentages")

Plotting array live times

There are multiple reasons why some arrays could be offline during parts of the study. Perhaps a receiver was lost, or the location became inaccessible. actel accounts for array downtimes when calculating array jumps, and you can see those downtimes too using the function plotLive().

This function is very straight foward, and works both on the output of one of the main analyses, or on the output of preload().


# assuming 'results' is the output of an actel analysis

# You can also specify which arrays should be displayed, if individual stations should show
# up or not, and customise aesthetics:
plotLive(results, array = "A1", show.stations = FALSE, array.size = 3)

What would you like to see here?

actel is a work in progress. Is there any anything you would like to do or see in your data that is missing? Have you though of any cool function for actel? Get in touch!

I hope you enjoy using actel!