diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2311789bea4b10cca0fe405e2a3449942ea91115..7fbc5e9ea8d4bdbe38f49aeefaab3dc8ad3e06bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 **User Facing**
 * Add Cellranger Version 3.1.0
 * Add CI Artifacts
+* Add Vizapp
 
 **Background**
 
diff --git a/README.md b/README.md
index 504ea0089664ed4b2559a6a1e462251ed1eb91c7..6323ec5b79b16f933558813f4c745cba11be01ef 100755
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ To Run:
     * path to the fastq location
     * R1 and R2 only necessary but can include I2
     * only fastq's in designFile (see below) are used, not present will be ignored
-    * eg: **--fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/\*.fastq.gz'**
+    * eg: **--fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r10k/\*.fastq.gz'**
   * **--designFile**
     * path to design file (csv format) location
     * column 1 = "Sample"
@@ -35,7 +35,7 @@ To Run:
     * column 3 = "fastq_R2"
     * can have repeated "Sample" if there are multiple fastq R1/R2 pairs for the samples
     * can be downloaded [HERE](https://git.biohpc.swmed.edu/BICF/Astrocyte/cellranger_count/blob/master/docs/design.csv)
-    * eg: **--designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/design.csv'**
+    * eg: **--designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r10k/design.csv'**
   * **--genome**
     * reference genome
     * requires workflow/conf/biohpc.config to work
@@ -94,7 +94,7 @@ To Run:
     * eg: **--outDir 'test'**
 * FULL EXAMPLE:
   ```
-  nextflow run workflow/main.nf --fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/*.fastq.gz' --designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r100k/design.csv' --genome 'GRCh38-3.0.0' --kitVersion 'three' --version '3.1.0' --outDir 'test'
+  nextflow run workflow/main.nf --fastq '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r10k/*.fastq.gz' --designFile '/project/shared/bicf_workflow_ref/workflow_testdata/cellranger/cellranger_count/hu.v3s2r10k/design.csv' --genome 'GRCh38-3.0.0' --kitVersion 'three' --version '3.1.0' --outDir 'test'
   ```
 * Design example:
 
diff --git a/vizapp/functions.R b/vizapp/functions.R
new file mode 100644
index 0000000000000000000000000000000000000000..8e30560bfb52c279fa4dc4158880f96ae7e40567
--- /dev/null
+++ b/vizapp/functions.R
@@ -0,0 +1,98 @@
+LoadData <- function(dim=c("pca","tsne","umap"),dir,samp){
+  exp <- readMM(paste0(dir,samp,"/outs/filtered_feature_bc_matrix/matrix.mtx.gz"))
+  features <- read.table(paste0(dir,samp,"/outs/filtered_feature_bc_matrix/features.tsv.gz"),quote="\t")
+  barcodes <- read.table(paste0(dir,samp,"/outs/filtered_feature_bc_matrix/barcodes.tsv.gz"),quote="\t")
+  
+  exp.raw <- readMM(paste0(dir,samp,"/outs/raw_feature_bc_matrix/matrix.mtx.gz"))
+  features.raw <- read.table(paste0(dir,samp,"/outs/filtered_feature_bc_matrix/features.tsv.gz"),quote="\t")
+  barcodes.raw <- read.table(paste0(dir,samp,"/outs/raw_feature_bc_matrix/barcodes.tsv.gz"),quote="\t")
+  
+  dr <- list()
+  for (i in dim){
+    if (i=="pca"){
+      dr[[i]] <- read.csv(paste0(dir,samp,"/outs/analysis/",i,"/10_components/projection.csv"))
+      dr[[i]] <- dr[[i]][,1:3]
+    } else {
+      dr[[i]] <- read.csv(paste0(dir,samp,"/outs/analysis/",i,"/2_components/projection.csv"))
+    }
+  }
+  rm(i)
+  
+  cl <- c("graphclust",paste0("kmeans_",2:10,"_clusters"))
+  cluster <- list()
+  deg <- list()
+  for (i in cl){
+    cluster[[i]] <- read.csv(paste0(dir,samp,"/outs/analysis/clustering/",i,"/clusters.csv"))
+    deg[[i]] <- read.csv(paste0(dir,samp,"/outs/analysis/diffexp/",i,"/differential_expression.csv"))
+  }
+  rm(i)
+  
+  qc <- read.csv(paste0(dir,samp,"/outs/metrics_summary.csv"))
+  qc <- data.frame(t(qc))
+  qc[,2] <- qc[,1]
+  qc[,1] <- rownames(qc)
+  qc <- qc[-1,]
+  colnames(qc) <- c("Metric","Value")
+  
+  results <- list(
+    sample=samp,
+    exp=exp,
+    features=features,
+    barcodes=barcodes,
+    exp.raw=exp.raw,
+    features.raw=features.raw,
+    barcodes.raw=barcodes.raw,
+    dr=dr,
+    cluster=cluster,
+    deg=deg,
+    qc=qc
+  )
+  return(results)
+}
+
+Plot.cluster <- function(dr,cluster){
+  pl <-merge(dr,cluster,by="Barcode",all.x=TRUE)
+  axis.labs <- colnames(pl)[2:3]
+  colnames(pl)[2:3] <- c("dim1","dim2")
+  plot.out <- ggplot(pl,aes(x=dim1,y=dim2,col=factor(Cluster)))+geom_point()+scale_color_viridis(discrete=TRUE)+xlab(axis.labs[1])+ylab(axis.labs[2])+labs(col="Cluster")+theme_cowplot()
+  return(plot.out)
+}
+
+Plot.feature <- function(dr,ft){
+  dr$exp <- ft
+  axis.labs <- colnames(dr)[2:3]
+  colnames(dr)[2:3] <- c("dim1","dim2")
+  if (sum(dr$exp) != 0){
+    plot.out <- ggplot(dr,aes(x=dim1,y=dim2,col=exp))+geom_point()+scale_color_viridis(option="inferno")+xlab(axis.labs[1])+ylab(axis.labs[2])+labs(col="Expression")+theme_cowplot()
+  } else {
+    plot.out <- ggplot(dr,aes(x=dim1,y=dim2,col=exp))+geom_point()+scale_color_gradient(low="black",high="black")+xlab(axis.labs[1])+ylab(axis.labs[2])+labs(col="Expression")+theme_cowplot()
+  }
+  return(plot.out)
+}
+
+Plot.violinbox <- function(ft,cluster){
+  cluster$exp <- ft
+  cluster$Cluster <- factor(cluster$Cluster)
+  plot.out <- ggplot(cluster,aes(x=Cluster,y=exp,fill=Cluster))+geom_violin(scale="width",trim=TRUE)+geom_boxplot(width=0.25,fill="white",outlier.shape=NA)+scale_fill_viridis(discrete=TRUE)+ylab("Expression")+theme_cowplot()+theme(axis.text.x=element_text(angle=45))
+
+  return(plot.out)
+}
+
+Plot.cliffknee <- function(barcodes.raw,exp.raw,barcodes){
+  umi <- matrix(nrow=length(barcodes.raw[,1]),ncol=4)
+  umi[,1] <- t(colSums(exp.raw))
+  umi[,2] <- as.character(barcodes.raw[,1])
+  umi <- as.data.frame(umi)
+  umi[,1] <- as.numeric(levels(umi[,1]))[umi[,1]]
+  colnames(umi) <- c("nUMI","barcodes","rank","Cell")
+  umi <- umi[order(umi$nUMI,decreasing=TRUE),]
+  umi$rank <- 1:nrow(umi)
+  umi$Cell <- factor(as.character(umi$barcodes %in% barcodes[,1]))
+  umi$Cell <- factor(umi$Cell,levels(umi$Cell)[c(2,1)])
+  plot.out <- ggplot(umi,aes(x=rank,y=nUMI,col=Cell))+geom_point()+scale_color_manual(values=c("darkgreen","darkred"))+
+    scale_x_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))+
+    scale_y_log10(breaks=trans_breaks("log10",function(x) 10^x),labels=trans_format("log10",math_format(10^.x)))+
+    annotation_logticks()+xlab("Barcode Rank")+ylab("nUMI")+theme_cowplot()
+  
+  return(plot.out)
+}
diff --git a/vizapp/global.R b/vizapp/global.R
new file mode 100644
index 0000000000000000000000000000000000000000..988fc942d71c2db605dec0e86e2d8504ae2b06f7
--- /dev/null
+++ b/vizapp/global.R
@@ -0,0 +1,16 @@
+library(shiny)
+library(shinythemes)
+library(Matrix)
+library(ggplot2)
+library(RColorBrewer)
+library(viridis)
+library(cowplot)
+library(scales)
+
+setwd("../")
+source("./vizapp/functions.R")
+  
+#load data
+dir.shared <- "/work/BICF/s189701/cellranger_count/workflow/output/count310/"
+samples <- list.dirs(dir.shared,full.names=FALSE,recursive=FALSE)
+results <- LoadData(dim=c("umap","tsne","pca"),dir=dir.shared,samp=samples[1])
diff --git a/vizapp/server.R b/vizapp/server.R
index 81017c8445db8d640af1798cc8160bdffe2ec789..595710378f2ad30ed97394052d217f11e424f2e9 100644
--- a/vizapp/server.R
+++ b/vizapp/server.R
@@ -1,20 +1,365 @@
-# This example implements a simple file browser for accessing results.
-
 library(shiny)
-library(shinyFiles)
-
-# Results are available in the directory specified by the outputDir environment
-# variable, red by Sys.getenv
-
-rootdir <- Sys.getenv('outputDir')
-
-
-shinyServer(function(input, output, session) {
-
-    # The backend for a simple file chooser, restricted to the
-    # rootdir we obtained above.
-    # See https://github.com/thomasp85/shinyFiles
-
-    shinyFileChoose(input, 'files', roots=c('workflow'=rootdir), filetypes=c('', 'bed', 'xls','wig'), session=session)
+library(shinythemes)
+library(Matrix)
+library(ggplot2)
+library(RColorBrewer)
+library(viridis)
+library(cowplot)
+library(scales)
 
+shinyServer(function(input,output,session){
+  #reactive inputs
+  values <- reactiveValues(
+    results=results,
+    dr.c="",cluster.c="",
+    dr.f="",feature.f="",
+    cluster.vb="",feature.vb="",
+    cluster.deg="",cluster.1.deg="",alpha.deg="",fc.deg="",direction.deg=""
+  )
+  values$results <- eventReactive(input$go.d,{
+    LoadData(dim=c("umap","tsne","pca"),dir=dir.shared,samp=input$sample)
+  })
+  output$loaded <- eventReactive(input$go.d,{
+    paste0("Sample ",values$results()$sample)
+  })
+  output$nav.analysis <- renderUI({
+    req(values$results()$sample)
+    tabsetPanel(type="tabs",
+      tabPanel("Cluster Plot",
+        sidebarPanel(
+          h3(textOutput("lab.sample.c")),
+          uiOutput("dr.c"),
+          uiOutput("cluster.c"),
+          actionButton("go.c","Submit")
+        ),
+        mainPanel(
+          h3(textOutput("lab.dr.c")),
+          h4(textOutput("lab.cluster.c")),
+          plotOutput("plot.cluster.c"),
+          tags$br(),
+          uiOutput("button.download.c")
+        )
+      ),
+      tabPanel("Feature Plot",
+        sidebarPanel(
+          h3(textOutput("lab.sample.f")),
+          uiOutput("dr.f"),
+          uiOutput("feature.f"),
+          actionButton("go.f","Submit")
+        ),
+        mainPanel(
+          h3(textOutput("lab.feature.f")),
+          h4(textOutput("lab.dr.f")),
+          plotOutput("plot.feature"),
+          tags$br(),
+          uiOutput("button.download.f")
+        )
+      ),
+      tabPanel("ViolinBox Plot",
+        sidebarPanel(
+          h3(textOutput("lab.sample.vb")),
+          uiOutput("cluster.vb"),
+          uiOutput("feature.vb"),
+          actionButton("go.vb","Submit"),
+          br(),
+          br(),
+          plotOutput("plot.cluster.vb")
+        ),
+        mainPanel(
+          h3(textOutput("lab.feature.vb")),
+          h4(textOutput("lab.cluster.vb")),
+          plotOutput("plot.violinbox"),
+          tags$br(),
+          uiOutput("button.download.vb"),
+          tags$br(),
+          tags$br(),
+          tableOutput("table.expression.vb")
+        )
+      ),
+      tabPanel("Differentially Expressed Features",
+        sidebarPanel(
+          h3(textOutput("lab.sample.deg")),
+          uiOutput("cluster.deg"),
+          uiOutput("cluster.1.deg"),
+          numericInput("alpha.deg","Maximum p-value",min=0,max =1,value=0.05,step=0.001),
+          numericInput("fc.deg","Minimum Fold Change",min=0,max =50,value=0,step=0.5),
+          radioButtons("direction.deg","Fold Change Direction",c("Positively Expressed"="up","Negatively Expressed"="down","Both"="both"),selected="up"),
+          actionButton("go.deg","Submit"),
+          br(),
+          br(),
+          plotOutput("plot.cluster.deg")
+        ),
+        mainPanel(
+          h3(textOutput("lab.cluster.1.deg")),
+          h4(textOutput("lab.cluster.deg")),
+          h5(textOutput("lab.alpha.deg")),
+          h5(textOutput("lab.fc.deg")),
+          uiOutput("download.deg.button"),
+          tags$br(),
+          tags$br(),
+          tableOutput("table.deg")
+        )
+      )
+    )
+  })
+  output$nav.qc <- renderUI({
+    req(values$results()$sample)
+    tabPanel("Output",
+      sidebarPanel(
+        h3(textOutput("lab.sample.qc")),
+        h4(textOutput("lab.cell.count")),
+        br(),
+        tableOutput("qc")
+      ),
+      mainPanel(
+        plotOutput("plot.cliffknee")
+      )
+    )
+  })
+  
+  #sidebar input/outputs
+  output$lab.sample.c <- reactive({paste0("Sample ",values$results()$sample)})
+  output$dr.c <- renderUI({selectInput("dr.c","Dimentionality Reduction",names(values$results()$dr))})
+  output$cluster.c <- renderUI({selectInput("cluster.c","Clustering",names(values$results()$cluster))})
+  output$lab.sample.f <- reactive({paste0("Sample ",values$results()$sample)})
+  output$dr.f <- renderUI({selectInput("dr.f","Dimentionality Reduction",names(values$results()$dr))})
+  output$feature.f <- renderUI({textInput("feature.f","Feature",levels(values$results()$features[,2])[1])})
+  output$lab.sample.vb <- reactive({paste0("Sample ",values$results()$sample)})
+  output$cluster.vb <- renderUI({selectInput("cluster.vb","Clustering",names(values$results()$cluster))})
+  output$feature.vb <- renderUI({textInput("feature.vb","Feature",levels(values$results()$features[,2])[1])})
+  output$plot.cluster.vb <- renderPlot({
+    req(input$go.vb)
+    print(plot.cluster.vb())
+  })
+  output$lab.sample.deg <- reactive({paste0("Sample ",values$results()$sample)})
+  output$cluster.deg <- renderUI({selectInput("cluster.deg","Clustering",names(values$results()$cluster))})
+  output$cluster.1.deg <- renderUI({
+    clust <- levels(factor(values$results()$cluster[[req(input$cluster.deg)]]$Cluster))
+    selectInput("cluster.1.deg", "Specific Cluster",clust,clust[1])
+  })
+  observe({
+    if (!is.numeric(input$alpha.deg)) {
+      updateNumericInput(session,"alpha","Maximum p-value",min=0,max =1,value=0.05,step=0.001)
+    }
+  })
+  observe({
+    if (!is.numeric(input$fc.deg)) {
+      updateNumericInput(session,"fc","Minimum Fold Change",min=0,max =50,value=0,step=0.5)
+    }
+  })
+  output$lab.sample.qc <- reactive({paste0("Sample ",values$results()$sample)})
+  output$lab.cell.count <- renderText({paste0(nrow(values$results()$barcodes)," Cells Detected")})  
+  output$qc <- renderTable(values$results()$qc)
+  
+  #main input/outputs
+  output$lab.dr.c <- eventReactive(input$go.c,{
+    req(input$go.c)
+    paste0(toupper(req(input$dr.c))," Reduction")
+  },ignoreNULL=FALSE)
+  output$lab.cluster.c <- eventReactive(input$go.c,{
+    req(input$go.c)
+    paste0(toupper(req(input$cluster.c))," Clustering")
+  },ignoreNULL=FALSE)
+  output$plot.cluster.c <- renderPlot({
+    req(input$go.c)
+    print(plot.cluster.c())
+  })
+  output$lab.feature.f <- eventReactive(input$go.f,{
+    req(input$go.f)
+    if(toupper(req(input$feature.f)) %in% as.character(values$results()$features[,2])){
+      toupper(req(input$feature.f))
+    } else {
+      paste0(req(input$feature.f)," NOT PRESENT")
+    }
+  },ignoreNULL=FALSE)
+  output$lab.dr.f <- eventReactive(input$go.f,{
+    req(input$go.f)
+    paste0(toupper(req(input$dr.f))," Reduction")
+  },ignoreNULL=FALSE)
+  output$plot.feature <- renderPlot({
+    req(input$go.f)
+    print(plot.feature())
+  })
+  output$lab.feature.vb <- eventReactive(input$go.vb,{
+    req(input$go.vb)
+    if(toupper(req(input$feature.vb)) %in% as.character(values$results()$features[,2])){
+      toupper(req(input$feature.vb))
+    } else {
+      paste0(req(input$feature.vb)," NOT PRESENT")
+    }
+  },ignoreNULL=FALSE)
+  output$lab.cluster.vb <- eventReactive(input$go.vb,{
+    req(input$go.vb)
+    paste0(toupper(req(input$cluster.vb))," Clustering")
+  },ignoreNULL=FALSE)
+  output$plot.violinbox <- renderPlot({
+    req(input$go.vb)
+    print(plot.violinbox())
+  })
+  output$table.expression.vb <- renderTable({
+    req(input$go.vb)
+    table.expression.vb()
+  })
+  output$lab.cluster.1.deg <- eventReactive(input$go.deg,{
+    req(input$go.deg)
+    paste0("Cluster ",req(input$cluster.1.deg)," DEGs")
+  },ignoreNULL=FALSE)
+  output$lab.cluster.deg <- eventReactive(input$go.deg,{
+    req(input$go.deg)
+    paste0(toupper(req(input$cluster.deg))," Clustering")
+  },ignoreNULL=FALSE)
+  output$lab.alpha.deg <- eventReactive(input$go.deg,{
+    req(input$go.deg)
+    paste0("Maximum p-value <- ",req(input$alpha.deg))
+  },ignoreNULL=FALSE)
+  output$lab.fc.deg <- eventReactive(input$go.deg,{
+    req(input$go.deg)
+    if (req(input$direction.deg) == "up"){
+      paste0("Minimum fold-change difference <- ",req(input$fc.deg)," above the other cells")
+    } else if (req(input$direction.deg) == "down") {
+      paste0("Minimum fold-change difference <- ",req(input$fc.deg)," below the other cells")
+    } else {
+      paste0("Minimum fold-change difference <- ",req(input$fc.deg)," above & below the other cells")
+    }
+  },ignoreNULL=FALSE)
+  output$table.deg <- renderTable({
+    req(input$go.deg)
+    table.deg()
+  })
+  output$plot.cluster.deg <- renderPlot({
+    req(input$go.deg)
+    print(plot.cluster.deg())
+  })
+  output$download.deg.button <- renderUI({
+    req(input$go.deg)
+    downloadButton("download.deg","Download Table")
+  })
+  output$plot.cliffknee <- renderPlot({print(Plot.cliffknee(barcodes.raw=values$results()$barcodes.raw,exp.raw=values$results()$exp.raw,barcodes=values$results()$barcodes))})
+  
+  #reactive download buttons
+  output$button.download.c <- renderUI({
+    req(input$go.c)
+    downloadButton("download.c","Download Figure")
+  })
+  output$button.download.f <- renderUI({
+    req(input$go.f)
+    downloadButton("download.f","Download Figure")
+  })
+  output$button.download.vb <- renderUI({
+    req(input$go.vb)
+    downloadButton("download.vb","Download Figure")
+  })
+  output$button.download.deg <- renderUI({
+    req(input$go.deg)
+    downloadButton("download.deg","Download Table")
+  })
+    
+  #save current parameters
+  values$dr.c <- eventReactive(input$go.c,{input$dr.c})
+  values$cluster.c <- eventReactive(input$go.c,{input$cluster.c})
+  values$dr.f <- eventReactive(input$go.f,{input$dr.f})
+  values$feature.f <- eventReactive(input$go.f,{toupper(input$feature.f)})
+  values$cluster.vb <- eventReactive(input$go.vb,{input$cluster.vb})
+  values$feature.vb <- eventReactive(input$go.vb,{toupper(input$feature.vb)})
+  values$cluster.deg <- eventReactive(input$go.deg,{input$cluster.deg})
+  values$cluster.1.deg <- eventReactive(input$go.deg,{input$cluster.1.deg})
+  values$alpha.deg <- eventReactive(input$go.deg,{input$alpha.deg})
+  values$fc.deg <- eventReactive(input$go.deg,{input$fc.deg})
+  values$direction.deg <- eventReactive(input$go.deg,{input$direction.deg})
+  
+  #plot functions
+  plot.cluster.c <- eventReactive(input$go.c,{
+    Plot.cluster(
+    values$results()$dr[[req(input$dr.c)]],values$results()$cluster[[req(input$cluster.c)]])
+  },ignoreNULL=FALSE)
+  plot.feature <- eventReactive(input$go.f,{
+    if(toupper(req(input$feature.f)) %in% as.character(values$results()$features[,2])){
+      Plot.feature(values$results()$dr[[req(input$dr.f)]],values$results()$exp[as.numeric(rownames(values$results()$features[values$results()$features[,2]==toupper(req(input$feature.f)),])),])
+    } else {
+      plot.new()
+    }
+  },ignoreNULL=FALSE)
+  plot.violinbox <- eventReactive(input$go.vb,{
+    if(toupper(req(input$feature.vb)) %in% as.character(values$results()$features[,2])){
+      Plot.violinbox(values$results()$exp[as.numeric(rownames(values$results()$features[values$results()$features[,2]==toupper(req(input$feature.vb)),])),],values$results()$cluster[[req(input$cluster.vb)]])
+    } else {
+      plot.new()
+    }
+  },ignoreNULL=FALSE)
+  plot.cluster.vb <- eventReactive(input$go.vb,{
+    Plot.cluster(
+      values$results()$dr[["umap"]],values$results()$cluster[[req(input$cluster.vb)]])
+  },ignoreNULL=FALSE)
+  plot.cluster.deg <- eventReactive(input$go.deg,{
+    req(input$cluster.1.deg)
+    Plot.cluster(
+      values$results()$dr[["umap"]],values$results()$cluster[[input$cluster.deg]])
+  },ignoreNULL=FALSE)
+  
+  #table functions
+  table.expression.vb <- eventReactive(input$go.vb,{
+    if(toupper(req(input$feature.vb)) %in% as.character(values$results()$features[,2])){
+      tab <- values$results()$deg[[req(input$cluster.vb)]][values$results()$deg[[req(input$cluster.vb)]][,2]==toupper(req(input$feature.vb)),c(2,grep("Mean.Counts",names(values$results()$deg[[req(input$cluster.vb)]])))]
+      colnames(tab) <- c("Feature",gsub(".Mean.Counts","",names(tab[,-1])))
+      tab <- data.frame(t(tab))
+      tab[,2] <- tab[,1]
+      tab[,1] <- rownames(tab)
+      tab <- tab[-1,]
+      colnames(tab) <- c("Cluster",paste0("Ave ",req(input$feature.vb)," Expression"))
+      tab
+    } else {
+      ""
+    }
+  },ignoreNULL=FALSE)
+  table.deg <- eventReactive(input$go.deg,{
+    tab <- values$results()$deg[[input$cluster.deg]]
+    tab <- tab[tab[paste0("Cluster.",req(input$cluster.1.deg),".Adjusted.p.value")]<=input$alpha.deg,]
+    if (input$fc.deg == 0){
+      fc <- 0
+    } else {
+      fc <- log2(input$fc.deg)
+    }
+    if (input$direction.deg=="up"){
+      tab <- tab[tab[paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change")]>=fc,]
+    } else if (input$direction.deg=="down"){
+      tab <- tab[tab[paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change")]<=-fc,]
+    } else {
+      tab <- tab[tab[paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change")]>=fc | tab[paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change")]<=-fc,]
+    }
+    tab <- tab[,c(colnames(values$results()$deg[[input$cluster.deg]])[2],paste0("Cluster.",req(input$cluster.1.deg),".Mean.Counts"),paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change"),paste0("Cluster.",req(input$cluster.1.deg),".Adjusted.p.value"))]
+    tab <- tab[order(abs(tab[paste0("Cluster.",req(input$cluster.1.deg),".Log2.fold.change")]),decreasing=TRUE),]
+    tab
+  },ignoreNULL=FALSE)
+  
+  #download
+  output$download.c <- downloadHandler(
+    filename <- function(){paste0("clusters_",values$dr.c(),"_",values$cluster.c(),".pdf")},
+    content <- function(file){
+      pdf(file,onefile=FALSE)
+      print(plot.cluster.c())
+      dev.off()
+    }
+  )
+  output$download.f <- downloadHandler(
+    filename <- function(){paste0("feature_",values$dr.f(),"_",toupper(values$feature.f()),".pdf")},
+    content <- function(file){
+      pdf(file,onefile=FALSE)
+      print(plot.feature())
+      dev.off()
+    }
+  )
+  output$download.vb <- downloadHandler(
+    filename <- function(){paste0("violinbox_",values$cluster.vb(),"_",toupper(values$feature.vb()),".pdf")},
+    content <- function(file){
+      pdf(file,onefile=FALSE)
+      print(plot.violinbox())
+      dev.off()
+    }
+  )
+  output$download.deg <- downloadHandler(
+    filename <- function(){paste0("deg_",values$cluster.deg(),"_cluster.",values$cluster.1.deg(),"_p",values$alpha.deg(),"_fc",values$fc.deg(),values$direction.deg(),".csv")},
+    content <- function(file){
+      write.csv(table.deg(),file,row.names=FALSE,quote=FALSE)
+    }
+  )
 })
diff --git a/vizapp/ui.R b/vizapp/ui.R
index 79f4cc99131a5d5dcb3d0e4694650db178ed8c5c..e1a6a90180d0d05ba63922ff567ba566efe53b8e 100644
--- a/vizapp/ui.R
+++ b/vizapp/ui.R
@@ -1,30 +1,18 @@
-library(shiny)
-library(shinyFiles)
-
-
-shinyUI(fluidPage(
-
-  verticalLayout(
-
-    # Application title
-    titlePanel("Astrocyte Example"),
-
-    wellPanel(
-
-        helpText("This is a minimal example, demonstrating how
-        a Shiny visualization application can access the output of a workflow.
-        Here we provide a file browser using the shinyFiles package. Real
-        Astrocyte vizapps would provide custom methods to access and visualize
-        output."),
-
-        helpText("The workflow output is in the directory set in the
-        outputDir environment variable. this can be retrieved in R with the
-        command Sys.getenv('outputDir')"),
-
-        # A simple file browser within the workflow output directory
-        # See https://github.com/thomasp85/shinyFiles
-        shinyFilesButton('files', label='Browse workflow output', title='Please select a file', multiple=FALSE)
-
+navbarPage(theme=shinytheme("slate"),"BICF Cellranger Count Analysis (cellranger 3.1.0 version)",
+  tabPanel("Select Data",
+    mainPanel(
+      selectInput("sample","Available Samples",samples),
+      actionButton("go.d","Load"),
+      br(),
+      br(),
+      h4("Please whait until the sample has been loaded and a message below displays this, it may take a few minutes"),
+      h3(textOutput("loaded"))
     )
+  ),
+  tabPanel("Analysis",
+    uiOutput("nav.analysis")
+  ),
+  tabPanel("QC",
+    uiOutput("nav.qc")
   )
-))
+)
diff --git a/workflow/main.nf b/workflow/main.nf
index de45c73039d0b5e077bc8b29901ec8eb946329a5..4a7edee181dbe2b2c447408fed7eb8523391bdb2 100755
--- a/workflow/main.nf
+++ b/workflow/main.nf
@@ -148,7 +148,7 @@ process count211 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --expect-cells=${expectCells211}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     } 
     else {
@@ -157,7 +157,7 @@ process count211 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --force-cells=${forceCells211}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     }
 
@@ -192,7 +192,7 @@ process count301 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --expect-cells=${expectCells301} --chemistry=${chemistryParam301}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     } 
     else {
@@ -201,7 +201,7 @@ process count301 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --force-cells=${forceCells301} --chemistry=${chemistryParam301}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     }
 
@@ -236,7 +236,7 @@ process count302 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --expect-cells=${expectCells302} --chemistry=${chemistryParam302}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     } 
     else {
@@ -245,7 +245,7 @@ process count302 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --force-cells=${forceCells302} --chemistry=${chemistryParam302}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     }
 
@@ -280,7 +280,7 @@ process count310 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --expect-cells=${expectCells310} --chemistry=${chemistryParam310}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     }
     else {
@@ -289,7 +289,7 @@ process count310 {
       ulimit -a
       bash ${baseDir}/scripts/filename_check.sh -r ${ref}
       cellranger count --id=${sample} --transcriptome=./${ref} --fastqs=. --sample=${sample} --force-cells=${forceCells310} --chemistry=${chemistryParam310}
-      sed -E 's/("([^"]*)")?,/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
+      sed -E 's/("([^"]*)")?(,|\$)/\\2\t/g' ${sample}/outs/metrics_summary.csv | tr -d "," | sed "s/^/${sample}\t/" > ${sample}_metrics_summary.tsv
       """
     }