attackR package for
R models how much of a prey’s visual field is occupied by a predator as it attacks, given information on the predator shape, size and speed.
Its intended use is in biological studies of prey escape behaviours, where they are known or hypothesised to respond to particular thresholds of angular size of the predator (e.g. Temizer et al. 2015), or rate of change of this angular size (e.g. Paglianti & Domenici 2006) (note, other models incorporate other variables to determine escape response likelihoods, such as presence of other prey; see Hatsopoulos 1995, Preuss 2006, Hein et al. 2019).
The code was developed for a study published in PNAS (Cade et al. 2020) on humpback whale foraging on anchovies. In the case of whales it has special functionality for determining how the timing of the whale’s mouth opening during a lunge feeding event affects how much of the prey’s visual field is occupied. However, it can be used with virtually any predator-prey combination.
While the following explanation is fairly straightforward and may seem overly precise, the extreme and unique characteristics of the biomechanics of whale lunge feeding necessitated this level of detail. See [HERE] for an explanation of this approach applied to whales.
When a predator approaches a prey, it occupies space in the prey’s visual field. That is, its profile subtends an angle (⍺) on the prey’s retina, usually determined by its maximum width (Dill 1974):
If the predator comes closer, the angle increases. The rate of change in ⍺, that is d⍺/dt, is simply the change in ⍺ divided by the time this took.
Note as the predator gets closer, depending on its shape the widest apparent part of it from the prey’s perspective may shift forward along the body. Given a predator shape profile,
attackR takes account of this shift when calculating ⍺ and d⍺/dt.
As the predator gets closer, it takes up a relatively greater proportion of the visual field, so at constant speeds both ⍺ and d⍺/dt show an exponential relationship with distance/time:
The d⍺/dt allows the prey to judge how fast the predator is approaching, decide if it is a threat and thus whether to initiate an escape response. Studies have shown many prey species react to consistent values of d⍺/dt which, when applied to their common predators, represent evolutionarily determined predator speed:distance combinations which minimise redundant or unnecessary escape attempts but maximise the chances of escape when the predator is a real threat.
From the prey perspective, the attacker can be approximated by a circular shape projected on a screen that reproduces the same ⍺ and d⍺/dt at a particular viewing distance. These ‘looming animations’ are commonly used to study escape responses and determine thresholds of d⍺/dt at which escape responses are initiated (e.g. the Apparent Looming Threshold or ALT, Dill 1974). See the
loomeR package for creating looming animations, including from
⍺ and d⍺/dt are determined by several aspects of the predator; its size, speed and shape. The
attackR package uses these to calculate ⍺ and d⍺/dt for every stage of a hypothetical attack, and given threshold values of d⍺/dt for the prey, the distance of the predator at that moment and the time remaining until it is captured, assuming it does not move.
Here is a typical input for the
attack_model function which determines ⍺.
attack_model(speed = 350, # speed in cm/s model_length = 500, # determines how far away predator starts attack from frequency = 60, # resolution/frame rate in Hz body_length = 146, # cm - from nose to tail body_width_v = 45, # cm - width at maximum width in vertical plane profile_v = sl_profile_v) # shape profile in vertical plane
These are the minumum required inputs, but there are others (see here for full list).
As a general overview of what the function does:
1:model_length), it calculates how far away the predator is at the given
cmalong the body)
Here we will show a simple example of how
attackR determines the ⍺ and d⍺/dt for an attack by a California sea-lion (Zalophus californianus).
To determine the ⍺ of a predator, especially how it may change as it gets closer to the prey,
attack_model requires a shape profile. The shape profile is simply a vector of proportional widths evenly-spaced along the body from nose to tail (or their equivalents). The predator’s length and maximum width values are entered separately. There are various ways to construct these profiles, from simple to complex: e.g. measured from photos or other morphometric measurements, or determined digitally. Here, as an example we will use an outline of a sea-lion (Fig. 5, Feldkamp 1987) extracted from underwater photos. This study also tells us a sea-lion’s maximum width is situated 40% along the body from the snout (d in the Figure). Table 1 also gives us some measurements of a sea-lion (146 cm length, 45 cm maximum diameter).
We are going to apply these morphometric measurements and our derived profile to calculate the ⍺ of this sea-lion.
The simplest shape profile consists of only three points: proportional widths at the nose, tail and midpoint of the body (there can be any number of widths in a profile, but they must be evenly spaced along the body, which in this case means the midpoint). The location of the maximum width along the body is also required, if it doesn’t happen to occur at the midpoint. This is expressed as a location along the length as a proportion of the total length from the nose. It can be anterior or posterior of the midpoint. In this case it is 40% along the body, so entered as 0.40. The nose and tail will typically be zero, but don’t have to be.
These are used to calculate the midpoint width expressed as a proportion of the maximum width. For example, here the midpoint and maximum widths were measured in ImageJ as 360 and 377 pixels respectively, so the proportional midpoint width is: 360/377 = 0.95.
The function interpolates between these measurements to approximate the shape of the predator at the resolution of the units used, which in this case would be every cm. For every stage of the attack, it will calculate ⍺ at every cm along the body and determine which is greatest at any particular viewing distance.
This interpolated profile is obviously a very simplistic representation of the animal. In this representation, because the body anterior of the maximum width is perfectly triangular, at all viewing distances the maximum width will project the maximum ⍺. However in reality, more anterior parts of the body may project a larger ⍺:
In this example with the sleek sea-lion, the difference this makes to ⍺ are probably minor, but in predators with different shapes this could cause considerable differences. (See the whale vignette for an example).
The higher the resolution of the profile, the better its representation of the predator shape, and better estimate of how ⍺ changes. Therefore, you may want to input a more representative shape profile.
The shape profiles used by
attackR can be at any resolution as long as they are evenly spaced. Here is an example where we determine proportional widths at every 5% along the body. Again, this could be done very quickly with a printout and ruler. Here, the profile image was opened in a simple graphics application, and scaled to a grid so that its length occupied 20 units.
Here, all that is required is measurements of the blue lines, again using ImageJ.
## Measurements from ImageJ pixel_widths_v <- c(0, 121, 166, 182, 204, 246, 303, 343, 377, 373, 360, 359, 344, 309, 256, 192, 147, 136, 133, 129, 0) ## Convert to proportional sl_profile_v <- pixel_widths_v/max(pixel_widths_v) ## Print print(round(sl_profile_v, 2)) #>  0.00 0.32 0.44 0.48 0.54 0.65 0.80 0.91 1.00 0.99 0.95 0.95 0.91 0.82 0.68 #>  0.51 0.39 0.36 0.35 0.34 0.00
Note, that because this profile contains a measurement for the maximum width (i.e. it lies at 0.40 along the body in this case), to get the proportional profile we can simply divide the pixel widths by its maximum value, and we can see the final profile contains a value of 1.0. Therefore, it does not need to be entered separately via the
max_width_loc_v input. If it happened to lie intermediate to one of the measurements at the chosen resolution, the pixel widths would have to be divided by the pixel width at the maximum width location, and its position would be entered via
max_width_loc_v (see above example). Therefore, it’s always easier to use profiles at a resolution that captures the maximum width.
It’s immediately clear that this interpolated profile is much more representative of the true predator body shape, and so estimates of ⍺ will be more realistic at close distances.
What if the predator has a different shape in the horizontal and vertical profiles of its body? A sea-lion is fairly consistently shaped along its body in both planes, so the above example would probably be sufficient to represent the ⍺ of the body as a whole. However, the
attack_model function allows both horizontal and vertical profiles to be entered, and selection of which ⍺ between them to use.
Note how in the above examples inputs are appended by
_v. This relates to the vertical profile, and there are similar inputs for the horizontal profile appended with
Here we construct a horizontal shape profile (image from Fig. 3a, English 1976). We ignore the flippers and approximate the shape of the body in the fin regions because they are thin relative to the body in the frontal view, and so don’t contribute significantly to the ⍺ of the predator as a whole (the overall aim is to approximate the size of the looming predator in the prey’s visual field, not capture every detail).
## Measurements from ImageJ pixel_widths_h <- c(0, 110, 186, 250, 278, 320, 346, 392, 416, 426, 420, 392, 394, 352, 308, 284, 252, 222, 260, 310, 0) ## Convert to proportional sl_profile_h <- pixel_widths_h/max(pixel_widths_h) ## Print print(round(sl_profile_h, 2)) #>  0.00 0.26 0.44 0.59 0.65 0.75 0.81 0.92 0.98 1.00 0.99 0.92 0.92 0.83 0.72 #>  0.67 0.59 0.52 0.61 0.73 0.00
Now we can input both profiles and use
width_filter to select which ⍺ between horizontal and vertical planes to use for every instance of the model. We can also have one plane a different width than the other at the maximum width for predators that are more ellipsoid in shape.
attack_model(speed = 350, # speed in cm/s model_length = 500, # determines how far away predator starts attack from frequency = 60, # resolution/frame rate in Hz body_length = 146, # cm - from nose to tail body_width_v = 45, # cm - width at maximum width in vertical plane profile_v = sl_profile_v, # shape profile in vertical plane body_width_h = 50, # cm - width at maximum width in horizontal plane profile_h = sl_profile_h, # shape profile in horizontal plane width_filter = "mid") # how to select ⍺ between v and h
width_filter has the following options to select between vertical and horizontal maximum ⍺ if they differ:
"mid"- midpoint or mean value (the default)
"max"- maximum value
"min"- minimum value
"v"- use vertical value only regardless of horizontal value
"h"- use horizontal value only regardless of vertical value
"max_width_v"- use the ⍺ of the vertical max width, ignore all other parts of body
"max_width_h"- use the ⍺ of the horizontal max width, ignore all other parts of body
It depends on the predator shape which of these you may want to use to best represent its ‘true’ ⍺ when using the model in experiments.
The other inputs to the
attack_model function are fairly self explanatory:
The speed need not be a single value, but can be a vector of variable speeds at the input
frequency. In this case,
model_length is not required, and it is assumed the predator meets the prey at the last value in the
speed vector. However, if you want the predator to meet the prey earlier, a
model_length value less than the length of the
speed vector can be entered. Units must be same length unit as morphometric inputs per second.
It is important that all morphometric inputs are in the same length units, and that
speed also uses the same length unit per second.
Resolution of the model in Hz. How many ⍺, d⍺/dt etc. calculated per second. If
speed is a vector should be at same resolution. Equivalent to frame rate or FPS, and any looming animation created by the
loomeR package will use this as the frame rate.
Location of these along the body from the nose as a proportion of the total length. Only required if they are not included as part of the shape profiles.
Plot the resulting ⍺ and d⍺/dt, and specify the X-axis range (in time units).
Plot a range of ⍺ and d⍺/dt. Each input is a vector of two values. If
simple_output = FALSE these ranges are also subset into their own elements of the output
By default (
simple_output = TRUE), the output of
attack_model is a
data.frame with every row representing an instance (or ‘frame’) of the model at the input
frequency. The data frame contains columns for frame, speed, time, time reversed, distance of the nose of the predator, α, and dα/dt.
simple_output = FALSE the output is a
list object given class
attack_model containing the above data frame, plus inputs, subset regions (if ⍺ or d⍺/dt ranges are entered), and data detailing how ⍺ was calculated (interpolated profiles, locations of maximum apparent width at each frame, etc.). This option greatly increases the time the function takes to run. However, it is required if you intend to create a looming animation from the output in the
The output is also plotted by default (
plot = TRUE), and if ⍺ or d⍺/dt ranges are entered these are also plotted.
mod <- attack_model(speed = 350, # speed in cm/s model_length = 500, # determines how far away predator starts attack from frequency = 60, # resolution/frame rate in Hz body_length = 146, # cm - from nose to tail body_width_v = 45, # cm - width at maximum width in vertical plane profile_v = sl_profile_v) # shape profile in vertical plane
get_dist(mod, dadt = 0.90) #> attack_model input - distance is from nose #>  70
At this speed, this predator is 70cm from the prey when the d⍺/dt value of 0.90 is first exceeded.
loomeR package for creating a looming animation from the output of
attackR. For this to work the output must be saved (i.e. assigned) as an object within
R, and the option
simple_output = FALSE must be used. This results in a
list object of class
loomeR will recognise.
(NOTE 13-01-2020 - Not implemented just yet. Coming very soon!)
See here for the much more complicated case of how this approach was applied to attacks by lunge-feeding whales.
Cade D.E., Carey N., Domenici P., Potvin J., & Goldbogen J.A., 2020. Predator-informed looming stimulus experiments reveal how large filter feeding whales capture highly maneuverable forage fish. Proceedings of the National Academy of Sciences, 117 (1) 472-478. https://doi.org/10.1073/pnas.1911099116
Dill L.M., 1974. The escape response of the zebra danio (Brachydanio rerio) I. The stimulus for escape. Animal Behaviour 22, 711–722. https://doi.org/10.1016/S0003-3472(74)80022-9
Domenici, P., Hale, M.E., 2019. Escape responses of fish: a review of the diversity in motor control, kinematics and behaviour. Journal of Experimental Biology 222, jeb166009. https://doi.org/10.1242/jeb.166009
English, A.Wm., 1976. Limb movements and locomotor function in the California sea lion (Zalophus californianus). Journal of Zoology 178, 341–364. https://doi.org/10.1111/j.1469-7998.1976.tb02274.x
Feldkamp, S.D., 1987. Swimming in the California sea lion: morphometrics, drag and energetics. Journal of Experimental Biology 131, 117–135.
Hatsopoulos N., Gabbiani F., & Laurent G., 1995. Elementary computation of object approach by a wide-field visual neuron. Science 270(5238):1000-1003.
Paglianti, A., Domenici, P., 2006. The effect of size on the timing of visually mediated escape behaviour in staghorn sculpin Leptocottus armatus. Journal of Fish Biology 68, 1177–1191. https://doi.org/10.1111/j.0022-1112.2006.00991.x
Preuss T., Osei-Bonsu P.E., Weiss S.A., Wang C., & Faber D.S., 2006. Neural representation of object approach in a decision-making motor circuit. Journal of Neuroscience 26(13):3454-3464.
Temizer I., Donovan J.C., Baier H., & Semmelhack J.L., 2015. A visual pathway for looming-evoked escape in larval zebrafish. Current Biology 25(14):1823-1834.