FLightR analysis example of red-backed shrike geolocator data

0. Set up output and run options

set.seed(123)

To run or to load?

Parts of this code take time to run, so if you want to go through examples fast and do not want to install all the software

Run_everything=FALSE # Change to TRUE if you want run everything by your computer

Online or local data?

This script can operate with online or local data. If Use_local_data is set to TRUE the working directory expected to have folders data. If Run_everything is set to TRUE the results directory will be created and all the results will be saved there.

Use_local_data=FALSE # Change to TRUE if you want to use local data

Checks and downloads

if (Use_local_data) {
   if (!'results' %in% list.dirs(full.names=FALSE, recursive=FALSE)) {
       if (Run_everything) {
          dir.create('results')
       } else {
          stop('results directory not found!')
       }
   } 
   if (!'data' %in% list.dirs(full.names=FALSE, recursive=FALSE)) stop('data directory not found!')
} else {
   if (!'results' %in% list.dirs(full.names=FALSE, recursive=FALSE)) dir.create('results')
   download.file('https://git.io/fAKZH', destfile='./results/Result.RDS', mode='wb')
   download.file('https://git.io/fAK15', destfile='./results/Summary.RDS', mode='wb')
}
if (Use_local_data & !'data' %in% list.dirs(full.names=FALSE, recursive=FALSE)) stop('data directory not found') 

Install package

Note that we used FLightR 0.4.7 version, and running this example in later versions may provide slightly different results. To install the latest CRAN version try

install.packages('FLightR')

To run version 0.4.7 which we use in this example try

library(devtools)
install_github('eldarrak/FLightR@0.4.7')
## Downloading GitHub repo eldarrak/FLightR@0.4.7
## from URL https://api.github.com/repos/eldarrak/FLightR/zipball/0.4.7
## Installation failed: 404: Not Found
##  (404)

The latest version is available here:

install_github('eldarrak/FLightR')

Load package

library(FLightR)

1. Data preparation and import

The procedure of the definition of the twilight events, i.e. sunrises and sunsets, is not implemented in FLightR. For this purpose you can use other R packages, e.g. BAStag, twGeos or GeoLight Lisovski et al. 2012a, or online service http://tags.animalmigration.org. In this software, you will have to search for the twilight times semi-automatically and then visually explore the results, manually removing twilights defined obviously wrong or around which the light pattern is atypical or systematically biased, for instance, when a bird enters or exits a cavity during the twilight (Rakhimberdiev et al. 2016). An example of the routine for the twilight definition in BAStag is available as appendix A4 to Rakhimberdiev et al. 2016.

FLightR works with files of the ‘TAGS’ format, which are CSV files containing the following fields:

  • datetime – date and time in ISO 8601 format e.g. 2013-06-16T00:00:11.000Z;
  • light – light value measured by tag;
  • twilight – assigned by the software numeric indication of whether the record belongs to sunrise (1), sunset (2) or none of those (0);
  • excluded – indication of whether a twilight was excluded during manual inspection (logical, TRUE | FALSE);
  • interp - indication of whether the light value at twilight was interpolated (logical, TRUE | FALSE). The fields excluded and interp may have values of TRUE only for twilight > 0. The online service http://tags.animalmigration.org saves data in the TAGS format. In the R packages GeoLight and BAStag or twGeos, the annotated twilight data need to be exported to TAGS, for which the functions in the FLightR (GeoLight2TAGS, BAStag2TAGS or twGeos2TAGS) can be used.

We will use the TAGS formatted data based on the original .lux file from Pedersen et al..

The original file is available here and the annotated file in tags format here.

The function get.tags.data reads comma separated file in the TAGS format, detects the tag type, checks whether the light data are log-transformed, transforms them back from the log scale if needed and creates an object, containing

  • the recorded light data,
  • the detected twilight events,
  • the light level data at the moment of each determined sunrise and sunset and around them (24 fixes before and 24 after it events into an object of two lists
  • technical parameters of the tag, added automatically, unless preset by the user.

The finction works with all the common tag types: mk tags (produced by British Antarctic Survey, Lotek, and Migrate Technology Ltd.), Intigeo tags (Migrate technology Ltd.) and GDL tags (Swiss Ornithological Institute).

if (Use_local_data) {
   FLightR.data<-get.tags.data("./data/TAGS.M034_08jun15_135409driftadj.csv")
} else {
   FLightR.data<-get.tags.data("https://git.io/fAoHs")
}
## Detected Intigeo_Mode_1 tag
## Data found to be logtransformed
## tag saved data every 300 seconds, and is assumed to measure data every 60 seconds, and write down max

2. Calibration

Geolocators measure light levels with different precision, and calibration is needed to establish the relationship between the observed and the expected light levels for each device. This relationship is depicted by the calibration parameters (slopes), calculated using the data recorded in known (calibration) geographic positions, e.g. where the animal was tagged, recaptured or observed. FLightR uses a ‘template fit’ for calibration Ekstrom 2004, 2007. For each tag it finds the linear (on a log-log scale) relationship between the light levels measured in known locations and the theoretical light levels, estimated from current sun angle in these locations with the deterministic equation developed by Ekstrom Rakhimberdiev et al. 2015.

To calculate the calibration parameters user needs to create a data frame where the geographic coordinates of the calibration location, and the start and end dates of the calibration period, i. e. the period of residence in the known location, are specified: * calibration.start (POSIXct format) * calibration.stop (POSIXct format) * lon (numeric) * lat (numeric) The data frame contains as many rows as many distinct calibration periods the track contains.

Calibration.periods<-data.frame(
        calibration.start=as.POSIXct(c(NA, '2015-05-15')),
        calibration.stop=as.POSIXct(c('2014-07-15', NA)),
        lon=12.23, lat=55.98) 
        #use c() also for the geographic coordinates, 
        #if you have more than one calibration location
        # (e. g.,  lon=c(5.43, 6.00), lat=c(52.93,52.94))
print(Calibration.periods)
##   calibration.start calibration.stop   lon   lat
## 1              <NA>       2014-07-15 12.23 55.98
## 2        2015-05-15             <NA> 12.23 55.98

** Please carefully look at the data.frame you have created!**

The first column should contain dates of the calibration start and the second - ends of the calibration periods.

In this example, we have two calibration periods in the same location, at the beginning and at the end of the track. This is a common case, as the birds are often recaptured at the same location, where they were tagged.

When multiple calibration locations are available, each of them has to be processed with the function plot_slopes_by_location. In this case, in the Calibration periods data frame, each row should refer to one calibration period. Compiling the data frame with multiple calibration locations, use c() also for the geographic coordinates (e. g., lon=c(5.43, 6.00), lat=c(52.93,52.94)).

A Calibration object is compiled with the functionmake.calibration from the created Calibration periods data frame and the FLightR.data object.

if (Run_everything) {
    Calibration<-make.calibration(FLightR.data, Calibration.periods, model.ageing=TRUE)
} else {
    Result<-readRDS(file='./results/Result.RDS')
    Calibration<-Result[[3]]
    rm(Result)
}

This object contains all the calibration parameters for the tag, and it will be further used for calculation of geographic positions across the track. When there are more than one calibration periods, the parameter model.ageing can be set TRUE to account for the tag ageing. In this case, the calibration parameters are calculated, based on the assumption that the calibration slope changes linearly with time. Alternatively, one can use one very long calibration period to try estimating ageing of the tag. We would reccommend to have at least two months in a known location to be able to do that.

Find calibration periods for a known calibration location

The exact period of a tagged animal’s stay in a known location is usually unknown, but it can be derived from the data. For this, calibration slopes for the sunset and sunrise of each day of the tracking period are calculated, based on the assumption that the tag remained in the same known position all the time. The slopes are calculated and plotted with the function plot_slopes_by_location.

plot_slopes_by_location(Proc.data=FLightR.data, location=c(12.23, 55.98), ylim=c(-1.5, 1.5))
## 
 checking dawn 1
 checking dawn 2
 checking dawn 3
 checking dawn 4
 checking dawn 5
 checking dawn 6
 checking dawn 7
 checking dawn 8
 checking dawn 9
 checking dawn 10
 checking dawn 11
 checking dawn 12
 checking dawn 13
 checking dawn 14
 checking dawn 15
 checking dawn 16
 checking dawn 17
 checking dawn 18
 checking dawn 19
 checking dawn 20
 checking dawn 21
 checking dawn 22
 checking dawn 23
 checking dawn 24
 checking dawn 25
 checking dawn 26
 checking dawn 27
 checking dawn 28
 checking dawn 29
 checking dawn 30
 checking dawn 31
 checking dawn 32
 checking dawn 33
 checking dawn 34
 checking dawn 35
 checking dawn 36
 checking dawn 37
 checking dawn 38
 checking dawn 39
 checking dawn 40
 checking dawn 41
 checking dawn 42
 checking dawn 43
 checking dawn 44
 checking dawn 45
 checking dawn 46
 checking dawn 47
 checking dawn 48
 checking dawn 49
 checking dawn 50
 checking dawn 51
 checking dawn 52
 checking dawn 53
 checking dawn 54
 checking dawn 55
 checking dawn 56
 checking dawn 57
 checking dawn 58
 checking dawn 59
 checking dawn 60
 checking dawn 61
 checking dawn 62
 checking dawn 63
 checking dawn 64
 checking dawn 65
 checking dawn 66
 checking dawn 67
 checking dawn 68
 checking dawn 69
 checking dawn 70
 checking dawn 71
 checking dawn 72
 checking dawn 73
 checking dawn 74
 checking dawn 75
 checking dawn 76
 checking dawn 77
 checking dawn 78
 checking dawn 79
 checking dawn 80
 checking dawn 81
 checking dawn 82
 checking dawn 83
 checking dawn 84
 checking dawn 85
 checking dawn 86
 checking dawn 87
 checking dawn 88
 checking dawn 89
 checking dawn 90
 checking dawn 91
 checking dawn 92
 checking dawn 93
 checking dawn 94
 checking dawn 95
 checking dawn 96
 checking dawn 97
 checking dawn 98
 checking dawn 99
 checking dawn 100
 checking dawn 101
 checking dawn 102
 checking dawn 103
 checking dawn 104
 checking dawn 105
 checking dawn 106
 checking dawn 107
 checking dawn 108
 checking dawn 109
 checking dawn 110
 checking dawn 111
 checking dawn 112
 checking dawn 113
 checking dawn 114
 checking dawn 115
 checking dawn 116
 checking dawn 117
 checking dawn 118
 checking dawn 119
 checking dawn 120
 checking dawn 121
 checking dawn 122
 checking dawn 123
 checking dawn 124
 checking dawn 125
 checking dawn 126
 checking dawn 127
 checking dawn 128
 dawn 128 was excluded from the calibration
 checking dawn 129
 dawn 129 was excluded from the calibration
 checking dawn 130
 checking dawn 131
 dawn 131 was excluded from the calibration
 checking dawn 132
 checking dawn 133
 dawn 133 was excluded from the calibration
 checking dawn 134
 dawn 134 was excluded from the calibration
 checking dawn 135
 dawn 135 was excluded from the calibration
 checking dawn 136
 dawn 136 was excluded from the calibration
 checking dawn 137
 dawn 137 was excluded from the calibration
 checking dawn 138
 dawn 138 was excluded from the calibration
 checking dawn 139
 dawn 139 was excluded from the calibration
 checking dawn 140
 dawn 140 was excluded from the calibration
 checking dawn 141
 dawn 141 was excluded from the calibration
 checking dawn 142
 dawn 142 was excluded from the calibration
 checking dawn 143
 dawn 143 was excluded from the calibration
 checking dawn 144
 dawn 144 was excluded from the calibration
 checking dawn 145
 dawn 145 was excluded from the calibration
 checking dawn 146
 dawn 146 was excluded from the calibration
 checking dawn 147
 dawn 147 was excluded from the calibration
 checking dawn 148
 dawn 148 was excluded from the calibration
 checking dawn 149
 dawn 149 was excluded from the calibration
 checking dawn 150
 dawn 150 was excluded from the calibration
 checking dawn 151
 dawn 151 was excluded from the calibration
 checking dawn 152
 dawn 152 was excluded from the calibration
 checking dawn 153
 dawn 153 was excluded from the calibration
 checking dawn 154
 dawn 154 was excluded from the calibration
 checking dawn 155
 dawn 155 was excluded from the calibration
 checking dawn 156
 dawn 156 was excluded from the calibration
 checking dawn 157
 dawn 157 was excluded from the calibration
 checking dawn 158
 dawn 158 was excluded from the calibration
 checking dawn 159
 dawn 159 was excluded from the calibration
 checking dawn 160
 dawn 160 was excluded from the calibration
 checking dawn 161
 dawn 161 was excluded from the calibration
 checking dawn 162
 dawn 162 was excluded from the calibration
 checking dawn 163
 dawn 163 was excluded from the calibration
 checking dawn 164
 dawn 164 was excluded from the calibration
 checking dawn 165
 dawn 165 was excluded from the calibration
 checking dawn 166
 dawn 166 was excluded from the calibration
 checking dawn 167
 dawn 167 was excluded from the calibration
 checking dawn 168
 dawn 168 was excluded from the calibration
 checking dawn 169
 dawn 169 was excluded from the calibration
 checking dawn 170
 dawn 170 was excluded from the calibration
 checking dawn 171
 dawn 171 was excluded from the calibration
 checking dawn 172
 dawn 172 was excluded from the calibration
 checking dawn 173
 dawn 173 was excluded from the calibration
 checking dawn 174
 dawn 174 was excluded from the calibration
 checking dawn 175
 dawn 175 was excluded from the calibration
 checking dawn 176
 dawn 176 was excluded from the calibration
 checking dawn 177
 dawn 177 was excluded from the calibration
 checking dawn 178
 dawn 178 was excluded from the calibration
 checking dawn 179
 dawn 179 was excluded from the calibration
 checking dawn 180
 dawn 180 was excluded from the calibration
 checking dawn 181
 dawn 181 was excluded from the calibration
 checking dawn 182
 dawn 182 was excluded from the calibration
 checking dawn 183
 dawn 183 was excluded from the calibration
 checking dawn 184
 dawn 184 was excluded from the calibration
 checking dawn 185
 dawn 185 was excluded from the calibration
 checking dawn 186
 dawn 186 was excluded from the calibration
 checking dawn 187
 dawn 187 was excluded from the calibration
 checking dawn 188
 dawn 188 was excluded from the calibration
 checking dawn 189
 dawn 189 was excluded from the calibration
 checking dawn 190
 dawn 190 was excluded from the calibration
 checking dawn 191
 dawn 191 was excluded from the calibration
 checking dawn 192
 dawn 192 was excluded from the calibration
 checking dawn 193
 dawn 193 was excluded from the calibration
 checking dawn 194
 dawn 194 was excluded from the calibration
 checking dawn 195
 dawn 195 was excluded from the calibration
 checking dawn 196
 dawn 196 was excluded from the calibration
 checking dawn 197
 dawn 197 was excluded from the calibration
 checking dawn 198
 dawn 198 was excluded from the calibration
 checking dawn 199
 dawn 199 was excluded from the calibration
 checking dawn 200
 dawn 200 was excluded from the calibration
 checking dawn 201
 dawn 201 was excluded from the calibration
 checking dawn 202
 dawn 202 was excluded from the calibration
 checking dawn 203
 dawn 203 was excluded from the calibration
 checking dawn 204
 dawn 204 was excluded from the calibration
 checking dawn 205
 dawn 205 was excluded from the calibration
 checking dawn 206
 dawn 206 was excluded from the calibration
 checking dawn 207
 dawn 207 was excluded from the calibration
 checking dawn 208
 dawn 208 was excluded from the calibration
 checking dawn 209
 dawn 209 was excluded from the calibration
 checking dawn 210
 dawn 210 was excluded from the calibration
 checking dawn 211
 dawn 211 was excluded from the calibration
 checking dawn 212
 dawn 212 was excluded from the calibration
 checking dawn 213
 dawn 213 was excluded from the calibration
 checking dawn 214
 dawn 214 was excluded from the calibration
 checking dawn 215
 dawn 215 was excluded from the calibration
 checking dawn 216
 dawn 216 was excluded from the calibration
 checking dawn 217
 dawn 217 was excluded from the calibration
 checking dawn 218
 dawn 218 was excluded from the calibration
 checking dawn 219
 dawn 219 was excluded from the calibration
 checking dawn 220
 dawn 220 was excluded from the calibration
 checking dawn 221
 dawn 221 was excluded from the calibration
 checking dawn 222
 dawn 222 was excluded from the calibration
 checking dawn 223
 dawn 223 was excluded from the calibration
 checking dawn 224
 dawn 224 was excluded from the calibration
 checking dawn 225
 dawn 225 was excluded from the calibration
 checking dawn 226
 dawn 226 was excluded from the calibration
 checking dawn 227
 dawn 227 was excluded from the calibration
 checking dawn 228
 dawn 228 was excluded from the calibration
 checking dawn 229
 dawn 229 was excluded from the calibration
 checking dawn 230
 dawn 230 was excluded from the calibration
 checking dawn 231
 dawn 231 was excluded from the calibration
 checking dawn 232
 dawn 232 was excluded from the calibration
 checking dawn 233
 checking dawn 234
 checking dawn 235
 checking dawn 236
 checking dawn 237
 checking dawn 238
 checking dawn 239
 checking dawn 240
 checking dawn 241
 checking dawn 242
 checking dawn 243
 dawn 243 was excluded from the calibration
 checking dawn 244
 checking dawn 245
 checking dawn 246
 checking dawn 247
 checking dawn 248
 checking dawn 249
 checking dawn 250
 checking dawn 251
 checking dawn 252
 checking dawn 253
 checking dawn 254
 checking dawn 255
 checking dawn 256
 checking dawn 257
 checking dawn 258
 checking dawn 259
 checking dawn 260
 checking dawn 261
 checking dawn 262
 checking dawn 263
 checking dawn 264
 checking dawn 265
 checking dawn 266
 checking dawn 267
 checking dawn 268
 checking dawn 269
 checking dawn 270
 checking dawn 271
 checking dawn 272
 checking dawn 273
 checking dawn 274
 checking dawn 275
 checking dawn 276
 checking dawn 277
 checking dawn 278
 checking dawn 279
 checking dawn 280
 checking dawn 281
 checking dawn 282
 checking dawn 283
 checking dawn 284
 checking dawn 285
 checking dawn 286
 checking dawn 287
 checking dawn 288
 checking dawn 289
 checking dawn 290
 dawn 290 was excluded from the calibration
 checking dawn 291
 checking dawn 292
 checking dawn 293
 checking dawn 294
 checking dawn 295
 checking dawn 296
 checking dawn 297
 checking dawn 298
 checking dawn 299
 checking dawn 300
 checking dawn 301
 checking dawn 302
 checking dawn 303
 checking dawn 304
 checking dawn 305
 checking dawn 306
 checking dawn 307
 checking dawn 308
 checking dawn 309
 checking dawn 310
 checking dawn 311
 checking dawn 312
 checking dawn 313
 checking dawn 314
 checking dawn 315
 checking dawn 316
 checking dawn 317
 checking dawn 318
 checking dawn 319
 checking dawn 320
 checking dawn 321
 checking dawn 322
 checking dawn 323
 checking dawn 324
 checking dawn 325
 checking dawn 326
 checking dawn 327
 checking dawn 328
 checking dawn 329
 checking dawn 330
 checking dawn 331
 checking dawn 332
 checking dawn 333
 checking dawn 334
 checking dawn 335
 checking dawn 336
 checking dawn 337
 checking dawn 338
 checking dawn 339
 checking dawn 340
 checking dawn 341
 checking dawn 342
 checking dawn 343
 checking dawn 344
 checking dawn 345
 checking dawn 346
 checking dusk 1
 checking dusk 2
 checking dusk 3
 checking dusk 4
 checking dusk 5
 checking dusk 6
 checking dusk 7
 checking dusk 8
 checking dusk 9
 checking dusk 10
 checking dusk 11
 checking dusk 12
 checking dusk 13
 checking dusk 14
 checking dusk 15
 checking dusk 16
 checking dusk 17
 checking dusk 18
 checking dusk 19
 checking dusk 20
 checking dusk 21
 checking dusk 22
 checking dusk 23
 checking dusk 24
 checking dusk 25
 checking dusk 26
 checking dusk 27
 checking dusk 28
 checking dusk 29
 checking dusk 30
 checking dusk 31
 checking dusk 32
 checking dusk 33
 checking dusk 34
 checking dusk 35
 checking dusk 36
 checking dusk 37
 checking dusk 38
 checking dusk 39
 checking dusk 40
 checking dusk 41
 checking dusk 42
 checking dusk 43
 checking dusk 44
 checking dusk 45
 checking dusk 46
 checking dusk 47
 checking dusk 48
 checking dusk 49
 checking dusk 50
 checking dusk 51
 checking dusk 52
 checking dusk 53
 checking dusk 54
 checking dusk 55
 checking dusk 56
 checking dusk 57
 checking dusk 58
 checking dusk 59
 checking dusk 60
 checking dusk 61
 checking dusk 62
 checking dusk 63
 checking dusk 64
 checking dusk 65
 checking dusk 66
 checking dusk 67
 checking dusk 68
 checking dusk 69
 checking dusk 70
 checking dusk 71
 checking dusk 72
 checking dusk 73
 checking dusk 74
 checking dusk 75
 checking dusk 76
 checking dusk 77
 checking dusk 78
 checking dusk 79
 checking dusk 80
 checking dusk 81
 checking dusk 82
 checking dusk 83
 checking dusk 84
 checking dusk 85
 checking dusk 86
 checking dusk 87
 checking dusk 88
 checking dusk 89
 checking dusk 90
 checking dusk 91
 checking dusk 92
 checking dusk 93
 checking dusk 94
 checking dusk 95
 checking dusk 96
 checking dusk 97
 checking dusk 98
 checking dusk 99
 checking dusk 100
 checking dusk 101
 checking dusk 102
 checking dusk 103
 checking dusk 104
 checking dusk 105
 checking dusk 106
 checking dusk 107
 checking dusk 108
 checking dusk 109
 checking dusk 110
 checking dusk 111
 checking dusk 112
 checking dusk 113
 checking dusk 114
 checking dusk 115
 checking dusk 116
 checking dusk 117
 checking dusk 118
 checking dusk 119
 checking dusk 120
 checking dusk 121
 checking dusk 122
 checking dusk 123
 checking dusk 124
 checking dusk 125
 checking dusk 126
 checking dusk 127
 checking dusk 128
 checking dusk 129
 checking dusk 130
 checking dusk 131
 checking dusk 132
 checking dusk 133
 checking dusk 134
 dusk 134 was excluded from the calibration
 checking dusk 135
 dusk 135 was excluded from the calibration
 checking dusk 136
 checking dusk 137
 checking dusk 138
 dusk 138 was excluded from the calibration
 checking dusk 139
 dusk 139 was excluded from the calibration
 checking dusk 140
 dusk 140 was excluded from the calibration
 checking dusk 141
 dusk 141 was excluded from the calibration
 checking dusk 142
 dusk 142 was excluded from the calibration
 checking dusk 143
 checking dusk 144
 dusk 144 was excluded from the calibration
 checking dusk 145
 dusk 145 was excluded from the calibration
 checking dusk 146
 checking dusk 147
 dusk 147 was excluded from the calibration
 checking dusk 148
 dusk 148 was excluded from the calibration
 checking dusk 149
 dusk 149 was excluded from the calibration
 checking dusk 150
 checking dusk 151
 dusk 151 was excluded from the calibration
 checking dusk 152
 dusk 152 was excluded from the calibration
 checking dusk 153
 checking dusk 154
 dusk 154 was excluded from the calibration
 checking dusk 155
 dusk 155 was excluded from the calibration
 checking dusk 156
 dusk 156 was excluded from the calibration
 checking dusk 157
 dusk 157 was excluded from the calibration
 checking dusk 158
 dusk 158 was excluded from the calibration
 checking dusk 159
 dusk 159 was excluded from the calibration
 checking dusk 160
 dusk 160 was excluded from the calibration
 checking dusk 161
 dusk 161 was excluded from the calibration
 checking dusk 162
 dusk 162 was excluded from the calibration
 checking dusk 163
 dusk 163 was excluded from the calibration
 checking dusk 164
 dusk 164 was excluded from the calibration
 checking dusk 165
 dusk 165 was excluded from the calibration
 checking dusk 166
 dusk 166 was excluded from the calibration
 checking dusk 167
 dusk 167 was excluded from the calibration
 checking dusk 168
 dusk 168 was excluded from the calibration
 checking dusk 169
 dusk 169 was excluded from the calibration
 checking dusk 170
 dusk 170 was excluded from the calibration
 checking dusk 171
 dusk 171 was excluded from the calibration
 checking dusk 172
 dusk 172 was excluded from the calibration
 checking dusk 173
 dusk 173 was excluded from the calibration
 checking dusk 174
 dusk 174 was excluded from the calibration
 checking dusk 175
 dusk 175 was excluded from the calibration
 checking dusk 176
 dusk 176 was excluded from the calibration
 checking dusk 177
 dusk 177 was excluded from the calibration
 checking dusk 178
 dusk 178 was excluded from the calibration
 checking dusk 179
 dusk 179 was excluded from the calibration
 checking dusk 180
 dusk 180 was excluded from the calibration
 checking dusk 181
 dusk 181 was excluded from the calibration
 checking dusk 182
 dusk 182 was excluded from the calibration
 checking dusk 183
 dusk 183 was excluded from the calibration
 checking dusk 184
 dusk 184 was excluded from the calibration
 checking dusk 185
 dusk 185 was excluded from the calibration
 checking dusk 186
 dusk 186 was excluded from the calibration
 checking dusk 187
 dusk 187 was excluded from the calibration
 checking dusk 188
 dusk 188 was excluded from the calibration
 checking dusk 189
 dusk 189 was excluded from the calibration
 checking dusk 190
 dusk 190 was excluded from the calibration
 checking dusk 191
 dusk 191 was excluded from the calibration
 checking dusk 192
 dusk 192 was excluded from the calibration
 checking dusk 193
 dusk 193 was excluded from the calibration
 checking dusk 194
 dusk 194 was excluded from the calibration
 checking dusk 195
 dusk 195 was excluded from the calibration
 checking dusk 196
 dusk 196 was excluded from the calibration
 checking dusk 197
 dusk 197 was excluded from the calibration
 checking dusk 198
 dusk 198 was excluded from the calibration
 checking dusk 199
 dusk 199 was excluded from the calibration
 checking dusk 200
 dusk 200 was excluded from the calibration
 checking dusk 201
 dusk 201 was excluded from the calibration
 checking dusk 202
 dusk 202 was excluded from the calibration
 checking dusk 203
 dusk 203 was excluded from the calibration
 checking dusk 204
 dusk 204 was excluded from the calibration
 checking dusk 205
 dusk 205 was excluded from the calibration
 checking dusk 206
 dusk 206 was excluded from the calibration
 checking dusk 207
 checking dusk 208
 checking dusk 209
 dusk 209 was excluded from the calibration
 checking dusk 210
 checking dusk 211
 checking dusk 212
 checking dusk 213
 checking dusk 214
 checking dusk 215
 checking dusk 216
 checking dusk 217
 checking dusk 218
 dusk 218 was excluded from the calibration
 checking dusk 219
 checking dusk 220
 checking dusk 221
 checking dusk 222
 checking dusk 223
 checking dusk 224
 checking dusk 225
 checking dusk 226
 checking dusk 227
 checking dusk 228
 checking dusk 229
 checking dusk 230
 checking dusk 231
 checking dusk 232
 checking dusk 233
 checking dusk 234
 checking dusk 235
 dusk 235 was excluded from the calibration
 checking dusk 236
 checking dusk 237
 checking dusk 238
 checking dusk 239
 checking dusk 240
 checking dusk 241
 checking dusk 242
 checking dusk 243
 checking dusk 244
 checking dusk 245
 checking dusk 246
 checking dusk 247
 checking dusk 248
 checking dusk 249
 checking dusk 250
 checking dusk 251
 checking dusk 252
 checking dusk 253
 checking dusk 254
 checking dusk 255
 checking dusk 256
 checking dusk 257
 checking dusk 258
 checking dusk 259
 checking dusk 260
 checking dusk 261
 checking dusk 262
 checking dusk 263
 checking dusk 264
 checking dusk 265
 checking dusk 266
 checking dusk 267
 checking dusk 268
 checking dusk 269
 checking dusk 270
 checking dusk 271
 checking dusk 272
 checking dusk 273
 checking dusk 274
 checking dusk 275
 checking dusk 276
 checking dusk 277
 checking dusk 278
 checking dusk 279
 checking dusk 280
 checking dusk 281
 checking dusk 282
 checking dusk 283
 checking dusk 284
 checking dusk 285
 checking dusk 286
 checking dusk 287
 checking dusk 288
 checking dusk 289
 checking dusk 290
 checking dusk 291
 checking dusk 292
 checking dusk 293
 checking dusk 294
 checking dusk 295
 checking dusk 296
 checking dusk 297
 checking dusk 298
 checking dusk 299
 checking dusk 300
 checking dusk 301
 checking dusk 302
 checking dusk 303
 checking dusk 304
 checking dusk 305
 checking dusk 306
 checking dusk 307
 checking dusk 308
 checking dusk 309
 checking dusk 310
 checking dusk 311
 checking dusk 312
 checking dusk 313
 checking dusk 314
 checking dusk 315
 checking dusk 316
 checking dusk 317
 checking dusk 318
 checking dusk 319
 checking dusk 320
 checking dusk 321
 checking dusk 322
 checking dusk 323
 checking dusk 324
 checking dusk 325
 checking dusk 326
 checking dusk 327
 checking dusk 328
 checking dusk 329
 checking dusk 330
 checking dusk 331
 checking dusk 332
 checking dusk 333
 checking dusk 334
 checking dusk 335
 checking dusk 336
 checking dusk 337
 checking dusk 338
 checking dusk 339
 checking dusk 340
 checking dusk 341
 checking dusk 342
 checking dusk 343
 checking dusk 344


## calibration method used: parametric.slope
## NULL
abline(v=as.POSIXct("2015-05-15")) # end of first calibration period
abline(v=as.POSIXct("2014-07-15")) # start of the second calibration period

Looking at the plot, we can define the time periods, during which the tag resided in the calibration location (recall, that we assume that the tag remained in this location all the time). Because calibration slopes reflect the adequacy of the light level measured by the device, they vary little, in time and between sunsets and sunrises, as long as the tagged animal stays in the calibration location, but become apparently diverse, when it moves away from it. Both patterns are clearly distinguishable at the plot.

Play with abline() to find the proper boundaries for the calibration.

With the current tag it is a bit complicated to see the end of the calibration period and also the first arrival back to the calibration site. To solve the problem we have made two runs - first with the obcvious short calibration period:

Calibration.periods<-data.frame(
        calibration.start=as.POSIXct(c(NA)),
        calibration.stop=as.POSIXct(c("2014-07-07")),
        lon=12.23, lat=55.98) 

We ran the full estimation procedure with based on this short calibration. Looked at bird departure and arrival dates from and to breeding site (with simple plot_lon_lat(Result)), used these dates to create new calibration periods and to run the final analysis. If you will do the same, please note, that you should select edges of the calibration period on a safe side - at least 24 hours before the migration.

Find a calibration location for a known calibration period

It may happen that an animal was tagged in the High Arctic under polar day conditions or that it moved far away from the capture site immedialtly after tagging and the roof-top calibration data are not available. Even in such cases it is still possibe to obtain calibration parameters for a resident period at unknown location. FLightR approach to this problem is similar to Hill-Ekstrom calibration Lisovski et al. 2012b implemented in GeoLight Lisovksi et al. 2012a. If bird is assumed to be resident at some period one can try:

# ~ 15 min run time
Location<-find.stationary.location(FLightR.data, '2014-09-05', '2014-10-07',
                                   initial.coords=c(25, -10))

After 15 minutes the function will return geographic coordinates of the location for which the range of errors in slopes is minimal. User has to provide the initial coordinates, which should be within a few thousand kilometers from the hypothetical real location.

Note that this function is experimental and does not always produce meaningful results . Try it from different initial locations, and check whether it gets to the same result.

3. Assign spatial extent

Before running the model you will have to make a scientific guess on where you expect your bird to fly and assign a spatial grid (50 X 50 km) with user-defined boundaries, within which your model will calculate probabilities of presence of the birds. The wider you set the grid boundaries,the longer will take the model to run. If you have set the boundaries too narrow, you will see it in the output map: the defined location points will bounce close to the grid boundaries (as in our example XXXX). In this case you will have to extend the grid and re-run the model.
To set up the grid use the function make.grid and define the boundaries: left, right. bottom and top. It is possible that your tagged animal cannot occur or stay between two subsequent twilights over particular areas, for example, over open water if it is a landbird or deep inland if it is a marine animal. In this case we recommend to apply additional parameters distance.from.land.allowed.to.use and distance.from.land.allowed.to.stay. Such restrictions will minimize the area processed and this way facilitate the analysis. Each of the parameters require a vector of two numbers: the minimal and the maximal distances (in km) from shoreline, at which the animal is allowed to occur/stay. The numbers can be negative. For instance, distance.from.land.allowed.to.stay=-30, will not allow your bird to stay further than 30 km inland from the shore. In our example we allow our shrike to fly over the water, but not further than 200 km offshore, and to be statuionary within 50 km from the land.

Grid<-make.grid(left=5, bottom=-33, right=50, top=60,
   distance.from.land.allowed.to.use=c(-Inf, 200),
   distance.from.land.allowed.to.stay=c(-Inf, 50))

The resulting Grid is a matrix with the columns: lon (longitude), lat (latitude) and Stay (probability of stay). Grid cells that presumably cannot be visited by the animal are excluded from the data, while the locations at which an animal cannot be stationary are given a low probability of stay. The function produces a visual representation of the created grid with orange poins where the bird is allowed to be stationary and grey, where the bird can fly but not stay. Have a look at the figure and make sure it is correct. Using masks can side track model estimation to the local minima, and we recommend to initially run the model without the mask, enable the mask for the second run and visually compare the results to see if the model has converged to similar tracks.

4. Prepare the model for run

At this stage, all the objects, created at earlier steps: the light data with the detected twilight events (FLightR.data), the spatial parameters (Grid), geographic coordinates of the initial location, where the tracking has started (start), and the calibration parameters (Calibration), are to be incorporated in one complex object , which will be used in the main run. Use the function make.prerun.object for the compilation. Using this function you can also change the priors for the movement model. For example we set M.mean parameter to 750 km, because we know that shrikes migrate fast and also because we have explored the results and figured out that average migration distance was actually 750 km.

if (Run_everything) {
   # ~ 15 min run time
   all.in<-make.prerun.object(FLightR.data, Grid, start=c(12.23, 55.98),
                              Calibration=Calibration, M.mean=750)
} else {
    Result<-readRDS(file='./results/Result.RDS')
    all.in<-Result[-c(5,6)]
    rm(Result)
}                              

5. Particle filter run

Once you have got the “run.particle.filter” running, expect your computer to be busy for about 45 minutes. During this time it will generate the model output (we will call it “Results”) containing: * a table of positions at each twilight ($Results$Quantiles), * statistics of the positions (mean, median values and credible intervals), * a table of parameters of the movement model ($Results$Movement.results), * posterior distribution of the parameters at every twilight ($Results$Points.rle) and * at every transition between twilights ($Results$Transitions.rle).

Within run.particle.filter, the following parameters can be defined: * nParticles - number of particles (we recommend to use 1e4 for test and 1e6 for the analysis); * threads - amount of parallel threads to use for the run default is -1 that means all available except one; * known.last - TRUE if you know that in the end of the logging period tag occurred in a known place (FALSE is the default option); * check.outliers – FALSE by default. Set it to TRUE if you wish on-the-fly outliers detection, highly recommended if the results have strong outliers. * b - the maximum distance allowed to be travelled between two subsequent twilights.

if (Run_everything) {
nParticles=1e6
Result<-run.particle.filter(all.in, threads=-1,
            nParticles=nParticles, known.last=TRUE,
            precision.sd=25, check.outliers=F, 
            b=1700)
    saveRDS(Result, file='./results/Result.RDS')
} else {
    Result<-readRDS(file='./results/Result.RDS')
}

6. First exploration - plot longitude and latitude

After the results have been saved the first thing to do is to plot change of longitude and latitude over time. This is a very important graph.

plot_lon_lat(Result)

With this graph, please, carefully check whether: 1. Your track does not approach boundaries of the spatial grid you defined (you ave to keep those in mind assessing the graph). If this is the case, change spatial extend and rerun the analysis. 2. There are no sudden jumps that have no uncertainty measurements around them. These are likely outliers that should be excluded beforehands. 3. Presented by the model estiamates of time-periods spent by the bird at the calibration site match calibration periods assigned before the model run. If they do not, correct the calibration periods, redo the calibration and rerun the model. 4. There are no S-shape patterns in estimated latitude around equinox. Such patterns point at either incorrect calibration or very poor data. Try to improve your calibration periods or concider taking calibration data from another tag taken from the same species.

7. Summary

Repeatability of output

Note that however many times you will re-run the model with the same input parameters, you will never get the same output. Please, do not panic, as stochasticity of probabilities is an inherent feature of Bayesian analysis. Also, if you look closer at your results, you will notice that the outputs vary within each others’ standard errors.

Defining stopovers

FLightR is honest defining stopovers, which may seem a disappointing feature, but it makes us thinking. In general, geolocation analysis is all about how likely the bird was present in specific location at specific moment and how likely it was moving between two subsequent locations. It is not a problem when you work with long-distance migrants, such as bar-tailed godwit Rakhimberdiev et al. 2016, since it has very apparent stopover phases between apparent migration-flight bouts. However, many bird species migrate in little hops and literary stop “at every bush”. Here you can get rather messy results, due to the overlapping probability distributions. In any case, we recommend to play with the stopover probabilities by tweaking the cut-off probability parameter of 1stationary.migration.summary`. Recall that for each location and time moment the model generates a probability that the bird was moving to the next location. The cut-off probability is the minimal threshold probability of movement, at which we assume that the bird was actually moving. Depending on the assigned cut-off probability parameter, the model will consider the bird more or less likely to be stationary. In birds migrating in long leaps with few stops, defined stopovers are usually rather robust. However, in hopping migrants, probabilities of stopovers may vary, depending on the chosen cut-off probability parameter, which is a bad news if describing stopovers is the prior goal of your study. But, frankly speaking, what is stopover and does it exist in migrants moving in short hops? Presenting your results, you may arbitrarily choose the most adequate (repeatable) output and mention the cut-off probability, with which it was obtained. However, if you want to describe stopovers explicitly, you might want to present outputs obtained with several cut-off probability parameters and speculate about the variation. Most likely, some of your stopovers will be defined repeatedly with a range of cut-off parameters being assigned, and some will be less robust. Our shrike had rather distinct migration/stopover pattern. However, we get a slightly more stopovers with cut-off probabilities of 0.1 and 0.2.

To distinguish between the phases of movement and stationarity use the function stationary.migration.summary helps . The process usually takes around 15 minutes of computer time.

if (Run_everything) {
   Summary<-stationary.migration.summary(Result, prob.cutoff = 0.2)
   saveRDS(Summary, file='./results/Summary.RDS')
} else {
   Summary<-readRDS(file='./results/Summary.RDS')
}

To visualise results of this function we will plot them on a map.

# Now we want to plot the detected stationary periods on a map
Summary$Stationary.periods$stopover_duration<-as.numeric(difftime(Summary$Stationary.periods$Departure.Q.50,Summary$Stationary.periods$Arrival.Q.50, units='days'))
# Now I want to select the periods which were >=2 days and 
Main_stopovers<-Summary$Stationary.periods[is.na(Summary$Stationary.periods$stopover_duration) | Summary$Stationary.periods$stopover_duration>=2,]
# delete breeding season
Main_stopovers<-Main_stopovers[-which(is.na(Main_stopovers$stopover_duration)),]

Coords2plot<-cbind(Result$Results$Quantiles$Medianlat, Result$Results$Quantiles$Medianlon)

for (i in 1:nrow(Summary$Potential_stat_periods)) {
  Coords2plot[Summary$Potential_stat_periods[i,1]:
    Summary$Potential_stat_periods[i,2],1] =  
    Summary$Stationary.periods$Medianlat[i]
   
  Coords2plot[Summary$Potential_stat_periods[i,1]:
    Summary$Potential_stat_periods[i,2],2] =  
    Summary$Stationary.periods$Medianlon[i]
}
Coords2plot<-Coords2plot[!duplicated(Coords2plot),]

library(maps)
library(mapdata)

#pdf('FLightR_shrike_migration_with_stopovers.pdf', width=6, height=9)
par(mar=c(0,0,0,0))
map('worldHires', ylim=c(-35, 60), xlim=c(-20, 50), col=grey(0.7),
    fill=TRUE, border=grey(0.9), mar=rep(0.5, 4), myborder=0)

lines(Coords2plot[,1]~Coords2plot[,2], col='red', lwd=2)
points(Coords2plot[,1]~Coords2plot[,2], ,lwd=2, col='red', pch=19)

# Here we assign the colours to represent time of the year
Seasonal_palette<-grDevices::colorRampPalette(grDevices::hsv(1-((1:365)+(365/4))%%365/365,
                                              s=0.8, v=0.8), space="Lab")
Seasonal_colors<-Seasonal_palette(12)

Main_stopovers$Main_month<-as.numeric(format(Main_stopovers$Arrival.Q.50+
                                             Main_stopovers$stopover_duration/2, format='%m'))

points(Main_stopovers$Medianlat~Main_stopovers$Medianlon, pch=21, 
       cex=log(as.numeric(Main_stopovers$stopover_duration)),
       bg=Seasonal_colors[Main_stopovers$Main_month])

# Now, for each of these points we plot the uncertainties
# Horizontal
segments(y0=Main_stopovers$Medianlat, x0=Main_stopovers$FstQu.lon,
         x1=Main_stopovers$TrdQu.lon, lwd=2)
# Vertical
segments(x0=Main_stopovers$Medianlon, y0=Main_stopovers$FstQu.lat,
         y1=Main_stopovers$TrdQu.lat, lwd=2)

# and we also need to add breeding site here:
points(x=12.23, y=55.98, cex=6, pch=21 , bg=Seasonal_colors[6])

# dev.off()

8. Getting specific output

The function find.times.distribution derives the time at which an animal arrived or departed from the area and provides the measure of its uncertainty. First, select grid points of interest. For example in the current data we are interested in the date when our bird left from the breding grounds and when it was back. We will make a boundary at 55.5&deg latitude:

Index<-which(Result$Spatial$Grid[,2]>55)

Estimate probabilities of occurrence within the area at each twilight:

Arrivals.breeding<-find.times.distribution(Result,Index)
print(Arrivals.breeding)
##                 Q.025                Q.25                Q.50
## 1 2014-07-16 03:05:31 2014-07-22 20:57:33 2014-07-23 01:24:22
## 2 2015-05-12 08:51:25 2015-05-12 23:41:42 2015-05-13 06:19:53
##                  Q.75               Q.975
## 1 2014-07-23 04:50:07 2014-07-24 04:45:13
## 2 2015-05-20 17:56:25 2015-05-26 09:59:18

9. Visualisation of the results

Plot a simple map

Plot a map with the most probable positions, i. e. combinations of the most probable latitude and longitude for each twilight:

library(grid)
try(map.FLightR.ggmap(Result, zoom=3))
## Source : https://maps.googleapis.com/maps/api/staticmap?center=15.975,28.351289&zoom=3&size=640x640&scale=2&maptype=terrain&language=en-EN
## Scale for 'x' is already present. Adding another scale for 'x', which
## will replace the existing scale.
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
## Saving 7 x 5 in image

Plot utilization distribution

Plot space utilisation distribution for the wintering range:

try(plot_util_distr(Result, 
    dates=data.frame(as.POSIXct('2014-12-01'), as.POSIXct('2015-01-31')),
    add.scale.bar=TRUE, percentiles=0.5, zoom=7))
## function will plot 122 twilights
## Warning: bounding box given to google - spatial extent only approximate.
## converting bounding box to center/zoom specification. (experimental)
## Source : https://maps.googleapis.com/maps/api/staticmap?center=-21.37494,19.083408&zoom=7&size=640x640&scale=2&maptype=terrain&language=en-EN
## Saving 7 x 5 in image

## $res_buffers
## class       : SpatialPolygonsDataFrame 
## features    : 1 
## extent      : 18.58561, 19.58121, -22.88378, -19.8661  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
## variables   : 1
## names       : percentile 
## value       :        0.5 
## 
## $p

## 
## $bg
## 1280x1280 terrain map image from Google Maps.  see ?ggmap to plot it.

References

  1. Ekstrom, P. (2004). An advance in geolocation by light. Memoirs of the National Insitute of Polar Research, Special Issue, 58, 210–226.
  2. Ekstrom, P. (2007). Error measures for template-fit geolocation based on light. Deep Sea Research Part II: Topical Studies in Oceanography, 54, 392–403.
  3. Lisovski, S., Hahn, S. & Hodgson, D. (2012a). GeoLight - processing and analysing light-based geolocator data in R. Methods in Ecology and Evolution, 3, 1055–1059.
  4. Lisovski, S., Hewson, C.M., Klaassen, R.H.G., Korner-Nievergelt, F., Kristensen, M.W. & Hahn, S. (2012b). Geolocation by light: accuracy and precision affected by environmental factors. Methods in Ecology and Evolution, 3, 603–612.
  5. Pedersen L., et. al.
  6. Rakhimberdiev, E., Winkler, D.W., Bridge, E., Seavy, N.E., Sheldon, D., Piersma, T. & Saveliev, A. (2015). A hidden Markov model for reconstructing animal paths from solar geolocation loggers using templates for light intensity. Movement Ecology, 3, 25.
  7. Rakhimberdiev, E., Senner, N. R., Verhoeven, M. A., Winkler, D. W., Bouten, W. and Piersma T. (2016) Comparing inferences of solar geolocation data against high-precision GPS data: annual movements of a double-tagged Black-Tailed Godwit. - Journal of Avian Biology 47: 589-596.

P.S. The html file from this markdown can be recereated with folloing code

download.file('https://git.io/fAKP5', 'tmp2.rmd', cacheOK = FALSE)
rmarkdown::render('tmp2.rmd', output_format = 'html_document',
        output_options=list(toc=TRUE, toc_float=list(collapsed=FALSE)), 
        encoding='utf-8')