Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

S3method(plot,giottoTree)
S3method(print,giotto_plot_save_param)
export("sankeyLabel<-")
export(FSV_show)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# GiottoVisuals 0.2.16 (in development)

## enhancements
- `plot()` on a `giottoTree` from `Giotto::calculateClusterTree()` gains `what = c("tree", "heatmap")`. `"tree"` is the plain `hclust` plot, as before; `"heatmap"` draws the correlation matrix the tree was built from, in leaf order with its branches on both axes, so the colours and branches always agree.
- `showClusterHeatmap()` gains `cluster_custom_order`, to lay the clusters out in a given order, such as a cluster tree's leaf order (`tree$labels[tree$order]`). The clusters are then not clustered and no dendrogram is drawn, so the plot shows the correlations in that arrangement without claiming a structure. `expression_values` also accepts any expression name, not only `"normalized"` / `"scaled"` / `"custom"`.
- image layers in spatial plots sample with `terra::spatSample(method = "display")`, which reads from the image's overviews when it has them, instead of `"regular"`, which ignored them. On a 10x JPEG-2000 `.ome.tif`, adding a whole-image layer went from ~2.3 s to ~0.2 s. Plotted pixel values now come from the overview level, so they are averaged rather than exact.
- plot functions accept `view` and `space`: the name of a view or coordinate-frame recipe slotted on the object. The object is pre-narrowed through `GiottoClass::resolveRecipe()` once, so every slot read in a plot shares one resolver pass. The pass is scoped to the plot's own `spat_unit` / `feat_type` (GiottoClass >= 0.7.3), so on an object whose units do not share cell IDs, such as cells and nuclei, `spatPlot2D(view = )` no longer fails with "invalid extent" from a unit the view had narrowed to nothing. Added to `spatPlot2D()`, `spatInSituPlotPoints()`, `spatInSituPlotHex()`, `spatInSituPlotDensity()`, `spatDeconvPlot()`, `spatFeatPlot2D()` and `spatCellPlot2D()`. Plots that read no coordinates take `view` only, since a space changes nothing they draw: the heatmap / violin / ridge / dot / dendrogram family and `dimPlot2D()`, `dimFeatPlot2D()`, `dimCellPlot2D()`.
Expand Down
60 changes: 60 additions & 0 deletions R/plot_cluster_tree.R
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,66 @@ showClusterDendrogram <- function(gobject,
}


#' @title Plot a cluster tree
#' @name plot.giottoTree
#' @description Draw a `giottoTree` from `Giotto::calculateClusterTree()`,
#' either as the tree itself or as the correlation matrix it was built from.
#' @param x a `giottoTree`
#' @param what `"tree"` (default) draws the dendrogram with the base `hclust`
#' method. `"heatmap"` draws the correlation matrix recorded on the tree, in
#' leaf order, with the tree's branches on both axes.
#' @param ... passed to the base `hclust` plot method (e.g. `hang = -1`), or
#' to `ComplexHeatmap::Heatmap()`
#' @returns invisibly: `x` for `"tree"`, the `Heatmap` object for `"heatmap"`
#' @details
#' The heatmap shows the matrix **the branches were built from**, so the two
#' always agree. It describes the tree, not whatever object is current: to see
#' correlations recomputed from an object in a tree's order, use
#' [showClusterHeatmap()] with `cluster_custom_order =
#' tree$labels[tree$order]`, which draws no branches. For the tree with
#' annotations and per-cluster evidence, see [plotClusterTree()].
#' @examples
#' g <- GiottoData::loadGiottoMini("visium")
#' tree <- Giotto::calculateClusterTree(g, cluster_column = "leiden_clus")
#' plot(tree, hang = -1)
#' plot(tree, what = "heatmap")
#' @method plot giottoTree
#' @export
plot.giottoTree <- function(x, what = c("tree", "heatmap"), ...) {
what <- match.arg(what)
if (identical(what, "tree")) {
# the plain hclust method, without `what` reaching its graphics args
y <- x
class(y) <- setdiff(class(x), "giottoTree")
graphics::plot(y, ...)
return(invisible(x))
}

cm <- attr(x, "cor_matrix")
if (is.null(cm)) {
stop("[plot.giottoTree] this tree carries no correlation matrix. ",
"To draw correlations from an object in its order, use ",
"`showClusterHeatmap(cluster_custom_order = ",
"tree$labels[tree$order])`.", call. = FALSE)
}
package_check(pkg_name = "ComplexHeatmap", repository = "Bioc")
p <- attr(x, "params")
title <- sprintf("%s correlation of cluster means%s",
p$cor %null% "", if (is.null(p$n_feats)) "" else
sprintf(", %d features", p$n_feats))
hm <- ComplexHeatmap::Heatmap(
matrix = cm[x$labels, x$labels, drop = FALSE],
cluster_rows = x,
cluster_columns = x,
name = "r",
column_title = trimws(title),
...
)
ComplexHeatmap::draw(hm)
invisible(hm)
}


#' @title plotClusterTree
#' @name plotClusterTree
#' @description Publication figure for an annotated cluster tree: the
Expand Down
38 changes: 38 additions & 0 deletions man/plot.giottoTree.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions tests/testthat/test-plot-cluster-tree.R
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,29 @@ test_that("plotClusterTree counts within the tree's view, and flags another", {
"the tree was built with `view = \"v\"`"
), "clusters with no leaf")
})


test_that("plot(tree) draws the tree, and what = 'heatmap' its own matrix", {
skip_if_not_installed("ComplexHeatmap")
fx <- .pct_gobject()
tree <- .pct_tree(fx$gobject)
grDevices::pdf(NULL)
on.exit(grDevices::dev.off(), add = TRUE)

expect_no_warning(expect_identical(plot(tree, hang = -1), tree))

hm <- plot(tree, what = "heatmap")
expect_s4_class(hm, "Heatmap")
# the matrix the branches were built from, so the two cannot disagree
expect_identical(hm@matrix,
attr(tree, "cor_matrix")[tree$labels, tree$labels])
expect_identical(hm@row_dend_param$obj$merge, tree$merge)
})


test_that("a tree without its matrix says where to go instead", {
fx <- .pct_gobject()
tree <- .pct_tree(fx$gobject)
attr(tree, "cor_matrix") <- NULL
expect_error(plot(tree, what = "heatmap"), "cluster_custom_order")
})
Loading