A new method to link covariance-defined lines of least resistance to realized macroevolutionary change
Authors: Anonymous
Type: Software
Published: 2026-08-03

<div class="body pm-cursor-color pm-text-color pm-background-color pm-editing-root-node pm-scroll-container">
<div class="pm-content">
<div class="yaml-block pm-code-block">--- editor_options: markdown: wrap: 72 ---</div>
<h1 class=" pm-heading">Supporting Data and Code for "A new method to link covariance-defined lines of least resistance to realized macroevolutionary change"</h1>
<h1 class=" pm-heading">Data</h1>
<p>This folder contains data and phylogenetic trees to replicate the analyses on Mammals and Lepidosaurs.</p>
<h2 class=" pm-heading">File contents</h2>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Supplementary Table S1.xlsx</code></h3>
<p>Mammals raw data including humerus, radius, femur, tibia and greater skull lengths and substrate from Serio et al. (2024). Two additional columns include body mass data and related references.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">mammaltree.txt</code></h3>
<p>Phylogenetic tree in newik format for mammalian species included in Supplementary Table S1.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Supplementary Table S2.xlsx</code></h3>
<p>Lepidosaurs raw data including forelimb, hindlimb and snout-vent lengths, body mass and vertebral count.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">lepitree.txt</code></h3>
<p>Phylogenetic tree in newik format for lepidosaur species included in Supplementary Table S2.</p>
<h1 class=" pm-heading">Codes</h1>
<p>This folder contains the current development files for the covariance-aware multivariate extension of <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphylo</code>, together with tools for covariance preparation, evolvability summaries, clade-level analyses, and export of results.</p>
<h2 class=" pm-heading">File contents</h2>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">prepMV.R</code></h3>
<p>Contains <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">prepMV()</code>, an upstream diagnostic and preparation function for the response matrix and its covariance structure.</p>
<p>By default, <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">prepMV()</code> performs diagnosis only. It evaluates:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p>numbers of observations and traits</p>
</li>
<li class="pm-list-item">
<p>observation-to-trait and trait-to-observation ratios</p>
</li>
<li class="pm-list-item">
<p>trait variances and differences in scale</p>
</li>
<li class="pm-list-item">
<p>exact duplicate and sign-reversed variables</p>
</li>
<li class="pm-list-item">
<p>numerical rank and linear dependence</p>
</li>
<li class="pm-list-item">
<p>covariance eigenvalues</p>
</li>
<li class="pm-list-item">
<p>positive definiteness</p>
</li>
<li class="pm-list-item">
<p>Cholesky feasibility</p>
</li>
<li class="pm-list-item">
<p>covariance condition number</p>
</li>
</ul>
<p>When <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">action = "apply"</code>, the function can prepare one of four covariance treatments:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">sample</code>, the ordinary sample covariance when numerically suitable</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">tipRidge</code>, a regularized tip covariance estimated with <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">mvMORPH::mvols</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">pca</code>, an explicitly reduced PCA representation</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">phyRidge</code>, an explicitly requested Brownian evolutionary covariance estimated with <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">mvMORPH::mvgls</code></p>
</li>
</ul>
<p>The <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">auto</code> option retains the ordinary sample covariance when it is safe and otherwise recommends full-space tip-covariance regularization. PCA is never selected automatically when exact biological redundancy must first be resolved deliberately.</p>
<p>The returned <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">rrArgs</code> component contains the prepared <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">y</code> and <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">MV</code> arguments that can be passed directly to <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphylo()</code>.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphyloMV supporting functions.R</code></h3>
<p>Contains auxiliary RRphyloMV functions called internally by <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphylo()</code>. These functions implement ridge-penalty optimization, the multivariate ridge solver, Mahalanobis dispersion, and related internal calculations. They are not intended to be called directly in routine analyses.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphyloMV.R</code></h3>
<p>Contains the main <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphylo()</code> implementation.</p>
<p>When <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">MV = TRUE</code>, the function estimates the covariance matrix from the matched tip phenotypes. A user-supplied positive-definite covariance matrix can instead be passed through <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">MV</code>. The multivariate response is centred, whitened by the Cholesky factor of the covariance matrix, fitted through a common phylogenetic ridge-regression problem, and then re-coloured into the original trait coordinates.</p>
<p>The returned object contains, among other elements:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">tree</code>, the matched phylogeny</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">rates</code>, the scalar branch-rate magnitudes</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">aces</code>, the estimated ancestral phenotypes</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">predicted.phenotype</code>, the fitted terminal phenotypes</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">multiple.rates</code>, the re-coloured multivariate branch-rate matrix</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">lambda</code>, the optimized ridge penalty</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">x1.rate</code>, when an evolutionary covariate is supplied</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">MVinfo</code>, when covariance-aware fitting is used. This includes the covariance matrix, its inverse, effective penalties, eigenvalues, and eigenvectors</p>
</li>
</ul>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">getEvolvability.R</code></h3>
<p>Contains <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">getEvolvability()</code>, which translates an RRphyloMV result into summaries of covariance-defined potential evolvability and realized macroevolutionary use.</p>
<p>The function eigendecomposes the covariance matrix and projects the re-coloured branch-rate vectors onto its eigenvectors. It returns:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">AxisSummary</code>, containing eigenvalues, variance explained, effective penalties, realized energy, signed energy, absolute displacement, and mean branch alignment</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Loadings</code>, the covariance-axis loadings</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">BranchScores</code>, signed branch projections onto the covariance axes</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">BranchEnergy</code>, squared branch projections</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">BranchSignedEnergy</code>, signed squared branch projections</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">BranchAlignment</code>, the fraction of each branch-rate vector associated with each axis</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">BranchWeights</code>, the weights used for axis-level summaries</p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">TipScores</code> and, when available, <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">NodeScores</code></p>
</li>
</ul>
<p>Available branch-weighting schemes are <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">branch.length</code>, <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">equal</code>, <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">rate.magnitude</code>, and <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">branch.length.rate</code>. The default is branch-length weighting.</p>
<p>The current implementation is descriptive. It does not perform the former rotation-null test and does not return rotation-based p-values. Deprecated null-test arguments are ignored with a warning.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Evola auxilliary functions.R</code></h3>
<p>Contains auxiliary functions for post-hoc evolvability analyses. These functions support clade-level projection onto local or global covariance axes, comparison of cranial and appendicular loadings, and calculation of angles between axes. They are used after <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">getEvolvability()</code> and need not be called for the basic workflow.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">exportEvola.R</code></h3>
<p>Contains <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">exportEvola()</code>, which writes selected <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">getEvolvability()</code> results to an Excel workbook.</p>
<p>The workbook contains:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Axis Metrics & Loadings</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Signed Branch Energy</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Branch Alignment</code></p>
</li>
</ul>
<p>When a tree or vector of tip labels is supplied, the branch-level matrices are matched to terminal species and the most negative and positive signed-energy values, together with the highest and lowest alignment values, are exported for the requested axes.</p>
<h3 class=" pm-heading"><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Study Cases Script.R</code></h3>
<p>The routine to replicate the analyses on Mammals and Lepidosaurs.</p>
<h2 class=" pm-heading">Required packages</h2>
<p>The main workflow uses functions from:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">RRphylo</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">ape</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">phytools</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">parallel</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">doParallel</code></p>
</li>
</ul>
<p>Optional functionality additionally requires:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">mvMORPH</code> for covariance regularization in <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">prepMV()</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">openxlsx</code> for <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">exportEvola()</code></p>
</li>
</ul>
<h2 class=" pm-heading">Loading the files</h2>
<p>Source the main and auxiliary files before running an analysis:</p>
<pre class="r pm-fixedwidth-font"><code>source("RRphyloMV supporting functions.R")
source("RRphyloMV.R")
source("prepMV.R")
source("getEvolvability.R")
source("Evola auxilliary functions.R")
source("exportEvola.R")</code></pre>
<p>The two auxiliary files must be available because their functions are called by the main RRphyloMV and evolvability routines.</p>
<h2 class=" pm-heading">Minimal usage</h2>
<p>Assume that:</p>
<ul class="pm-list pm-bullet-list">
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">tree</code> is an object of class <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">phylo</code></p>
</li>
<li class="pm-list-item">
<p><code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">Y</code> is a numeric matrix or data frame of response traits</p>
</li>
<li class="pm-list-item">
<p>species names are stored in <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">rownames(Y)</code></p>
</li>
</ul>
<h3 class=" pm-heading">1. Diagnose the covariance structure</h3>
<pre class="r pm-fixedwidth-font"><code>prep <- prepMV(Y)
prep</code></pre>
<p>This performs diagnosis only and does not alter the data or covariance matrix.</p>
<h3 class=" pm-heading">2. Fit RRphyloMV with the ordinary tip covariance</h3>
<p>When the diagnosis reports a safe covariance matrix:</p>
<pre class="r pm-fixedwidth-font"><code>RRmv <- RRphylo(
  tree = tree,
  y = Y,
  MV = TRUE,
  clus = 0.5
)</code></pre>
<p>Alternatively, use <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">prepMV()</code> to prepare the arguments explicitly:</p>
<pre class="r pm-fixedwidth-font"><code>prep <- prepMV(
  Y,
  action = "apply",
  method = "sample"
)

RRmv <- RRphylo(
  tree = tree,
  y = prep$rrArgs$y,
  MV = prep$rrArgs$MV,
  clus = 0.5
)</code></pre>
<h3 class=" pm-heading">3. Fit with a regularized tip covariance when needed</h3>
<pre class="r pm-fixedwidth-font"><code>prep <- prepMV(
  Y,
  action = "apply",
  method = "tipRidge",
  target = "unitVariance"
)

RRmv <- RRphylo(
  tree = tree,
  y = prep$rrArgs$y,
  MV = prep$rrArgs$MV,
  clus = 0.5
)</code></pre>
<p>This retains the full supplied trait space. The inferred covariance geometry is conditional on the selected regularization target.</p>
<h3 class=" pm-heading">4. Extract evolvability summaries</h3>
<pre class="r pm-fixedwidth-font"><code>evola <- getEvolvability(
  RRmv,
  branch.weights = "branch.length"
)

evola
head(evola$AxisSummary)</code></pre>
<p>For branch-level results:</p>
<pre class="r pm-fixedwidth-font"><code>head(evola$BranchScores)
head(evola$BranchSignedEnergy)
head(evola$BranchAlignment)</code></pre>
<h3 class=" pm-heading">5. Export results</h3>
<pre class="r pm-fixedwidth-font"><code>exportEvola(
  evola = evola,
  tree = tree,
  outputPath = "Evola_results.xlsx",
  nAxes = 3,
  nExtreme = 5
)</code></pre>
<h2 class=" pm-heading">Analysis with an evolutionary covariate</h2>
<p>A predictor such as body mass can be supplied through <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">x1</code>:</p>
<pre class="r pm-fixedwidth-font"><code>RRmv <- RRphylo(
  tree = tree,
  y = Y,
  x1 = X1,
  MV = TRUE,
  clus = 0.5
)

 evola <- getEvolvability(
  RRmv,
  branch.weights = "branch.length"
)</code></pre>
<p>Supplying <code class="pm-code pm-fixedwidth-font pm-chunk-background-color pm-block-border-color">x1</code> changes estimation of the branch-rate vectors. It does not automatically replace the covariance matrix of the response traits with a residual covariance matrix.</p>
<h2 class=" pm-heading">Important interpretation</h2>
<p>Covariance eigenvalues and effective penalties describe covariance-defined potential phenotypic directions. Branch scores, energy, displacement, and alignment describe realized use of those directions by the estimated branch-rate vectors. These outputs are phenotypic and macroevolutionary summaries. They are not direct estimates of additive genetic covariance or population-level response to selection.</p>
</div>
</div>