#' Plots the minimum spanning tree on cells.
#'
#' @param cds CellDataSet for the experiment
#' @param x the column of reducedDimS(cds) to plot on the horizontal axis
#' @param y the column of reducedDimS(cds) to plot on the vertical axis
#' @param color_by the cell attribute (e.g. the column of pData(cds)) to map to each cell's color
#' @param show_tree whether to show the links between cells connected in the minimum spanning tree
#' @param show_backbone whether to show the diameter path of the MST used to order the cells
#' @param backbone_color the color used to render the backbone.
#' @param markers a gene name or gene id to use for setting the size of each cell in the plot
#' @param use_color_gradient Whether or not to use color gradient instead of cell size to show marker expression level
#' @param markers_linear a boolean used to indicate whether you want to scale the markers logarithimically or linearly
#' @param show_cell_names draw the name of each cell in the plot
#' @param show_state_number show state number
#' @param cell_size The size of the point for each cell
#' @param cell_link_size The size of the line segments connecting cells (when used with ICA) or the principal graph (when used with DDRTree)
#' @param cell_name_size the size of cell name labels
#' @param state_number_size the size of the state number
#' @param show_branch_points Whether to show icons for each branch point (only available when reduceDimension was called with DDRTree)
#' @param theta How many degrees you want to rotate the trajectory
#' @param ... Additional arguments passed into scale_color_viridis function
#' @return a ggplot2 plot object
#' @import ggplot2
#' @importFrom reshape2 melt
#' @importFrom igraph get.edgelist
#' @importFrom tibble rownames_to_column
#' @importFrom viridis scale_color_viridis
#' @importFrom dplyr left_join mutate n slice
#' @export
#' @examples
#' \dontrun{
#' lung <- load_lung()
#' plot_cell_trajectory(lung)
#' plot_cell_trajectory(lung, color_by="Pseudotime", show_backbone=FALSE)
#' plot_cell_trajectory(lung, markers="MYH3")
#' }
plot_cell_trajectory <- function(cds,
x=1,
y=2,
color_by="State",
show_tree=TRUE,
show_backbone=TRUE,
backbone_color="black",
markers=NULL,
use_color_gradient = FALSE,
markers_linear = FALSE,
show_cell_names=FALSE,
show_state_number = FALSE,
cell_size=1.5,
cell_link_size=0.75,
cell_name_size=2,
state_number_size = 2.9,
show_branch_points=TRUE,
theta = 0,
...) {
requireNamespace("igraph")
gene_short_name <- NA
sample_name <- NA
sample_state <- pData(cds)$State
data_dim_1 <- NA
data_dim_2 <- NA
#TODO: need to validate cds as ready for this plot (need mst, pseudotime, etc)
lib_info_with_pseudo <- pData(cds)
if (is.null(cds@dim_reduce_type)){
stop("Error: dimensionality not yet reduced. Please call reduceDimension() before calling this function.")
}
if (cds@dim_reduce_type == "ICA"){
reduced_dim_coords <- reducedDimS(cds)
} else if (cds@dim_reduce_type %in% c("simplePPT", "DDRTree") ){
reduced_dim_coords <- reducedDimK(cds)
} else {
stop("Error: unrecognized dimensionality reduction method.")
}
ica_space_df <- Matrix::t(reduced_dim_coords) %>%
as.data.frame() %>%
select_(prin_graph_dim_1 = x, prin_graph_dim_2 = y) %>%
dplyr::mutate(sample_name = rownames(.), sample_state = rownames(.))
dp_mst <- minSpanningTree(cds)
if (is.null(dp_mst)){
stop("You must first call orderCells() before using this function")
}
edge_df <- dp_mst %>%
igraph::as_data_frame() %>%
select_(source = "from", target = "to") %>%
left_join(ica_space_df %>% select_(source="sample_name", source_prin_graph_dim_1="prin_graph_dim_1", source_prin_graph_dim_2="prin_graph_dim_2"), by = "source") %>%
left_join(ica_space_df %>% select_(target="sample_name", target_prin_graph_dim_1="prin_graph_dim_1", target_prin_graph_dim_2="prin_graph_dim_2"), by = "target")
data_df <- t(monocle::reducedDimS(cds)) %>%
as.data.frame() %>%
select_(data_dim_1 = x, data_dim_2 = y) %>%
tibble::rownames_to_column("sample_name") %>%
dplyr::mutate(sample_state) %>%
left_join(lib_info_with_pseudo %>% tibble::rownames_to_column("sample_name"), by = "sample_name")
return_rotation_mat <- function(theta) {
theta <- theta / 180 * pi
matrix(c(cos(theta), sin(theta), -sin(theta), cos(theta)), nrow = 2)
}
rot_mat <- return_rotation_mat(theta)
cn1 <- c("data_dim_1", "data_dim_2")
cn2 <- c("source_prin_graph_dim_1", "source_prin_graph_dim_2")
cn3 <- c("target_prin_graph_dim_1", "target_prin_graph_dim_2")
data_df[, cn1] <- as.matrix(data_df[, cn1]) %*% t(rot_mat)
edge_df[, cn2] <- as.matrix(edge_df[, cn2]) %*% t(rot_mat)
edge_df[, cn3] <- as.matrix(edge_df[, cn3]) %*% t(rot_mat)
markers_exprs <- NULL
if (is.null(markers) == FALSE) {
markers_fData <- subset(fData(cds), gene_short_name %in% markers)
if (nrow(markers_fData) >= 1) {
markers_exprs <- reshape2::melt(as.matrix(exprs(cds[row.names(markers_fData),])))
colnames(markers_exprs)[1:2] <- c('feature_id','cell_id')
markers_exprs <- merge(markers_exprs, markers_fData, by.x = "feature_id", by.y="row.names")
#print (head( markers_exprs[is.na(markers_exprs$gene_short_name) == FALSE,]))
markers_exprs$feature_label <- as.character(markers_exprs$gene_short_name)
markers_exprs$feature_label[is.na(markers_exprs$feature_label)] <- markers_exprs$Var1
}
}
if (is.null(markers_exprs) == FALSE && nrow(markers_exprs) > 0){
data_df <- merge(data_df, markers_exprs, by.x="sample_name", by.y="cell_id")
data_df$feature_label <- factor(data_df$feature_label, levels = markers)
if(use_color_gradient) {
if(markers_linear){
g <- ggplot(data=data_df, aes(x=data_dim_1, y=data_dim_2)) + geom_point(aes(color= value), size=I(cell_size), na.rm = TRUE) +
scale_color_viridis(name = paste0("value"), ...) + facet_wrap(~feature_label)
} else {
g <- ggplot(data=data_df, aes(x=data_dim_1, y=data_dim_2)) + geom_point(aes(color=log2(value + 1)), size=I(cell_size), na.rm = TRUE) +
scale_color_viridis(name = paste0("log2(value + 1)"), ...) + facet_wrap(~feature_label)
}
} else {
if(markers_linear){
g <- ggplot(data=data_df, aes(x=data_dim_1, y=data_dim_2, size= (value * 0.1))) + facet_wrap(~feature_label)
} else {
g <- ggplot(data=data_df, aes(x=data_dim_1, y=data_dim_2, size=log2(value + 1))) + facet_wrap(~feature_label)
}
}
} else {
g <- ggplot(data=data_df, aes(x=data_dim_1, y=data_dim_2))
}
if (show_tree){
g <- g + geom_segment(aes_string(x="source_prin_graph_dim_1", y="source_prin_graph_dim_2", xend="target_prin_graph_dim_1", yend="target_prin_graph_dim_2"), size=cell_link_size, linetype="solid", na.rm=TRUE, data=edge_df)
}
# FIXME: setting size here overrides the marker expression funtionality.
# Don't do it!
if (is.null(markers_exprs) == FALSE && nrow(markers_exprs) > 0){
if(use_color_gradient) {
# g <- g + geom_point(aes_string(color = color_by), na.rm = TRUE)
} else {
g <- g + geom_point(aes_string(color = color_by), na.rm = TRUE)
}
}else {
if(use_color_gradient) {
# g <- g + geom_point(aes_string(color = color_by), na.rm = TRUE)
} else {
g <- g + geom_point(aes_string(color = color_by), size=I(cell_size), na.rm = TRUE)
}
}
if (show_branch_points && cds@dim_reduce_type == 'DDRTree'){
mst_branch_nodes <- cds@auxOrderingData[[cds@dim_reduce_type]]$branch_points
branch_point_df <- ica_space_df %>%
slice(match(mst_branch_nodes, sample_name)) %>%
dplyr::mutate(branch_point_idx = seq_len(n()))
g <- g +
geom_point(aes_string(x="prin_graph_dim_1", y="prin_graph_dim_2"),
size=5, na.rm=TRUE, branch_point_df) +
geom_text(aes_string(x="prin_graph_dim_1", y="prin_graph_dim_2", label="branch_point_idx"),
size=4, color="white", na.rm=TRUE, branch_point_df)
}
if (show_cell_names){
g <- g + geom_text(aes(label=sample_name), size=cell_name_size)
}
if (show_state_number){
g <- g + geom_text(aes(label = sample_state), size = state_number_size)
}
g <- g +
#scale_color_brewer(palette="Set1") +
scTools_theme_opts() +
xlab(paste("Component", x)) +
ylab(paste("Component", y)) +
theme(legend.position="top", legend.key.height=grid::unit(0.35, "in")) +
#guides(color = guide_legend(label.position = "top")) +
theme(legend.key = element_blank()) +
theme(panel.background = element_rect(fill='white'))
g
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.