-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add plot_granges
#6
Changes from 27 commits
ffbeac3
f3dcd5a
b4c4136
1886cb4
b6a7358
224e5f2
2aba65e
7fa6954
123c788
4bac60a
75428d2
ea6f464
1790d52
236aa27
9e9170a
424fe6b
4eefe87
70ca8d6
a4a6785
94837cf
7f44587
64e4de0
6dfd4b2
bbc4def
b9b7388
af48390
96fa7f5
e6137b2
b4a28bb
c265cf2
00c57a7
0c66dc9
963a9ff
008b5d6
e32322f
48a0558
916e254
a24edaa
73f173d
57cbc97
c9e9088
c65a351
b0b5a45
aa46568
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
#' @rdname plot_shinygosling | ||
#' | ||
#' @title Plot a GRanges object using Shiny and Gosling | ||
#' | ||
#' @description This function creates a Shiny app that displays a | ||
#' Gosling plot of a given GRanges object. It visualizes genomic | ||
#' ranges with both rectangle and point representations, and | ||
#' allows for customization of the plot title and subtitle. | ||
|
||
#' The function creates two tracks: a reference track with | ||
#' rectangles and an alternative track with points. It assumes | ||
#' that the GRanges object has 'am_class' and 'ALT' metadata | ||
#' columns. The 'am_class' column is used for coloring the points, | ||
#' while 'ALT' is used for the text of the points. | ||
|
||
#' @param gr A GRanges object containing the genomic ranges to | ||
#' be plotted. | ||
#' @param title Character string. The title of the plot. Default is | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The convention in AlphaMissenseR is to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved bbc4def There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not updated in the commit. I'm expecting something like #' @param title the character(1) title of the plot <etc> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
#' "GRanges Plot". | ||
#' @param subtitle Character string. The subtitle of the plot. Default | ||
#' is "Stacked nucleotide example". | ||
#' @param plot_type Character string. Select the type of gosling plot. | ||
#' Default is "bar" | ||
#' - "bars": Stacked bar plot with height based on pathogenicity score | ||
#' - "lolipop": variation of a bar chart where the bar is replaced with a | ||
#' line and a dot at the end to show mutation variations. | ||
#' | ||
#' @return A Shiny app object that, when run, displays the Gosling | ||
#' plot. | ||
#' | ||
#' @note This function requires the shiny, shiny.gosling, and GenomicRanges | ||
#' packages to be installed. | ||
#' | ||
#' @examples | ||
#' if (requireNamespace("GenomicRanges")) { | ||
#' | ||
#' ## Create a sample GRanges object from AlphamissenseR | ||
#' gpos <- | ||
#' am_data("hg38") |> | ||
#' filter(uniprot_id == "Q1W6H9") |> | ||
#' to_GPos() | ||
#' | ||
#' ## Plot the GRanges object | ||
#' plot_granges(gpos, mode = "bar", title = "Q1W6H9 track", subtitle | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. format so that the rendered example follows the convention of the package #' plot_granges(
#' gpos, mode = "bar", title = "Q1W6H_track",
#' subtitle = "bar plot example"
#' ) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
#' = "bar plot example") | ||
#' } | ||
#' | ||
#' | ||
#' @export | ||
plot_granges <- | ||
function(gr, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the indentation when function arguments span more than one line is (also avoid 'cryptic' names where possible) plot_granges <-
function(
granges,
title = "GRanges Plot",
subtitle = "Stacked nucleotide example"
)
{
... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
title = "GRanges Plot", | ||
subtitle = "Stacked nucleotide example", | ||
plot_type = "bars") | ||
{ | ||
## Validate input | ||
stopifnot( | ||
"Input must be a GRanges or GPos object" = | ||
inherits(gr, c("GRanges", "GPos")) | ||
) | ||
stopifnot( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, combine assertions into a single stopifnot(
is(granges, "GRanges"),
isScalarCharacter(title),
isScalarCharacter(subtitle),
isScalarCharacter(plot_type)
) Actually I think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
"Title must be a scalar string" = | ||
is.character(title) && length (title) == 1 && !is.na(title) && | ||
nzchar(title) | ||
) | ||
stopifnot( | ||
"Subtitle must be a scalar string" = | ||
is.character(subtitle) && length (subtitle) == 1 && !is.na(subtitle) | ||
&& nzchar(subtitle) | ||
) | ||
stopifnot( | ||
"Type must be a scalar string" = | ||
is.character(plot_type) && length (plot_type) == 1 && !is.na(plot_type) | ||
&& nzchar(plot_type) | ||
) | ||
|
||
## Define categories and color mapping | ||
categories <- c("likely_benign", "ambiguous", "likely_pathogenic") | ||
colormapping <- c("#89d5f5", "gray", "#f56c6c") | ||
|
||
## Get range from GRanges object | ||
r <- range(gr) | ||
|
||
## Prepare track data | ||
track_data <- track_data_gr( | ||
gr, | ||
chromosomeField = "seqnames", | ||
genomicFields = c("start", "end") | ||
) | ||
|
||
## This fixes the bug if .gosling directory does not already exist | ||
cache_dir <- file.path(tools::R_user_dir("AlphaMissenseR", which = "cache"), ".gosling") | ||
if (!dir.exists(cache_dir)) | ||
## TODO: check return value to ensure directory is created successfully | ||
dir.create(cache_dir, recursive = TRUE) | ||
|
||
## trigger the option for bars or lolipop | ||
if (plot_type =="bars"){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As best practice use 'identical(plot_type, "bars") There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
#define single track | ||
track_bar <- add_single_track( | ||
width = 800, | ||
height = 180, | ||
data = track_data, | ||
mark = "bar", | ||
x = visual_channel_x( | ||
field = "start", type = "genomic", axis = "bottom" | ||
), | ||
xe = visual_channel_x(field = "end", type = "genomic"), | ||
y = visual_channel_y( | ||
field = "am_pathogenicity", type = "quantitative", axis = "right" | ||
), | ||
color = visual_channel_color( | ||
field = "am_pathogenicity", | ||
type = "quantitative" | ||
), | ||
tooltip = visual_channel_tooltips( | ||
visual_channel_tooltip(field = "REF", type = "nominal", | ||
alt = "Reference"), | ||
visual_channel_tooltip(field = "ALT", type = "nominal", | ||
alt = "Alternative / Mutation"), | ||
visual_channel_tooltip( | ||
field = "am_pathogenicity", | ||
type = "quantitative", | ||
alt = "AM_Pathogenicity Score", | ||
format = "0.2" | ||
) ), | ||
size = list(value = 5) | ||
) | ||
|
||
composed_view <- compose_view( | ||
layout = "linear", | ||
xDomain = list(chromosome = as.character(seqnames(r)), | ||
interval = c(start(r), end(r))), | ||
tracks = track_bar | ||
|
||
) | ||
|
||
## other track | ||
} else if (plot_type == "lolipop"){ | ||
|
||
## Define multi tracks | ||
track_ref <- add_single_track( | ||
data = track_data, | ||
mark = "rect", | ||
x = visual_channel_x(field = "start", type = "genomic", axis = "top"), | ||
xe = visual_channel_x(field = "end", type = "genomic"), | ||
size = list(value = 50), | ||
stroke = "lightgrey", | ||
strokeWidth = list(value = 1), | ||
opacity = list(value = 0.3) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should some of these parameters be exposed as arguments for the user to customize? If so I'd write the function definition as something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see the latest comment on the integration with gosling API |
||
) | ||
|
||
track_alt <- add_single_track( | ||
data = track_data, | ||
mark = "point", | ||
x = visual_channel_x(field = "start", type = "genomic", axis = "top"), | ||
xe = visual_channel_x(field = "end", type = "genomic"), | ||
y = visual_channel_y(field = "am_class", type="nominal", | ||
domain= categories, axis = "left",baseline = "ambiguous" ), | ||
text = list(field = "ALT", type = "nominal"), | ||
size = list(value = 5), | ||
tooltip = visual_channel_tooltips( | ||
visual_channel_tooltip(field = "REF", type = "nominal", | ||
alt = "Reference"), | ||
visual_channel_tooltip(field = "ALT", type = "nominal", | ||
alt = "Alternative / Mutation"), | ||
visual_channel_tooltip( | ||
field = "am_pathogenicity", | ||
type = "quantitative", | ||
alt = "AM_Pathogenicity Score", | ||
format = "0.2" | ||
) ) | ||
) | ||
|
||
## Compose view | ||
composed_view <- compose_view( | ||
width = 800, | ||
height = 180, | ||
multi = TRUE, | ||
layout = "linear", | ||
xDomain = list( | ||
chromosome = as.character(seqnames(r)), | ||
interval = c(start(r), end(r)) | ||
), | ||
alignment = "overlay", | ||
color = visual_channel_color( | ||
field = "am_class", | ||
type = "nominal", | ||
domain = categories, | ||
baseline = "ambiguous", | ||
range = colormapping, | ||
legend = TRUE | ||
), | ||
tracks = add_multi_tracks(track_ref, track_alt) | ||
) | ||
|
||
} | ||
## trigger check | ||
else { | ||
stop("Invalid plot_type. Use 'bars' or 'lolipop'") | ||
} | ||
## Arrange into view | ||
arranged_view3 <- arrange_views( | ||
title = title, | ||
subtitle = subtitle, | ||
views = composed_view | ||
) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm following correctly, I think it would be useful to break this function into two INTERNAL, the first constructing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
## Create Shiny app | ||
ui <- fluidPage( | ||
use_gosling(clear_files = FALSE), | ||
goslingOutput("gosling_plot") | ||
) | ||
|
||
server <- function(input, output, session) { | ||
output$gosling_plot <- renderGosling({ | ||
gosling( | ||
component_id = "component_3", | ||
arranged_view3 | ||
) | ||
}) | ||
} | ||
|
||
## Return the Shiny app | ||
shinyApp(ui, server) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -241,6 +241,32 @@ r3dmol::r3dmol() |> | |
r3dmol::m_zoom_to() | ||
``` | ||
|
||
# Visualizing sequence tracks | ||
|
||
The variant prediction data can also be visualized on a genome browser. Mis-sense point mutations can be tracked alongside pathogenicity on multiple scales by utilizing Gosling, a declarative genomics visualization library. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please wrap to 80 characters There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
First, create a GPos object for a protein of interest. | ||
```{r mk_gpos} | ||
library(GenomicRanges) | ||
|
||
tbl <- | ||
am_data("hg38") |> | ||
filter(uniprot_id == "Q1W6H9") | ||
|
||
gpos <- | ||
tbl |> | ||
to_GPos() | ||
gp <- as(gpos, "GRanges") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make this step unnecessary / compress creation of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
gp | ||
|
||
``` | ||
|
||
The function `plot_granges` serves as a wrapper that processes the alphamissenseR formatted GPos object into a multiscale lolipop plot in [shiny.gosling][]. The resulting plot is a shinyapp object that can be embedded in Rmarkdown or Quarto. | ||
```{r plot_example} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a more descriptive name instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
AlphaMissenseR::plot_granges(gr, title = "Test track : Q1W6H9", subtitle = "Multiscale plot in Shiny.Gosling") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to qualify as At the end of the day the plot is not actually very interesting, and the formatting (with 1/2 points on the left, right, and bottom, and with the legend obscuring many points, at least for me) is not very good; is there a more compelling visualization that make better use of the display capabilities of shiny.gosling? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
``` | ||
|
||
|
||
# Finally | ||
|
||
Remember to disconnect and shutdown all managed DuckDB connections. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
--- | ||
title: "A. Introduction" | ||
output: rmarkdown::html_vignette | ||
runtime: shiny | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you tell me what the consequences of this line are, especially for displaying the page in a pkgdown site like at https://mtmorgan.github.io/AlphaMissenseR ? If there are consequences, or if the intention is to provide further Gosling-based functionality, then does it make sense to introduce a new vignette, 'D. Gosling Integration'. For instance, perhaps like the AlphaFold vignette there is a 'fast path' that basically does everything for the user to created a canned visualization, and a more step-by-step illustrating construction of arbitrary Gosling artifacts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No obvious functionality differences on pkgdown because if you're publishing vignettes they are usually forced rendered as static HTML pages by knitr. The intention was if people did run the rmd then the document would start up the shiny runtime enabling the interactive |
||
vignette: > | ||
%\VignetteIndexEntry{A. Introduction} | ||
%\VignetteEngine{knitr::rmarkdown} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 'white space' changes replace spaces with tabs, but tabs are not used in AlphaMissesnseR. In general PRs should contain the essential changes required for the feature being implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved e6137b2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry to be a pain but the original indentation was 8 spaces, not 4 and not tab.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
b0b5a45