Skip to content

Commit

Permalink
Merge pull request #83 from Artur-man/main
Browse files Browse the repository at this point in the history
Introduction of tiles, more analysis features and more interactive options
  • Loading branch information
Artur-man authored Mar 15, 2024
2 parents 7ef7295 + 0b2ab35 commit da5eae1
Show file tree
Hide file tree
Showing 149 changed files with 5,889 additions and 2,544 deletions.
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ Description: VoltRon is a novel spatial omic analysis toolbox for multi-omics in
License: MIT + file LICENSE
SystemRequirements: OpenCV 4.7 (or higher): libopencv-dev (Debian, Ubuntu) or opencv-devel (Fedora)
Encoding: UTF-8
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
biocViews:
Imports: methods, S4Vectors, EBImage, FNN, Matrix, XML, dplyr, ggforce,
ggplot2, ggpubr, ggrepel, hdf5r, htmltools, igraph, irlba, rjson, magick, raster,
reshape2, rlang, scales, shiny, shinyjs, stringr, terra, uwot, data.table, interp,
fastDummies, anndata, basilisk, reticulate, sp, ids
reshape2, rlang, scales, shiny, shinyjs, stringr, terra, uwot, data.table, RCDT,
fastDummies, anndata, basilisk, reticulate, sp, ids, rstudioapi
LinkingTo: Rcpp, RcppArmadillo (>= 0.4)
Collate:
'RcppExports.R'
Expand Down
31 changes: 24 additions & 7 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ S3method("vrGraph<-",VoltRon)
S3method("vrImages<-",vrAssay)
S3method("vrImages<-",vrImage)
S3method("vrMainAssay<-",VoltRon)
S3method("vrMainChannel<-",vrAssay)
S3method("vrMainChannel<-",vrImage)
S3method("vrMainImage<-",VoltRon)
S3method("vrMainImage<-",vrAssay)
Expand All @@ -31,6 +32,9 @@ S3method(as.Seurat,VoltRon)
S3method(as.VoltRon,Seurat)
S3method(as.Zarr,"magick-image")
S3method(as.Zarr,VoltRon)
S3method(combineChannels,VoltRon)
S3method(combineChannels,vrAssay)
S3method(combineChannels,vrImage)
S3method(flipCoordinates,VoltRon)
S3method(flipCoordinates,vrAssay)
S3method(getFeatures,VoltRon)
Expand Down Expand Up @@ -63,7 +67,6 @@ S3method(vrCoordinates,vrAssay)
S3method(vrCoordinates,vrImage)
S3method(vrData,VoltRon)
S3method(vrData,vrAssay)
S3method(vrDistances,vrAssay)
S3method(vrEmbeddingNames,VoltRon)
S3method(vrEmbeddingNames,vrAssay)
S3method(vrEmbeddings,VoltRon)
Expand All @@ -83,9 +86,11 @@ S3method(vrImages,VoltRon)
S3method(vrImages,vrAssay)
S3method(vrImages,vrImage)
S3method(vrMainAssay,VoltRon)
S3method(vrMainChannel,vrAssay)
S3method(vrMainChannel,vrImage)
S3method(vrMainImage,VoltRon)
S3method(vrMainImage,vrAssay)
S3method(vrSampleNames,vrMetadata)
S3method(vrSegments,VoltRon)
S3method(vrSegments,vrAssay)
S3method(vrSegments,vrImage)
Expand Down Expand Up @@ -115,7 +120,10 @@ export(as.Giotto)
export(as.Seurat)
export(as.VoltRon)
export(as.Zarr)
export(changeAssayNames)
export(changeSampleNames)
export(combineChannels)
export(combineGraphs)
export(convertAnnDataToVoltRon)
export(flipCoordinates)
export(formAssay)
Expand All @@ -133,23 +141,20 @@ export(getSpatialNeighbors)
export(getUMAP)
export(importCosMx)
export(importGeoMx)
export(importImageData)
export(importVisium)
export(importXenium)
export(make_css)
export(merge_sampleMetadata)
export(modulateImage)
export(normalizeData)
export(registerSpatialData)
export(resizeImage)
export(subset_sampleMetadata)
export(transferData)
export(vrAssayNames)
export(vrAssayParams)
export(vrAssayTypes)
export(vrBarPlot)
export(vrCoordinates)
export(vrData)
export(vrDistances)
export(vrEmbeddingFeaturePlot)
export(vrEmbeddingNames)
export(vrEmbeddingPlot)
Expand All @@ -168,10 +173,12 @@ export(vrMainChannel)
export(vrMainImage)
export(vrNeighbourhoodEnrichment)
export(vrProportionPlot)
export(vrSampleNames)
export(vrScatterPlot)
export(vrSegments)
export(vrSpatialFeaturePlot)
export(vrSpatialPlot)
export(vrSpatialPlotInteractive)
export(vrSpatialPoints)
export(vrViolinPlot)
exportClasses(VoltRon)
Expand All @@ -184,11 +191,14 @@ exportMethods("[[")
exportMethods("[[<-")
import(ggplot2)
import(shiny)
importClassesFrom(Matrix,dgCMatrix)
importFrom(EBImage,writeImage)
importFrom(FNN,get.knn)
importFrom(FNN,get.knnx)
importFrom(Matrix,colSums)
importFrom(Matrix,forceSymmetric)
importFrom(Matrix,sparseMatrix)
importFrom(RCDT,delaunay)
importFrom(S4Vectors,DataFrame)
importFrom(S4Vectors,metadata)
importFrom(XML,xmlToList)
Expand All @@ -201,6 +211,7 @@ importFrom(basilisk,basiliskStart)
importFrom(basilisk,basiliskStop)
importFrom(data.table,data.table)
importFrom(data.table,fread)
importFrom(data.table,setkey)
importFrom(dplyr,"%>%")
importFrom(dplyr,add_row)
importFrom(dplyr,arrange)
Expand Down Expand Up @@ -239,22 +250,27 @@ importFrom(hdf5r,readDataSet)
importFrom(htmltools,HTML)
importFrom(ids,random_id)
importFrom(igraph,"E<-")
importFrom(igraph,"V<-")
importFrom(igraph,E)
importFrom(igraph,V)
importFrom(igraph,add_edges)
importFrom(igraph,as_adjacency_matrix)
importFrom(igraph,cluster_leiden)
importFrom(igraph,disjoint_union)
importFrom(igraph,edge_attr_names)
importFrom(igraph,get.data.frame)
importFrom(igraph,graph_from_adjacency_matrix)
importFrom(igraph,induced_subgraph)
importFrom(igraph,make_empty_graph)
importFrom(igraph,neighborhood)
importFrom(igraph,simplify)
importFrom(igraph,subgraph)
importFrom(igraph,union)
importFrom(igraph,vcount)
importFrom(igraph,vertices)
importFrom(interp,neighbours)
importFrom(interp,tri.mesh)
importFrom(irlba,irlba)
importFrom(magick,geometry_size_percent)
importFrom(magick,image_composite)
importFrom(magick,image_contrast)
importFrom(magick,image_crop)
importFrom(magick,image_data)
Expand Down Expand Up @@ -291,6 +307,7 @@ importFrom(rlang,eval_tidy)
importFrom(rlang,list2)
importFrom(rlang,quo_get_expr)
importFrom(rlang,quo_text)
importFrom(rstudioapi,viewer)
importFrom(scales,viridis_pal)
importFrom(shinyjs,hide)
importFrom(shinyjs,show)
Expand Down
114 changes: 99 additions & 15 deletions R/annotation.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
#' @param object a list of VoltRon (or Seurat) objects
#' @param label the name of the new metadata feature (annotation) of selected spatial points
#' @param assay a reference spatial data set, used only if \code{object_list} is \code{NULL}
#' @param ... additional parameters passed to \code{vrSpatialPlot}
#' @param use.image if TRUE, use only the image
#' @param image_name the name of the main image
#' @param channel the name of the main channel
#' @param ... additional parameters passed to \code{vrSpatialPlot}.
#'
#' @import shiny
#' @importFrom shinyjs useShinyjs show hide
Expand All @@ -20,7 +23,7 @@
#' @export
#'
#' @return a vector of annotations
annotateSpatialData <- function(object, label, assay = NULL, ...) {
annotateSpatialData <- function(object, label = "annotation", assay = NULL, use.image = FALSE, image_name = NULL, channel = NULL, ...) {

if(!inherits(object, "VoltRon"))
stop("Please provide a VoltRon object!")
Expand All @@ -39,8 +42,23 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
metadata <- Metadata(object, assay = sample_metadata[assay, "Assay"])
coords <- vrCoordinates(object, assay = assay)

# set label names
if(label %in% colnames(metadata)){
unique_names <- make.unique(c(colnames(metadata)[grepl(paste0("^", label), colnames(metadata))], label))
label <- unique_names[length(unique_names)]
}

# get image name and channel
if(is.null(image_name)){
image_name <- vrMainImage(object[[assay]])
}

# get image
g <- vrSpatialPlot(object, assay = assay, ...) + labs(title = "")
if(use.image){
g <- magick::image_ggplot(vrImages(object, assay = assay, name = image_name, channel = channel)) + labs(title = "")
} else{
g <- vrSpatialPlot(object, assay = assay, background = c(image_name, channel), ...) + labs(title = "")
}

## UI and Server ####

Expand All @@ -50,8 +68,29 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
sidebarLayout(position = "left",

sidebarPanel(

# margin settings
tags$style(make_css(list('.well', 'margin', '7%'))),

# # specific settings for dealing with simultaneous click and brush events
# # https://jokergoo.github.io/2021/02/20/differentiate-brush-and-click-event-in-shiny/
tags$script(HTML("
$('#plot').mousedown(function(e) {
var parentOffset = $(this).offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
Shiny.setInputValue('x1', relX);
Shiny.setInputValue('y1', relY);
}).mouseup(function(e) {
var parentOffset = $(this).offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
Shiny.setInputValue('x2', relX);
Shiny.setInputValue('y2', relY);
Shiny.setInputValue('action', Math.random());
});
")),

# Interface
fluidRow(
column(12,h4("Annotation Interface")),
Expand Down Expand Up @@ -85,7 +124,15 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
),
mainPanel(
shinyjs::useShinyjs(),
plotOutput("image_plot", click = "plot_click", height = "1000px"),
plotOutput("image_plot",
height = "1000px",
hover = "plot_hover",
click = "plot_click",
dblclick = "plot_dblclick",
brush = brushOpts(
id = "plot_brush", fill = "green",
resetOnNew = TRUE
)),
width = 8
)
)
Expand All @@ -96,16 +143,32 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
# Initialize data frame to store points
selected_corners <- reactiveVal(data.frame(x = numeric(0), y = numeric(0)))
selected_corners_list <- reactiveVal(list())
ranges <- reactiveValues(x = g$coordinates$limits$x, y = g$coordinates$limits$y)

## point double click event and zoom ####
observeEvent(input$plot_dblclick, {
brush <- input$plot_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- g$coordinates$limits$x
ranges$y <- g$coordinates$limits$y
}
})

# point click event
## point click event ####
observeEvent(input$plot_click, {
click <- input$plot_click
x <- click$x
y <- click$y

# Append new point to the data frame
new_point <- data.frame(x = x, y = y)
selected_corners(rbind(selected_corners(), new_point))
brush <- input$plot_brush
if (is.null(brush)) {
click <- input$plot_click
x <- click$x
y <- click$y

# Append new point to the data frame
new_point <- data.frame(x = x, y = y)
selected_corners(rbind(selected_corners(), new_point))
}
})

# reset and remove buttons
Expand Down Expand Up @@ -149,6 +212,7 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
}
})

## image output ####
output$image_plot <- renderPlot({

# visualize already selected polygons
Expand All @@ -162,7 +226,9 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {

# add currently selected points
g <- g +
ggplot2::geom_point(aes(x = x, y = y), data = selected_corners(), color = "red", shape = 16)
ggplot2::geom_point(aes(x = x, y = y), data = selected_corners(), color = "red", shape = 16) +
# coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = FALSE) +
coord_equal(xlim = ranges$x, ylim = ranges$y, ratio = 1)

# add label to currently selected points
datax_label_ind <- length(selected_corners_list()) + 1
Expand All @@ -173,7 +239,7 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
if(length(selected_corners_list()) > 0){
for (i in 1:length(selected_corners_list())){
cur_corners <- selected_corners_list()[[i]]
if(is.null(input[[paste0("sample",i)]])){
if(is.null(input[[paste0("region",i)]])){
cur_corners <- data.frame(x = mean(cur_corners[,1]), y = max(cur_corners[,2]), region = paste("Region ", i))
} else {
cur_corners <- data.frame(x = mean(cur_corners[,1]), y = max(cur_corners[,2]), region = input[[paste0("region",i)]])
Expand All @@ -198,7 +264,7 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
# collect labels
selected_label_list <- sapply(1:length(selected_polygon_list), function(i) input[[paste0("region",i)]])

# annotate spatial points
### annotate spatial points ####
spatialpoints <- rownames(metadata)
new_label <- rep("undefined", length(spatialpoints))
names(new_label) <- spatialpoints
Expand All @@ -213,6 +279,24 @@ annotateSpatialData <- function(object, label, assay = NULL, ...) {
metadata[[label]] <- new_label
Metadata(object, assays = sample_metadata[assay, "Assay"]) <- metadata

## add polygons to a new assay ####
segments <- selected_polygon_list
names(segments) <- selected_label_list
coords <- t(sapply(segments, function(seg){
apply(seg, 2, mean)
}, simplify = TRUE))
new_assay <- formAssay(coords = coords, segments = segments,
type = "ROI",
image = vrImages(object, assay = assay),
main_image = vrMainImage(object[[assay]]),
name = assay)
object <- addAssay.VoltRon(object,
assay = new_assay,
metadata = data.frame(check.rows = FALSE, row.names = rownames(coords)),
assay_name = "ROIannotation",
sample = sample_metadata[assay, "Sample"],
layer = sample_metadata[assay, "Layer"])

# stop app and return
stopApp(object)
})
Expand Down
Loading

0 comments on commit da5eae1

Please sign in to comment.