annotation_colors option in plotMarkerHeatmap?
Hello, thanks for a lovely package.
I was wondering if it is possible to provide annotation_colors to plotMarkerHeatmap, similar to how one can provide it to plotScoreHeatmap?
Thanks!
Should work, yep.
annotation_colors just needs to look something like this. labels needs to be the name of the element in the list, and then label1, label2, etc. should match your actual labels:
annotation_colors = list(
labels = c(label1 = "red", label2 = "blue")
)
If you give equivalent of plotScoreHeatmap(..., annotation_colors = list(labels = c(label1 = "red", label2 = "blue"))) then annotation_colors gets passed directly through to pheatmap::pheatmap to do its job. (In the docs as "... Additional parameters for heatmap control passed to pheatmap")
Thanks for your fast response! That's what I thought should work, but it isn't for me. Note that plotScoreHeatmap accepts my annotation_colors without error, but plotMarkerHeatmap errors out (I tried it twice in case the capitalization change mattered).
> plt = SingleR::plotScoreHeatmap(celltypes_mousernaseq,
+ annotation_colors = list(Labels = mouse_colors))
> x = SingleR::plotMarkerHeatmap(celltypes_mousernaseq, test = norm_counts,
+ label = "Neurons",
+ annotation_colors = list(labels = mouse_colors))
Error in SingleR::plotMarkerHeatmap(celltypes_mousernaseq, test = norm_counts, :
unused argument (annotation_colors = list(labels = mouse_colors))
> x = SingleR::plotMarkerHeatmap(celltypes_mousernaseq, test = norm_counts,
+ label = "Neurons",
+ annotation_colors = list(Labels = mouse_colors))
Error in SingleR::plotMarkerHeatmap(celltypes_mousernaseq, test = norm_counts, :
unused argument (annotation_colors = list(Labels = mouse_colors))
Oh! You're right. Looking further, the commit where the ... machinery was added happened after the last Bioconductor release, so it's likely that it's only a feature in the devel version at the moment.
There's another Bioconductor release coming next month, but I'll have to leave the decision to @LTLA whether to make an extra push to the current release.
In the meantime, try using this plotMarkerHeatmapAlt version. (Simple enough function... only change I've actually made here was the SingleR::: to access the only internal I've noticed, in the first line. But I'm unfortunately not in a position to test so 🤞):
plotMarkerHeatmapAlt <- function(
results,
test,
label,
other.labels=NULL,
assay.type="logcounts",
display.row.names=NULL,
use.pruned=FALSE,
order.by.effect="cohens.d",
order.by.summary="min.rank",
top=20,
num.threads=bpnworkers(BPPARAM),
BPPARAM = SerialParam(),
...)
{
test <- SingleR:::.to_clean_matrix(test, assay.type, check.missing=FALSE, num.threads=num.threads)
config <- configureMarkerHeatmap(
results,
test,
label=label,
other.labels=other.labels,
assay.type=assay.type,
use.pruned=use.pruned,
order.by.effect=order.by.effect,
order.by.summary=order.by.summary,
num.threads=num.threads
)
to.show <- head(config$rows, top)
predictions <- config$predictions
test <- test[to.show, config$columns, drop=FALSE]
if (!is.null(display.row.names)) {
rownames(test) <- display.row.names[to.show]
}
limits <- range(test, na.rm=TRUE)
colnames(test) <- seq_len(ncol(test))
pheatmap::pheatmap(
test,
breaks=seq(limits[1], limits[2], length.out=26),
color=viridis::viridis(25),
annotation_col=data.frame(labels=predictions, row.names=colnames(test)),
cluster_col=FALSE,
show_colnames=FALSE,
...
)
}
Thanks! I'm using version 2.8, so I made similar adjustments to that version, and now it is working! I appreciate your help! (Also, I didn't realize you can access internal functions with :::, so cool!)
Altered version:
plotMarkerHeatmapAlt = function(
results,
test,
label,
other.labels=NULL,
assay.type="logcounts",
display.row.names=NULL,
use.pruned=FALSE,
order.by="rank.logFC.cohen",
top=20,
BPPARAM = BiocParallel::SerialParam(),
...)
{
test <- SingleR:::.to_clean_matrix(test, assay.type, check.missing=FALSE)
all.markers <- metadata(results)$de.genes[[label]]
if (use.pruned) {
labfield <- "pruned.labels"
} else {
labfield <- "labels"
}
predictions <- results[[labfield]]
ckeep <- seq_len(ncol(test))
if (!is.null(other.labels)) {
ckeep <- predictions %in% other.labels
predictions <- predictions[ckeep]
for (n in names(all.markers)) {
if (!(n %in% other.labels) && n != label) {
all.markers[[n]] <- NULL
}
}
} else if (anyNA(predictions)) {
ckeep <- !is.na(predictions)
predictions <- predictions[ckeep]
}
rkeep <- rownames(test) %in% unlist(all.markers)
test <- test[rkeep,ckeep,drop=FALSE]
# Prioritize the markers with interesting variation in the test data for
# visualization. If we only have one label, we use the most abundant markers.
if (length(unique(predictions)) > 1L) {
interesting <- scran::scoreMarkers(test, predictions, BPPARAM=BPPARAM)
stats <- interesting[[label]]
o <- order(stats[[order.by]], decreasing=!startsWith(order.by, "rank."))
to.show <- rownames(test)[o]
} else {
abundance <- rowMeans(test)
to.show <- names(abundance)[order(abundance, decreasing=TRUE)]
}
to.show <- match(head(to.show, top), rownames(test))
colnames(test) <- seq_len(ncol(test))
col.order <- order(predictions)
test <- test[to.show,col.order,drop=FALSE]
predictions <- predictions[col.order]
if (!is.null(display.row.names)) {
rownames(test) <- display.row.names[rkeep][to.show]
}
limits <- range(test, na.rm=TRUE)
pheatmap::pheatmap(
test,
breaks=seq(limits[1], limits[2], length.out=26),
color=viridis::viridis(25),
annotation_col=data.frame(labels=predictions, row.names=colnames(test)),
cluster_col=FALSE,
show_colnames=FALSE,
...
)
}