Introduction to workloopR
Vikram B. Baliga
2024-12-14
Source:vignettes/Introduction-to-workloopR.Rmd
Introduction-to-workloopR.Rmd
Welcome to workloopR
In this vignette, we’ll provide an overview of core functions in
workloopR
. Other vignettes within the package give more
details with respect to specific use-cases. Examples with code can also
be found within each function’s Help doc.
workloopR
(pronounced “work looper”) provides functions
for the import, transformation, and analysis of muscle physiology
experiments. As you may have guessed, the initial motivation was to
provide functions to analyze work loop experiments in R, but we have
expanded this goal to cover additional types of experiments that are
often involved in work loop procedures. There are three currently
supported experiment types: work loop, simple twitch, and tetanus.
Analytical pipelines
To cut to the chase, workloopR
offers the ability to
import, transform, and then analyze a data file. For example, with a
work loop file:
library(workloopR)
## import the workloop.ddf file included in workloopR
wl_dat <-read_ddf(system.file("extdata", "workloop.ddf",
package = 'workloopR'),
phase_from_peak = TRUE)
## select cycles 3 through 5 using a peak-to-peak definition
wl_selected <- select_cycles(wl_dat, cycle_def = "p2p", keep_cycles = 3:5)
## run the analysis function and get the full object
wl_analyzed <- analyze_workloop(wl_selected, GR = 2)
## for brevity, the print() method for this object produces a simple output
wl_analyzed
#> File ID: workloop.ddf
#> Cycles: 3 cycles kept out of 6
#> Mean Work: 0.00308 J
#> Mean Power: 0.08474 W
## but see the structure for the full output, e.g.
#str(wl_analyzed)
## or run the analysis but get the simplified version
wl_analyzed_simple <- analyze_workloop(wl_selected, simplify = TRUE, GR = 2)
wl_analyzed_simple
#> Cycle Work Net_Power
#> a A 0.002785397 0.07639783
#> b B 0.003147250 0.08661014
#> c C 0.003305744 0.09122522
Batch processing of files within a directory (e.g. successive trials of an experiment) is also readily achieved:
## batch read and analyze files included with workloopR
analyzed_wls <- read_analyze_wl_dir(system.file("extdata/wl_duration_trials",
package = 'workloopR'),
cycle_def = "p2p",
keep_cycles = 2:4,
phase_from_peak = TRUE
)
## now summarize
summarized_wls <- summarize_wl_trials(analyzed_wls)
summarized_wls
#> File_ID Cycle_Frequency Amplitude Phase Stimulus_Pulses
#> 1 01_4pulse.ddf 28 3.15 -24.36 4
#> 2 02_2pulse.ddf 28 3.15 -24.64 2
#> 3 03_6pulse.ddf 28 3.15 -24.92 6
#> 4 04_4pulse.ddf 28 3.15 -24.64 4
#> Stimulus_Frequency mtime Mean_Work Mean_Power
#> 1 300 1734147269 0.0028362363 0.078967198
#> 2 300 1734147269 0.0009686570 0.026247519
#> 3 300 1734147269 -0.0001310863 -0.004017894
#> 4 300 1734147269 0.0024082708 0.066959552
Sections below will give more specific overviews.
Data import
Data that are stored in .ddf format (e.g. generated by Aurora
Scientific’s Dynamic Muscle Control and Analysis Software) are easily
imported via the function read_ddf()
. Two additional
all-in-one functions (read_analyze_wl()
and
read_analyze_wl_dir()
) also import data and subsequently
transform and analyze them. More on those functions later!
Importing via these functions generates objects of class
muscle_stim
, which are formatted to work nicely with
workloopR
’s core functions and help with error checking
procedures throughout the package. muscle_stim
objects are
organized to store time-series data for Time, Position, Force, and
Stimulation in a data.frame
and also store core metadata
and experimental parameters as Attributes.
We’ll provide a quick example using data that are included within the package.
library(workloopR)
## import the workloop.ddf file included in workloopR
wl_dat <-read_ddf(system.file("extdata", "workloop.ddf",
package = 'workloopR'),
phase_from_peak = TRUE)
## muscle_stim objects have their own print() and summary() S3 methods
## for example:
summary(wl_dat) # some handy info about the imported file
#> # Workloop Data: 3 channels recorded over 0.3244s
#>
#> File ID: workloop.ddf
#> Mod Time (mtime): 2024-12-14 03:34:29.341419
#> Sample Frequency: 10000Hz
#>
#> data.frame Columns:
#> Position (mm)
#> Force (mN)
#> Stim (TTL)
#>
#> Stimulus Offset: 0.012s
#> Stimulus Frequency: 300Hz
#> Stimulus Width: 0.2ms
#> Stimulus Pulses: 4
#> Gear Ratio: 1
#>
#> Cycle Frequency: 28Hz
#> Total Cycles (L0-to-L0): 6
#> Amplitude: 3.15mm
## see the first few rows of data stored within
head(wl_dat)
#> # Workloop Data: 3 channels recorded over 6e-04s
#> File ID: workloop.ddf
#>
#> Time Position Force Stim
#> 1 1e-04 0.503939 304.8715 0
#> 2 2e-04 0.506197 305.5165 0
#> 3 3e-04 0.505552 304.8715 0
#> 4 4e-04 0.506197 304.3875 0
#> 5 5e-04 0.505229 305.1940 0
#> 6 6e-04 0.506842 305.0330 0
Attributes
Again, important object metadata and experimental parameters are
stored as attributes. We make extensive use of attributes throughout the
package and most functions will update at least one attribute after
completion. So please see this feature of your muscle_stim
objects for important info!
You can use attributes
on an object itself
(e.g. attributes(wl_dat)
), but we’ll avoid doing so because
the printout can be pretty lengthy.
Instead, let’s just look at a couple interesting ones.
## names(attributes(x) gives a list of all the attributes' names
names(attributes(wl_dat))
#> [1] "names" "class" "row.names"
#> [4] "stimulus_frequency" "cycle_frequency" "total_cycles"
#> [7] "cycle_def" "amplitude" "phase"
#> [10] "position_inverted" "units" "sample_frequency"
#> [13] "header" "units_table" "protocol_table"
#> [16] "stim_table" "stimulus_pulses" "stimulus_offset"
#> [19] "stimulus_width" "gear_ratio" "file_id"
#> [22] "mtime"
## take a look at the stimulation protocol
attr(wl_dat, "protocol_table")
#> Wait.s Then.action On.port Units Parameters
#> 1 0.00 Stimulus-Train Stimulator .012, 300, 0.2, 4, 28 NA
#> 2 0.01 Sine Wave Length Out 28,3.15,6 NA
#> 3 0.00 Stimulus-Train Stimulator 0,0,0,0,0 NA
#> 4 0.10 Stop NA
## at what frequency were cyclic changes to Position performed?
attr(wl_dat, "cycle_frequency")
#> [1] 28
## at what frequency were data recorded?
attr(wl_dat, "sample_frequency")
#> [1] 10000
Data from files that are not of .ddf format
Data that are read from other file formats can be constructed into
muscle_stim
objects via as_muscle_stim()
.
Should you need to do this, please refer to our vignette “Importing data
from non .ddf sources” for an overview.
Transformations and corrections to data
Prior to analyses, data can be transformed or corrected.
Transformational functions include gear ratio correction
(fix_GR()
) and position inversion
(invert_position()
). The core idea behind these two
functions is to correct issues related to data acquisition.
For example, to apply a gear ratio correction of 2:
## this multiples Force by 2
## and multiplies Position by (1/2)
wl_fixed <- fix_GR(wl_dat, GR = 2)
# quick check:
max(wl_fixed$Force)/max(wl_dat$Force) #5592.578 / 2796.289 = 2
#> [1] 2
max(wl_fixed$Position)/max(wl_dat$Position) #1.832262 / 3.664524 = 0.5
#> [1] 0.5
A particularly important transformation -
select_cycles()
Another ‘transformational’ function is select_cycles()
,
which subsets cycles within a work loop experiment. This is a necessary
step prior to analyses of work loop data: data are labeled by cycle for
use with analyze_workloop()
.
Data analytical functions
Core analytical functions include analyze_workloop()
for
work loop files and isometric_timing()
for twitches.
analyze_workloop()
computes instantaneous velocity, net
work, instantaneous power, and net power for work loop experiments on a
per-cycle basis. isometric_timing()
provides summarization
of twitch kinetics.
To see more details about these functions, please refer to “Analyzing work loop experiments in workloopR” for work loop analyses and “Working with twitch files in workloopR” for twitches.
Some functions are readily available for batch processing of files.
The read_analyze_wl_dir()
function allows for the batch
import, cycle selection, gear ratio correction, and ultimately work
& power computation for all work loop experiment files within a
specified directory. The get_wl_metadata()
and
summarize_wl_trials()
functions organize scanned files by
recency (according to their time of last modification: ‘mtime’) and then
report work and power output in the order that trials were run.
This ultimately allows for the time_correct()
function
to correct for degradation of the muscle (according to power & work)
over time, assuming that the first and final trials are identical in
experimental parameters. If these parameters are not identical, we
advise against using this function.