Title: | Sound Waves Onto Morphometric Data |
---|---|
Description: | Implement a promising, and yet little explored protocol for bioacoustical analysis, the eigensound method by MacLeod, Krieger and Jones (2013) <doi:10.4404/hystrix-24.1-6299>. Eigensound is a multidisciplinary method focused on the direct comparison between stereotyped sounds from different species. 'SoundShape', in turn, provide the tools required for anyone to go from sound waves to Principal Components Analysis, using tools extracted from traditional bioacoustics (i.e. 'tuneR' and 'seewave' packages), geometric morphometrics (i.e. 'geomorph' package) and multivariate analysis (e.g. 'stats' package). For more information, please see Rocha and Romano (2021) and check 'SoundShape' repository on GitHub for news and updates <https://github.com/p-rocha/SoundShape>. |
Authors: | Pedro Rocha [aut, cre] |
Maintainer: | Pedro Rocha <[email protected]> |
License: | GPL-3 |
Version: | 1.3.2 |
Built: | 2024-11-21 09:12:38 UTC |
Source: | CRAN |
Recreate each ".wav"
file on a given folder while placing calls at the beginning of sound window. New ".wav"
files will be stored on a new folder, which is automatically created.
align.wave( wav.at = NULL, wav.to = "Aligned", time.length = 1, time.perc = 0.005, flim = NULL, dBlevel = 25, f = 44100, wl = 512, ovlp = 70 )
align.wave( wav.at = NULL, wav.to = "Aligned", time.length = 1, time.perc = 0.005, flim = NULL, dBlevel = 25, f = 44100, wl = 512, ovlp = 70 )
wav.at |
filepath to the folder where |
wav.to |
name of the folder where new |
time.length |
intended length for the time (X-axis) in seconds. Should be a value that encompasses all sounds in the study. By default: |
time.perc |
slight time gap (in percentage) relative to the intended length that encompass all sounds in the study (i.e. |
flim |
modifications of the frequency limits (Y-axis) to focus on acoustic units. Useful for recordings with low signal-to-noise ratio. Vector with two values in kHz. By default: |
dBlevel |
absolute amplitude value to be used as relative amplitude contour, which will serve as reference for call placement. By default: |
f |
sampling frequency of |
wl |
length of the window for the analysis. By default: |
ovlp |
overlap between two successive windows (in %) for increased spectrogram resolution. By default: |
Pedro Rocha
MacLeod, N., Krieger, J. & Jones, K. E. (2013). Geometric morphometric approaches to acoustic signal analysis in mammalian biology. Hystrix, the Italian Journal of Mammalogy, 24(1), 110-125.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
Useful links:
library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "align.wave") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "align.wave-output") if(!dir.exists(store.at)) dir.create(store.at) # Select acoustic units to be analyzed data(cuvieri) spectro(cuvieri, flim = c(0,3)) # Visualize sound data that will be used # Cut acoustic units from original Wave cut.cuvieri1 <- cutw(cuvieri, f=44100, from=0, to=0.5, output = "Wave") cut.cuvieri2 <- cutw(cuvieri, f=44100, from=0.7, to=1.2, output = "Wave") cut.cuvieri3 <- cutw(cuvieri, f=44100, from=1.4, to=1.9, output = "Wave") # Export ".wav" files containing selected acoustic units and store on previosly created folder writeWave(cut.cuvieri1, filename = file.path(wav.at, "cut.cuvieri1.wav"), extensible = FALSE) writeWave(cut.cuvieri2, filename = file.path(wav.at, "cut.cuvieri2.wav"), extensible = FALSE) writeWave(cut.cuvieri3, filename = file.path(wav.at, "cut.cuvieri3.wav"), extensible = FALSE) # Align acoustic units selected at 1% of time lenght align.wave(wav.at = wav.at, wav.to = "Aligned", time.length = 0.5, time.perc = 0.01, dBlevel = 25) # Verify alignment using eigensound function featuring analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), store.at = store.at, flim=c(0, 3), tlim=c(0,0.5), dBlevel = 25, plot.exp = TRUE, plot.as = "jpeg") # To see jpeg files created, check folder specified by store.at
library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "align.wave") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "align.wave-output") if(!dir.exists(store.at)) dir.create(store.at) # Select acoustic units to be analyzed data(cuvieri) spectro(cuvieri, flim = c(0,3)) # Visualize sound data that will be used # Cut acoustic units from original Wave cut.cuvieri1 <- cutw(cuvieri, f=44100, from=0, to=0.5, output = "Wave") cut.cuvieri2 <- cutw(cuvieri, f=44100, from=0.7, to=1.2, output = "Wave") cut.cuvieri3 <- cutw(cuvieri, f=44100, from=1.4, to=1.9, output = "Wave") # Export ".wav" files containing selected acoustic units and store on previosly created folder writeWave(cut.cuvieri1, filename = file.path(wav.at, "cut.cuvieri1.wav"), extensible = FALSE) writeWave(cut.cuvieri2, filename = file.path(wav.at, "cut.cuvieri2.wav"), extensible = FALSE) writeWave(cut.cuvieri3, filename = file.path(wav.at, "cut.cuvieri3.wav"), extensible = FALSE) # Align acoustic units selected at 1% of time lenght align.wave(wav.at = wav.at, wav.to = "Aligned", time.length = 0.5, time.perc = 0.01, dBlevel = 25) # Verify alignment using eigensound function featuring analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), store.at = store.at, flim=c(0, 3), tlim=c(0,0.5), dBlevel = 25, plot.exp = TRUE, plot.as = "jpeg") # To see jpeg files created, check folder specified by store.at
Recording of a series of three stereotyped calls emitted by a male frog Physalaemus centralis (Amphibia, Anura, Leptodactylidae). Edited from original ".wav"
file for optimal sinal to noise ratio and reduced time duration.
data(centralis)
data(centralis)
An object of the class "Wave"
(tuneR
package).
Duration = 2.89 s. Sampling Frequency = 44100 Hz.
Recorded at Formoso do Araguaia Municipality, Tocantins State, Brazil, on 9 December 1992. Air temperature 25ºC.
Original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0031188). Recorded by Adão José Cardoso.
data(centralis) seewave::oscillo(centralis) seewave::spectro(centralis) threeDspectro(centralis,tlim=c(0, 0.8), flim=c(0, 4), samp.grid=FALSE, dBlevel=25)
data(centralis) seewave::oscillo(centralis) seewave::spectro(centralis) threeDspectro(centralis,tlim=c(0, 0.8), flim=c(0, 4), samp.grid=FALSE, dBlevel=25)
Recording of a series of three stereotyped calls emitted by a male frog Physalaemus cuvieri (Amphibia, Anura, Leptodactylidae). Edited from original ".wav"
file for optimal sinal to noise ratio and reduced time duration.
data(cuvieri)
data(cuvieri)
An object of class "Wave"
; see (tuneR
package).
Duration = 1.96 s. Sampling Frequency = 44100 Hz.
Recorded at São José dos Campos Municipality, São Paulo State, Brazil, on 24 September 2013. Air temperature 22ºC.
Original recording housed at Coleção Bioacústica da Universidade Federal de Minas Gerais (CBUFMG-00196). Recorded by Pedro Rocha.
data(cuvieri) seewave::oscillo(cuvieri) seewave::spectro(cuvieri) threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=FALSE)
data(cuvieri) seewave::oscillo(cuvieri) seewave::spectro(cuvieri) threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=FALSE)
eigensound
functionThis sample file was acquired using eigensound(analysis.type = "threeDshape")
and features 3D point coordinates (i.e. semilandmarks) from the calls of three frog species: Physalaemus centralis, P. cuvieri and P. kroyeri (Amphibia, Anura, Leptodactylidae).
data(eig.sample)
data(eig.sample)
An object of the class "array"
(base
package).
"array"
is a special type of "list"
that can be thought as a filing cabinet, in which the array
is the cabinet and each element is an arquive. This special list
can be used in the subsequent steps of the eigensound protocol (MacLeod et al., 2013; Rocha & Romano in prep).
Each species is represented by three stereotyped acoustic units (i.e. notes from their advertisement calls), which are available as sample data from SoundShape
("Wave"
objects: centralis
, cuvieri
and kroyeri
). See Rocha & Romano (in prep) for details.
Prior to eigensound
analysis, each of the sample calls had the acoustic units selected, stored as separate ".wav"
files, and aligned at beggining of sound window using align.wave
(see Examples
section).
eig.sample
is composed of 9 elements (i.e. three species, each represented by three acoustic units). Each element is a matrix with 3200 rows and 3 columns (i.e. X, Y and Z coordinates of 3200 semilandmarks). The number of semilandmarks acquired will depend on the number of cells per side on the sound window (i.e. x.length
and y.length
arguments from eigensound
function).
The analysis itself (eigensound
function) featured relative amplitude backgroud at 25 dB (dBlevel = 25
), sampling grid of 70 cells on the time (X-axis) and 47 cells on the frequency (Y-axis) (x.length = 70
, y.length = 47
, respectively). Sound window ranged from 0 to 0.8 s (X-axis), and from 0 to 4 kHz (Y-axis) (tlim = c(0, 0.8)
, flim = c(0, 4)
, respectively).
Spectrogram parameters were the same as eigensound
default: f = 44100
, wl = 512
, ovlp = 70
.
Sample data of "Wave"
objects employed on eigensound
analysis:
centralis
: Advertisement call of Physalaemus centralis; original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0031188). Recorded by Adão José Cardoso.
cuvieri
: Advertisement call of Physalaemus cuvieri; original recording housed at Coleção Bioacústica da Universidade Federal de Minas Gerais (CBUFMG-00196). Recorded by Pedro Rocha.
kroyeri
: Advertisement call of Physalaemus kroyeri; Original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0032047). Recorded by Werner Bokermann.
MacLeod, N., Krieger, J. & Jones, K. E. (2013). Geometric morphometric approaches to acoustic signal analysis in mammalian biology. Hystrix, the Italian Journal of Mammalogy, 24(1), 110-125.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
data(eig.sample) # PCA using 3D semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top") # Verify hypothetical sound surfaces for each Principal Component hypo.surf(threeD.out=eig.sample, PC=1, flim=c(0, 4), tlim=c(0, 0.8), x.length=70, y.length=47, plot.exp = FALSE) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Recreate eig.sample object # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "eig.sample") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "eig.sample-output") if(!dir.exists(store.at)) dir.create(store.at) # Select three acoustic units within each sound data data(cuvieri) spectro(cuvieri, flim = c(0,4)) cut.cuvieri1 <- cutw(cuvieri, f=44100, from=0, to=0.5, output = "Wave") cut.cuvieri2 <- cutw(cuvieri, f=44100, from=0.7, to=1.2, output = "Wave") cut.cuvieri3 <- cutw(cuvieri, f=44100, from=1.4, to=1.9, output = "Wave") data("centralis") spectro(centralis, flim = c(0,4)) cut.centralis1 <- cutw(centralis, f=44100, from=0.1, to=0.8, output = "Wave") cut.centralis2 <- cutw(centralis, f=44100, from=1.05, to=1.75, output = "Wave") cut.centralis3 <- cutw(centralis, f=44100, from=2.1, to=2.8, output = "Wave") data("kroyeri") spectro(kroyeri, flim = c(0,4)) cut.kroyeri1 <- cutw(kroyeri, f=44100, from=0.1, to=1, output = "Wave") cut.kroyeri2 <- cutw(kroyeri, f=44100, from=1.5, to=2.3, output = "Wave") cut.kroyeri3 <- cutw(kroyeri, f=44100, from=2.9, to=3.8, output = "Wave") # Export new wave files containing acoustic units and store on previosly created folder writeWave(cut.cuvieri1, filename = file.path(wav.at, "cut.cuvieri1.wav"), extensible = FALSE) writeWave(cut.cuvieri2, filename = file.path(wav.at, "cut.cuvieri2.wav"), extensible = FALSE) writeWave(cut.cuvieri3, filename = file.path(wav.at, "cut.cuvieri3.wav"), extensible = FALSE) writeWave(cut.centralis1, filename = file.path(wav.at, "cut.centralis1.wav"), extensible = FALSE) writeWave(cut.centralis2, filename = file.path(wav.at, "cut.centralis2.wav"), extensible = FALSE) writeWave(cut.centralis3, filename = file.path(wav.at, "cut.centralis3.wav"), extensible = FALSE) writeWave(cut.kroyeri1, filename = file.path(wav.at, "cut.kroyeri1.wav"), extensible = FALSE) writeWave(cut.kroyeri2, filename = file.path(wav.at, "cut.kroyeri2.wav"), extensible = FALSE) writeWave(cut.kroyeri3, filename = file.path(wav.at, "cut.kroyeri3.wav"), extensible = FALSE) # Place sounds at beggining of sound window before analysis align.wave(wav.at = wav.at, wav.to = "Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), store.at = store.at, flim=c(0, 4), tlim=c(0, 0.8), plot.exp = TRUE, plot.as = "jpeg", dBlevel = 25) # Go to folder specified by store.at and check jpeg files created # Run eigensound function using analysis.type = "threeDshape" on aligned wave files # Store results as R object eig.sample <- eigensound(analysis.type="threeDshape", wav.at = file.path(wav.at, "Aligned"), flim=c(0, 4), tlim=c(0, 0.8), dBlevel=25, plot.exp = FALSE, x.length=70, y.length = 47, log.scale = TRUE)
data(eig.sample) # PCA using 3D semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top") # Verify hypothetical sound surfaces for each Principal Component hypo.surf(threeD.out=eig.sample, PC=1, flim=c(0, 4), tlim=c(0, 0.8), x.length=70, y.length=47, plot.exp = FALSE) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Recreate eig.sample object # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "eig.sample") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "eig.sample-output") if(!dir.exists(store.at)) dir.create(store.at) # Select three acoustic units within each sound data data(cuvieri) spectro(cuvieri, flim = c(0,4)) cut.cuvieri1 <- cutw(cuvieri, f=44100, from=0, to=0.5, output = "Wave") cut.cuvieri2 <- cutw(cuvieri, f=44100, from=0.7, to=1.2, output = "Wave") cut.cuvieri3 <- cutw(cuvieri, f=44100, from=1.4, to=1.9, output = "Wave") data("centralis") spectro(centralis, flim = c(0,4)) cut.centralis1 <- cutw(centralis, f=44100, from=0.1, to=0.8, output = "Wave") cut.centralis2 <- cutw(centralis, f=44100, from=1.05, to=1.75, output = "Wave") cut.centralis3 <- cutw(centralis, f=44100, from=2.1, to=2.8, output = "Wave") data("kroyeri") spectro(kroyeri, flim = c(0,4)) cut.kroyeri1 <- cutw(kroyeri, f=44100, from=0.1, to=1, output = "Wave") cut.kroyeri2 <- cutw(kroyeri, f=44100, from=1.5, to=2.3, output = "Wave") cut.kroyeri3 <- cutw(kroyeri, f=44100, from=2.9, to=3.8, output = "Wave") # Export new wave files containing acoustic units and store on previosly created folder writeWave(cut.cuvieri1, filename = file.path(wav.at, "cut.cuvieri1.wav"), extensible = FALSE) writeWave(cut.cuvieri2, filename = file.path(wav.at, "cut.cuvieri2.wav"), extensible = FALSE) writeWave(cut.cuvieri3, filename = file.path(wav.at, "cut.cuvieri3.wav"), extensible = FALSE) writeWave(cut.centralis1, filename = file.path(wav.at, "cut.centralis1.wav"), extensible = FALSE) writeWave(cut.centralis2, filename = file.path(wav.at, "cut.centralis2.wav"), extensible = FALSE) writeWave(cut.centralis3, filename = file.path(wav.at, "cut.centralis3.wav"), extensible = FALSE) writeWave(cut.kroyeri1, filename = file.path(wav.at, "cut.kroyeri1.wav"), extensible = FALSE) writeWave(cut.kroyeri2, filename = file.path(wav.at, "cut.kroyeri2.wav"), extensible = FALSE) writeWave(cut.kroyeri3, filename = file.path(wav.at, "cut.kroyeri3.wav"), extensible = FALSE) # Place sounds at beggining of sound window before analysis align.wave(wav.at = wav.at, wav.to = "Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), store.at = store.at, flim=c(0, 4), tlim=c(0, 0.8), plot.exp = TRUE, plot.as = "jpeg", dBlevel = 25) # Go to folder specified by store.at and check jpeg files created # Run eigensound function using analysis.type = "threeDshape" on aligned wave files # Store results as R object eig.sample <- eigensound(analysis.type="threeDshape", wav.at = file.path(wav.at, "Aligned"), flim=c(0, 4), tlim=c(0, 0.8), dBlevel=25, plot.exp = FALSE, x.length=70, y.length = 47, log.scale = TRUE)
eigensound
is the main feature of SoundShape
package. For each ".wav"
file on a given folder, the fuction will compute spectrogram data and acquire semilandmarks using a 3D representation of sound (analysis.type = "threeDshape"
), allowing its users to acquire, and simultaneously store point coordinates (i.e. semilandmarks) as an R object, and/or in TPS format – the native file format of James Rohlf’s TPS series (Rohlf, 2015).
Moreover, eigensound
also allow its user to export 2D and 3D spectrogram images (plot.exp = TRUE
) that are helpful during the protocol for error verification and for illustrative purposes (see Rocha & Romano in prep). Alternativaly, eigensound
feature the option of acquiring semilandmarks as the cross-correlation between energy quantiles and a curve of relative amplitude from 2D spectrograms (analysis.type = "twoDshape"
; see Details
section).
eigensound( analysis.type = NULL, wav.at = NULL, store.at = wav.at, dBlevel = 25, flim = c(0, 10), tlim = c(0, 1), x.length = 80, y.length = 60, log.scale = TRUE, back.amp = 35, add.points = FALSE, add.contour = TRUE, lwd = 1, EQ = c(0.05, 0.15, 0.3, 0.5, 0.7, 0.85, 0.95), mag.time = 1, f = 44100, wl = 512, ovlp = 70, plot.exp = TRUE, plot.as = "jpeg", plot.type = "surface", rotate.Xaxis = 60, rotate.Yaxis = 40, TPS.file = NULL )
eigensound( analysis.type = NULL, wav.at = NULL, store.at = wav.at, dBlevel = 25, flim = c(0, 10), tlim = c(0, 1), x.length = 80, y.length = 60, log.scale = TRUE, back.amp = 35, add.points = FALSE, add.contour = TRUE, lwd = 1, EQ = c(0.05, 0.15, 0.3, 0.5, 0.7, 0.85, 0.95), mag.time = 1, f = 44100, wl = 512, ovlp = 70, plot.exp = TRUE, plot.as = "jpeg", plot.type = "surface", rotate.Xaxis = 60, rotate.Yaxis = 40, TPS.file = NULL )
analysis.type |
type of analysis intended. If |
wav.at |
filepath to the folder where |
store.at |
filepath to the folder where spectrogram plots and |
dBlevel |
absolute amplitude value to be used as relative amplitude contour, which will serve as reference for semilandmark acquisition in both |
flim |
modifications of the frequency limits (Y-axis). Vector with two values in kHz. By default: |
tlim |
modifications of the time limits (X-axis). Vector with two values in seconds. By default: |
x.length |
only applies when |
y.length |
only applies when |
log.scale |
only applies when |
back.amp |
only applies when |
add.points |
only applies when |
add.contour |
only applies when |
lwd |
only applies when |
EQ |
only applies when |
mag.time |
only applies when |
f |
sampling frequency of |
wl |
length of the window for the analysis. By default: |
ovlp |
overlap between two successive windows (in %) for increased spectrogram resolution. By default: |
plot.exp |
a logical. If |
plot.as |
only applies when |
plot.type |
only applies when |
rotate.Xaxis |
only applies when |
rotate.Yaxis |
only applies when |
TPS.file |
Desired name for the |
When analysis.type = "twoDshape"
and add.points = TRUE
, eigensound
will compute semilandmarks acquired by cross-correlation between energy quantiles (i.e. EQ
) and a curve of relative amplitude (i.e. dBlevel
). However, this is often subtle and prone to incur in errors (e.g. bad alignment of acoustic units; inappropriate X and Y coordinates for the sound window; narrow banded calls). Therefore, a more robust protocol of error verification is achieved using add.points = FALSE
and add.contour = TRUE
(default), which allow for quick verification of acoustic units alignment and the shape of each curve of relative amplitude (specified by dBlevel
).
In order to store the results from eigensound
function and proceed with the Geometric Morphometric steps of the analysis (e.g. geomorph
package; Adams et al., 2017), one can simultaneosly assign the function's output to an R
object and/or store them as a tps
file to be used by numerous softwares of geometric analysis of shape, such as the TPS series (Rohlf, 2015).
Additionally, one may also export 2D or 3D plots as jpeg
(compressed image) or tiff
(uncompressed image) file formats, which can be edited for publication purposes.
Pedro Rocha
Adams, D. C., M. L. Collyer, A. Kaliontzopoulou & Sherratt, E. (2017) Geomorph: Software for geometric morphometric analyses. R package version 3.0.5. https://cran.r-project.org/package=geomorph.
MacLeod, N., Krieger, J. & Jones, K. E. (2013). Geometric morphometric approaches to acoustic signal analysis in mammalian biology. Hystrix, the Italian Journal of Mammalogy, 24(1), 110-125.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
Rohlf, F.J. (2015) The tps series of software. Hystrix 26, 9-12.
Useful links:
library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "eigensound") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "eigensound-output") if(!dir.exists(store.at)) dir.create(store.at) # Cut acoustic units from original Wave cut.cuvieri <- cutw(cuvieri, f=44100, from=0, to=0.9, output = "Wave") cut.centralis <- cutw(centralis, f=44100, from=0, to=0.9, output = "Wave") cut.kroyeri <- cutw(kroyeri, f=44100, from=0.2, to=1.1, output = "Wave") # Export ".wav" files containing acoustic units and store on previosly created folder writeWave(cut.cuvieri, filename = file.path(wav.at, "cut.cuvieri.wav"), extensible = FALSE) writeWave(cut.centralis, filename = file.path(wav.at, "cut.centralis.wav"), extensible = FALSE) writeWave(cut.kroyeri, filename = file.path(wav.at, "cut.kroyeri.wav"), extensible = FALSE) # Create 2D spectrograms using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", flim=c(0, 4), tlim=c(0, 0.8), plot.exp=TRUE, wav.at = wav.at, store.at = store.at) # Create 3D spectrograms using analysis.type = "threeDshape" and store point coordinates eig.data <- eigensound(analysis.type = "threeDshape", plot.exp=TRUE, wav.at = wav.at, store.at = store.at, flim=c(0, 4), tlim=c(0, 0.8))
library(seewave) library(tuneR) # Create temporary folder to store ".wav" files wav.at <- file.path(base::tempdir(), "eigensound") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "eigensound-output") if(!dir.exists(store.at)) dir.create(store.at) # Cut acoustic units from original Wave cut.cuvieri <- cutw(cuvieri, f=44100, from=0, to=0.9, output = "Wave") cut.centralis <- cutw(centralis, f=44100, from=0, to=0.9, output = "Wave") cut.kroyeri <- cutw(kroyeri, f=44100, from=0.2, to=1.1, output = "Wave") # Export ".wav" files containing acoustic units and store on previosly created folder writeWave(cut.cuvieri, filename = file.path(wav.at, "cut.cuvieri.wav"), extensible = FALSE) writeWave(cut.centralis, filename = file.path(wav.at, "cut.centralis.wav"), extensible = FALSE) writeWave(cut.kroyeri, filename = file.path(wav.at, "cut.kroyeri.wav"), extensible = FALSE) # Create 2D spectrograms using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", flim=c(0, 4), tlim=c(0, 0.8), plot.exp=TRUE, wav.at = wav.at, store.at = store.at) # Create 3D spectrograms using analysis.type = "threeDshape" and store point coordinates eig.data <- eigensound(analysis.type = "threeDshape", plot.exp=TRUE, wav.at = wav.at, store.at = store.at, flim=c(0, 4), tlim=c(0, 0.8))
Using the coordinates acquired by eigensound(analysis.type = "threeDshape")
, this function creates 3D plots containing hypothetical sound surfaces that represent either the mean shape configuration (consensus), or minimum and maximum deformations relative to Principal Components in a Principal Components Analysis (PCA).
Note: The output of hypo.surf
must be interpreted along with the ordination of Principal Components (e.g. pca.plot
), both featuring the same object used for threeD.out
argument. By doing so, hypo.surf
enhance the comprehension on how sound shape changed along the ordination plot .
hypo.surf( threeD.out = NULL, PC = 1, flim = c(0, 4), tlim = c(0, 0.8), x.length = 70, y.length = 47, log.scale = TRUE, f = 44100, wl = 512, ovlp = 70, plot.exp = FALSE, plot.as = "jpeg", store.at = NULL, rotate.Xaxis = 60, rotate.Yaxis = 40, cex.axis = 0.5, cex.lab = 0.9, cex.main = 1.1, lwd = 0.1, xlab = "Time coordinates", ylab = "Frequency coordinates", zlab = "Amplitude", colkey = list(plot = TRUE, cex.clab = 0.9, cex.axis = 0.8, side = 4, length = 0.5, width = 0.7, labels = TRUE, tick = TRUE, lty = 1, lwd = 1, lwd.ticks = 1) )
hypo.surf( threeD.out = NULL, PC = 1, flim = c(0, 4), tlim = c(0, 0.8), x.length = 70, y.length = 47, log.scale = TRUE, f = 44100, wl = 512, ovlp = 70, plot.exp = FALSE, plot.as = "jpeg", store.at = NULL, rotate.Xaxis = 60, rotate.Yaxis = 40, cex.axis = 0.5, cex.lab = 0.9, cex.main = 1.1, lwd = 0.1, xlab = "Time coordinates", ylab = "Frequency coordinates", zlab = "Amplitude", colkey = list(plot = TRUE, cex.clab = 0.9, cex.axis = 0.8, side = 4, length = 0.5, width = 0.7, labels = TRUE, tick = TRUE, lty = 1, lwd = 1, lwd.ticks = 1) )
threeD.out |
the output of |
PC |
Principal Component intended for the plot. Alternativaly, it is also possible to create mean shape configuration (consensus) from sample |
flim |
modifications of the frequency limits (Y-axis). Vector with two values in kHz. Should be the same employed on |
tlim |
modifications of the time limits (X-axis). Vector with two values in seconds. Should be the same employed on |
x.length |
length of sequence (i.e. number of cells per side on sound window) to be used as sampling grid coordinates on the time (X-axis). Should be the same employed on |
y.length |
length of sequence (i.e. number of cells per side on sound window) to be used as sampling grid coordinates on the frequency (Y-axis). Should be the same employed on |
log.scale |
a logical. If |
f |
sampling frequency of |
wl |
length of the window for the analysis. Should be the same employed on |
ovlp |
overlap between two successive windows (in %) for increased spectrogram resolution. Should be the same employed on |
plot.exp |
a logical. If |
plot.as |
only applies when |
store.at |
only applies when |
rotate.Xaxis |
rotation of the X-axis. Same as |
rotate.Yaxis |
rotation of the Y-axis. Same as |
cex.axis |
similarly as in |
cex.lab |
similarly as in |
cex.main |
similarly as in |
lwd |
Similarly as in |
xlab |
a character string indicating the label to be written on the x-axis. By default: |
ylab |
a character string indicating the label to be written on the y-axis. By default: |
zlab |
a character string indicating the label to be written on the z-axis. By default: |
colkey |
Similarly as |
Some codes from hypo.surf
were adapted from plotTangentSpace
function (geomorph
package version 3.1.2), which is now deprecated and replaced by current functions gm.prcomp
, summary.gm.prcomp
and plot.gm.prcomp
. More specifically, the code chunk related to the acquisition of hypothetical point configurations from each PC (i.e. warp grids) was the same as in plotTangentSpace
. However, the hypothetical configurations from plotTangentSpace
were plotted along with ordination of PCs, whereas hypo.surf
focuses solely on hypothetical 3D surfaces that represent minimum, maximum and mean deformations relative to each PCs.
Pedro Rocha
MacLeod, N., Krieger, J. & Jones, K. E. (2013). Geometric morphometric approaches to acoustic signal analysis in mammalian biology. Hystrix, the Italian Journal of Mammalogy, 24(1), 110-125.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
gm.prcomp
, summary.gm.prcomp
, plot.gm.prcomp
, geomorph
, eigensound
, pca.plot
Useful links:
data(eig.sample) # PCA using three-dimensional semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Clear current R plot to prevent errors grDevices::dev.off() # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top") # Verify hypothetical sound surfaces using hypo.surf hypo.surf(threeD.out=eig.sample, PC=1, flim=c(0, 4), tlim=c(0, 0.8), x.length=70, y.length=47)
data(eig.sample) # PCA using three-dimensional semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Clear current R plot to prevent errors grDevices::dev.off() # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top") # Verify hypothetical sound surfaces using hypo.surf hypo.surf(threeD.out=eig.sample, PC=1, flim=c(0, 4), tlim=c(0, 0.8), x.length=70, y.length=47)
Recording of a series of three stereotyped calls emitted by a male frog Physalaemus kroyeri (Amphibia, Anura, Leptodactylidae). Edited from original ".wav"
file for optimal sinal to noise ratio and reduced time duration.
data(kroyeri)
data(kroyeri)
An object of the class "Wave"
(tuneR
package).
Duration = 3.91 s. Sampling Frequency = 44100 Hz.
Recorded at Ilhéus Municipality, Bahia State, Brazil, on 05 August 1972. Air temperature 24ºC.
Original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0032047). Recorded by Werner Bokermann.
data(kroyeri) seewave::oscillo(kroyeri) seewave::spectro(kroyeri) threeDspectro(kroyeri,tlim=c(0, 1), flim=c(0, 4), samp.grid=FALSE, dBlevel=25)
data(kroyeri) seewave::oscillo(kroyeri) seewave::spectro(kroyeri) threeDspectro(kroyeri,tlim=c(0, 1), flim=c(0, 4), samp.grid=FALSE, dBlevel=25)
Ordination of Principal Components from the output of a Principal Components Analysis performed by prcomp
function (stats
package). Require a factor
object with groups
, which enable the plot to feature colored groups and convex hulls (if desired).
pca.plot( PCA.out = NULL, groups = NULL, col.gp = grDevices::rainbow(length(levels(groups))), conv.hulls = NULL, col.conv = grDevices::rainbow(length(levels(conv.hulls))), PCs = c(1, 2), main = "Ordination of PCA coordinates", sp.as = "points", sp.text = NULL, cross.origin = TRUE, lwd = 1, lty = "dotted", leg = TRUE, leg.labels = groups, leg.pos = "topright", cex.leg = 1, cex = 1, cex.axis = 1, cex.lab = 1, cex.main = 1 )
pca.plot( PCA.out = NULL, groups = NULL, col.gp = grDevices::rainbow(length(levels(groups))), conv.hulls = NULL, col.conv = grDevices::rainbow(length(levels(conv.hulls))), PCs = c(1, 2), main = "Ordination of PCA coordinates", sp.as = "points", sp.text = NULL, cross.origin = TRUE, lwd = 1, lty = "dotted", leg = TRUE, leg.labels = groups, leg.pos = "topright", cex.leg = 1, cex = 1, cex.axis = 1, cex.lab = 1, cex.main = 1 )
PCA.out |
the output of a Principal Components Analysis performed by |
groups |
groups to use as colors and/or convex hulls. Must be a |
col.gp |
a |
conv.hulls |
groups to use for convex hulls. Must be a |
col.conv |
a |
PCs |
a vector of length two with the Principal Components intended for the plot. By default: |
main |
main title of output plot. Should be presented between quotation marks. By default: |
sp.as |
enables one to choose between ploting elements as |
sp.text |
only applies when |
cross.origin |
A logical. If |
lwd |
only applies when |
lty |
only applies when |
leg |
a logical. If |
leg.labels |
only applies when |
leg.pos |
only applies when |
cex.leg |
only applies when |
cex |
same as in |
cex.axis |
same as in |
cex.lab |
same as in |
cex.main |
same as in |
Require the output of prcomp
and a vector with groups
to plot. In addition, it is also possible to include convex hulls around each group (i.e. conv.hulls
) and to control the colors intended for each group (i.e. col.gp
) and for each convex hull (i.e. col.conv
).
Pedro Rocha
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
prcomp
, palette
, rgb
, rainbow
, legend
Useful links:
data(eig.sample) # PCA using 3D semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Clear current R plot to prevent errors grDevices::dev.off() # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top")
data(eig.sample) # PCA using 3D semilandmark coordinates pca.eig.sample <- stats::prcomp(geomorph::two.d.array(eig.sample)) # Verify names for each acoustic unit and the order in which they appear dimnames(eig.sample)[[3]] # Create factor to use as groups in subsequent ordination plot sample.gr <- factor(c(rep("centralis", 3), rep("cuvieri", 3), rep("kroyeri", 3))) # Clear current R plot to prevent errors grDevices::dev.off() # Plot result of Principal Components Analysis pca.plot(PCA.out = pca.eig.sample, groups = sample.gr, conv.hulls = sample.gr, main="PCA of 3D coordinates", leg=TRUE, leg.pos = "top")
This sample file features a list of three data.frame
objects containing the selection boxes for the acoustic units of centralis
, cuvieri
and kroyeri
. The selection was performed manually using Raven Pro software, which is commonplace in bioacoustic analysis.
data(raven.list)
data(raven.list)
An object of the class "list"
(base
package).
This sample list was built to illustrate the usage of raven.to.wave
function.
Each data.frame
in the list represent selection boxes from Raven Pro software featuring either centralis
, cuvieri
or kroyeri
samples. These, in turn, are acoustic recordings containing three stereotyped calls emitted by a male frog Physalaemus cuvieri, P. centralis or P. kroyeri (Amphibia, Anura, Leptodactylidae), respectively.
Sample data of "Wave"
objects:
centralis
: Advertisement call of Physalaemus centralis; original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0031188). Recorded by Adão José Cardoso.
cuvieri
: Advertisement call of Physalaemus cuvieri; original recording housed at Coleção Bioacústica da Universidade Federal de Minas Gerais (CBUFMG-00196). Recorded by Pedro Rocha.
kroyeri
: Advertisement call of Physalaemus kroyeri; Original recording housed at Fonoteca Neotropical Jacques Vielliard (FNJV-0032047). Recorded by Werner Bokermann.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create folders on your console # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create temporary folder to store original ".wav" files containing multiple units orig.wav <- file.path(base::tempdir(), "original wave") if(!dir.exists(orig.wav)) dir.create(orig.wav) # Create temporary folder to store sample ".wav" files from original recordings wav.at <- file.path(base::tempdir(), "wav samples") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "output") if(!dir.exists(store.at)) dir.create(store.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Select acoustic units based on Raven Pro selections # # # # Using raven.to.wave function # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Export original sample ".wav" files from SoundShape examples tuneR::writeWave(centralis, extensible = TRUE, filename = file.path(orig.wav, "centralis.wav")) tuneR::writeWave(cuvieri, extensible = TRUE, filename = file.path(orig.wav, "cuvieri.wav")) tuneR::writeWave(kroyeri, extensible = TRUE, filename = file.path(orig.wav, "kroyeri.wav")) # Store Raven Pro selection tables at same folder from original ".wav" files for(i in 1:length(raven.list)){ write.table(raven.list[i], file=file.path(orig.wav, names(raven.list)[i]), quote=FALSE, sep="\t", row.names = FALSE, col.names = colnames(raven.list[[i]])) } # end loop # Verify if folder has both original ".wav" files and Raven's selections dir(orig.wav) ### ## Start here when using your own recordings # Export a ".wav" sample for each selection made in Raven Pro raven.to.wave(orig.wav.folder = orig.wav, wav.samples = wav.at) # Verify samples dir(wav.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Align acoustic units using align.wave # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Place sounds at the beginning of a sound window align.wave(wav.at=wav.at, wav.to="Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), dBlevel = 25, store.at=store.at, plot.exp=TRUE, flim=c(0, 4), tlim=c(0, 0.8), add.contour = TRUE) # Go to folder specified by store.at and check jpeg files created # If alignment/window dimensions are not ideal, repeat the process with new settings
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create folders on your console # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create temporary folder to store original ".wav" files containing multiple units orig.wav <- file.path(base::tempdir(), "original wave") if(!dir.exists(orig.wav)) dir.create(orig.wav) # Create temporary folder to store sample ".wav" files from original recordings wav.at <- file.path(base::tempdir(), "wav samples") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "output") if(!dir.exists(store.at)) dir.create(store.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Select acoustic units based on Raven Pro selections # # # # Using raven.to.wave function # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Export original sample ".wav" files from SoundShape examples tuneR::writeWave(centralis, extensible = TRUE, filename = file.path(orig.wav, "centralis.wav")) tuneR::writeWave(cuvieri, extensible = TRUE, filename = file.path(orig.wav, "cuvieri.wav")) tuneR::writeWave(kroyeri, extensible = TRUE, filename = file.path(orig.wav, "kroyeri.wav")) # Store Raven Pro selection tables at same folder from original ".wav" files for(i in 1:length(raven.list)){ write.table(raven.list[i], file=file.path(orig.wav, names(raven.list)[i]), quote=FALSE, sep="\t", row.names = FALSE, col.names = colnames(raven.list[[i]])) } # end loop # Verify if folder has both original ".wav" files and Raven's selections dir(orig.wav) ### ## Start here when using your own recordings # Export a ".wav" sample for each selection made in Raven Pro raven.to.wave(orig.wav.folder = orig.wav, wav.samples = wav.at) # Verify samples dir(wav.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Align acoustic units using align.wave # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Place sounds at the beginning of a sound window align.wave(wav.at=wav.at, wav.to="Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), dBlevel = 25, store.at=store.at, plot.exp=TRUE, flim=c(0, 4), tlim=c(0, 0.8), add.contour = TRUE) # Go to folder specified by store.at and check jpeg files created # If alignment/window dimensions are not ideal, repeat the process with new settings
".wav"
files using selections from Raven Pro software.Create one ".wav"
file for each selection created using Raven Pro software, which is commonplace in bioacoustical analysis. Each selection (i.e. line in table) should represent an acoustic unit from the sample study.
raven.to.wave( orig.wav.folder = NULL, raven.at = orig.wav.folder, wav.samples = "wav samples" )
raven.to.wave( orig.wav.folder = NULL, raven.at = orig.wav.folder, wav.samples = "wav samples" )
orig.wav.folder |
filepath to the folder where original |
raven.at |
filepath to the folder where selection tables from Raven Pro software are stored. Should be presented between quotation marks. File name should end with |
wav.samples |
folder where new |
Pedro Rocha
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
Useful links:
Report bugs at https://github.com/p-rocha/SoundShape/issues
Raven Pro software https://www.ravensoundsoftware.com/software/raven-pro/
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create folders on your console # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create temporary folder to store original ".wav" files containing multiple units orig.wav <- file.path(base::tempdir(), "original wave") if(!dir.exists(orig.wav)) dir.create(orig.wav) # Create temporary folder to store sample ".wav" files from original recordings wav.at <- file.path(base::tempdir(), "wav samples") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "output") if(!dir.exists(store.at)) dir.create(store.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Select acoustic units based on Raven Pro selections # # # # Using raven.to.wav function # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Export original sample ".wav" files from SoundShape examples tuneR::writeWave(centralis, extensible = TRUE, filename = file.path(orig.wav, "centralis.wav")) tuneR::writeWave(cuvieri, extensible = TRUE, filename = file.path(orig.wav, "cuvieri.wav")) tuneR::writeWave(kroyeri, extensible = TRUE, filename = file.path(orig.wav, "kroyeri.wav")) # Store Raven Pro selection tables at same folder from original ".wav" files for(i in 1:length(raven.list)){ write.table(raven.list[i], file=file.path(orig.wav, names(raven.list)[i]), quote=FALSE, sep="\t", row.names = FALSE, col.names = colnames(raven.list[[i]])) } # end loop # Verify if folder has both original ".wav" files and Raven's selections dir(orig.wav) ### ## Start here when using your own recordings # Export a ".wav" sample for each selection made in Raven Pro raven.to.wave(orig.wav.folder = orig.wav, wav.samples = wav.at) # Verify samples dir(wav.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Align acoustic units using align.wave # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Place sounds at the beginning of a sound window align.wave(wav.at=wav.at, wav.to="Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), dBlevel = 25, store.at=store.at, plot.exp=TRUE, flim=c(0, 4), tlim=c(0, 0.8), add.contour = TRUE) # Go to folder specified by store.at and check jpeg files created # If alignment/window dimensions are not ideal, repeat process with new settings
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create folders on your console # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Create temporary folder to store original ".wav" files containing multiple units orig.wav <- file.path(base::tempdir(), "original wave") if(!dir.exists(orig.wav)) dir.create(orig.wav) # Create temporary folder to store sample ".wav" files from original recordings wav.at <- file.path(base::tempdir(), "wav samples") if(!dir.exists(wav.at)) dir.create(wav.at) # Create temporary folder to store results store.at <- file.path(base::tempdir(), "output") if(!dir.exists(store.at)) dir.create(store.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Select acoustic units based on Raven Pro selections # # # # Using raven.to.wav function # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Export original sample ".wav" files from SoundShape examples tuneR::writeWave(centralis, extensible = TRUE, filename = file.path(orig.wav, "centralis.wav")) tuneR::writeWave(cuvieri, extensible = TRUE, filename = file.path(orig.wav, "cuvieri.wav")) tuneR::writeWave(kroyeri, extensible = TRUE, filename = file.path(orig.wav, "kroyeri.wav")) # Store Raven Pro selection tables at same folder from original ".wav" files for(i in 1:length(raven.list)){ write.table(raven.list[i], file=file.path(orig.wav, names(raven.list)[i]), quote=FALSE, sep="\t", row.names = FALSE, col.names = colnames(raven.list[[i]])) } # end loop # Verify if folder has both original ".wav" files and Raven's selections dir(orig.wav) ### ## Start here when using your own recordings # Export a ".wav" sample for each selection made in Raven Pro raven.to.wave(orig.wav.folder = orig.wav, wav.samples = wav.at) # Verify samples dir(wav.at) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Align acoustic units using align.wave # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# # Place sounds at the beginning of a sound window align.wave(wav.at=wav.at, wav.to="Aligned", time.length = 0.8, time.perc = 0.005, dBlevel = 25) # Verify alignment using analysis.type = "twoDshape" eigensound(analysis.type = "twoDshape", wav.at = file.path(wav.at, "Aligned"), dBlevel = 25, store.at=store.at, plot.exp=TRUE, flim=c(0, 4), tlim=c(0, 0.8), add.contour = TRUE) # Go to folder specified by store.at and check jpeg files created # If alignment/window dimensions are not ideal, repeat process with new settings
SoundShape
package provide the tools required to implement a promising, and yet little explored method for bioacoustical analysis, the so called eigensound protocol developed by MacLeod, Krieger, & Jones (2013). Eigensound was developed for taxonomy-based bioacoustics and focuses on the comparison between acoustic units from different species. The method consists on applying a sampling grid over the 3D representation of sound (i.e. spectrogram data) and then translate the spectrogram into a dataset that can be analyzed similarly to 3D coordinate sets used in Geometric Morphometrics Methods, thus enabling the direct comparison between stereotyped calls from different species. For more information on SoundShape
and the eigensound method, see Rocha & Romano (2021) and MacLeod et al. (2013).
The following set of functions crosses the bridge between Bioacoustics and Geometric Morphometrics:
raven.to.wave
: Export sample ".wav"
files using selections from Raven Pro software.
align.wave
: Automatic placement of calls at the beginning of a sound window.
eigensound
: Calculate spectrogram data for each ".wav"
file on a given folder and acquire semilandmarks using a 3D representation of sound.
pca.plot
: Plot ordination of Principal Components with convex hulls.
hypo.surf
: Hypothetical 3D plots of sound surfaces representing a sample of sounds submitted to eigensound
.
threeDspectro
: 3D spectrograms from a single object of class "Wave"
.
Maintainer: Pedro Rocha [email protected]
Useful links:
"Wave"
objectsCreate 3D spectrograms from a single object of class "Wave"
.
This function works similarly as spectro
, with spectrogram data internally computed by spectro
. However, the 3D plot is generated by persp3D
.
threeDspectro( wave, tlim = NULL, flim = NULL, samp.grid = FALSE, plot.type = "surface", along = "x", skip.lines = 5, space.lines = 0.6, x.length = 100, y.length = 70, lwd = 0.1, plot.exp = FALSE, log.scale = FALSE, cex = 0.5, cex.axis = 0.5, cex.lab = 0.9, cex.main = 1, store.at = NULL, plot.as = "jpeg", color = seewave::spectro.colors(80), f = 44100, wl = 512, ovlp = 70, dBlevel = 30, resfac = 1, rotate.Xaxis = 60, rotate.Yaxis = 40, main = "Spectrogram 3D", scalelab = expression("Amplitude (dB)"), colkey = list(plot = TRUE, cex.clab = 0.8, cex.axis = 1, side = 4, length = 1, width = 1, labels = TRUE, tick = TRUE, lty = 1, lwd = 1, lwd.ticks = 1) )
threeDspectro( wave, tlim = NULL, flim = NULL, samp.grid = FALSE, plot.type = "surface", along = "x", skip.lines = 5, space.lines = 0.6, x.length = 100, y.length = 70, lwd = 0.1, plot.exp = FALSE, log.scale = FALSE, cex = 0.5, cex.axis = 0.5, cex.lab = 0.9, cex.main = 1, store.at = NULL, plot.as = "jpeg", color = seewave::spectro.colors(80), f = 44100, wl = 512, ovlp = 70, dBlevel = 30, resfac = 1, rotate.Xaxis = 60, rotate.Yaxis = 40, main = "Spectrogram 3D", scalelab = expression("Amplitude (dB)"), colkey = list(plot = TRUE, cex.clab = 0.8, cex.axis = 1, side = 4, length = 1, width = 1, labels = TRUE, tick = TRUE, lty = 1, lwd = 1, lwd.ticks = 1) )
wave |
an |
tlim |
modifications of the time limits (X-axis). Vector with two values in seconds. By default: |
flim |
modifications of the frequency limits (Y-axis). Vector with two values in kHz. By default: |
samp.grid |
a logical. If |
plot.type |
allows the choice between |
along |
only applies when |
skip.lines |
only applies when |
space.lines |
only applies when |
x.length |
only applies when |
y.length |
only applies when |
lwd |
only applies when |
plot.exp |
a logical. If |
log.scale |
only applies when |
cex |
only applies when |
cex.axis |
Similarly as in |
cex.lab |
Similarly as in |
cex.main |
Similarly as in |
store.at |
only applies when |
plot.as |
only applies when |
color |
Color palette to be used for the amplitude (Z-axis). Same default as |
f |
sampling frequency of |
wl |
length of the window for spectrogram calculation. By default: |
ovlp |
overlap between two successive windows (in %) for increased spectrogram resolution. By default: |
dBlevel |
absolute amplitude value to be used as relative background on 3D plot. Same as |
resfac |
resolution factor, in which an value > 1 will increase the resolution. Can be one value or a vector of two numbers, for the x and y values, respectively. Note: Same as in |
rotate.Xaxis |
rotation of the X-axis. Same as |
rotate.Yaxis |
rotation of the Y-axis. Same as |
main |
main title of output plot. Should be presented between quotation marks. By default: |
scalelab |
Similarly as |
colkey |
Similarly as |
Similarly as spectro
, any colour palette can be used to describe the amplitude (Z-axis). Some suggestions: seewave::temp.colors, seewave::spectro.colors, seewave::reverse.heat.colors, seewave::reverse.cm.colors, seewave::reverse.topo.colors, grDevices::cm.colors, grDevices::grey.colors, grDevices::heat.colors, grDevices::topo.colors
.
Pedro Rocha
MacLeod, N., Krieger, J. & Jones, K. E. (2013). Geometric morphometric approaches to acoustic signal analysis in mammalian biology. Hystrix, the Italian Journal of Mammalogy, 24(1), 110-125.
Rocha, P. & Romano, P. (2021) The shape of sound: A new R
package that crosses the bridge between Bioacoustics and Geometric Morphometrics. Methods in Ecology and Evolution, 12(6), 1115-1121.
spectro
, seewave
, eigensound
, align.wave
, persp3D
, plot3D
, align.wave
Useful links:
# As simple as this threeDspectro(centralis) threeDspectro(cuvieri) threeDspectro(kroyeri) # Controling some arguments threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), dBlevel=50) # As points threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=TRUE, plot.type="points") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=TRUE, plot.type="points", x.length = 20, y.length = 50) # As lines threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines", along="y") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines", along="y", skip.lines=18, space.lines=0.8) # Try different colors threeDspectro(cuvieri, color=seewave::reverse.terrain.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, color=seewave::reverse.cm.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, color=grDevices::heat.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) # Rotation threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), rotate.Xaxis=40, rotate.Yaxis=50) # Export your graph threeDspectro(cuvieri, plot.exp=TRUE, store.at=tempdir(), tlim=c(0,0.5), flim=c(0,4))
# As simple as this threeDspectro(centralis) threeDspectro(cuvieri) threeDspectro(kroyeri) # Controling some arguments threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), dBlevel=50) # As points threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=TRUE, plot.type="points") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), samp.grid=TRUE, plot.type="points", x.length = 20, y.length = 50) # As lines threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines", along="y") threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), plot.type = "lines", along="y", skip.lines=18, space.lines=0.8) # Try different colors threeDspectro(cuvieri, color=seewave::reverse.terrain.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, color=seewave::reverse.cm.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) threeDspectro(cuvieri, color=grDevices::heat.colors(80), samp.grid=FALSE, tlim=c(0, 0.5), flim=c(0, 4)) # Rotation threeDspectro(cuvieri, tlim=c(0, 0.5), flim=c(0, 4), rotate.Xaxis=40, rotate.Yaxis=50) # Export your graph threeDspectro(cuvieri, plot.exp=TRUE, store.at=tempdir(), tlim=c(0,0.5), flim=c(0,4))