Skip to content

Commit

Permalink
New icy tree style and added documentation (#16)
Browse files Browse the repository at this point in the history
- the new icytree style is now the default for R-based plots (breaking change) because the old style is bad for networks that are not tree-child.
- the icytree style option (:fulltree) is only supported with RCall. The old style (:majortree) is the default for the Gadfly-based plot.
- new manual
- cladewiseorder! is no longer used. It could be deleted from PhyloNetworks or un-exported.
  • Loading branch information
Cielbird authored Jul 21, 2021
1 parent 9e1154c commit eb77c43
Show file tree
Hide file tree
Showing 16 changed files with 647 additions and 100 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PhyloPlots"
uuid = "c0d5b6db-e3fc-52bc-a87d-1d050989ed3b"
license = "MIT"
version = "0.2.4"
version = "0.3.0"

[deps]
ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
Expand Down
4 changes: 3 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterMarkdown = "997ab1e6-3595-5248-9280-8efb232c3433"
# will be added by the CI platform as being developed:
# PhyloPlots = "c0d5b6db-e3fc-52bc-a87d-1d050989ed3b"
# will be added to track master version in make.jl:
# PhyloNetworks = "33ad39ac-ed31-50eb-9b15-43d0656eaa72"
RCall = "6f49c342-dc21-5d91-9882-a32aef131414"

[compat]
Documenter = "~0.26"
Documenter = "~0.27"
10 changes: 9 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@ using Documenter, DocumenterMarkdown
using Pkg
Pkg.add(PackageSpec(name="PhyloNetworks", rev="master"))

using PhyloNetworks
using PhyloPlots
DocMeta.setdocmeta!(PhyloPlots, :DocTestSetup, :(using PhyloPlots); recursive=true)

makedocs(
sitename = "PhyloPlots.jl",
authors = "Cécile Ané",
authors = "Cécile Ané and Guilhem Ané",
modules = [PhyloPlots], # to list plot() methods from PhyloPlots only, not from Gadfly etc.
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"), # easier local build
pages = [
"home" => "index.md",
"manual" => [
"installation" => "man/installation.md",
"getting started" => "man/getting_started.md",
"untangling edges" => "man/untangling_edges.md",
"better edges" => "man/better_edges.md",
"adding data" => "man/adding_data.md",
],
"library" => [
"public" => "lib/public.md",
"internals" => "lib/internals.md",
Expand Down
71 changes: 71 additions & 0 deletions docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,66 @@
version of Documenter was released. If so, up the dependency, check locally
that it works, make any updates as needed.
- update Julia version in `.github/workflows/ci.yml`, `matrix.version`
## The "Documenter md" format

### Note on the format

The documentation pages are all written in this format. It is a regular md, but
with extra blocks of codes (as `@example` and `@setup`) that contain Julia
commands. These lines will be executed during the `makedoc()` process. See the
`Documenter` [doc](https://juliadocs.github.io/Documenter.jl/stable/man/syntax/)
for more details on the syntax. For instance, @example blocks with the same "name"
are run in the same session. Otherwise, an @example blocks with no name
is run in its own anonymous Modules.

### Setting up the plot environment

Some of these blocs may contain plots, which are going to be drawn during the
process, requiring the use of `PhyloPlots` along with `RCall`. Hence,
before the doc is built, `.github/workflows/ci.yml` installs `R` on the server,
sets up the julia environment with dependencies like `PhyloPlots` before
starting the build in itself.

### Directory of the plots

We chose to group all the output plots in the directory `assets/figures`.
Hence, the typical setup in a documentation page containing plots is:

```@setup name
using PhyloNetworks, PhyloPlots, RCall
mkpath("../assets/figures")
figname(x) = joinpath("..", "assets", "figures", x)
```

The `mkpath` command is there to ensure that the target directory does indeed
exist. In theory, it only needs to be called once (by the first documentation
page being built). However, as this order might be subject to change over time,
it could be safer to include it on every such page.

### Format of the plots

After trial and error and discussions, we chose to use only the *SVG* format
for the plot. This format should ensure that when a plot is drawn again,
identical, in a new build, then Git will recognize that it has not change, and
hence not save a new version of it. This should ensure that the repository does
not grow unreasonably at each build of the doc, i.e. after each push to
master. The typical commands to save and display a plot should hence be:

```@example name
R"svg"(figname("my_useful_name.svg"), width=4, height=3); # hide
plot(net, :R);
R"dev.off()" # hide
nothing # hide
```
![my_useful_name](../assets/figures/my_useful_name.svg)

I like to add `R"par"(mar=[.1,.1,.1,.1]) # hide` since the default margins are too wide for my preference.

**Warning**: this is not like an interactive session. If the same file name
is re-used by some other documentation page for some other plot, only the
final version of the plot will be committed by git, with possible unintended
consequences. Make sure to use different file names for plots that are supposed
to look different (across the whole site).

## to make a local version of the website

Expand All @@ -42,3 +102,14 @@ julia> include("make.jl")
it will:
- tests the `jldoctest` blocks of examples in the docstrings
- creates or updates a `build/` directory with html files

## references

big difference:

[blabla](@ref)
[`blabla`](@ref)

The first version will look for a *section* header "blabla", to link to that section.
The secon version will look for a *function* named "blabla",
to link to the documentation for that function.
15 changes: 15 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ objects can be displayed via [Gadfly](http://gadflyjl.org/stable/),
and through [R](https://www.r-project.org)
via [RCall](https://github.com/JuliaInterop/RCall.jl).

## manual outline

```@contents
Pages = [
"man/installation.md",
"man/getting_started.md",
"man/untangling_edges.md",
"man/better_edges.md",
"man/adding_data.md"
]
Depth = 3
```

## library outline

```@contents
Pages = ["lib/public.md", "lib/internals.md"]
Depth = 1
Expand Down
108 changes: 108 additions & 0 deletions docs/src/man/adding_data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
```@setup adding_data
using PhyloNetworks, PhyloPlots, RCall, DataFrames
mkpath("../assets/figures")
figname(x) = joinpath("..", "assets", "figures", x)
```

# Adding data

In this section, we will look over ways of adding extra information or data to a plot.

## Adding labels

!!! note
For demonstration purposes, I will walk through the process of adding labels to edges,
with notes on how to do the same for nodes in parentheses.

To add labels on edges (or nodes), we need to know their numbers. We can use the
`showEdgeNumbers = true` option for this. (Use `showNodeNumbers = true` to see node numbers).

```@example adding_data
R"svg"(figname("adding_data1.svg"), width=3, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
net = readTopology("(A,((B,#H1),((C)#H1, D)));") # hide
plot(net, :R, showEdgeNumber=true);
R"dev.off()" # hide
nothing # hide
```
![example1](../assets/figures/adding_data1.svg)

We will need to define a DataFrame with two columns of information: the number of the edge (or
node), and the label that goes on it, like this:

| Number | Label |
|--------|------------------|
| 1 | "My first edge" |
| 2 | "My second edge" |

After including the DataFrames package, we can define it as so:
```@repl
using DataFrames
DataFrame(Number=[1, 2], Label=["My first edge", "My second edge"])
```
Using this dataframe as input to the `edgeLabel` (`nodeLabel` for nodes) option puts the text on the correct edges:
```@example adding_data
R"svg"(figname("edge_labels_example.svg"), width=4, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
net = readTopology("(A,((B,#H1),(C,(D)#H1)));") # hide
plot(net, :R, edgeLabel=DataFrame(Number=[1, 2], Label=["My first edge", "My second edge"]));
R"dev.off()" # hide
nothing # hide
```
![example2](../assets/figures/edge_labels_example.svg)

## Adding other data using R

We can use the return values of [`plot`](@ref) to get some information on the coordinates of
different elements of the plot. Using this, we can add any other information we want.

The [`plot`](@ref) function returns the following tuple:
```
(xmin, xmax, ymin, ymax, node_x, node_y, node_yB, node_yE,
edge_xB, edge_xE, edge_yB, edge_yE, ndf, edf)
```
See the documentation for descriptions on every element: [`plot`](@ref)

## Side clade bars example

Here's some example code that adds bars to denote clades in the margin:

```@example adding_data
R"svg"(figname("side_bars.svg"), width=4, height=4) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
net = readTopology("(((((((1,2),3),4),5),(6,7)),(8,9)),10);");
plot(net, :R, xlim=(1, 10))
R"segments"([9, 9, 9], [0.8, 7.8, 9.8], [9, 9, 9], [7.2, 9.2, 10.2])
R"text"([9.5, 9.5, 9.5], [4, 8.5, 10], ["C", "B", "A"])
R"dev.off()" # hide
nothing # hide
```
![example3](../assets/figures/side_bars.svg)

Let's break this down step by step.
First, we read the topology, and plot the graph normally. `plot` actually returns
a value, from which we can get useful information.
Below, we store the plot output in `res`, then check its first two values
because they contain the default range of the x axis; `xmin` and `xmax`.

```@example adding_data
res = plot(net, :R);
res[1:2]
```

Looking at `xmin` and `xmax` returned by default, we can see that the x
range is about `(0.3, 9)`. To give us extra space to work with, we can
set `xlim` to `(1,10)`, forcing the range to be wider.

```julia
plot(net, :R, xlim=(1, 10));
```

Knowing the coordinates, we can now add more information to the plot through
`RCall`. For this, I use the `segments` and `text` functions to add side bars with
text on them.

```
R"segments"([9, 9, 9], [0.8, 7.8, 9.8], [9, 9, 9], [7.2, 9.2, 10.2])
R"text"([9.5, 9.5, 9.5], [4, 8.5, 10], ["C", "B", "A"])
```
102 changes: 102 additions & 0 deletions docs/src/man/better_edges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
```@setup better_edges
using PhyloNetworks, PhyloPlots, RCall, DataFrames
mkpath("../assets/figures")
figname(x) = joinpath("..", "assets", "figures", x)
```

# Better edges

## Different hybrid edge styles

We can use the `style` option to visualize minor hybrid edges as simple lines,
unlike the [icytree](https://icytree.org/) style visualization. `style` is by default `:fulltree`,
but by switching it to `:majortree`, we can draw minor hybrid edges as diagonal lines.

```@example better_edges
R"svg"(figname("style_example.svg"), width=3, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
net = readTopology("(A,((B,#H1),(C,(D)#H1)));") # hide
plot(net, :R, style=:majortree);
R"dev.off()" # hide
nothing # hide
```
![example1](../assets/figures/style_example.svg)

## Using edge lengths

We can use `useEdgeLength=true` to draw a plot that uses the network's edge lengths to determine the lengths of the
lines. For this, we'll use a network that has branch lengths:

```@example better_edges
R"svg"(figname("edge_len_example.svg"), width=6, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
R"layout"([1 2]) # hide
net = readTopology("(A:3.3,((B:1.5,#H1:0.5):1.5,((C:1)#H1:1.8,D:1.1):.2):0.3);")
df = DataFrame(Number=[-3, 3], Label=["N", "H1"]); # hide
plot(net, :R, useEdgeLength=true, ylim = [-1, 5.5], nodeLabel = df); # hide
R"text"([3], [0], ["useEdgeLength=true"]) # hide
plot(net, :R, useEdgeLength=false, ylim = [-1, 5.5], nodeLabel = df); # hide
R"text"([3], [0], ["useEdgeLength=false"]) # hide
R"dev.off()" # hide
nothing # hide
```
![example2](../assets/figures/edge_len_example.svg)

!!! note
I used a DataFrame to add labels to the plot. For more on this,
see the [Adding labels](@ref) section.

If branch lengths represent time, D could represent a fossil, or a virus strain sequenced
a year before the others. Seeing this visually is the advantage of `useEdgeLengths=true`

This network happens to be time consistent, because the distance
along the time (x) axis from node `N` to the hybrid node `H1` is
the same both ways.

!!! note "Time consistency"
A network is time-consistent if all the paths between 2 given nodes all
have the same length.
Time inconsistency can occur when branch lengths are not measured in
calendar time, such as if branch lengths are in substitutions per site
(some paths might evolve with more substitutions than others), or in
number of generations (some lineages might have 1 generation per year,
others more or fewer generations per year), or in coalescent units
(number of generations / effective population size).

A time-consistent network may be ultrametric (the distance
between the root and the tips is the same across all tips),
or not like the network above.

Time inconsistent networks like these ones below might cause confusion:

```@example better_edges
R"svg"(figname("edge_len_example2.svg"), width=6, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
R"layout"([1 2]) # hide
net1 = readTopology("(A:3.3,((B:1.5,#H1:1.2):1.5,((C:1.8)#H1:1,D:1.1):.2):0.3);");
net2 = readTopology("(A:3.3,((B:1.5,#H1:0.2):1.5,((C:1)#H1:1.8,D:1.1):.2):0.3);");
plot(net1, :R, useEdgeLength=true); # hide
plot(net2, :R, useEdgeLength=true); # hide
R"dev.off()" # hide
nothing # hide
```
![example3](../assets/figures/edge_len_example2.svg)

It may be useful to consider using `style=:majortree` if it causes
too much confusion, since the `:majortree` style doesn't visually represent
minor edge lengths. Because of this, I used the `showEdgeLength=true` option to
see the information anyway.

```@example better_edges
R"svg"(figname("edge_len_example3.svg"), width=6, height=3) # hide
R"par"(mar=[.1,.1,.1,.1]) # hide
R"layout"([1 2])
plot(net1, :R, useEdgeLength=true, style = :majortree, showEdgeLength=true, arrowlen=0.1);
plot(net2, :R, useEdgeLength=true, style = :majortree, showEdgeLength=true, arrowlen=0.1);
R"dev.off()" # hide
nothing # hide
```
![example4](../assets/figures/edge_len_example3.svg)

I also used the `arrowlen=0.1` option to show the arrow tips to show the direction of minor edges,
which are hidden by default when using the `style=:majortree` option.
Loading

2 comments on commit eb77c43

@cecileane
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/41301

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.3.0 -m "<description of version>" eb77c434f67a29e92ab648f523757b46cffee5a0
git push origin v0.3.0

Please sign in to comment.