# Building a minimal genome browser with h5vc and shiny

In this vignette we will have a look at another powerful use-case for `h5vc` which is interactive data exploration. This can be a great tool to communicate your results to cour colaborators.

If you want to see the end result first, head over to the rstudio shiny server hosting service, where we have put an example shiny application demonstrating this.

- The minimal genome browser
- The minimal variant browser

## Prerequisites

For this vignette you will have to know about:

- creating tallies (see the respective vignette)
- writing simple shiny applications (have a look at their documentation)

## The Data

We will use the yeast tally file that we created in the `h5vc.creating.tallies` vignette as our single data input.

## The Shiny App

The shiny app that we write is the most basic genome broser imaginable, it will have controls for the chromosome, genomic position and the windowsize (i.e. zoom level) of the current view and it will generate a `mismatchPlot` from the tally file and the inputs that shows us the respective region of the genome in all samples present in the tally file.

The shiny app consists of two files: `ui.R` defining the user interface and `server.R` defining the calculations / plots that the UI will be populated with.

### ui.R

In the user interface file we define a `sliderInput` for the windowsize and two other inputs `chromSelect` and `genomicPositionSelect` that will be generated by the server. We do this since the available chromosomes depend on the tally file and the available positions depend on the selected chromosome.

    library(shiny)
    shinyUI(pageWithSidebar(
      # Application title
      headerPanel("Simple Genome Browser"),
      # Sidebar with a slider inputs and selection boxes
      sidebarPanel(
        sliderInput("windowsize",
                    "Windowsize:",
                    min = 10,
                    max = 200,
                    value = 50,
                    step = 5),
        uiOutput("chromSelect"),
        uiOutput("genomicPositionSelect")
      ),
      # Show a plot of the region
      mainPanel(
        plotOutput("mismatchPlot", height=800)
      )
    ))

### server.R

In `server.R` the logic of our application is stored, basically we load the required packages, have a look into the tally file to check for chromosomes and chromosome lengths and then generate the controls for the user to select chromosome and position.

The main calculations happen in `output$mismatchPlot`, were we take the chromosome and position and windowsize selected by the user and get the respective data from the tallyFile. That data is then handed to the `mismatchPlot` function and creates the plot we send back to the user (i.e. the web browser).

    library(shiny)
    library(h5vc)
    library(rhdf5)
    tallyFile <- "yeast.hfs5"
    study <- "/yeast"
    h5ls( tallyFile )
    chromosomes  <- h5ls( tallyFile )
    chromlengths <- as.numeric(subset( chromosomes, otype == "H5I_DATASET" & name == "Reference" )$dim)
    chromosomes  <- subset( chromosomes, otype == "H5I_GROUP" & name != "yeast" )$name
    names(chromlengths) = chromosomes

    # Define server logic required to generate and plot a random distribution
    shinyServer(function(input, output) {

      output$chromSelect <- renderUI({
        selectInput( "chrom", "Chromosome", choices = c("I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII","XIII","XIV","XV","XVI", "Mito"))
      })

      output$genomicPositionSelect <- renderUI({
        sliderInput( "gpos", "Genomic Position:", min = 10, max = chromlengths[input$chrom] - 10, value = 200 )
      })

      group <- reactive({ paste( study, input$chrom, sep="/" ) })

      sampleData <- reactive({ sd = getSampleData( tallyFile, group() ); sd$Sample = c("YB210","s288c"); sd })

      pos <- reactive({
        min( max( input$windowsize + 1, input$gpos ), chromlengths[input$chrom] - input$windowsize - 1 )
      })

      data <- reactive({
        h5dapply(
          tallyFile,
          group(),
          blocksize = input$windowsize*3,
          names = c("Coverages","Counts","Deletions"),
          range = c( max( pos() - input$windowsize, 0 ), min( pos() + input$windowsize, chromlengths[input$chrom] )  )
        )[[1]]

      })

      output$mismatchPlot <- renderPlot({
        p = mismatchPlot(
          data(),
          sampleData(),
          samples = c("s288c","YB210"),
          input$windowsize,
          pos()
          )
        print(p)
      })
    })

## Including Variant Calls

Obviously this genome browser has limited use in its current state but by adding a file of variants as an input and making them selectabe we can turn it into a browser for potential variant calls and can then easily go through those and inspect the region to get an idea of the quality of our calls. There is a lot of potential for creating tremendously usefull and visually impressive ways of communicating your reserach to your collaborators and peers.

### Calling the variants

We use the following code to call variants using the build-in functionality of `h5vc`. We call variants from the perspective of the YB210 strain, taking the s288c strain as our control.

    library(rhdf5)
    library(h5vc)
    setwd("~/ShinyApps/Yeast")
    tallyFile <- "yeast.hfs5"
    study <- "/yeast"
    h5ls( tallyFile )
    chromosomes <- h5ls( tallyFile )
    chromosomes <- subset( chromosomes, otype == "H5I_GROUP" & name != "yeast" )$name
    variantCalls <- list()
    for( chrom in chromosomes ){
      group <- paste( study, chrom, sep = "/" )
      sdat <- getSampleData( tallyFile, group )
      sdat$Group <- "yeast"
      variantCalls[[chrom]] <- h5dapply(
        filename = tallyFile,
        group = group,
        blocksize = 100000,
        FUN = callVariantsPairedFancy,
        sampledata = sdat,
        cl = vcConfParams( returnDataPoints = TRUE, minStrandAltSupport = 4 ),
        names = c( "Counts", "Coverages", "Reference" ),
        verbose = TRUE
      )
    }
    for( chrom in chromosomes ){
      variantCalls[[chrom]] <- do.call( rbind, variantCalls[[chrom]] )
    }
    variantCalls <- do.call( rbind, variantCalls )
    rownames(variantCalls) = NULL
    variantCalls$Support = variantCalls$caseCountFwd + variantCalls$caseCountRev
    variantCalls$Coverage = variantCalls$caseCoverageFwd + variantCalls$caseCoverageRev
    variantCalls$AF = variantCalls$Support / variantCalls$Coverage
    save( variantCalls, file = "yeast.variants.RDa" )

### Extending the functionality of the genome browser

Now we have to make some changes to the genome browser shiny app so that it loads the list of variants and allows us to browse and filter them. The result of the efforts described below is linked here:

- The minimal variant browser

#### Changes to the interface

We will make three changes to the interface: 1. We move the `mismatchPlot` to a separate tab and add another tab which will contain a table of all the variants fulfilling current filtering criteria as well as a tab showing summary pots of the filtered variants (a histogram of the allele frequency for now). 2. We add filter selectors to the sidebar, we will allow filtering on allele freqeuncy (`AF` column), Support and Coverage 3. We replace the genomic position selector with a variant selector

The new `ui.R` looks like this:

    library(shiny)
    shinyUI(pageWithSidebar(

      # Application title
      headerPanel("Simple Variant Browser - Yeast Strains Example"),

      # Sidebar with a slider inputs and selection boxes
      sidebarPanel(
        sliderInput("windowsize",
                    "Windowsize:",
                    min = 10,
                    max = 200,
                    value = 50,
                    step = 5),
        uiOutput("chromSelect"),
        sliderInput("af",
                    "Allele Frequency:",
                    min = 0,
                    max = 1,
                    value = c(0.1,1.0),
                    step = 0.01),
        sliderInput( "minSupport",
                     "Minimum Support",
                     min = 2,
                     max = 200,
                     value = 2),
        sliderInput( "minCoverage",
                     "Minimum Coverage",
                     min = 10,
                     max = 500,
                     value = 50,
                     step = 5),
        uiOutput("variantSelect"),
        textOutput("diag")
      ),

      # Show a plot of the region
      mainPanel(
        tabsetPanel(
          tabPanel( title = "Region Mismatch Plot", plotOutput("mismatchPlot", height=800) ),
          tabPanel( title = "Variant Table", tableOutput("variantTable") ),
          tabPanel( title = "Variant Summary Plots", plotOutput("afHist") )
        )
      )
    ))

### Changes to the server-side computations

Here we have to add the code to load the variant calls, dynamically generate the variant selector and update some methods for generating the plots / calculating the current position to plot (since this now depends on the sleected variant.)

The new `server.R` looks like this:

    library(shiny)
    library(h5vc)
    library(rhdf5)
    library(ggplot2)
    library(grid)

    tallyFile <- "yeast.hfs5"
    study <- "/yeast"
    h5ls( tallyFile )
    chromosomes  = h5ls( tallyFile )
    chromlengths = as.numeric(subset( chromosomes, otype == "H5I_DATASET" & name == "Reference" )$dim)
    chromosomes  = subset( chromosomes, otype == "H5I_GROUP" & name != "yeast" )$name
    names(chromlengths) = chromosomes

    load(file="yeast.variants.RDa")
    variantCalls$start <- variantCalls$start + 1 #fixing difference in counting 0-based vs. 1-based
    variantCalls$end <- variantCalls$end + 1
    # Define server logic required to generate and plot a random distribution
    shinyServer(function(input, output) {

      output$chromSelect <- renderUI({
        selectInput( "chrom", "Chromosome", choices = c("I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII","XIII","XIV","XV","XVI", "Mito"))
      })

      group <- reactive({ paste( study, input$chrom, sep="/" ) })

      sampleData <- reactive({ sd = getSampleData( tallyFile, group() ); sd$Sample = c("YB210","s288c"); sd })

      variants <- reactive({
        subset( variantCalls, seqnames == input$chrom & AF >= input$af[1] & AF <= input$af[2] & Support >= input$minSupport & Coverage >= input$minCoverage )
      })

      output$variantSelect <- renderUI({
        tmp = seq(nrow(variants()))
        names(tmp) =  paste( variants()$start, " - ", variants()$refAllele, "/", variants()$altAllele, sep="" )
        selectInput( "var", "Variant:", choices = tmp )
      })

      pos <- reactive({
        variants()$start[as.numeric(input$var)]
      })

      data <- reactive({
        if( nrow(variants()) > 0 ){
          h5dapply(
            filename = tallyFile,
            group = group(),
            blocksize = input$windowsize*3,
            names = c("Coverages","Counts","Deletions"),
            range = c( max( pos() - input$windowsize, 0 ), min( pos() + input$windowsize, chromlengths[input$chrom] )  )
          )[[1]]
        }else{
          NULL
        }
      })

      output$mismatchPlot <- renderPlot({
        if( nrow(variants()) > 0 ){
          p = mismatchPlot(
            data(),
            sampleData(),
            samples = c("s288c","YB210"),
            input$windowsize,
            pos()
          )
          print(p)
        }
      })

      output$variantTable <- renderTable({
        variants()[,c("seqnames", "start", "refAllele", "altAllele", "AF", "Support", "Coverage")]
      })

      output$afHist = renderPlot({
        hist( variants()$AF, breaks = seq(0,1,0.01) )
      })

    })

## Conclusions

So there you have it, your own variant browser ready to be deployed on the web for your collaborators or the readers of your paper to access, browse and filter as they like. And we did all of this in a bit over `100` lines of code.

There is a whole bunch of other useful plots, filters and functionalities that could be added to this tool, downloading filtered variants or generated plots would be one of the more obvious ones.