---
title: "cgMLST comparison report"
date: "`r format(Sys.time(), '%d %B, %Y')`"
output:
  html_document:
    toc: true
    toc_depth: 2
---

<style type="text/css">
.main-container {
  max-width: 3600px;
  margin-left: auto;
  margin-right: auto;
}
</style>

<style>
  tbody tr:hover {
  background: yellow;
} 

</style>


```{r setup, include=FALSE}
knitr::opts_chunk$set(out.width = '80%',fig.asp= 0.5,fig.align='center',echo=FALSE, warning=FALSE, message=FALSE, fig.height = 20, fig.width = 20, fig.align = "center")
options(markdown.HTML.header = system.file("misc", "datatables.html", package = "knitr"))

```


```{r load_packages, echo=FALSE}

suppressPackageStartupMessages(library(magrittr))
suppressPackageStartupMessages(library(reshape2)) # for converting matrix
suppressPackageStartupMessages(library(ggplot2)) # for plotting (which?)
suppressPackageStartupMessages(library(ape)) # read/write data
suppressPackageStartupMessages(library(DT)) # datatable 
suppressPackageStartupMessages(library(plotly)) # interactive plots/trees
suppressPackageStartupMessages(library(dendextend)) ##  get_nodes_attr
suppressPackageStartupMessages(library(ggtree)) ## nice trees


```


```{r define_functions, echo=FALSE}

read_distance_matrix <- function(file, sep = " ", header = FALSE){
  if(!file.exists(file)) {stop(paste("File",file,"does Not exist")); return(NA)}
  distance_matrix <- read.delim(file, sep=sep, stringsAsFactors = F, header = header)
  
  # check if distance matrix has at least 2 entries:
  if(ncol(distance_matrix) == 2 & nrow(distance_matrix) == 1) {return(NA)}
  
  # create proper row and column names
    rownames(distance_matrix) <- sub(".fasta","",distance_matrix[,1])
  distance_matrix <- distance_matrix[,-1]
  colnames(distance_matrix) <- rownames(distance_matrix)
  
  # order matrix
  distance_matrix <- as.matrix(distance_matrix[order(colnames(distance_matrix)),order(colnames(distance_matrix))])
  
  return(distance_matrix)
}

reorder_cormat <- function(cormat){
  dd <- as.dist(cormat)
  hc <- hclust(dd)
  cormat <-cormat[hc$order, hc$order]
}

get_upper_tri <- function(cormat){
  cormat[lower.tri(cormat)]<- NA
  return(cormat)
}


plot_distance_matrix <- function(distance_matrix2, param_color_thr = c(0,1,5,10,20), param_size = 3, param_legendsize = 12, label_color = "black"){
  
  # remove diagonal elements
  diag(distance_matrix2) <- NA
  
  # Reorder the correlation matrix
  distance_matrix2 <- reorder_cormat(distance_matrix2)
  
  # convert to data frame
  
  # melt matrix
  distance_matrix.m <- reshape2::melt(distance_matrix2, na.rm = TRUE, value.name="Distance",varnames=c("Sample1","Sample2"), id.vars = "id")
  
  p1 <- ggplot(distance_matrix.m, aes(Sample1, Sample2)) +
    geom_tile(aes(fill = Distance), colour = "white", show.legend = F) + 
    geom_text(aes(label = round(Distance, 1)), size = param_size) +
    scale_fill_gradientn(colours = c("white", "yellow", "orange", "red"), values = scales::rescale(param_color_thr)) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, size = param_legendsize, hjust = 1, color = label_color),  axis.text.y = element_text(size = param_legendsize, color = label_color), axis.title.x = element_blank(),
          axis.title.y = element_blank()) + coord_fixed()
  
  
  return(p1)
  
}

```




```{r define_data}

dev_mode <- F # receive parameters from snakemake, set to T for testing purposes

if(dev_mode){
  source(file = "report_cluster_test_params.R")
} else {
  
workdir <-   snakemake@input[["workdir"]]
  
samples_related_file <- snakemake@input[["samples_related"]]
match_overview_file <- snakemake@input[["match_overview"]]
distance_matrix_filtered_file <- snakemake@input[["distance_matrix_filtered"]]
distance_matrix_file <- snakemake@input[["distance_matrix"]]
#distance_table_file <- snakemake@input[["distance_table"]]
sample_meta_file <- snakemake@input[["sample_meta"]]
allele_stats_file <- snakemake@input[["allele_stats"]]
nwk_all_file <- snakemake@input[["mstree_all"]]
nwk_filtered_file <- snakemake@input[["mstree_filtered"]]

external_name  <- snakemake@params[["name"]]
clustering_method  <- snakemake@params[["clustering_method"]]
samplesheet  <- snakemake@params[["samplesheet"]]
distance_threshold  <- snakemake@params[["clustering_threshold"]]
parameters  <- snakemake@params[["parameters"]]
outdir  <- snakemake@params[["outdir"]]
threshold_range  <- snakemake@params[["threshold_range"]]

comparison_allele_profile_file <- snakemake@params[["comparison_db"]]

hashid_file <- file.path(workdir, snakemake@input[["hashids"]])

config = file.path(workdir,"config.yaml")

log <- file(snakemake@log[[1]], open="wt")

# redirect output to log file
sink(log)
sink(log, type="message")

}

```


```{r load_data, echo=FALSE}

allele_stats <- read.delim(allele_stats_file, stringsAsFactors = F, header = T, sep = "\t")

distance_matrix <- read_distance_matrix(distance_matrix_file)

distance_matrix_filtered <- read_distance_matrix(distance_matrix_filtered_file,header = T, sep = "\t")
# make exception if too few samples
if(is.na(distance_matrix_filtered)){
  runChunk <- F  
  # TODO collect closest samples
} else {
  runChunk <- T  
}

# eval = runChunk

samples_meta <- read.delim(sample_meta_file, stringsAsFactors = F, header = T, sep = "\t")

samples_extern <- read.delim(samplesheet, stringsAsFactors = F, header = T, sep = "\t")$sample

hashids <- read.delim(hashid_file, stringsAsFactors = F)

#sample_timestamps <- read.delim(sample_timestamps_file, stringsAsFactors = F, header = T, sep = "\t")
nwk_filtered <- ape::read.tree(nwk_filtered_file)

clustering_threshold_range <- as.numeric(strsplit(threshold_range,"[ ,;]+")[[1]])

```

```{r preprocess_data}

# # re-order matrix
# # round distances
distance_matrix <- round(distance_matrix,0)
distance_matrix_filtered <- round(distance_matrix_filtered,0)

# create distance table, distance beteen internal and external samples
distance_table <- distance_matrix[which(rownames(distance_matrix) %in% samples_extern), which(! rownames(distance_matrix) %in% samples_extern)]

#if (!is.matrix(distance_table)){
if(length(samples_extern) == 1 ){
  distance_table <- t(as.matrix(distance_table))
  rownames(distance_table) <- samples_extern
}

# melt matrix
distance_table.m <- reshape2::melt(distance_table)
colnames(distance_table.m) <- c("Sample_query","Sample_comparisonDB","Distance")

# best matches

best_match_table <- do.call(rbind,lapply(unique(distance_table.m$Sample_query), function(mysample){
  mymatches <- distance_table.m[distance_table.m$Sample_query == mysample,]
  mymin <- min(mymatches$Distance)
  mybestmatch <- mymatches[which.min(mymatches$Distance),]
  return(mybestmatch)
}))


largest_distance <- max(best_match_table$Distance)
smalles_distance <- min(best_match_table$Distance)


# filter distant samples away
distance_limit <- 500

if(largest_distance > distance_limit) distance_limit <- largest_distance
distance_table_filtered.m <- distance_table.m[distance_table.m$Distance < distance_limit,]

# melt filtered distance matrix

if(!is.na(distance_matrix_filtered)){
  distance_matrix_filtered.m <- reshape2::melt(distance_matrix_filtered)
colnames(distance_matrix_filtered.m) <- c("Sample1","Sample2","Distance")

  distance_matrix_filtered.m <- distance_matrix_filtered.m[distance_matrix_filtered.m$Sample1 != distance_matrix_filtered.m$Sample2,]
  
}

```

# Cluster report for `r basename(workdir)` {.tabset}

## Overview

```{r overview_stats, echo=FALSE}

# Quality
bad_allele_threshold <- 0.05
bad_allele_fraction <- rowSums(allele_stats[,-c(1,2,3)])/rowSums(allele_stats[,-1])
good_allele_fraction <- 1 - bad_allele_fraction
bad_samples <- allele_stats[which(bad_allele_fraction > bad_allele_threshold),1]
bad_sample_count <- sum(bad_allele_fraction > bad_allele_threshold)

# add quality summary to allele_stats
locus_count <- sum(allele_stats[1,-1])


allele_stats <- data.frame(allele_stats[,1],good_allele_fraction=round(good_allele_fraction,2),bad_allele_fraction=round(bad_allele_fraction,2),allele_stats[,-1])
colnames(allele_stats)[1:3] <- c("Sample","Fraction of\nloci found","Fraction of\nmissing loci")

sample_count_internal <- ncol(distance_table)
sample_count_external <- nrow(distance_table)

```

* All data in `r workdir`

* Last update on `r strsplit(as.character(file.info(distance_matrix_file)$mtime[1]), split = " ")[[1]][1]`.

* Comparison database is `r comparison_allele_profile_file`.

* Last update of comparison database on `r strsplit(as.character(file.info(comparison_allele_profile_file)$mtime[1]), split = " ")[[1]][1]`.

* Comparison database contains `r sample_count_internal` samples.

* External database contains `r sample_count_external` samples.

* Lowest distance between query and comparison data: `r smalles_distance`

* Scheme contains `r locus_count` loci

* `r bad_sample_count` samples were of bad quality (having more than `r bad_allele_threshold * 100` per cent missing or dubiously called alleles ), see __Allele statistics__ for details.



## Allele statistics

Note that only the allele statistics of the external data are shown here. For the allele statistics of the entire dataset refer to the chewieSnake report of the comparison db.


```{r allele_stats, echo=FALSE}

DT::datatable(allele_stats, filter = 'top',rownames= FALSE, escape = FALSE, 
          extensions = list("ColReorder" = NULL, "Buttons" = NULL, "FixedColumns" = list(leftColumns=1)),
    options = list(
                dom = 'BRrltpi',
                autoWidth=FALSE,
                scrollX = TRUE,
                fixedColumns = TRUE,
                lengthMenu = list(c(10, 50, -1), c('10', '50', 'All')),
                ColReorder = TRUE,
                buttons =
                  list(
                    'copy',
                    'print',
                    list(
                      extend = 'collection',
                      buttons = c('csv', 'excel', 'pdf'),
                      text = 'Download'
                    ),
                    I('colvis')
                  )
              ))


# more stats, viz

ggplot(allele_stats, aes(x=EXC)) + geom_histogram(binwidth = 10) + xlab("Number of exact matches")
ggplot(allele_stats, aes(x=LNF)) + geom_histogram(binwidth = 1) + xlab("Number of loci not found")
ggplot(allele_stats, aes(x=PLOT)) + geom_histogram(binwidth = 1) + xlab("Number of contig-tip loci (PLOT)")
ggplot(allele_stats, aes(x=NIPH)) + geom_histogram(binwidth = 1) + xlab("Number of possible paralogs")


```


### Abbreviations

*  EXC - alleles which have exact matches (100% DNA identity) with previously identified alleles

*  INF - inferred new alleles using Prodigal CDS predictions

*  LNF - loci not found. No alleles were found for the number of loci in the schema shown. This means that, for those loci, there were no BLAST hits or they were not within the BSR threshold for allele assignment.

* PLOT - possible loci on the tip of the query genome contigs (see image below). A locus is classified as PLOT when the CDS of the query genome has a BLAST hit with a known larger allele that covers the CDS sequence entirely and the unaligned regions of the larger allele exceeds one of the query genome contigs ends. This could be an artifact caused by genome fragmentation resulting in a shorter CDS prediction by Prodigal. To avoid locus misclassification, loci in such situations are classified as PLOT.

*  NIPH - non-informative paralogous hit (see image below). When ≥ 2 CDSs in the query genome match one locus in the schema with a BSR > 0.6, that locus is classified as NIPH. This suggests that such locus can have paralogous (or orthologous) loci in the query genome and should be removed from the analysis due to the potential uncertainty in allele assignment (for example, due to the presence of multiple copies of the same mobile genetic element (MGE) or as a consequence of gene duplication followed by pseudogenization). A high number of NIPH may also indicate a poorly assembled genome due to a high number of smaller contigs which result in partial CDS predictions. These partial CDSs my contain conserved domains that match multiple loci. This classification takes precedence over PLOT classification.
* NIPHEM - similar to NIPH classification (NIPH with exact match), but specifically referring to exact matches. Whenever > 1 CDS matches different alleles of the same locus with 100% DNA similarity during the first DNA sequence comparison, the NIPHEM tag is attributed. The loci classified as NIPHEM are included in NIPH statistics file column, but represent a distinct classification in the MLST profile.

    
* ALM - alleles 20% larger than length mode of the distribution of the matched loci (CDS length > (locus length mode + locus length mode * 0.2)) (see image below). This determination is based on the currently identified set of alleles for a given locus.
* ASM - similar to ALM but for alleles 20% smaller than length mode distribution of the matched loci (CDS length < (locus length mode - locus length mode * 0.2)).


See [here](https://github.com/B-UMMI/chewBBACA/wiki/2.-Allele-Calling) for more details.


## Allele distance table


The allele distance table compares query samples vs. samples from the comparisonDB.



### Best comparisonDB match for each query sample

```{r best_match_table, echo=FALSE}

DT::datatable(best_match_table, filter = 'top',rownames= FALSE, escape = FALSE, 
          extensions = list("ColReorder" = NULL, "Buttons" = NULL, "FixedColumns" = list(leftColumns=1)),
    options = list(
                dom = 'BRrltpi',
                autoWidth=FALSE,
                scrollX = TRUE,
                order = list(list(2, 'asc')),
                fixedColumns = TRUE,
                lengthMenu = list(c(10, 50, -1), c('10', '50', 'All')),
                ColReorder = TRUE,
                buttons =
                  list(
                    'copy',
                    'print',
                    list(
                      extend = 'collection',
                      buttons = c('csv', 'excel', 'pdf'),
                      text = 'Download'
                    ),
                    I('colvis')
                  )
              ))





```

### All comparisonDB distances to all query samples below threshold

All distances above `r distance_limit` have been omitted.

`r if(!runChunk) paste("No matches found between comparisonDB and query samples below threshold",distance_threshold)`


```{r distance_table, echo=FALSE, eval = runChunk}

DT::datatable(distance_table_filtered.m, filter = 'top',rownames= FALSE, escape = FALSE, 
          extensions = list("ColReorder" = NULL, "Buttons" = NULL, "FixedColumns" = list(leftColumns=1)),
    options = list(
                dom = 'BRrltpi',
                autoWidth=FALSE,
                scrollX = TRUE,
                order = list(list(2, 'asc')),
                fixedColumns = TRUE,
                lengthMenu = list(c(10, 50, -1), c('10', '50', 'All')),
                ColReorder = TRUE,
                buttons =
                  list(
                    'copy',
                    'print',
                    list(
                      extend = 'collection',
                      buttons = c('csv', 'excel', 'pdf'),
                      text = 'Download'
                    ),
                    I('colvis')
                  )
              ))


```

### Visualization of allele distance table

Shown are all matches between query data and comparisonDB data with allele distance smaller 30.

```{r viz_distance_table, echo=FALSE}



distance_table_related.m <- distance_table.m[distance_table.m$Distance < 30,]

param_color_thr = c(0,1,5,10,20)
label_color = "black"
# dynamic size
if (length(unique(distance_table_related.m$Sample_comparisonDB)) > 30 | length(unique(distance_table_related.m$Sample_query)) > 30){
  param_size = 1.5
  param_legendsize = 6
} else {
  param_size = 3
  param_legendsize = 12
}




p_distancetable <- ggplot(distance_table_related.m, aes(Sample_query, Sample_comparisonDB)) +
    geom_tile(aes(fill = Distance), colour = "white", show.legend = F) + 
    geom_text(aes(label = round(Distance, 1)), size = param_size) +
    scale_fill_gradientn(colours = c("white", "yellow", "orange", "red"), values = scales::rescale(param_color_thr)) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, size = param_legendsize, hjust = 1, color = label_color),  axis.text.y = element_text(size = param_legendsize, color = label_color), axis.title.x = element_blank(), axis.title.y = element_blank()) + coord_fixed()

p_distancetable

```

## Allele distance matrix

The pairwise distance matrix between all query and closely related comparisonDB samples has been clustered and colored to visualize similarity of groups of closely related strains.

`r if(!runChunk) "No matches found between query and comparisonDB samples below threshold "`


```{r distance_matrix, echo=FALSE, eval = runChunk}
  label_color <- ifelse(samples_meta$origin == "comparison_db", "black", "blue")

# dynamic size
if (nrow(distance_matrix_filtered) > 30){
  param_size = 1.5
  param_legendsize = 6
} else {
  param_size = 3
  param_legendsize = 12
}




  p1b <- plot_distance_matrix(distance_matrix_filtered, param_size = param_size, param_legendsize = param_legendsize, label_color = label_color)
  p1b
  
```


### Interactive visualization

The figure can be zommed, exported and on hover displays the distance value (z)

```{r interactive_distance_matrix, echo=FALSE, eval = runChunk}

a <- list(
  title = "Sample",
  showticklabels = TRUE,
  tickangle = 45
)

# interactive allele matrix
 p2 <- plot_ly(x=distance_matrix_filtered.m$Sample1,y=distance_matrix_filtered.m$Sample2,z=distance_matrix_filtered.m$Distance, type = "heatmap") %>%
 layout(xaxis = a, yaxis = a, showlegend = TRUE)
 p2

```




## Clustering

`r if(!runChunk) "No matches found between query and comparisonDB samples below threshold"`



```{r clustering, echo=FALSE, eval = runChunk}

# add clustering, cluster-address

clust <- distance_matrix_filtered %>% as.dist %>% hclust(., method = clustering_method)
dendro <- clust %>% as.dendrogram 
phylo <- clust %>% as.phylo

# subclusters
subcluster_counts <- lapply(clustering_threshold_range, function(cut_threshold) cut(dendro, h = cut_threshold)) %>% sapply(., function(x) length(x$lower))
names(subcluster_counts) <- clustering_threshold_range

# initialize cluster_address_matrix
cluster_address_matrix <- matrix(data = NA, nrow = nrow(distance_matrix_filtered), ncol = length(clustering_threshold_range), dimnames = list( rownames(distance_matrix_filtered),rev(clustering_threshold_range)))

# compute cluster membership for all thresholds
for(cut_threshold in clustering_threshold_range) {
  dendro_cut <- cut(dendro, h = cut_threshold)
  for (subcluster in 1:length(dendro_cut$lower)){
    cluster_address_matrix[dendro_cut$lower[[subcluster]] %>% get_nodes_attr("label") %>% .[!is.na(.)],as.character(cut_threshold)] <- subcluster
  }
}

# re-order
cluster_address_matrix <- cluster_address_matrix[,as.character(sort(as.numeric(colnames(cluster_address_matrix)),decreasing = T))]

# convert to single address
cluster_address <- apply(cluster_address_matrix,1,function(x) paste(x, collapse = "."))

# table of cluster membership
cluster_address_matrix_augmented <- as.data.frame(cluster_address_matrix)
colnames(cluster_address_matrix_augmented) <- paste("threshold",colnames(cluster_address_matrix_augmented),sep = "_")
cluster_address_matrix_augmented$Sample <- rownames(cluster_address_matrix)

cluster_address_matrix_augmented[] <- lapply( cluster_address_matrix_augmented, factor) 

cluster_address_matrix_augmented <- cluster_address_matrix_augmented[,c(ncol(cluster_address_matrix_augmented),1:(ncol(cluster_address_matrix_augmented)-1))]

# add hashid
#sample  hashID
cluster_address_matrix_augmented <- merge(cluster_address_matrix_augmented,hashids,by.x="Sample", by.y="sample")


```


The clustering is based on the allele distance matrix.

The allele distance matrix was hierarchically clustered using `r paste0(clustering_method,"-linkage")` clustering and the subsequent clustering was divided into different sub-clustered at the chosen thresholds `r paste(clustering_threshold_range,collape=",") `. At each threshold, samples are assigned to a cluster - resulting in a cluster member number. Searching the following table provides information which samples cluster together at a chosen allele threshold.

The combined cluster member numbers at all chosen threshold correspond to the cluster address.

Note that the cluster member numbers (cluster address) may be subject to change every time the clustering is run again!

The entire tree as well as the individual trees can be exported and visualized - together with relevant metadata - in interactive tools such as grapetree, phandango etc.

```{r visualize_clustering, eval = runChunk}

DT::datatable(cluster_address_matrix_augmented, caption = "Cluster membership", filter = 'top',rownames= FALSE, escape = FALSE, 
          extensions = list("ColReorder" = NULL, "Buttons" = NULL, "FixedColumns" = list(leftColumns=1)),
    options = list(
                dom = 'BRrltpi',
                autoWidth=FALSE,
                scrollX = TRUE,
                #fixedColumns = TRUE,
                lengthMenu = list(c(10, 50, -1), c('10', '50', 'All')),
                #ColReorder = TRUE,
                buttons =
                  list(
                    'copy',
                    'print',
                    list(
                      extend = 'collection',
                      buttons = c('csv', 'excel', 'pdf'),
                      text = 'Download'
                    ),
                    I('colvis')
                  )
              ))



clustering_summary <- cbind("Distance threshold" = names(subcluster_counts), "Cluster count" = subcluster_counts)
knitr::kable(clustering_summary,row.names = F)

```


### Details of clustering analysis using a cluster threshold of `r distance_threshold`

In the following, the clustering analysis is visualized as a `r paste0(clustering_method,"-linkage tree")`. At a cluster threshold of `r distance_threshold`, the tree is divided int sub-clusters (cluster types), indicated by the coloring of the branches.

```{r cluster_viz_overview, eval = runChunk}
color_value <- 3

if (length(phylo$tip.label) > 50) {
    my_cex_tiplabel <- 0.5
    my_cex_edgelabel <- 0.4
    } else{
    my_cex_tiplabel <- 0.8
    my_cex_edgelabel <- 0.7
  }



dendro %>% set("labels_cex", my_cex_tiplabel) %>% set("labels_col", value = rainbow(color_value), h=distance_threshold) %>% set("branches_k_color", value = rainbow(color_value), h = distance_threshold) %>% 
  plot(main = paste("Tree resulting from clustering analysis"), sub = paste("Colored by using cluster threshold of",distance_threshold), horiz = T, xlab = "Clustering threshold", ylab = "Samples")
abline(v= distance_threshold, col = 8 , lwd = 3)

```


### `r paste0(clustering_method,"-linkage tree")`

Shown here is the `r paste0(clustering_method,"-linkage tree")` with the branch length defined by the allele distance and with labels colored by comparisonDB (black) and query (blue) data.

```{r cluster_viz_overview_2, eval = runChunk}

if (length(phylo$tip.label) > 50) {
    my_cex_tiplabel <- 0.5
    my_cex_edgelabel <- 0.5
    } else{
    my_cex_tiplabel <- 0.8
    my_cex_edgelabel <- 0.8
  }
  

  edge_color <- ifelse(phylo$edge.length<1,"white","red") 
  tip_color <- ifelse(samples_meta$origin[match(phylo$tip.label,samples_meta$id)]=="comparison_db","black","blue")
  plot(phylo, main = paste0(clustering_method,"-linkage tree"), cex=my_cex_tiplabel, tip.color = tip_color)
  edgelabels(round(phylo$edge.length, 0), srt = 0, bg = "white", adj = c(0.5,1), col = edge_color, cex = my_cex_edgelabel, frame = "none")


```


### Cluster details

Shown here are the tree structures of the `r paste0(clustering_method,"-linkage tree")` for every sub-cluster defined by an allele distance of `r distance_threshold`. Clusters containing only a single sample are excluded.

Note that the cluster numbers can be looked up in the _cluster membership_ table above - in the field `r paste0("threshold_",distance_threshold)`. Furthermore, in the colored tree visualized above, every neighboring cluster is colored with a different color - starting with cluster 1 at the bottom.

```{r cluster_viz_details_3, results="asis", eval = runChunk}

dendro_cut <- cut(dendro, h = distance_threshold)
clusters_notplotted <- c()

#par_default <- par()
par(mar=c(2,2,4.1,6.1))

for (subtree in 1:length(dendro_cut$lower)){  
  dend <- dendro_cut$lower[[subtree]]
  
  cluster_size <- dend %>% get_nodes_attr("label") %>% (function(x) x[!is.na(x)]) %>% length
  if(cluster_size > 1){
    
  cat("\n")
  cat(paste("###","Cluster",subtree))
  cat("\n")

    
    plot(dend, horiz = T, main = paste("Subtree for cluster",subtree))
  } else {
    clusters_notplotted <- c(clusters_notplotted,subtree)
  }
}


```

The following clusters - only containing a single sample - were not plotted: `r if(!runChunk) {"NA"} else {paste(clusters_notplotted, collapse = ",")}`



## Minimum-spanning tree
A minimum spanning tree was computed based on the allele profiles using _grapetree_.

Note that you can visualize the tree more interactively and combine it with metadata using tools such as _grapetree_ or _phandango_. Large plots may not be optimally plotted here.


```{r trees3, echo=FALSE, out.width = "100%", eval = runChunk}  

  print("Version 3")

  if (nrow(samples_meta) > 30) {
    plot_label_size <- 2  
  } else {
    plot_label_size <- 6
  }
  
  ggtree(nwk_filtered) %<+% samples_meta + geom_tiplab(aes(color=origin),size=plot_label_size) + theme_tree2(legend.position="right") + labs(caption="allele distance")

```

## Links to files

All data is available at `r workdir`.



```{r file_info}



file_timestamps <- data.frame(
  name=c(
"distance matrix",
"filtered distance matrix",
"Minimum spanning tree of all comparisonDB and query samples",
"Minimum spanning tree of related comparisonDB and query samples"
  ),
  file=c(
distance_matrix_file,
distance_matrix_filtered_file,
nwk_all_file,
nwk_filtered_file
)
)

file_timestamps$Link <- paste0("<a href=",file_timestamps$file,">",file_timestamps$name,"</a>")

knitr::kable(file_timestamps, caption = "Overview of files used for this report and their modification date")


```


## Config and parameters
All  parameters are defined in the file config.yaml:


```{r }

#print(config)
scan(config,what=character(),sep="\n")

```

The individual tools and their versions are listed in the .yaml files in the directory `env`

## Help


### Grapetree instructions
* Download / copy minimum spanning tree
* Open grapetree
* Load tree file
* Load one or more metadata tsv files with the sample name in the first column (e.g. bakcharak summary data, geospatial/temporal metadata)
* E.g. subset data to particular clade and export data as json for sharing

### Other tools
* iTOL
* phandango
* ...


