Diff of /R/interactive.R [000000] .. [413088]

Switch to unified view

a b/R/interactive.R
1
####
2
# Spatial Interactive Plot (VoltRon) ####
3
####
4
5
####
6
## Background Shiny App ####
7
####
8
9
#' vrSpatialPlotInteractive
10
#'
11
#' @inheritParams shiny::runApp
12
#' @param plot_g the ggplot plot
13
#' @param shiny.options a list of shiny options (launch.browser, host, port etc.) passed \code{options} arguement of \link{shinyApp}. For more information, see \link{runApp}
14
#'
15
#' @importFrom shinyjs useShinyjs
16
#' 
17
#' @noRd
18
vrSpatialPlotInteractive <- function(plot_g = NULL, 
19
                                     shiny.options = list()){
20
  
21
  # js for Shiny
22
  shinyjs::useShinyjs()
23
24
  # UI
25
  ui <- mod_app_ui("app")
26
27
  # Server
28
  server <- function(input, output, session) {
29
    mod_app_server("app", plot_g = plot_g)
30
    session$onSessionEnded(function() {
31
      stopApp()
32
    })
33
  }
34
35
  # get shiny options
36
  shiny.options = configure_shiny_options(shiny.options)
37
  
38
  # Start Shiny Application
39
  shiny::runApp(
40
    shiny::shinyApp(ui, server, options = list(host = shiny.options[["host"]], port = shiny.options[["port"]], launch.browser = shiny.options[["launch.browser"]]),
41
                    onStart = function() {
42
                      onStop(function() {
43
                      })
44
                    })
45
  )
46
}
47
48
#' App UI
49
#'
50
#' @param id id of the module
51
#'
52
#' @import shiny
53
#'
54
#' @noRd
55
mod_app_ui <- function(id) {
56
  ns <- NS(id)
57
  plotOutput(ns("image_plot"),
58
             height = "1000px",
59
             dblclick = ns("plot_dblclick"),
60
             brush = brushOpts(
61
               id = ns("plot_brush"), fill = "green",
62
               resetOnNew = TRUE
63
             ))
64
}
65
66
#' App Server
67
#'
68
#' @param id id of the module
69
#' @param plot_g the ggplot plot
70
#'
71
#' @import ggplot2
72
#'
73
#' @noRd
74
mod_app_server <- function(id, plot_g = NULL) {
75
  moduleServer(id, function(input, output, session) {
76
77
    ranges <- reactiveValues(x = plot_g$coordinates$limits$x, y = plot_g$coordinates$limits$y)
78
    observeEvent(input$plot_dblclick, {
79
      brush <- input$plot_brush
80
      if (!is.null(brush)) {
81
        ranges$x <- c(brush$xmin, brush$xmax)
82
        ranges$y <- c(brush$ymin, brush$ymax)
83
      } else {
84
        ranges$x <- plot_g$coordinates$limits$x
85
        ranges$y <- plot_g$coordinates$limits$y
86
      }
87
    })
88
89
    # image output
90
    output$image_plot <- renderPlot({
91
      plot_g +
92
        ggplot2::coord_equal(xlim = ranges$x, ylim = ranges$y, ratio = 1)
93
    })
94
  })
95
}
96
97
#' configure_shiny_options
98
#'
99
#' @param shiny.options a list of shiny options (launch.browser, host, port etc.) passed \code{options} arguement of \link{shinyApp}. For more information, see \link{runApp}
100
#'
101
#' @noRd
102
configure_shiny_options <- function(shiny.options){
103
  
104
  # check package
105
  if (!requireNamespace('rstudioapi'))
106
    stop("Please install rstudioapi package to use RStudio for interactive visualization")
107
  
108
  # launch.browser
109
  if("launch.browser" %in% names(shiny.options)){
110
    launch.browser <- shiny.options[["launch.browser"]]
111
  } else {
112
    launch.browser <- "RStudio"
113
  }
114
  if(!is.function(launch.browser)){
115
    if(launch.browser == "RStudio"){
116
      launch.browser <- rstudioapi::viewer
117
    } 
118
  }
119
  
120
  # host and port
121
  # if "port" is entered, parse "host" (or use default) but ignore "launch.browser"
122
  if("host" %in% names(shiny.options)){
123
    host <- shiny.options[["host"]]
124
  } else {
125
    host <- getOption("shiny.host", "0.0.0.0")
126
  }
127
  if("port" %in% names(shiny.options)){
128
    port <- shiny.options[["port"]]
129
    launch.browser <- TRUE
130
  } else {
131
    port <- getOption("shiny.port")
132
  }
133
  return(list(host = host, port = port, launch.browser = launch.browser))
134
}
135
136
####
137
# Spatial Interactive Plot (Vitessce) ####
138
####
139
140
#' vrSpatialPlotInteractive
141
#'
142
#' Interactive Plotting identification of spatially resolved cells, spots, and ROI on associated images from multiple assays in a VoltRon object.
143
#'
144
#' @param zarr.file The zarr file of a VoltRon object
145
#' @param group.by a grouping label for the spatial entities
146
#' @param reduction The name of the reduction to visualize an embedding alongside with the spatial plot.
147
#' @param shiny.options a list of shiny options (host, port etc.) passed \code{options} argument of \link{wc$widget}.
148
#' 
149
#' @noRd
150
vrSpatialPlotVitessce <- function(zarr.file, group.by = "Sample", reduction = NULL, shiny.options = NULL) {
151
152
  # check package
153
  if (!requireNamespace('vitessceR'))
154
    stop("Please install vitessceR package for using interactive visualization!: devtools::install_github('vitessce/vitessceR')")
155
156
  # check file
157
  if(!dir.exists(zarr.file))
158
    stop(zarr.file, " is not found at the specified location!")
159
  
160
  # get embedding
161
  if(is.null(reduction)){
162
    obs_embedding_paths <- c("obsm/spatial")
163
  } else {
164
    obs_embedding_paths <- c(paste0("obsm/", reduction), "obsm/spatial")
165
  }
166
167
  # initiate vitessceR
168
  vc <- vitessceR::VitessceConfig$new(schema_version = "1.0.15", name = "MBrain")
169
  dataset <- vc$add_dataset("My dataset")
170
  
171
  # add ome tiff if exists
172
  ometiff.file <- gsub("zarr[/]?$", "ome.tiff", zarr.file)
173
  if(file.exists(ometiff.file)){
174
    w_img <- vitessceR::MultiImageWrapper$new(
175
      image_wrappers = list(
176
        vitessceR::OmeTiffWrapper$new(name="Test1", img_path=ometiff.file)
177
      )
178
    )
179
    dataset <- dataset$add_object(w_img)
180
  } 
181
  
182
  # add anndata
183
  w_data <- vitessceR::AnnDataWrapper$new(
184
    adata_path=zarr.file,
185
    obs_set_paths = c(paste0("obs/", group.by)),
186
    obs_set_names = c(group.by),
187
    obs_locations_path = "obsm/spatial",
188
    obs_segmentations_path = "obsm/segmentation",
189
    obs_embedding_paths = obs_embedding_paths
190
  )
191
  dataset <- dataset$add_object(w_data)
192
193
  # set up vitessce pane  
194
  spatial <- vc$add_view(dataset, vitessceR::Component$SPATIAL)
195
  cell_sets <- vc$add_view(dataset, vitessceR::Component$OBS_SETS)
196
  spatial_segmentation_layer_value <- list(opacity = 1, radius = 0, visible = TRUE, stroked = FALSE)
197
  spatial_layers <- vc$add_view(dataset, vitessceR::Component$LAYER_CONTROLLER)
198
199
  if(is.null(reduction)){
200
    vc$layout(
201
      vitessceR::hconcat(spatial, 
202
                         vitessceR::hconcat(cell_sets, spatial_layers))
203
    )
204
  } else {
205
    umap <- vc$add_view(dataset, vitessceR::Component$SCATTERPLOT, mapping = reduction)
206
    vc$layout(
207
      vitessceR::hconcat(spatial, 
208
                         vitessceR::vconcat(umap, 
209
                                            vitessceR::hconcat(cell_sets, spatial_layers)))
210
    )
211
  }
212
213
  if(length(shiny.options) == 0){
214
    vc$widget(theme = "light")
215
  } else {
216
    if (!requireNamespace('rstudioapi'))
217
      stop("Please install rstudioapi package!: install.packages('rstudioapi')")
218
    message("Listening widget from ", shiny.options[["host"]], ":", shiny.options[["port"]])
219
    base = rstudioapi::translateLocalUrl(paste0(shiny.options[["host"]],":",shiny.options[["port"]]), absolute=TRUE)
220
    vc$widget(theme = "light", base_url=base, port=shiny.options[["port"]])
221
  }
222
}