| Title: | Point-and-Click Cluster Analysis of Molecular and Trait Data |
|---|---|
| Description: | A 'shiny' application and a set of plain R functions for clustering samples from dominant markers, SNP genotypes (CSV, VCF or HapMap), quantitative or mixed traits, and DNA or protein sequences. It computes distance matrices, builds trees by UPGMA, WPGMA, single, complete or Ward linkage, neighbour joining or BIONJ, and checks them with marker bootstrap support (Felsenstein 1985 <doi:10.1111/j.1558-5646.1985.tb00420.x>), cophenetic correlation, average silhouette width, the gap statistic and Mantel tests. It also offers principal coordinates and principal components, k-means and partitioning around medoids, and exports a self-contained HTML report and an R script that reproduces the analysis. |
| Authors: | Ebenezer Ogoe [aut, cre, cph] (Co-creator; wrote the 2026 package), Michael Obeng [aut] (Co-creator of Clusnalyst (2022)), Stephen Amoako [aut] (Co-creator of Clusnalyst (2022)) |
| Maintainer: | Ebenezer Ogoe <ebenezerogoe@gmail.com> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-14 22:33:29 UTC |
| Source: | https://github.com/ebenogoe/clusnalyst |
Align sequences with the msa package
align_sequences(d, method = c("ClustalOmega", "ClustalW", "Muscle"))align_sequences(d, method = c("ClustalOmega", "ClustalW", "Muscle"))
d |
A |
method |
|
The same object with an aligned matrix in x.
Attach metadata to a dataset
attach_metadata(d, meta)attach_metadata(d, meta)
d |
A |
meta |
A data frame from |
d with meta holding one row per sample (in sample order).
Resamples the markers, traits or alignment sites with replacement, recomputes the distance matrix and the tree for each replicate, and reports how often each group in the original tree is found again (Felsenstein 1985). For rooted trees the groups are clades; for unrooted NJ and BIONJ trees they are bipartitions.
bootstrap_tree( d, tree, distance = NULL, B = 100, seed = 1, sqrt_binary = FALSE, scale = TRUE, progress = NULL )bootstrap_tree( d, tree, distance = NULL, B = 100, seed = 1, sqrt_binary = FALSE, scale = TRUE, progress = NULL )
d |
The |
tree |
A |
distance |
Distance method used for the tree. |
B |
Number of bootstrap replicates. |
seed |
Random seed, so the run can be repeated exactly. |
sqrt_binary, scale
|
Passed to |
progress |
Optional function called with the share done (0 to 1). |
A list with support (percent, one value per internal node of
tree$phylo), trees (the replicate trees), B, failed and
seed.
Includes whichever results are present: data summary, quality check, distances, tree, bootstrap, cluster number, groups and ordination, plus the settings and software versions. Figures are embedded as SVG, so the file can be opened anywhere and needs no other files.
build_report( res, settings = list(), path, title = "Clusnalyst report", tree_layout = "rectangular" )build_report( res, settings = list(), path, title = "Clusnalyst report", tree_layout = "rectangular" )
res |
A list with any of |
settings |
The settings list. |
path |
Output file. |
title |
Report title. |
tree_layout |
Tree layout for the figure. |
path, invisibly.
Write an R script that repeats an analysis
build_script(settings, source, meta_file = NULL)build_script(settings, source, meta_file = NULL)
settings |
A settings list (see |
source |
List describing the data: |
meta_file |
Optional metadata file name. |
A character string of R code.
Hierarchical methods give a rooted, ultrametric tree. NJ and BIONJ give
an unrooted tree; give outgroup to root it. Negative branch lengths
from NJ are set to zero.
build_tree(dist, method = "upgma", outgroup = NULL)build_tree(dist, method = "upgma", outgroup = NULL)
dist |
A |
method |
A method from |
outgroup |
Optional sample name(s) to root an NJ or BIONJ tree on. |
A cl_tree list with phylo (an ape tree), hclust (for
hierarchical methods), method and rooted.
d <- clusnalyst_demo("binary") tr <- build_tree(compute_distance(d), "upgma")d <- clusnalyst_demo("binary") tr <- build_tree(compute_distance(d), "upgma")
The Okabe and Ito palette (safe for colour-blind readers), without its yellow and black, and HCL colours beyond eight groups.
cl_palette(n)cl_palette(n)
n |
Number of colours. |
Character vector of hex colours.
Missing values are handled pairwise: each pair of samples is compared on the markers (or sites) both of them have.
compute_distance(d, method = NULL, sqrt_binary = FALSE, scale = TRUE)compute_distance(d, method = NULL, sqrt_binary = FALSE, scale = TRUE)
d |
A |
method |
A method from |
sqrt_binary |
Use sqrt(1 - S) for binary measures. |
scale |
Scale numeric traits to unit variance before Euclidean or Manhattan distances. |
Binary measures are returned as 1 minus the similarity. Set
sqrt_binary = TRUE for the square root form that ade4::dist.binary()
returns, which is Euclidean. For biallelic SNPs, IBS distance equals
Prevosti's distance.
A dist object with a method attribute.
d <- clusnalyst_demo("binary") dm <- compute_distance(d, "jaccard")d <- clusnalyst_demo("binary") dm <- compute_distance(d, "jaccard")
Majority-rule consensus of bootstrap trees
consensus_tree(boot, p = 0.5)consensus_tree(boot, p = 0.5)
boot |
Result of |
p |
Share of trees a group must appear in (0.5 = majority rule). |
An ape tree.
The correlation between the distances you started with and the distances implied by the tree. Values near 1 mean the tree keeps the original distances well.
cophenetic_cor(dist, tree)cophenetic_cor(dist, tree)
dist |
A |
tree |
A |
A number.
Compare tree methods by cophenetic correlation
cophenetic_table(dist, methods = tree_choices())cophenetic_table(dist, methods = tree_choices())
dist |
A |
methods |
Methods to compare. |
A data frame sorted from the best-fitting method down.
Data types Clusnalyst works with
data_types()data_types()
A named character vector, labels as names.
Default distance for a dataset
default_distance(d)default_distance(d)
d |
A |
A method name.
Every step of the app is described by one entry in this list. The app
fills it in as you go, run_analysis() replays it, and
build_script() turns it into R code.
default_settings(d = NULL)default_settings(d = NULL)
d |
Optional |
A named list.
Five small datasets for trying the app. binary, snp and traits
are simulated (see data-raw/make_demos.R in the source). dna is the
woodmouse cytochrome b alignment from the ape package, and protein is
the hemoglobin alpha example from the msa package.
demo_info() clusnalyst_demo(name = c("snp", "binary", "traits", "dna", "protein"))demo_info() clusnalyst_demo(name = c("snp", "binary", "traits", "dna", "protein"))
name |
One of |
demo_info() returns a data frame describing each dataset.
clusnalyst_demo() returns a cl_data object, with metadata
where the demo has it.
clusnalyst_demo("snp")clusnalyst_demo("snp")
Looks at the file extension first and then at the first lines of the file.
detect_format(path, name = basename(path))detect_format(path, name = basename(path))
path |
Path to the file. |
name |
Original file name, if |
One of "csv", "tsv", "excel", "vcf", "hapmap" or
"fasta".
Distance measures available for a data type
distance_choices(type)distance_choices(type)
type |
A data type from |
A named character vector (labels as names). The first entry is the default.
Markers (or traits) are filtered first, then samples are checked against the markers that are left.
filter_data( d, max_marker_missing = 0.2, min_maf = 0, drop_monomorphic = TRUE, max_sample_missing = 0.5, drop_empty_sites = TRUE )filter_data( d, max_marker_missing = 0.2, min_maf = 0, drop_monomorphic = TRUE, max_sample_missing = 0.5, drop_empty_sites = TRUE )
d |
A |
max_marker_missing |
Largest share of missing values allowed per marker or trait (0 to 1). |
min_maf |
Smallest minor allele (or band) frequency kept (marker data only). |
drop_monomorphic |
Drop markers or traits that do not vary. |
max_sample_missing |
Largest share of missing values allowed per sample. |
drop_empty_sites |
For aligned sequences, drop sites that are gaps in every sequence. |
The filtered cl_data, with a filter element recording what
was removed.
Accepts two-letter calls (AA, AG), separated calls (A/G, A|G) and
single IUPAC codes (A, R, Y, ...). For each marker the most common
allele is the reference, so a dosage counts copies of the other allele:
0 = homozygous for the common allele, 1 = heterozygous, 2 = homozygous
for the other allele. Markers with more than two alleles count every
allele that is not the common one.
genotypes_to_dosage(m)genotypes_to_dosage(m)
m |
Character matrix with samples in rows and markers in columns. |
Numeric matrix of 0, 1, 2 and NA, same dimensions as m.
genotypes_to_dosage(matrix(c("AA", "AG", "GG", "R", "NN", "A/G"), 3))genotypes_to_dosage(matrix(c("AA", "AG", "GG", "R", "NN", "A/G"), 3))
Guess the data type of a table
guess_type(tab)guess_type(tab)
tab |
A data frame whose first column holds IDs and whose other columns are character. |
A list with type and encoding.
Can PCA or k-means be used on this dataset?
has_numeric(d)has_numeric(d)
d |
A |
TRUE for marker data and for data with numeric traits.
Uses the samples the two matrices share.
mantel_test(d1, d2, permutations = 999, seed = 1)mantel_test(d1, d2, permutations = 999, seed = 1)
d1, d2
|
|
permutations |
Number of permutations. |
seed |
Random seed. |
A list with r, p, n and permutations.
Useful for a Mantel test of genetic distance against geography (for example latitude and longitude) or any measured covariates.
metadata_distance(meta, columns, scale = FALSE)metadata_distance(meta, columns, scale = FALSE)
meta |
A data frame with sample names as row names. |
columns |
Numeric columns to use. |
scale |
Scale the columns first. |
A Euclidean dist object.
For each k from 2 to k_max, splits the samples into k groups and
records the average silhouette width (Rousseeuw 1987), the within-group
sum of squares (for an elbow plot) and, optionally, the gap statistic
(Tibshirani et al. 2001). Hierarchical trees are cut with
stats::cutree(); NJ and BIONJ trees cannot be cut that way, so
partitioning around medoids (PAM) is used instead.
optimal_k(dist, tree = NULL, k_max = 10, gap = FALSE, gap_B = 50, seed = 1)optimal_k(dist, tree = NULL, k_max = 10, gap = FALSE, gap_B = 50, seed = 1)
dist |
A |
tree |
Optional |
k_max |
Largest k to try. |
gap |
Also compute the gap statistic (slower). |
gap_B |
Reference datasets for the gap statistic. |
seed |
Random seed for the gap statistic. |
A list with a table (one row per k), best_silhouette,
best_gap and clustering (how the groups were formed).
PCoA (classical multidimensional scaling) works from any distance matrix. PCA needs numeric data; missing values are replaced by the column mean, and traits (not markers) are scaled to unit variance.
ordinate(dist = NULL, d = NULL, method = c("pcoa", "pca"), n_axes = 5)ordinate(dist = NULL, d = NULL, method = c("pcoa", "pca"), n_axes = 5)
dist |
A |
d |
A |
method |
|
n_axes |
Number of axes to keep. |
A cl_ord list with scores, variance (percent for every
axis) and method.
Split samples into groups
partition( dist, k, method = c("tree", "pam", "kmeans"), tree = NULL, d = NULL, seed = 1 )partition( dist, k, method = c("tree", "pam", "kmeans"), tree = NULL, d = NULL, seed = 1 )
dist |
A |
k |
Number of groups. |
method |
|
tree |
A hierarchical |
d |
A |
seed |
Random seed for k-means. |
A named integer vector of group numbers. Groups are numbered in the order they first appear down the tree when a tree is given.
Heatmap of a distance matrix
plot_heatmap(dist, order = NULL, dark = FALSE, interactive = TRUE)plot_heatmap(dist, order = NULL, dark = FALSE, interactive = TRUE)
dist |
A |
order |
Optional sample order (for example the tree's tip order). |
dark |
Colours for a dark background. |
interactive |
Add hover text to each cell. |
A ggplot object.
Plot the cluster-number diagnostics
plot_k(kres, dark = FALSE)plot_k(kres, dark = FALSE)
kres |
Result of |
dark |
Colours for a dark background. |
A ggplot object.
Plot two distance matrices against each other
plot_mantel(mantel, labels = c("Distance 1", "Distance 2"), dark = FALSE)plot_mantel(mantel, labels = c("Distance 1", "Distance 2"), dark = FALSE)
mantel |
Result of |
labels |
Axis labels. |
dark |
Colours for a dark background. |
A ggplot object.
Plot an ordination
plot_ordination( ord, groups = NULL, group_title = "Group", axes = c(1, 2), labels = FALSE, ellipses = TRUE, tooltip = NULL, dark = FALSE )plot_ordination( ord, groups = NULL, group_title = "Group", axes = c(1, 2), labels = FALSE, ellipses = TRUE, tooltip = NULL, dark = FALSE )
ord |
A |
groups |
Optional named vector of groups for colour. |
group_title |
Legend title. |
axes |
Which two axes to plot. |
labels |
Show sample names. |
ellipses |
Draw 95% ellipses for groups with at least four samples. |
tooltip |
Optional named character vector of hover text. |
dark |
Colours for a dark background. |
A ggplot object.
Plot quality-check summaries
plot_qc(qc, dark = FALSE, thresholds = NULL)plot_qc(qc, dark = FALSE, thresholds = NULL)
qc |
Result of |
dark |
Colours for a dark background. |
thresholds |
Optional named list with |
A ggplot object.
Scree plot of an ordination
plot_scree(ord, n = 10, dark = FALSE)plot_scree(ord, n = 10, dark = FALSE)
ord |
A |
n |
Number of axes to show. |
dark |
Colours for a dark background. |
A ggplot object.
Plot bootstrap support values
plot_support(boot, dark = FALSE)plot_support(boot, dark = FALSE)
boot |
Result of |
dark |
Colours for a dark background. |
A ggplot object.
Plot a tree
plot_tree( tree, layout = "rectangular", groups = NULL, group_title = "Group", support = NULL, support_min = 0, tooltip = NULL, label_size = 3.5, title = NULL, dark = FALSE, show_scale = TRUE )plot_tree( tree, layout = "rectangular", groups = NULL, group_title = "Group", support = NULL, support_min = 0, tooltip = NULL, label_size = 3.5, title = NULL, dark = FALSE, show_scale = TRUE )
tree |
A |
layout |
One of |
groups |
Optional named vector (names = sample names) used to colour the tips. |
group_title |
Legend title for |
support |
Optional bootstrap support, one value per internal node. |
support_min |
Only show support at or above this value. |
tooltip |
Optional named character vector of hover text per tip. |
label_size |
Size of the tip labels. |
title |
Plot title. |
dark |
Colours for a dark background. |
show_scale |
Draw a branch-length scale bar. |
A ggplot object (interactive with ggiraph::girafe()).
For marker data: missing data per marker and per sample, minor allele (or band) frequency, heterozygosity and monomorphic markers. For traits: missing data and spread per trait. For sequences: lengths, gaps and variable sites.
qc_summary(d)qc_summary(d)
d |
A |
A list with markers and samples data frames and totals.
Read a FASTA file
read_fasta(path, type = NULL)read_fasta(path, type = NULL)
path |
Path to the file. |
type |
|
A cl_data object of type "dna" or "protein".
Read a HapMap genotype file
read_hapmap(path)read_hapmap(path)
path |
Path to a HapMap ( |
A cl_data object of type "snp".
Reads CSV, TSV or Excel tables (first column = sample IDs), VCF, HapMap and FASTA files. The data type and the table orientation are guessed when not given.
read_markers( path, name = basename(path), format = NULL, type = NULL, transpose = NULL )read_markers( path, name = basename(path), format = NULL, type = NULL, transpose = NULL )
path |
Path to the file. |
name |
Original file name (used for format detection). |
format |
File format; guessed with |
type |
Data type, one of |
transpose |
|
A cl_data object.
f <- system.file("extdata", "demo_binary.csv", package = "clusnalyst") read_markers(f)f <- system.file("extdata", "demo_binary.csv", package = "clusnalyst") read_markers(f)
Read a sample metadata table
read_metadata(path, name = basename(path))read_metadata(path, name = basename(path))
path |
Path to a CSV, TSV or Excel file whose first column holds sample IDs. |
name |
Original file name. |
A data frame with sample IDs as row names.
A square table whose row and column names are the same samples is read
as a distance matrix. Anything else is read as data with
read_markers() and turned into distances with the default measure for
its type.
read_second_matrix(path, name = basename(path))read_second_matrix(path, name = basename(path))
path |
Path to the file. |
name |
Original file name. |
A dist object.
Read a VCF file as SNP dosages
read_vcf(path)read_vcf(path)
path |
Path to a |
A cl_data object of type "snp".
Run a whole analysis from settings
run_analysis(d, settings = default_settings(d), progress = NULL)run_analysis(d, settings = default_settings(d), progress = NULL)
d |
A |
settings |
A list like |
progress |
Optional function called with a message at each step. |
A list with data, dist, tree, boot, kres, groups and
ord.
res <- run_analysis(clusnalyst_demo("binary")) res$treeres <- run_analysis(clusnalyst_demo("binary")) res$tree
Run the Clusnalyst app
run_app( onStart = NULL, options = list(), enableBookmarking = NULL, uiPattern = "/", ... )run_app( onStart = NULL, options = list(), enableBookmarking = NULL, uiPattern = "/", ... )
onStart, options, enableBookmarking, uiPattern
|
Passed to
|
... |
Options passed to the app as golem options. |
A Shiny app object.
if (interactive()) run_app()if (interactive()) run_app()
Sample names of a Clusnalyst dataset
sample_names(d)sample_names(d)
d |
A |
Character vector.
A session file is JSON: the data, the metadata and the settings. Results are recomputed when the session is opened again, so nothing executable is stored.
save_session(d, settings, path) load_session(path)save_session(d, settings, path) load_session(path)
d |
The |
settings |
The settings list. |
path |
File to write or read. |
save_session() returns path invisibly; load_session()
returns a list with data and settings.
Bands from Kaufman and Rousseeuw (1990).
silhouette_meaning(asw)silhouette_meaning(asw)
asw |
Average silhouette width. |
A short phrase.
ggplot2 theme used by Clusnalyst
theme_clusnalyst(base_size = 12, dark = FALSE)theme_clusnalyst(base_size = 12, dark = FALSE)
base_size |
Base font size. |
dark |
Use colours for a dark background. |
A ggplot2 theme.
Tree-building methods
tree_choices()tree_choices()
A named character vector (labels as names).