Skip to content
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

Closed
wants to merge 44 commits into from
Closed
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ffbeac3
add integrated shiny.gosling plot embedded into vignette, first pass
lee-t May 24, 2024
f3dcd5a
minor labels
lee-t May 28, 2024
b4c4136
Merge branch 'mtmorgan:devel' into vis_shinygosling
lee-t May 28, 2024
1886cb4
update suggests w/shiny.gosling, fix runtime and library calls, updat…
lee-t May 29, 2024
b6a7358
update b_vis vignette. take screenshots for presentation
lee-t Jun 20, 2024
224e5f2
fix knitting error: seperating track objects
lee-t Jun 20, 2024
2aba65e
wrap lolipop plotting in function "plot_shinygosling" examples and ot…
lee-t Jul 29, 2024
7fa6954
Merge branch 'devel' into vis_shinygosling
nturaga Jul 29, 2024
123c788
Remove z_scratch.Rmd after consulting with Tram and Tyronne
nturaga Jul 29, 2024
4bac60a
Remove .Rproj
nturaga Jul 29, 2024
75428d2
Remove d_clinvar.R, fix DESCRIPTION
nturaga Jul 29, 2024
ea6f464
Remove .gosling repo
nturaga Jul 29, 2024
1790d52
revert changes to ignores
nturaga Jul 29, 2024
236aa27
Remove .RData
nturaga Jul 29, 2024
9e9170a
Fixes
nturaga Jul 29, 2024
424fe6b
checks for directory .gosling
tram-nguyen-n Jul 29, 2024
4eefe87
modify function; change colormap, change example, fix categories
lee-t Jul 29, 2024
70ca8d6
edit vignettes; remove gosling.shiny vis from intro, add to alphafold
lee-t Jul 29, 2024
a4a6785
add contributors to DESCRIPTION
lee-t Jul 29, 2024
94837cf
whitespace DESCRIPTION
lee-t Jul 29, 2024
7f44587
no `gosling` R package
lee-t Aug 2, 2024
64e4de0
fixes for example
lee-t Aug 2, 2024
6dfd4b2
rename as_granges->gr, get_range - > g; fix GRanges accesssors in zoo…
lee-t Aug 6, 2024
bbc4def
add validation for input types
lee-t Aug 6, 2024
b9b7388
use cache for gosling dir
lee-t Aug 6, 2024
af48390
add tooltips to lolipop plot
lee-t Aug 6, 2024
96fa7f5
'plot_type' selects between bars and lolipop plots
lee-t Aug 6, 2024
e6137b2
replace tabs with spaces (on Windows-1252)
lee-t Aug 7, 2024
b4a28bb
text and example changes to alphafold.Rmd; fix spelling of 'lollipop'
lee-t Aug 7, 2024
c265cf2
remove runtime from intro
lee-t Aug 7, 2024
00c57a7
sync help page for plot_shinygosling.rd
lee-t Aug 7, 2024
0c66dc9
fixing vignettes, trying to pass R CMD check
lee-t Aug 7, 2024
963a9ff
imports and cache creation reverted
lee-t Aug 7, 2024
008b5d6
reverting importFrom, cache order
lee-t Aug 7, 2024
e32322f
found the missing visual channel imports.
lee-t Aug 7, 2024
48a0558
some message suppression and link fixes
lee-t Aug 21, 2024
916e254
some cosmetics to the gosling section
lgeistlinger Aug 21, 2024
a24edaa
Rename plot_shinygosling to match function. Edit documentation wordin…
lee-t Sep 17, 2024
73f173d
change function indentation and input granges name
lee-t Sep 19, 2024
57cbc97
combine assertions into one `stopifnot()`, `plot_type` is already che…
lee-t Sep 19, 2024
c9e9088
change to use `identical()`
lee-t Sep 19, 2024
c65a351
format example
lee-t Sep 19, 2024
b0b5a45
reformat DESCRIPTION
lee-t Sep 19, 2024
aa46568
change @details
lee-t Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,30 @@ Title: Accessing AlphaMissense Data Resources in R
Version: 1.1.5
Authors@R:
c(person(
"Martin", "Morgan", role = c("aut", "cre"),
Copy link
Owner

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved e6137b2

Copy link
Owner

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.

Copy link
Author

@lee-t lee-t Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

email = "mtmorgan.xyz@gmail.com",
comment = c(ORCID = "0000-0002-5874-8148")
"Martin", "Morgan", role = c("aut", "cre"),
email = "mtmorgan.xyz@gmail.com",
comment = c(ORCID = "0000-0002-5874-8148")
), person(
"Tram", "Nguyen",
role = "aut"
"Tram", "Nguyen",
role = "aut"
), person(
"Chan Zuckerberg Initiative DAF CZF2019-002443",
role = "fnd"
"Tyrone", "Lee",
role = "ctb"
), person(
"NIH NCI ITCR U24CA180996",
role = "fnd"
"Nitesh", "Turaga",
role = "ctb"
), person(
"NIH NCI IOTN U24CA232979",
role = "fnd"
"Chan Zuckerberg Initiative DAF CZF2019-002443",
role = "fnd"
), person(
"NIH NCI ARTNet U24CA274159",
role = "fnd"
"NIH NCI ITCR U24CA180996",
role = "fnd"
), person(
"NIH NCI IOTN U24CA232979",
role = "fnd"
), person(
"NIH NCI ARTNet U24CA274159",
role = "fnd"
))
Description:
The AlphaMissense publication
Expand Down Expand Up @@ -51,7 +57,7 @@ Suggests:
ensembldb,
httr,
tidyr,
r3dmol, bio3d, shiny,
r3dmol, bio3d, shiny, shiny.gosling,
colorspace,
knitr,
rmarkdown,
Expand All @@ -60,6 +66,6 @@ biocViews: SNP, Annotation, FunctionalGenomics, StructuralPrediction,
Transcriptomics, VariantAnnotation, GenePrediction, ImmunoOncology
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.1
RoxygenNote: 7.3.2
VignetteBuilder: knitr
Config/testthat/edition: 3
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ export(db_disconnect_all)
export(db_range_join)
export(db_tables)
export(db_temporary_table)
export(plot_granges)
export(to_GPos)
import(GenomicRanges)
import(shiny)
import(shiny.gosling)
importFrom(BiocBaseUtils,isCharacter)
importFrom(BiocBaseUtils,isScalarCharacter)
importFrom(BiocBaseUtils,isScalarLogical)
Expand Down
226 changes: 226 additions & 0 deletions R/plot_shinygosling.R
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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in AlphaMissenseR is to use character(1) to describe a scalar character, or character() if it can be any length.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved bbc4def

Copy link
Owner

Choose a reason for hiding this comment

The 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>

Copy link
Author

Choose a reason for hiding this comment

The 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
Copy link
Owner

Choose a reason for hiding this comment

The 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"
#' )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#' = "bar plot example")
#' }
#'
#'
#' @export
plot_granges <-
function(gr,
Copy link
Owner

Choose a reason for hiding this comment

The 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"
    )
{
    ...

Copy link
Author

Choose a reason for hiding this comment

The 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(
Copy link
Owner

@mtmorgan mtmorgan Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, combine assertions into a single stopifnot(). Use the S4 is() to test S4 objects (this might require a #' @importFrom methods is); I think the assertion is(granges, "GRanges") is sufficient for your purposes?. The convention in the package uses isScalarCharacter(), along the lines of (check that these are correct with respect to NAandnzchar()`...). I am conservative in use of additional error text, hoping to think that the message is sufficiently clear, or if not clear then encountered commonly enough that the user has figured out how to interpret it (rather than encountering different messages in each package).

stopifnot(
    is(granges, "GRanges"),
    isScalarCharacter(title),
    isScalarCharacter(subtitle),
    isScalarCharacter(plot_type)
)

Actually I think the plot_type test needs to be more explicit -- isScalarCharacter(plot_type) && plot_type %in% <allowable values>.

Copy link
Author

Choose a reason for hiding this comment

The 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"){
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As best practice use 'identical(plot_type, "bars"), since this returns TRUE or FALSE, whereas as written this can return cryptic errors if, e.g., plot_typewhere NA or "" (I realize that the checks above ensure that this is not the case, but that does not mean that the better practice of usingidentical()` should be avoided).

Copy link
Author

Choose a reason for hiding this comment

The 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)
Copy link
Owner

Choose a reason for hiding this comment

The 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 GPos_plot(gpos, title, subtitle, ..., stroke = "lightgrey", <etc>) where more obscure arguments (including 'subtitle'?) go after the ... and follow as closely as possible whatever the shiny.gosling convention is.

Copy link
Author

Choose a reason for hiding this comment

The 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
)

Copy link
Owner

Choose a reason for hiding this comment

The 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 arranged_view3 and the second creating the shiny app. I think there would be value in some sort of sanity check after arranged_view3 has been created that the object is actually sensible -- sort of ensuring that your code has done what it is supposed to do with the inputs and whatever edge cases (e.g., a zero-row GPos) the user of GPos_plot() might provide.

Copy link
Author

Choose a reason for hiding this comment

The 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)
}
58 changes: 58 additions & 0 deletions man/plot_shinygosling.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions vignettes/alphafold.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap to 80 characters

Copy link
Author

Choose a reason for hiding this comment

The 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")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this step unnecessary / compress creation of gpos to same as in example page.

Copy link
Author

Choose a reason for hiding this comment

The 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}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a more descriptive name instead of plot_example, e.g., GPos_plot

Copy link
Author

Choose a reason for hiding this comment

The 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")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to qualify as AlphaMissenseR::GPos_plot(), just GPos_plot().

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?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```


# Finally

Remember to disconnect and shutdown all managed DuckDB connections.
Expand Down
1 change: 1 addition & 0 deletions vignettes/introduction.Rmd
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: "A. Introduction"
output: rmarkdown::html_vignette
runtime: shiny
Copy link
Owner

Choose a reason for hiding this comment

The 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.

Copy link
Author

Choose a reason for hiding this comment

The 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}
Expand Down