Skip to content

Commit

Permalink
Merge pull request #63 from clockor2/update-docs
Browse files Browse the repository at this point in the history
docs: 📝 Update docs
  • Loading branch information
LeoFeatherstone authored Apr 15, 2024
2 parents f32f0ce + 1b710ee commit 8dfb757
Show file tree
Hide file tree
Showing 26 changed files with 349 additions and 623 deletions.
1 change: 1 addition & 0 deletions docs/downloads/tree.newick
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(((t6:0.008363424601,t1:0.008363424601):0.1843945216,t4:0.1927579462):0.9210912675,(t5:0.2590608172,(t3:0.2514467128,(t7:0.03962970241,t2:0.03962970241):0.2118170104):0.007614104384):0.8547883965);
27 changes: 27 additions & 0 deletions docs/downloads/tree.nexus
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#NEXUS
[R-package APE, Thu Apr 11 13:55:53 2024]

BEGIN TAXA;
DIMENSIONS NTAX = 7;
TAXLABELS
t3
t5
t4
t7
t1
t6
t2
;
END;
BEGIN TREES;
TRANSLATE
1 t3,
2 t5,
3 t4,
4 t7,
5 t1,
6 t6,
7 t2
;
TREE * UNTITLED = [&R] ((1:1,((((2:1,3:1):1,4:1):1,5:1):1,6:1):1):1,7:1);
END;
31 changes: 10 additions & 21 deletions docs/examples/annotations.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
# Handling annotations
# Modifying annotations

All node objects have an `annotation` field where annotations. The `annotation` fiel itself stores an object for all annotated tags. For example `Node.annotations = {Type: Blue}` for some leaf nodes in the following example.
This is another example, in addition to "Annotations and Pre-Order Traversal", that shows how annotations can be modified without a Pre-Order search.

Here, we show show how annotations can be extracted and modified in a loop. We swap Blue an Green type annotations to Red and Yellow on a small tree.

Altered annotations are then writtedn back to newick or nexus.

```typescript
let newick = '((A[&Type=Blue],B[&Type=Blue]),C[&Type=Green]);'
let tree = readNewick(newick)

if (tree.leafList !== undefined) { // Avoids 'leafList' possibly undefined error
All node objects have an `annotation` field where annotations. The `annotation` fiel itself stores an object for all annotated tags. For example `Node.annotations = {Type: Blue}` for some leaf nodes in the following example.

for (let i=0; i<tree.leafList.length; i++) {
if(tree.leafList[i].annotation.Type == 'Blue') {
tree.leafList[i].annotation.Type = 'Red'
} else {
tree.leafList[i].annotation.Type = 'Yellow'
}
}
}
Altered annotations are then written back to newick.

console.log(writeNewick(tree, true))
// (("A"[&"Type"="Red"]:0.0,"B"[&"Type"="Red"]:0.0):0.0,"C"[&"Type"="Yellow"]:0.0):0.0;
// Note types changed ^
```
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="js" data-slug-hash="vYMrRKe" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/vYMrRKe">
modify-annotations</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
18 changes: 18 additions & 0 deletions docs/examples/annotationsPreOrder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Annotations and Pre-Order Traversal

Here is an example that demonstrating how developers might work with node annotations and employ a pre-order traversal of a tree. We choose to demonstrate these together, since it makes sense to use them together. - If you want do do something to once node, it's likely you might want to apply it to other nodes given some logical condition.

In this example, we develop a function to calculate the internal to external branch length ratio (IE ratio) of a tree - a measure of 'tippiness' with larger values corresponding to shorter external branch lengths. We then calculate the IE ratio of the subtree descending from each internal node of a starting tree, and annotate each node with this value.

For those coming to PhyloJS without a computer sciance background (like the writer of this tutorial), a pre-order traversal refers to the process of applying an operation to each node in a tree starting at the root and interating through each descending node. There are many other way of trversing a tree [here](https://en.wikipedia.org/wiki/Tree_traversal).

We also present this example in `TypeScript`, since it's a good example of something that might be part of a larger application where type-safety is valuable. If you want to run the example in `JavaScript`, just delete the type annotations (eg. delete `: number`, `: string`, and so on after variable declarations). You can then use the JavaScript compiler if you go to the Codepen link.

One final thing to note is that the pre-order traversal in PhyloJS is a method on the `Node` class rather than the `Tree` class. Hence, when we do a pre-order traversal in the example code, we apply it as `tree.root.applyPreOrder()` to start at the root node. Why is it a method on Nodes rather than Trees? This is for flexibilty. - You might want to begin a pre-order traversal at an internal node, rather than for the tree as a whole.

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html" data-slug-hash="xxezGQG" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/xxezGQG">
preorder-annotations</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
33 changes: 18 additions & 15 deletions docs/examples/fetch.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
Here, we demonstrate how to read in a tree from a url using a `fetch()` request from the fetch API. In this case, we are reading in a list of trees used for testing.

```typescript
let url = 'https://raw.githubusercontent.com/clockor2/phylojs/main/test/data/egTree.nwk'
let newick;

fetch(url)
.then(res => res.text())
.then(txt => {newick = txt})

// log first 99 characters to show newick is defined
console.log(newick.slice(0,99))
// Returns:
// (Jeddah-1_KF917527_camel_2013-11-08:0.0000013865,Jeddah-1_KF958702_human_2013-11-05:0.0000013652,((
```
# Reading trees from a URL

Here, we demonstrate how to read in a tree from a url using a `fetch()` request from the fetch API. In this case, we read Newick trees from a URL as part of a small app that counts the number of trees in the link and plots the first one with Phylocanvas.

The `fetch()` request is nested in the function `treesFromURL()`, which also handles plotting data to the screen. Key features are that the fetch request is asynchronous, so we annotate it with `await` and annotate the wrapper function with `async`. You can learn more about asynchronous function in JavaScript [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)

You can copy a url linking 5 trees that we use for testing here:
```text
https://raw.githubusercontent.com/clockor2/phylojs/main/test/data/egTree.nwk
```


<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html" data-slug-hash="XWQYVeV" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/XWQYVeV">
fetch-url-tree</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
40 changes: 0 additions & 40 deletions docs/examples/ieRatio.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/examples/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Examples

The following is a series of examples demonstrating how phylojs might be used in practice.
The following is a series of examples demonstrating how PhyloJS might be used in practice. Interactive examples are hosted with [CodePen](https://codepen.io/collection/aMxopV).
15 changes: 15 additions & 0 deletions docs/examples/ladderiseApp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Ladderising Newick Trees
Here is an example of an app that ladderises a user supplied Newick string. It also plots the tree with phylocanvas to show users the ladderisation.

You can paste in any Newick string, or use the following for convenience:

```
(t4:1,(((t2:1,t7:1):1,(t1:1,t3:1):1):1,(t6:1,t5:1):1):1);
```

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="ZEZovgM" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/ZEZovgM">
ladderise-app</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
41 changes: 9 additions & 32 deletions docs/examples/mrca.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
# Finding MRCA for a set of nodes
# Extracting Clades

This script demonstrates how the `getNodeByLabel`, `getMRCA`, and `getClade` methods on the `Tree` object can be wrapped in a function to find and extract subtrees given a newick string and list of desired taxa.
This script demonstrates how the `getNodeByLabel`, `getMRCA`, and `getClade` methods on the `Tree` class can be wrapped in a function to find and extract clades relating a subset of tips.

```typescript
import { readNewick, Tree, Node } from 'phylojs';
The particular function here takes a Newick string and list of desired taxa. We use TypeScript here as this would likely be part of a larger application needing type safety. Just remove type annotations and change the compiler in codepen to run it in JavaScript.

function findMRCAandExtractSubtree(newickStr: string, labels: string[]): Tree {
const tree: Tree = readNewick(newickStr);
const nodes: Node[] = labels.map(label => {
const node = tree.getNodeByLabel(label);
if (node === null) throw new Error(`No node found with label ${label}`);
return node;
});

const mrca = tree.getMRCA(nodes);
if (mrca === null) throw new Error('MRCA is null');

const subtree: Tree = tree.getClade(mrca);

return subtree;
}

const newickStr: string = '((A:0.1,B:0.2):0.3,(C:0.3,D:0.4):0.5,E:0.6);'; // Newick string as input
const labels: string[] = ['A', 'B', 'D']; // Leaf labels to find MRCA

try {
const subtree: Tree = findMRCAandExtractSubtree(newickStr, labels);
// Process the 'subtree' as needed
// For example, you might print it to the console
// console.log(subtree);
} catch (error) {
console.error(error);
}
```
<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="js" data-slug-hash="bGJKLjL" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/bGJKLjL">
extract-subtree</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
55 changes: 8 additions & 47 deletions docs/examples/pruneGraft.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,10 @@
Here we demonstrate pruning and grafting of nodes usig the `.addChild()` and `.removeChild()` methods on the `Node` class. In effect, these can be used to add or remove clades and tips.

As a general node, using the `.copy()` method produces a deep copy of a node, and so is useful to avoid recursion issues with continual grafting.

## Pruning
```typescript
let nwk = "((A,B),(C,D));"
let tree = readNewick(nwk)

// Get ancestor of tips A and B
let node = tree.getMRCA(tree.leafList.slice(0,2))
// Prune
tree
.nodeList[node.parent.id] // Select node's parent by `id`
.removeChild(node) // Pruning step

console.log(`
Original Nwk: ${nwk}
Pruned Tree: ${writeNewick(tree)}
`)
// Returns
// Original Nwk: ((A,B),(C,D));
// Pruned Tree: (("C":0.0,"D":0.0):0.0):0.0;
```

## Grafting
```typescript
let nwk = "((A,B),(C,D));"
let tree = readNewick(nwk)

// Get ancestor of tips A and B. NB this is a `cherry` (A,B)
let node = tree.getMRCA(tree.leafList.slice(0,2))

// Graft cherry onto tip `A` 2 times to make a ladder.
for (let i=0; i<2; i++) {
tree
//.nodeList[node.parent.id] // Select node's parent by `id`
.leafList[i]
.addChild(node.copy()) // .copy() to ensure we don't bump into recursion issues
}

console.log(`
Original Nwk: ${nwk}
Pruned Tree: ${writeNewick(tree)}
`)
// Return
// Original Nwk: ((A,B),(C,D));
// Pruned Tree: (((("A":0.0,"B":0.0):0.0)"A":0.0,(((("A":0.0,"B":0.0):0.0)"A":0.0,"B":0.0):0.0)"B":0.0):0.0,("C":0.0,"D":0.0):0.0):0.0;
```
As a general note, using the `.copy()` method produces a deep copy of a node, and so is useful to avoid recursion issues, especially with iterative grafting.

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html" data-slug-hash="XWQYVvB" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/XWQYVvB">
prune-graft</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
32 changes: 0 additions & 32 deletions docs/examples/reroot.md

This file was deleted.

31 changes: 31 additions & 0 deletions docs/examples/rerootingApp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Visualisation

Here is a minimal example of a small app that randomly reroots a starting tree. We parse a tree and use phylojs to reroot it randomly in a html widget. We use phylocanvas to visualise the tree. This example demonstrates rerooting, and connection with a plotting library such as phylocanvas.

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="yLrjLyL" data-editable="true" data-user="LeoFeatherstone" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/LeoFeatherstone/pen/yLrjLyL">
visualise-reroot</a> by Leo Featherstone (<a href="https://codepen.io/LeoFeatherstone">@LeoFeatherstone</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### How random rerooting works

```javaScript
// Randomly reroot tree on button click
function onClick() {

// Returns an index from 1,...,nNodes (0 is the root)
let randomIndex = Math.floor(nNodes * Math.random() + 1)

// Select node corresponding to index
let randomNode = tree.nodeList[randomIndex]

tree.reroot(randomNode)

treeVis.setProps({
source: phylojs.writeNewick(tree)
})

}
```
Loading

0 comments on commit 8dfb757

Please sign in to comment.