From 485bb68fe731f3a5510b963e3bbd2bb8b2e8cea6 Mon Sep 17 00:00:00 2001 From: Yu Wan Date: Sun, 28 Jun 2015 10:22:09 +1000 Subject: [PATCH 1/5] Update 28/6 --- plotTreeShiny/.RData | Bin 0 -> 53552 bytes plotTreeShiny/.Rhistory | 118 ++++++ plotTreeShiny/01_PlotTree.Rproj | 13 + plotTreeShiny/app.R | 391 ++++++++++++++++++ plotTreeShiny/checkHash.R | 15 + plotTreeShiny/plotTree.R | 21 +- plotTreeShiny/server.R | 192 --------- plotTreeShiny/ui.R | 175 -------- server_modified/server.R | 27 -- server_modified/ui.R | 27 -- shiny_practice/print_statemtn.r | 14 - shiny_practice/reactive/plot.pdf | Bin 10001 -> 0 bytes shiny_practice/reactive/plotTree.R | 320 -------------- shiny_practice/reactive/server.R | 80 ---- shiny_practice/reactive/ui.R | 48 --- shiny_practice/reactive_stable/plotTree.R | 320 -------------- shiny_practice/reactive_stable/server.R | 132 ------ shiny_practice/reactive_stable/ui.R | 48 --- .../runPlotTree.download/plotTree.R | 320 -------------- shiny_practice/runPlotTree.download/server.R | 51 --- shiny_practice/runPlotTree.download/ui.R | 38 -- shiny_practice/runPlotTree/plotTree.R | 320 -------------- shiny_practice/runPlotTree/server.R | 18 - shiny_practice/runPlotTree/ui.R | 26 -- .../runPlotTree_conditional/plotTree.R | 320 -------------- .../runPlotTree_conditional/server.R | 23 -- shiny_practice/runPlotTree_conditional/ui.R | 33 -- .../plotTree.R | 320 -------------- .../server.R | 42 -- .../runPlotTree_conditional_clustering/ui.R | 36 -- shiny_practice/runPlotTree_tabs/plotTree.R | 320 -------------- shiny_practice/runPlotTree_tabs/server.R | 18 - shiny_practice/runPlotTree_tabs/ui.R | 33 -- shiny_practice/uploadTree2/server.R | 21 - shiny_practice/uploadTree2/ui.R | 22 - shiny_practice/variable_relationships.txt | 127 ------ shiny_practice/wan/server.R | 36 -- shiny_practice/wan/ui.R | 28 -- 38 files changed, 540 insertions(+), 3553 deletions(-) create mode 100644 plotTreeShiny/.RData create mode 100644 plotTreeShiny/.Rhistory create mode 100644 plotTreeShiny/01_PlotTree.Rproj create mode 100644 plotTreeShiny/app.R create mode 100644 plotTreeShiny/checkHash.R delete mode 100644 plotTreeShiny/server.R delete mode 100644 plotTreeShiny/ui.R delete mode 100644 server_modified/server.R delete mode 100644 server_modified/ui.R delete mode 100644 shiny_practice/print_statemtn.r delete mode 100644 shiny_practice/reactive/plot.pdf delete mode 100644 shiny_practice/reactive/plotTree.R delete mode 100644 shiny_practice/reactive/server.R delete mode 100644 shiny_practice/reactive/ui.R delete mode 100644 shiny_practice/reactive_stable/plotTree.R delete mode 100644 shiny_practice/reactive_stable/server.R delete mode 100644 shiny_practice/reactive_stable/ui.R delete mode 100644 shiny_practice/runPlotTree.download/plotTree.R delete mode 100644 shiny_practice/runPlotTree.download/server.R delete mode 100644 shiny_practice/runPlotTree.download/ui.R delete mode 100644 shiny_practice/runPlotTree/plotTree.R delete mode 100644 shiny_practice/runPlotTree/server.R delete mode 100644 shiny_practice/runPlotTree/ui.R delete mode 100644 shiny_practice/runPlotTree_conditional/plotTree.R delete mode 100644 shiny_practice/runPlotTree_conditional/server.R delete mode 100644 shiny_practice/runPlotTree_conditional/ui.R delete mode 100644 shiny_practice/runPlotTree_conditional_clustering/plotTree.R delete mode 100644 shiny_practice/runPlotTree_conditional_clustering/server.R delete mode 100644 shiny_practice/runPlotTree_conditional_clustering/ui.R delete mode 100644 shiny_practice/runPlotTree_tabs/plotTree.R delete mode 100644 shiny_practice/runPlotTree_tabs/server.R delete mode 100644 shiny_practice/runPlotTree_tabs/ui.R delete mode 100644 shiny_practice/uploadTree2/server.R delete mode 100644 shiny_practice/uploadTree2/ui.R delete mode 100644 shiny_practice/variable_relationships.txt delete mode 100644 shiny_practice/wan/server.R delete mode 100644 shiny_practice/wan/ui.R diff --git a/plotTreeShiny/.RData b/plotTreeShiny/.RData new file mode 100644 index 0000000000000000000000000000000000000000..c93776ab15d6ad74101f057d08b4f9d80a6e99a5 GIT binary patch literal 53552 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

*$;)(^276-YW;z?b(e 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 Tx$-zCl73P`BFx?e^S}QCERi?w literal 0 HcmV?d00001 diff --git a/plotTreeShiny/.Rhistory b/plotTreeShiny/.Rhistory new file mode 100644 index 0000000..d9217ac --- /dev/null +++ b/plotTreeShiny/.Rhistory @@ -0,0 +1,118 @@ +library(shiny) +library(ape) +library(RLumShiny) +source("plotTree.R") +# This is a single-file shiny application +runApp("01_PlotTree") +runApp("bin") +runApp("bin") +sidebarPanel( +) +runApp("bin") +runApp("bin") +sidebarPanel( +numericInput("obs", "Observations:", 10) +), +runApp("bin") +runApp("bin") +source('~/.active-rstudio-document', echo=TRUE) +setwd("G:/01_Research/04_GitHub/01_PlotTree") +), # finished sidebarPanel +df <- read.table(input$info_file$datapath, header = TRUE, sep = ',') +runApp("bin") +library(shiny) +runApp("bin") +), # end of the sidebarPanel +runApp("bin") +runApp("bin") +runApp("bin") +runApp("bin") +runApp("bin") +runApp("bin") +runApp("bin") +runApp("bin") +setwd("G:/01_Research/04_GitHub/01_PlotTree") +runApp("bin") +?runApp +getwd() +runApp(appDir = "G:/01_Research/04_GitHub/01_PlotTree/bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +?file.copy +?file.copy +runApp(appDir = "bin") +runApp(appDir = "bin") +?paste +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +?downloadHandler +runApp(appDir = "bin") +?closure +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +?file.copy +runApp(appDir = "bin") +library(shiny) +library(ape) +library(RLumShiny) +source("plotTree.R") +setwd("G:/01_Research/04_GitHub/01_PlotTree/bin") +library(shiny) +library(ape) +library(RLumShiny) +source("plotTree.R") +runApp(appDir = "bin") +setwd("G:/01_Research/04_GitHub/01_PlotTree") +source("bin/plotTree.R") +runApp(appDir = "bin") +runApp(appDir = "bin") +?radioButtons +?radioButtons +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +png +?png +library(grDevices) +runApp(appDir = "bin") +runApp(appDir = "bin") +?pdf +runApp(appDir = "bin") +runApp(appDir = "bin") +?png +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +library(shiny) +library(ape) +library(RLumShiny) +library(grDevices) +source("plotTree.R") +setwd("G:/01_Research/04_GitHub/01_PlotTree") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") +runApp(appDir = "bin") diff --git a/plotTreeShiny/01_PlotTree.Rproj b/plotTreeShiny/01_PlotTree.Rproj new file mode 100644 index 0000000..8e3c2eb --- /dev/null +++ b/plotTreeShiny/01_PlotTree.Rproj @@ -0,0 +1,13 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX diff --git a/plotTreeShiny/app.R b/plotTreeShiny/app.R new file mode 100644 index 0000000..88862ce --- /dev/null +++ b/plotTreeShiny/app.R @@ -0,0 +1,391 @@ +library(shiny) +library(ape) +library(RLumShiny) +source("plotTree.R") + +# Please run this application in an external web browser but not in the built-in browser of shiny +# Files: bin\app.R and bin\plotTree.R +# Use runApp(appDir = "bin") to execute this application + +#======================== User interface ======================== + +ui <- fluidPage( + + #titlePanel("Plot tree"), + sidebarLayout( + sidebarPanel( + tabsetPanel( + tabPanel("Tree", + ### UPLOAD TREE + br(), + fileInput('tree_file', 'Upload tree file (nwk)', multiple = FALSE, + accept = c('biotree/newick','.nwk', '.tree')), + checkboxInput("label_tips", "Label tree tips?", value = FALSE), + conditionalPanel( + condition = "input.label_tips", + textInput("tip_label_size", label = "Text size", value = "1"), + textInput("offset", label = "Offset", value = "0") + ), + textInput("tree_line_width", label = "Branch width", value = "1.5"), + jscolorInput(inputId = "branch_colour", label = "Branch colour:", value = "#000000", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), + br() + ), # finished tree tab + + tabPanel("Info", + ### METADATA (info file) + br(), + fileInput('info_file', 'Upload metadata (CSV)'), + checkboxInput('chk_info', 'Use metadata', value = FALSE), + conditionalPanel( + condition = "input.chk_info", + checkboxInput('print_metadata', 'Print columns', value = FALSE), + conditionalPanel( + condition = "input.print_metadata", + selectInput('print_column', 'Metadata columns to print:', c(''), multiple=TRUE) + ), + "--------", + selectInput('colour_tips_by', 'Colour tips by:', c('')), + # options if colouring by tips + conditionalPanel( + condition = "input.colour_tips_by != '(none)'", + sliderInput("tip_size", label = "Tip size", min = 0.1, max = 20, value = 0.5), + ### COLOUR PANELS + checkboxInput("legend", "Legend for node colours?", value=TRUE), + selectInput("legend_pos", label = "Position for legend", + choices = list( "bottomleft"="bottomleft", "bottomright"="bottomright", + "top-left"="topleft", "topright"="topright") + ), + "--------", + checkboxInput("ancestral", "Ancestral state reconstruction?", value=FALSE), + sliderInput("pie_size", label = "Pie graph size", min = 0.1, max = 20, value = 0.5) + ) + ) + ), # finished metadata tab + + tabPanel("Data", + ### HEATMAP DATA + br(), + fileInput('heatmap_file', 'Upload heatmap file (CSV)', multiple = F, accept = c('text/csv', '.csv')), + checkboxInput('chk_heatmap', 'Plot heatmap', value = FALSE), + conditionalPanel( + condition = "input.chk_heatmap", h4("Heatmap options"), + selectInput("clustering", label = h5("Clustering:"), + choices = list("Select..." = F, "Cluster columns by values" = T, "Square matrix"="square"), + selected = "Select"), + "--------", + # OPTIONALLY DISPLAY COLOUR OPTIONS + checkboxInput("heat_colours_prompt", "Change heatmap colour ramp", value = FALSE), + conditionalPanel( + condition = "input.heat_colours_prompt", + jscolorInput(inputId = "start_col", label = "Start colour:", value = "FFFFFF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), + jscolorInput(inputId = "middle_col", label = "Middle colour:", value = "FFF94D", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), + jscolorInput(inputId = "end_col", label = "End colour:", value = "1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), + textInput("heatmap_breaks", label = "Breaks:", value = "100") + ), + # checkboxInput("heatColoursSpecify", "Specify heatmap colours manually", value=FALSE), + # conditionalPanel( + # condition = "input.heatColoursSpecify", + # textInput("heatmap_colour_vector", label = "R code (vector), e.g. rev(gray(seq(0,1,0.1)))", value = "") + # ), + "--------", + textInput("heatmap_decimal_places", label = "Decimal places to show in heatmap legend:", value = "1"), + textInput("col_label_cex", label = "Text size for column labels:", value = "0.75") + # textInput("vlines_heatmap", label = "y-coordinates for vertical lines (e.g. c(2,5)):", value = ""), + # jscolorInput(inputId="vlines_heatmap_col", label=h5("Colour for vertical lines:"), value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) + ) + ), # finished heatmap options + + tabPanel("Other", + tabsetPanel( + tabPanel("Barplots", + br(), + # bar plots + fileInput('bar_data_file', 'Upload data for bar plots (CSV)', multiple = F, accept = c('text/csv', '.csv')), + checkboxInput('chk_barplot', 'Plot bar graphs', value = FALSE), + conditionalPanel( + condition = "input.chk_barplot", h5("Barplot options"), + jscolorInput(inputId = "bar_data_col", label = "Colour for barplots:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) + ) + ), + tabPanel("Genome blocks", + br(), + # genome blocks + fileInput('blocks_file', 'Upload genome block coordinates', multiple = F, accept = c('text/tab', '.txt')), + checkboxInput('chk_blocks', 'Plot genome blocks', value = FALSE), + conditionalPanel( + condition = "input.chk_blocks", h5("Genome block plotting options"), + textInput("genome_size", label = "Genome size (bp):", value = "5E6"), + jscolorInput(inputId = "blocks_colour", label = "Colour for blocks:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), + sliderInput("blwd", label = "Block size", min = 0.1, max = 20, value = 5) + ) + ), + + tabPanel("SNPs", + br(), + # snps + fileInput('snps_file', 'Upload SNP allele table (CSV)', multiple = F, accept = c('text/csv', '.csv')), + checkboxInput('chk_snps', 'Plot SNPs', value = FALSE), + conditionalPanel( + condition = "input.chk_snps", h5("SNP plotting options"), + textInput("genome_size", label = "Genome size (bp):", value = "5E6"), # make this linked to previous conditional + jscolorInput(inputId = "snps_colour", label = "Colour for SNPs:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) + ) + ) + ) #finished tabsetPanels + ), # finished other data tab + + tabPanel("Layout", + br(), + h5("Relative widths"), + textInput("tree_width", label = "Tree", value = 10), + textInput("info_width", label = "Info columns", value = 10), + textInput("heatmap_width", label = "Heatmap", value = 30), + textInput("bar_width", label = "Bar plots", value = 10), + textInput("genome_width", label = "Genome data (blocks, SNPs)", value = 10), + br(), + h5("Relative heights"), + textInput("main_height", label = "Main panels", value = 100), + textInput("label_height", label = "Heatmap labels", value = 10), + br(), + h5("Borders"), + textInput("edge_width", label = "Border width/height", value = 1) + ), + + # Settings and the button for printing + tabPanel("Save", + br(), # prints an empty line in the html file that is displayed as the UI + radioButtons(inputId = "format", label = "Download type:", + choices = c("PNG" = "png", "PDF" = "pdf"), selected = "png"), + sliderInput(inputId = "w", label = "width (A4 = 210mm):", min = 180, max = 1200, value = 210, width = '80%', ticks = FALSE), + sliderInput(inputId = "h", label = "height (A4 = 297mm):", min = 180, max = 1200, value = 297, width = '80%', ticks = FALSE), + textInput("file_name", label = "File name", value = "figure"), # The default file name is "figure". + downloadButton('downloadButton') # This will generate a new variable 'downloadbutton' + ) # end of tabPanel "Save" + ), # finish tabsetPanel + + ### DRAW BUTTON + br(), + actionButton("draw_button", "Draw!") + ), # end of the sidebarPanel + + mainPanel( + plotOutput("Tree", height = 800) + ) + ) # finished sidebarLayout +) # end of fluidPage and the ui + +#======================== Server ========================= + +server <- function(input, output, session) { + + # An event observer for changes to INFO CSV file + observeEvent(input$info_file, + { + # read the CSV file and get the column names. + # re-reading this file repeatedly is inefficient + df <- read.table(input$info_file$datapath, header = TRUE, sep = ',') + + # build a list of values, this is what is required by update methods + info_cols <- list() + for (v in colnames(df)) { + info_cols[v] <- v + } + # update the two input widgets using the column names + + updateSelectInput(session, inputId = 'colour_tips_by', choices=c('(none)',info_cols[-1])) + updateSelectInput(session, inputId = 'print_column', choices=c(info_cols[-1])) + + # switch on the meta data plotting option + updateCheckboxInput(session, inputId = 'info_data', value=TRUE) + }) # end of observeEvent + + # An event observer for changes to HEATMAP file + observeEvent(input$heatmap_file, + { + # switch on the heatmap plotting option + updateCheckboxInput(session, inputId = 'chk_heatmap', value=TRUE) + }) + + # An event observer for changes to BAR DATA file + observeEvent(input$bar_data_file, + { + # switch on the heatmap plotting option + updateCheckboxInput(session, inputId = 'chk_barplot', value=TRUE) + }) + + # An event observer for changes to BLOCKS file + observeEvent(input$blocks_file, + { + # switch on the heatmap plotting option + updateCheckboxInput(session, inputId = 'chk_blocks', value=TRUE) + }) + + # An event observer for changes to SNPs file + observeEvent(input$snps_file, + { + # switch on the heatmap plotting option + updateCheckboxInput(session, inputId = 'chk_snps', value=TRUE) + }) + + ### PLOT THE TREE: defines the main plotting function which will be called by downloadHandler() as well + doPlotTree <-function() { + ### ALL VARIABLES PULLED FROM 'input' GO INSIDE HERE + isolate ({ + + l <- input$Layout + t <- input$Tree + i <- input$Info + o <- input$Other + d <- input$Data + + tree_file <- input$tree_file$datapath + + # tree plotting options + label_tips <- input$label_tips + tree_line_width <- as.integer(input$tree_line_width) + branch_colour <- input$branch_colour + tip_label_size <- as.integer(input$tip_label_size) + offset <- as.integer(input$offset) + + # metadata variables + info_file <- input$info_file$datapath + tip_size <- input$tip_size + colour_tips_by <- input$colour_tips_by + if (colour_tips_by == '(none)') {colour_tips_by <- NULL} + ancestral <- input$ancestral + pie_size <- input$pie_size + legend <- input$legend + legend_pos <- input$legend_pos + print_column <- input$print_column + print_metadata <- input$print_metadata + if (!print_metadata) { print_column <- NA } + + # heatmap variables + heatmap_file <- input$heatmap_file$datapath + cluster <- input$clustering + heatmap_decimal_places <- as.integer(input$heatmap_decimal_places) + col_label_cex <- as.integer(input$col_label_cex) + vlines_heatmap_col <-input$vlines_heatmap_col + vlines_heatmap <- input$vlines_heatmap + + # heatColoursSpecify <- input$heatColoursSpecify + + # if (heatColoursSpecify) { + # heatmap_colours <- input$heatmap_colour_vector + # } + # else { + heatmap_colours <- colorRampPalette(c(input$start_col,input$middle_col,input$end_col),space="rgb")(as.integer(input$heatmap_breaks)) + # } + + # barplot variables + bar_data_file <- input$bar_data_file$datapath + bar_data_col <- input$bar_data_col + + # block plot variables + blocks_file <- input$blocks_file$datapath + blocks_colour <- input$blocks_colour + blwd <- input$blwd + genome_size <- input$genome_size + + snps_file <- input$snps_file$datapath + snps_colour <- input$snps_colour + + # Layout/spacing + tree_width <- as.numeric(input$tree_width) + info_width <- as.numeric(input$info_width) + heatmap_width <- as.numeric(input$heatmap_width) + bar_width <- as.numeric(input$bar_width) + genome_width <- as.numeric(input$genome_width) + main_height <- as.numeric(input$main_height) + label_height <- as.numeric(input$label_height) + edge_width <- as.numeric(input$edge_width) + + # TRACK DATA TYPES TO PLOT + chk_heatmap <- input$chk_heatmap + chk_info <- input$chk_info + chk_barplot <- input$chk_barplot + chk_blocks <- input$chk_blocks + chk_snps <- input$chk_snps + + if (is.null(tree_file)) { return(NULL) } + + if (!chk_info) { info_file <- NULL } + else { info_file <- info_file } + + if (!chk_heatmap) { heatmap_file <- NULL } + else { heatmap_file <- heatmap_file } + + if (!chk_barplot) { bar_data_file <- NULL } + else { bar_data_file <- bar_data_file } + + if (!chk_blocks) { blocks_file <- NULL } + else { blocks_file <- blocks_file } + + if (!chk_snps) { snps_file <- NULL } + else { snps_file <- snps_file } + + }) # end isolate + + # underlying call to plotTree(), drawn to screen and to file + plotTree(tree = tree_file, + tip.labels = label_tips, tipLabelSize = tip_label_size, offset = offset, + lwd = tree_line_width, edge.color = branch_colour, + infoFile = info_file, infoCols = print_column, + colourNodesBy = colour_tips_by, tip.colour.cex = tip_size, + ancestral.reconstruction = ancestral, pie.cex = pie_size, + legend = legend, legend.pos = legend_pos, + heatmapData = heatmap_file, cluster = cluster, + heatmap.colours = heatmap_colours, + heatmapDecimalPlaces = heatmap_decimal_places, colLabelCex = col_label_cex, + vlines.heatmap = vlines_heatmap, vlines.heatmap.col = vlines_heatmap_col, + barData = bar_data_file, barDataCol = bar_data_col, + blockFile = blocks_file, block_colour = blocks_colour, blwd = blwd, + genome_size = genome_size, + snpFile = snps_file, snp_colour = snps_colour, + treeWidth = tree_width, infoWidth = info_width, dataWidth = heatmap_width, + barDataWidth = bar_width, blockPlotWidth = genome_width, + mainHeight = main_height, labelHeight = label_height, edgeWidth = edge_width + ) + } + + output$Tree <- renderPlot({ + input$draw_button # do not need to reset the draw_button value which increases by every click + doPlotTree() + }) # end render plot + + # downloads a high-definition plot of the input data + # This function is called when the download button is clicked + output$downloadButton <- downloadHandler( + + filename = function() { + # This is the default file name displayed in the download box poped up after clicking the download button. + # You can change the filename in the download box. + f <- input$file_name + if(input$format == "pdf"){ + return(paste(f, ".pdf", sep = "")) + } else { + return(paste(f, ".png", sep = "")) + } + }, + + content = function(tmp) { + # tmp: the file name of a non-existent temp file. + if(input$format == "pdf"){ + MM2Inch <- 0.03937 # convert to millimetres to inches because the unit for pdf(..) is inch. + pdf(tmp, width = as.numeric(input$w) * MM2Inch, height = as.numeric(input$w) * MM2Inch, paper = "special") + # "special": the paper size is specified by the width and height; a4r: landscape orientation + doPlotTree() # redraw the plot + dev.off() + } else { + png(tmp, width = as.numeric(input$w), height = as.numeric(input$w), units = "mm", res = 72) + # res: the resolution is set to 72 ppi + doPlotTree() # redraw the plot + dev.off() + } + } + ) +} # end of the function server(..) + +#======================== Executes the whole script ========================= + +shinyApp(ui = ui, server = server) \ No newline at end of file diff --git a/plotTreeShiny/checkHash.R b/plotTreeShiny/checkHash.R new file mode 100644 index 0000000..f3e9e3d --- /dev/null +++ b/plotTreeShiny/checkHash.R @@ -0,0 +1,15 @@ +checkHash <- function(s) { + # This function is designed to fix the problem of wrong colour paramters from the widget jscolorInput. + # colorRampPalette() of plotTree() uses col2rgb(), which takes strings like "#FFFFFF" but not "FFFFFF" as the input. + # therefore a '#' must be added to the beginnging of every initial input$*_col which does not contain the hash sign. + # However, the value picked up from the pop-up palette returns value starting from '#'. + # This disconsistancy between return values from the input box and the pop-up palette could be a bug of jscolorInput. + # FYI, errors of col2rgb: + # col2rgb("FFFFFF"): invalid color name 'FFFFFF' + # col2rgb("##FFFFFF"): invalid RGB specification + if (substring(s, 1, 1) != '#') { # for values from the input box of jscolorInput + return(paste('#', s, sep = '')) + } else { + return(s) # for values picked up from the pop-up palette + } +} \ No newline at end of file diff --git a/plotTreeShiny/plotTree.R b/plotTreeShiny/plotTree.R index f252869..991a191 100644 --- a/plotTreeShiny/plotTree.R +++ b/plotTreeShiny/plotTree.R @@ -73,31 +73,16 @@ return(list(m=as.matrix(m),w=w,h=h)) } -plotTree<-function(tree,ladderise=NULL,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { +plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { require(ape) -# PREPARE TREE, CHOOSE LADDERISATION OR NOT, AND GET TIP ORDER +# PREPARE TREE AND GET TIP ORDER if (is.character(tree)){ t<-read.tree(tree) } else t<-tree -if (is.null(ladderise)) -{ -tl<-t -} -else if (ladderise=="descending") -{ -tl<-ladderize(t, T) -} -else if (ladderise=="ascending") -{ -tl<-ladderize(t, F) -} -else if (!is.null(ladderise)) -{ -print("Ladderise option should be exactly 'ascending' or 'descending'. Any other command will raise this error. Leave option empty to order branches as per input tree.") -} +tl<-ladderize(t) tips<-tl$edge[,2] tip.order<-tips[tips<=length(tl$tip.label)] tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) diff --git a/plotTreeShiny/server.R b/plotTreeShiny/server.R deleted file mode 100644 index b39f094..0000000 --- a/plotTreeShiny/server.R +++ /dev/null @@ -1,192 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer( function(input, output, session) { - - # An event observer for changes to INFO CSV file - observeEvent(input$info_file, - { - # read the CSV file and get the column names. - # re-reading this file repeatedly is inefficient - df = read.table(input$info_file$datapath, header=TRUE, sep=',') - # build a list of values, this is what is required by update methods - info_cols = list() - for (v in colnames(df)) { - info_cols[v] = v - } - # update the two input widgets using the column names - updateSelectInput(session, inputId='colour_tips_by', choices=c('(none)',info_cols[-1])) - updateSelectInput(session, inputId='print_column', choices=c(info_cols[-1])) - - # switch on the meta data plotting option - updateCheckboxInput(session, inputId='info_data', value=TRUE) - } - ) - - # An event observer for changes to HEATMAP file - observeEvent(input$heatmap, - { - # switch on the heatmap plotting option - updateCheckboxInput(session, inputId='chk_heatmap', value=TRUE) - } - ) - - # An event observer for changes to BAR DATA file - observeEvent(input$barData, - { - # switch on the heatmap plotting option - updateCheckboxInput(session, inputId='chk_barplot', value=TRUE) - } - ) - - # An event observer for changes to BLOCKS file - observeEvent(input$blockFile, - { - # switch on the heatmap plotting option - updateCheckboxInput(session, inputId='chk_blocks', value=TRUE) - } - ) - - # An event observer for changes to SNPs file - observeEvent(input$snpFile, - { - # switch on the heatmap plotting option - updateCheckboxInput(session, inputId='chk_snps', value=TRUE) - } - ) - - output$Tree <- renderPlot({ - - input$drawButton == 0 - - ### ALL VARIABLES PULLED FROM 'input' GO INSIDE HERE - isolate ( { - - l<-input$Layout - t<-input$Tree - i<-input$Info - o<-input$Other - d<-input$Data - - treeFile <- input$tree$datapath - - # tree plotting options - label_tips <- input$label_tips - tree_line_width <- as.integer(input$tree_line_width) - branch_colour <- input$branch_colour - tipLabelSize <- as.integer(input$tipLabelSize) - offset <- as.integer(input$offset) - - # metadata variables - infoFile <- input$info_file$datapath - tip_size <- input$tip_size - colour_tips_by <- input$colour_tips_by - if (colour_tips_by == '(none)') {colour_tips_by <- NULL} - ancestral <- input$ancestral - pie_size <- input$pie_size - legend <- input$legend - legend_pos <- input$legend_pos - print_column <- input$print_column - print_metadata <- input$print_metadata - if (!print_metadata) { print_column <- NA } - - # heatmap variables - heatmapFile <- input$heatmap$datapath - cluster <- input$clustering - heatmapDecimalPlaces <- as.integer(input$heatmapDecimalPlaces) - colLabelCex <- as.integer(input$colLabelCex) - vlines_heatmap_col <-input$vlines_heatmap_col - vlines_heatmap <- input$vlines_heatmap - -# heatColoursSpecify <- input$heatColoursSpecify - -# if (heatColoursSpecify) { -# heatmap_colours <- input$heatmap_colour_vector -# } -# else { - heatmap_colours <- colorRampPalette(c(input$start_col,input$middle_col,input$end_col),space="rgb")(as.integer(input$heatmap_breaks)) -# } - - # barplot variables - barDataFile <- input$barData$datapath - barDataCol <- input$barDataCol - - # block plot variables - blockFile <- input$blockFile$datapath - block_colour <- input$block_colour - blwd <- input$blwd - genome_size <- input$genome_size - - snpFile <- input$snpFile$datapath - snp_colour <- input$snp_colour - - # Layout/spacing - tree_width <- as.numeric(input$tree_width) - info_width <- as.numeric(input$info_width) - heatmap_width <- as.numeric(input$heatmap_width) - bar_width <- as.numeric(input$bar_width) - genome_width <- as.numeric(input$genome_width) - main_height <- as.numeric(input$main_height) - label_height <- as.numeric(input$label_height) - edge_width <- as.numeric(input$edge_width) - - # TRACK DATA TYPES TO PLOT - chk_heatmap <- input$chk_heatmap - info_data <- input$info_data - chk_barplot <- input$chk_barplot - chk_blocks <- input$chk_blocks - chk_snps <- input$chk_snps - - if (is.null(treeFile)) { return(NULL) } - - if (!info_data) { infoFile <- NULL } - else { infoFile <- infoFile } - - if (!chk_heatmap) { heatmapFile <- NULL } - else { heatmapFile <- heatmapFile } - - if (!chk_barplot) { barDataFile <- NULL } - else { barDataFile <- barDataFile } - - if (!chk_blocks) { blockFile <- NULL } - else { blockFile <- blockFile } - - if (!chk_snps) { snpFile <- NULL } - else { snpFile <- snpFile } - - }) # end isolate - - - ### PLOT THE TREE - - # main plotting function - doPlotTree <-function() { - - # underlying call to plotTree(), drawn to screen and to file - plotTree(tree=treeFile, - tip.labels=label_tips, tipLabelSize=tipLabelSize, offset=offset, - lwd=tree_line_width, edge.color=branch_colour, - infoFile=infoFile, infoCols=print_column, - colourNodesBy=colour_tips_by, tip.colour.cex=tip_size, - ancestral.reconstruction=ancestral, pie.cex=pie_size, - legend=legend, legend.pos=legend_pos, - heatmapData=heatmapFile, cluster=cluster, - heatmap.colours=heatmap_colours, - heatmapDecimalPlaces=heatmapDecimalPlaces, colLabelCex=colLabelCex, - vlines.heatmap=vlines_heatmap, vlines.heatmap.col=vlines_heatmap_col, - barData=barDataFile, barDataCol=barDataCol, - blockFile=blockFile, block_colour=block_colour, blwd=blwd, - genome_size=genome_size, - snpFile=snpFile, snp_colour=snp_colour, - treeWidth=tree_width, infoWidth=info_width, dataWidth=heatmap_width, - barDataWidth=bar_width, blockPlotWidth=genome_width, - mainHeight=main_height, labelHeight=label_height, edgeWidth=edge_width - ) - } - - doPlotTree() - - }) # end render plot - -}) # shinyServer \ No newline at end of file diff --git a/plotTreeShiny/ui.R b/plotTreeShiny/ui.R deleted file mode 100644 index b360dd1..0000000 --- a/plotTreeShiny/ui.R +++ /dev/null @@ -1,175 +0,0 @@ -library(shiny) -library(ape) -library(RLumShiny) -shinyUI(fluidPage( - #titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - tabsetPanel( - - tabPanel("Tree", - - ### UPLOAD TREE - br(), - fileInput('tree', 'Upload tree file (nwk)', multiple=F, - accept=c('biotree/newick','.nwk', '.tree')), - - checkboxInput("label_tips", "Label tree tips?", value=FALSE), - conditionalPanel( - condition = "input.label_tips", - textInput("tipLabelSize", label = "Text size", value = "1"), - textInput("offset", label = "Offset", value = "0") - ), - - textInput("tree_line_width", label = "Branch width", value = "1.5"), - jscolorInput(inputId="branch_colour", label="Branch colour:", value="#000000", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - br() - ), # finished tree tab - - tabPanel("Info", - - ### METADATA (info file) - br(), - fileInput('info_file', 'Upload metadata (CSV)'), - checkboxInput('info_data', 'Use metadata', value = FALSE), - conditionalPanel( - condition = "input.info_data", - checkboxInput('print_metadata', 'Print columns', value = FALSE), - conditionalPanel( - condition = "input.print_metadata", - selectInput('print_column', 'Metadata columns to print:', c(''), multiple=TRUE) - ), - "--------", - selectInput('colour_tips_by', 'Colour tips by:', c('')), - # options if colouring by tips - conditionalPanel( - condition = "input.colour_tips_by != '(none)'", - sliderInput("tip_size", label = "Tip size", min = 0.1, max = 20, value = 0.5), - ### COLOUR PANELS - checkboxInput("legend", "Legend for node colours?", value=TRUE), - selectInput("legend_pos", label = "Position for legend", - choices = list( "bottomleft"="bottomleft", "bottomright"="bottomright", - "top-left"="topleft", "topright"="topright") - ), - "--------", - checkboxInput("ancestral", "Ancestral state reconstruction?", value=FALSE), - sliderInput("pie_size", label = "Pie graph size", min = 0.1, max = 20, value = 0.5) - ) - ) - ), # finished metadata tab - - - tabPanel("Data", - - ### HEATMAP DATA - br(), - fileInput('heatmap', 'Upload heatmap file (CSV)', multiple = F, accept = c('text/csv', '.csv')), - checkboxInput('chk_heatmap', 'Plot heatmap', value = FALSE), - - conditionalPanel( - condition = "input.chk_heatmap", h4("Heatmap options"), - selectInput("clustering", label = h5("Clustering:"), - choices = list("Select..."=F, "Cluster columns by values"=T, "Square matrix"="square"), - selected = "Select"), - "--------", - - # OPTIONALLY DISPLAY COLOUR OPTIONS - checkboxInput("heatColoursPrompt", "Change heatmap colour ramp", value=FALSE), - conditionalPanel( - condition = "input.heatColoursPrompt", - jscolorInput(inputId="start_col", label="Start colour:", value="FFFFFF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="middle_col", label="Middle colour:", value="FFF94D", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="end_col", label="End colour:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - textInput("heatmap_breaks", label = "Breaks:", value = "100") - ), - # checkboxInput("heatColoursSpecify", "Specify heatmap colours manually", value=FALSE), - # conditionalPanel( - # condition = "input.heatColoursSpecify", - # textInput("heatmap_colour_vector", label = "R code (vector), e.g. rev(gray(seq(0,1,0.1)))", value = "") - # ), - "--------", - textInput("heatmapDecimalPlaces", label = "Decimal places to show in heatmap legend:", value = "1"), - textInput("colLabelCex", label = "Text size for column labels:", value = "0.75") - # textInput("vlines_heatmap", label = "y-coordinates for vertical lines (e.g. c(2,5)):", value = ""), - # jscolorInput(inputId="vlines_heatmap_col", label=h5("Colour for vertical lines:"), value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) - ) - ), # finished heatmap options - - tabPanel("Other", - tabsetPanel( - tabPanel("Barplots", - br(), - # bar plots - fileInput('barData', 'Upload data for bar plots (CSV)', multiple = F, accept = c('text/csv', '.csv')), - checkboxInput('chk_barplot', 'Plot bar graphs', value = FALSE), - - conditionalPanel( - condition = "input.chk_barplot", h5("Barplot options"), - jscolorInput(inputId="barDataCol", label="Colour for barplots:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) - ) - ), - - tabPanel("Genome blocks", - br(), - # genome blocks - fileInput('blockFile', 'Upload genome block coordinates', multiple = F, accept = c('text/tab', '.txt')), - checkboxInput('chk_blocks', 'Plot genome blocks', value = FALSE), - - conditionalPanel( - condition = "input.chk_blocks", h5("Genome block plotting options"), - textInput("genome_size", label = "Genome size (bp):", value = "5E6"), - jscolorInput(inputId="block_colour", label="Colour for blocks:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - sliderInput("blwd", label = "Block size", min = 0.1, max = 20, value = 5) - ) - ), - - tabPanel("SNPs", - br(), - # snps - fileInput('snpFile', 'Upload SNP allele table (CSV)', multiple = F, accept = c('text/csv', '.csv')), - checkboxInput('chk_snps', 'Plot SNPs', value = FALSE), - - conditionalPanel( - condition = "input.chk_snps", h5("SNP plotting options"), - textInput("genome_size", label = "Genome size (bp):", value = "5E6"), # make this linked to previous conditional - jscolorInput(inputId="snp_colour", label="Colour for SNPs:", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T) - ) - ) - ) #finished other data subtabs - ), # finished other data tab - - tabPanel("Layout", - br(), - h5("Relative widths"), - textInput("tree_width", label = "Tree", value = 10), - textInput("info_width", label = "Info columns", value = 10), - textInput("heatmap_width", label = "Heatmap", value = 30), - textInput("bar_width", label = "Bar plots", value = 10), - textInput("genome_width", label = "Genome data (blocks, SNPs)", value = 10), - br(), - h5("Relative heights"), - textInput("main_height", label = "Main panels", value = 100), - textInput("label_height", label = "Heatmap labels", value = 10), - br(), - h5("Borders"), - textInput("edge_width", label = "Border width/height", value = 1) - ) - - ), # finish tabpanel - - ### DRAW BUTTON - br(), - actionButton("drawButton", "Draw!") - - # ADD PRINT BUTTON HERE - - ), # finished sidebarPanel - - mainPanel( - plotOutput("Tree", height=800) - ) - - ) # finished sidebarLayout -) # fluidPage -) # shinyUI \ No newline at end of file diff --git a/server_modified/server.R b/server_modified/server.R deleted file mode 100644 index 04847b6..0000000 --- a/server_modified/server.R +++ /dev/null @@ -1,27 +0,0 @@ -library(shiny) - -shinyServer( - - function(input, output, session) { - - # An event observer for changes to INFO CSV file - observeEvent(input$info_file, - { - # read the CSV file and get the column names. - # re-reading this file repeatedly is inefficient - df = read.table(input$info_file$datapath, header=TRUE, sep=',') - - # build a list of values, this is what is required by update methods - info_cols = list() - for (v in colnames(df)) { - info_cols[v] = v - } - - # update the two input widgets using the column names - updateSelectInput(session, 'highlight_column', choices=info_cols) - updateSelectInput(session, 'show_column', choices=info_cols) - } - ) - - } -) \ No newline at end of file diff --git a/server_modified/ui.R b/server_modified/ui.R deleted file mode 100644 index 1911c0a..0000000 --- a/server_modified/ui.R +++ /dev/null @@ -1,27 +0,0 @@ -library(shiny) - -shinyUI( - fluidPage( - titlePanel('tester'), - sidebarLayout( - sidebarPanel( - - fileInput('treeFile', 'Tree'), - - # Test widgets for selecting INFO CSV file and - # display column selection options. - checkboxInput("info_data", "Info Data"), - conditionalPanel( - condition = "input.info_data", - fileInput('info_file', 'Info CSV'), - selectInput('show_column', 'Show Columns', c(''), multiple=TRUE), - selectInput('highlight_column', 'Highlight By', c('')) - ), - - actionButton("update", "Update") - ), - - mainPanel() - ) - ) -) diff --git a/shiny_practice/print_statemtn.r b/shiny_practice/print_statemtn.r deleted file mode 100644 index 09e172d..0000000 --- a/shiny_practice/print_statemtn.r +++ /dev/null @@ -1,14 +0,0 @@ - sidebarPanel( - checkboxInput('returnDownload', 'Download figure?', FALSE), - conditionalPanel( - condition = "input.returnDownload == true", - radioButtons("download_type", "Download type:", - c("PDF" = "PDF", - "PNG" = "PNG")), - sliderInput(inputId="w", label = "width (A4=210mm):", min=60, max=600, value=210, width='80%', ticks=F), - sliderInput(inputId="h", label = "height (A4=297mm):", min=60, max=600, value=297, width='80%', ticks=F), - br(), - downloadLink('pdflink') - ), - actionButton("printButton", "Update print settings") - ), \ No newline at end of file diff --git a/shiny_practice/reactive/plot.pdf b/shiny_practice/reactive/plot.pdf deleted file mode 100644 index 7fb468c6e5a6a556c5f8324ccdc1405c1a94ac78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10001 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 IYAF%_7iUVZcmMzZ diff --git a/shiny_practice/reactive/plotTree.R b/shiny_practice/reactive/plotTree.R deleted file mode 100644 index 991a191..0000000 --- a/shiny_practice/reactive/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward.D2"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/reactive/server.R b/shiny_practice/reactive/server.R deleted file mode 100644 index ff072e6..0000000 --- a/shiny_practice/reactive/server.R +++ /dev/null @@ -1,80 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output, session) { - - tree <- input$tree - info <- input$info_file - heatmap <- input$heatmap - cluster <- input$clustering - colour_nodes <- input$colour_nodes - tip_size <- input$tip_size - - # heatmap colours - start_col <- input$start_col - middle_col <- input$middle_col - end_col <- input$end_col - heatmap_breaks <- as.integer(input$heatmap_breaks) - - highlight_column <- input$highlight_column - show_column <- input$show_column - - # track data types - chk_heatmap <- input$chk_heatmap - info_data <- input$info_data - - # An event observer for changes to INFO CSV file - observeEvent(input$info_file, - { - # read the CSV file and get the column names. - # re-reading this file repeatedly is inefficient - df = read.table(input$info_file$datapath, header=TRUE, sep=',') - - # build a list of values, this is what is required by update methods - info_cols = list() - for (v in colnames(df)) { - info_cols[v] = v - } - - # update the two input widgets using the column names - updateSelectInput(session, inputId='highlight_column', choices=info_cols) - updateSelectInput(session, inputId='show_column', choices=info_cols) - } - ) - - # we don't do anything if there's no tree file - if (is.null(treeFile)) { return(NULL) } - - # switch off metadata plotting if the box is unchecked - if (!info_data) { infoFile <- NULL } - else { infoFile <- info$datapath } - - # switch off heatmap plotting if the box is unchecked - if (!chk_heatmap) { heatmapFile <- NULL } - else { heatmapFile <- heatmap$datapath } - - # plotTree wrapping (to allow calling for plotting to screen or file) - doPlotTree <-function() { - plotTree(tree=tree$datapath, - infoFile=infoFile,colourNodesBy=highlight_column,tip.colour.cex=tip_size, - infoCols=show_column, - heatmapData=heatmapFile,cluster=cluster, - heatmap.colours=colorRampPalette(c(start_col,middle_col,end_col),space="rgb")(heatmap_breaks) - ) - } - - # PLOT THE TREE when button is pressed - - plot_tree <- F - plot_tree <- eventReactive(input$drawButton, function() { - plot_tree <- T - }) - - output$Tree <- renderPlot({ - if (!plot_tree) { return (NULL) } - doPlotTree() - plot_tree <- F - }) - -}) diff --git a/shiny_practice/reactive/ui.R b/shiny_practice/reactive/ui.R deleted file mode 100644 index 982b3bf..0000000 --- a/shiny_practice/reactive/ui.R +++ /dev/null @@ -1,48 +0,0 @@ -library(shiny) -library(ape) -library(RLumShiny) -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick','.nwk', '.tree')), - checkboxInput("info_data", "Info Data"), - conditionalPanel( - condition = "input.info_data", - fileInput('info_file', 'Info CSV'), - selectInput('show_column', 'Show Columns', c(''), multiple=TRUE), - selectInput('highlight_column', 'Highlight By', c('location')), - sliderInput("tip_size", label = h4("Tip size"), min = 0.1, - max = 20, value = 0.5) - ), - ### HEATMAP DATA - checkboxInput("chk_heatmap", "Heatmap file", value=FALSE), - - conditionalPanel( - condition = "input.chk_heatmap", "Heatmap", - fileInput('heatmap', 'Choose heatmap file', multiple = F, accept = c('text/csv', '.csv')), - - # HEATMAP OPTIONS - checkboxInput("optionsPrompt", "Check box if you wish to not use the default values.", value=FALSE), - conditionalPanel( - condition = "input.optionsPrompt", - selectInput("clustering", label = "Columns clustering:", - choices = list("Select"=F, "Cluster based on density"=T, "Cluster according to tree"="square"), selected = "Select"), - "Note: You can only cluster according to tree if your rows are equal to your tree tips. I.e. if you're viewing the dataset against itself.", - - jscolorInput(inputId="start_col", label="Start colour", value="FFFFFF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="middle_col", label="Middle colour", value="FFF94D", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="end_col", label="End colour", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - textInput("heatmap_breaks", label = "Breaks", value = "100") - ) - ), - actionButton("drawButton", "Draw!") - ), - - mainPanel( - plotOutput("Tree", height=800) - ) -) -) -) \ No newline at end of file diff --git a/shiny_practice/reactive_stable/plotTree.R b/shiny_practice/reactive_stable/plotTree.R deleted file mode 100644 index 991a191..0000000 --- a/shiny_practice/reactive_stable/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward.D2"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/reactive_stable/server.R b/shiny_practice/reactive_stable/server.R deleted file mode 100644 index 8f95db9..0000000 --- a/shiny_practice/reactive_stable/server.R +++ /dev/null @@ -1,132 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output, session) { - - tree <- eventReactive(input$drawButton, { - input$tree - }) - - info <- eventReactive(input$drawButton, { - input$info_file - }) - - heatmap <- eventReactive(input$drawButton, { - input$heatmap - }) - - cluster <- eventReactive(input$drawButton, { - input$clustering - }) - - colour_nodes <- eventReactive(input$drawButton, { - input$colour_nodes - }) - - tip_size <- eventReactive(input$drawButton, { - input$tip_size - }) - - - # heatmap colours - start_col <- eventReactive(input$drawButton, { - input$start_col - }) - middle_col <- eventReactive(input$drawButton, { - input$middle_col - }) - end_col <- eventReactive(input$drawButton, { - input$end_col - }) - heatmap_breaks <- eventReactive(input$drawButton, { - input$heatmap_breaks - }) - - - highlight_column <- eventReactive(input$drawButton, { - input$highlight_column - }) - - show_column <- eventReactive(input$drawButton, { - input$show_column - }) - - - # track data types - chk_heatmap <- eventReactive(input$drawButton, { - input$chk_heatmap - }) - - info_data <- eventReactive(input$drawButton, { - input$info_data - }) - - # An event observer for changes to INFO CSV file - observeEvent(input$info_file, - { - # read the CSV file and get the column names. - # re-reading this file repeatedly is inefficient - df = read.table(input$info_file$datapath, header=TRUE, sep=',') - - # build a list of values, this is what is required by update methods - info_cols = list() - for (v in colnames(df)) { - info_cols[v] = v - } - - # update the two input widgets using the column names - updateSelectInput(session, inputId='highlight_column', choices=info_cols) - updateSelectInput(session, inputId='show_column', choices=info_cols) - } - ) - - - output$Tree <- renderPlot({ - - highlight_column <- highlight_column() - show_column <- show_column() - treeFile <- tree() - infoFile <- info() - heatmapFile <- heatmap() - cluster <- cluster() - colour_nodes <- colour_nodes() - tip_size <- tip_size() - start_col <- start_col() - middle_col <- middle_col() - end_col <- end_col() - heatmap_breaks <- as.integer(heatmap_breaks()) - - chk_heatmap <- chk_heatmap() - info_data <- info_data() - - if (is.null(treeFile)) - return(NULL) - - if (!info_data) { - infoFile <- NULL - } - else { - infoFile <- infoFile$datapath - } - - if (!chk_heatmap) { - heatmapFile <- NULL - } else { - heatmapFile <- heatmapFile$datapath - } - - - doPlotTree <-function(){ - - plotTree(tree=treeFile$datapath,infoFile=infoFile, - heatmapData=heatmapFile,cluster=cluster,colourNodesBy=highlight_column, - infoCols=show_column, - tip.colour.cex=tip_size,heatmap.colours=colorRampPalette(c(start_col,middle_col,end_col),space="rgb")(heatmap_breaks)) - } - - doPlotTree() - - }) - -}) diff --git a/shiny_practice/reactive_stable/ui.R b/shiny_practice/reactive_stable/ui.R deleted file mode 100644 index 982b3bf..0000000 --- a/shiny_practice/reactive_stable/ui.R +++ /dev/null @@ -1,48 +0,0 @@ -library(shiny) -library(ape) -library(RLumShiny) -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick','.nwk', '.tree')), - checkboxInput("info_data", "Info Data"), - conditionalPanel( - condition = "input.info_data", - fileInput('info_file', 'Info CSV'), - selectInput('show_column', 'Show Columns', c(''), multiple=TRUE), - selectInput('highlight_column', 'Highlight By', c('location')), - sliderInput("tip_size", label = h4("Tip size"), min = 0.1, - max = 20, value = 0.5) - ), - ### HEATMAP DATA - checkboxInput("chk_heatmap", "Heatmap file", value=FALSE), - - conditionalPanel( - condition = "input.chk_heatmap", "Heatmap", - fileInput('heatmap', 'Choose heatmap file', multiple = F, accept = c('text/csv', '.csv')), - - # HEATMAP OPTIONS - checkboxInput("optionsPrompt", "Check box if you wish to not use the default values.", value=FALSE), - conditionalPanel( - condition = "input.optionsPrompt", - selectInput("clustering", label = "Columns clustering:", - choices = list("Select"=F, "Cluster based on density"=T, "Cluster according to tree"="square"), selected = "Select"), - "Note: You can only cluster according to tree if your rows are equal to your tree tips. I.e. if you're viewing the dataset against itself.", - - jscolorInput(inputId="start_col", label="Start colour", value="FFFFFF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="middle_col", label="Middle colour", value="FFF94D", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - jscolorInput(inputId="end_col", label="End colour", value="1755FF", position = "bottom", color = "transparent", mode = "HSV", slider = T, close = T), - textInput("heatmap_breaks", label = "Breaks", value = "100") - ) - ), - actionButton("drawButton", "Draw!") - ), - - mainPanel( - plotOutput("Tree", height=800) - ) -) -) -) \ No newline at end of file diff --git a/shiny_practice/runPlotTree.download/plotTree.R b/shiny_practice/runPlotTree.download/plotTree.R deleted file mode 100644 index 1bc9314..0000000 --- a/shiny_practice/runPlotTree.download/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/runPlotTree.download/server.R b/shiny_practice/runPlotTree.download/server.R deleted file mode 100644 index 3fac8d6..0000000 --- a/shiny_practice/runPlotTree.download/server.R +++ /dev/null @@ -1,51 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - treeFile <- input$tree - infoFile <- input$info - heatmapFile <- input$heatmap - - if (is.null(treeFile)) - return(NULL) - - if(input$returnDownload){ -if(input$type == 'PDF'){ - pdf("plot.pdf", width=as.numeric(input$w*3.94), height=as.numeric(input$h*3.94)) - plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) - dev.off() - - output$pdflink <- downloadHandler( - filename <- "myplot.pdf", - content <- function(file) { - file.copy("plot.pdf", file) - }) -#} else if (input$type == "SVG"){ -#svg("myplot.svg", width=as.numeric(input$w*3.94), height=as.numeric(input$h*3.94)) -# plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) -# dev.off() -# output$pdflink <- downloadHandler( -# filename <- "myplot.svg", -# content <- function(file) { -# file.copy("plot.svg", file) -# }) -} else if (input$type == "PNG"){ -png("plot.png", width=as.numeric(input$w*3.94), height=as.numeric(input$h*3.94)) - plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) - dev.off() - output$pdflink <- downloadHandler( - filename <- "myplot.png", - content <- function(file) { - file.copy("plot.png", file) - }) -} else { -stop(paste("Unexpected type returned:", input$type)) -} - } -plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) - - }) -}) diff --git a/shiny_practice/runPlotTree.download/ui.R b/shiny_practice/runPlotTree.download/ui.R deleted file mode 100644 index 895e28f..0000000 --- a/shiny_practice/runPlotTree.download/ui.R +++ /dev/null @@ -1,38 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', - '.nwk', '.tree')), - - fileInput('info', 'Choose info file', multiple=F, - accept=c('text/csv', - '.csv')), - - fileInput('heatmap', 'Choose heatmap file', multiple=F, - accept=c('text/csv', - '.csv')), - checkboxInput('returnDownload', 'download?', FALSE), - conditionalPanel( - condition = "input.returnDownload == true", - sliderInput(inputId="w", label = "width (A4=210mm):", min=60, max=600, value=210, width='80%', ticks=F), - sliderInput(inputId="h", label = "height (A4=297mm):", min=60, max=600, value=297, width='80%', ticks=F), -radioButtons("type", "Download type:", - c(#"SVG" = "SVG", - "PDF" = "PDF", - "PNG" = "PNG")), - br(), - downloadLink('pdflink') - ) - - ), - mainPanel( - plotOutput("Tree", height=2000)) - ) - ) -) diff --git a/shiny_practice/runPlotTree/plotTree.R b/shiny_practice/runPlotTree/plotTree.R deleted file mode 100644 index 1bc9314..0000000 --- a/shiny_practice/runPlotTree/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/runPlotTree/server.R b/shiny_practice/runPlotTree/server.R deleted file mode 100644 index 2871187..0000000 --- a/shiny_practice/runPlotTree/server.R +++ /dev/null @@ -1,18 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - treeFile <- input$tree - infoFile <- input$info - heatmapFile <- input$heatmap - - if (is.null(treeFile)) - return(NULL) - - plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) - - }) -}) \ No newline at end of file diff --git a/shiny_practice/runPlotTree/ui.R b/shiny_practice/runPlotTree/ui.R deleted file mode 100644 index 47fb8d9..0000000 --- a/shiny_practice/runPlotTree/ui.R +++ /dev/null @@ -1,26 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', - '.nwk', '.tree')), - - fileInput('info', 'Choose info file', multiple=F, - accept=c('text/csv', - '.csv')), - - fileInput('heatmap', 'Choose heatmap file', multiple=F, - accept=c('text/csv', - '.csv')) - - ), - mainPanel( - plotOutput("Tree", height=2000)) - ) - ) -) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_conditional/plotTree.R b/shiny_practice/runPlotTree_conditional/plotTree.R deleted file mode 100644 index 1bc9314..0000000 --- a/shiny_practice/runPlotTree_conditional/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/runPlotTree_conditional/server.R b/shiny_practice/runPlotTree_conditional/server.R deleted file mode 100644 index 2dd5c7e..0000000 --- a/shiny_practice/runPlotTree_conditional/server.R +++ /dev/null @@ -1,23 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - treeFile <- input$tree - infoFile <- input$info - heatmapFile <- input$heatmap - cluster <- input$heat_cluster - colour_nodes <- input$colour_nodes - tip_size <- input$tip_size - - if (is.null(treeFile)) - return(NULL) - - plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath, - heatmapData=heatmapFile$datapath,cluster=cluster,colourNodesBy=colour_nodes, - tip.colour.cex=tip_size) - - }) -}) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_conditional/ui.R b/shiny_practice/runPlotTree_conditional/ui.R deleted file mode 100644 index 537aff6..0000000 --- a/shiny_practice/runPlotTree_conditional/ui.R +++ /dev/null @@ -1,33 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', - '.nwk', '.tree')), - - fileInput('info', 'Choose info file', multiple=F, - accept=c('text/csv', - '.csv')), - - textInput("colour_nodes", label = h4("Colour nodes by"), value = "Enter variable name"), - - sliderInput("tip_size", label = h4("Tip size"), min = 0.1, - max = 20, value = 0.5), - - fileInput('heatmap', 'Choose heatmap file', multiple=F, - accept=c('text/csv', - '.csv')), - - checkboxInput("heat_cluster", label = "Cluster heatmap", value = TRUE) - - ), - mainPanel( - plotOutput("Tree", height=800)) - ) - ) -) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_conditional_clustering/plotTree.R b/shiny_practice/runPlotTree_conditional_clustering/plotTree.R deleted file mode 100644 index 1bc9314..0000000 --- a/shiny_practice/runPlotTree_conditional_clustering/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/runPlotTree_conditional_clustering/server.R b/shiny_practice/runPlotTree_conditional_clustering/server.R deleted file mode 100644 index 7753778..0000000 --- a/shiny_practice/runPlotTree_conditional_clustering/server.R +++ /dev/null @@ -1,42 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -### END R PLOTTING CODE - -shinyServer(function(input, output) { - - output$Tree <- renderPlot({ - - treeFile <- input$tree$datapath - heatmapFile = NULL - infoFile = NULL - clusteringOption = NULL - - if (is.null(treeFile)) - return(NULL) - - if(input$chk_meta) { - infoFile <- input$info$datapath - if (input$chk_heatmap) { - heatmapFile <- input$heatmap$datapath - } - } - if (input$chk_heatmap) { - heatmapFile <- input$heatmap$datapath - } - - if(!is.null(heatmapFile)) { - if(input$optionsPrompt) { - if(input$clustering == "Cluster based on density") { - clusteringOption = T - } else - if (input$clustering == "Cluster according to tree") { - clusteringOption = "square" - } - } - } - - plotTree(treeFile, heatmapFile, infoFile, cluster=clusteringOption) - }) -}) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_conditional_clustering/ui.R b/shiny_practice/runPlotTree_conditional_clustering/ui.R deleted file mode 100644 index 9d74ecd..0000000 --- a/shiny_practice/runPlotTree_conditional_clustering/ui.R +++ /dev/null @@ -1,36 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', '.nwk', '.tree')), - # This prompts the user for metadata file - checkboxInput("chk_meta", "Meta file"), - conditionalPanel( - condition = "input.chk_meta", - fileInput('info', 'Choose info file', multiple = F, accept = c('text/csv', '.csv')) - ), - - # This prompts the user for pan genome file - checkboxInput("chk_heatmap", "Heatmap file"), - conditionalPanel( - condition = "input.chk_heatmap", "Heatmap", - fileInput('heatmap', 'Choose heatmap file', multiple = F, accept = c('text/csv', '.csv')), - - # This displays a check box if the user wants to change tree options - checkboxInput("optionsPrompt", "Check box if you wish to not use the default values.", value=FALSE), - conditionalPanel( - condition = "input.optionsPrompt", - selectInput("clustering", label = "Columns clustering:", - choices = c("Select", "Cluster based on density", "Cluster according to tree"), selected = "Select"), "Note: You can only cluster according to tree if your rows are equal to your tree tips. - I.e. if you're viewing the dataset against itself.") - ) - ), - - mainPanel(plotOutput("Tree", height=2000)) - ) -) -) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_tabs/plotTree.R b/shiny_practice/runPlotTree_tabs/plotTree.R deleted file mode 100644 index 1bc9314..0000000 --- a/shiny_practice/runPlotTree_tabs/plotTree.R +++ /dev/null @@ -1,320 +0,0 @@ -# read data and convert to data frame -readMatrix<-function(heatmapData){ -if (is.matrix(heatmapData)) { -x = data.frame(heatmapData) -} -else if (is.data.frame(heatmapData)) { -x = heatmapData -} -else { -x<-read.csv(heatmapData,row.names=1) -} -x -} - -getLayout<-function(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10) { - -# m = layout matrix -# w = layout widths vector -# h = layout height vector - -# tree -w = c(edgeWidth,treeWidth) -m<-cbind(c(0,0,0),c(0,1,0)) # first two columns, edge + tree -x = 1 - -# info -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { -x = x + 1 -m<-cbind(m,c(0,x,0)) -w = c(w,infoWidth) -} -} - -# heatmap -if (!is.null(heatmapData)) { -x = x + 1 -m<-cbind(m,c(x+1,x,0)) # add heatmap & labels -x = x + 2 -m[1,2] = x # add heatmap scale above tree -w = c(w,dataWidth) -} - -# barplot -if (!is.null(barData)) { -x = x + 1 -m<-cbind(m,c(0,x,x+1)) # barplot and scale bar -x = x + 1 -w = c(w,barDataWidth) -} - -if (doBlocks) { -x = x + 1 -m<-cbind(m,c(0,x,0)) # recomb blocks -w = c(w,blockPlotWidth) -} - -# empty edge column -m<-cbind(m,c(0,0,0)) -w = c(w,edgeWidth) - -if (!is.null(heatmapData) | !is.null(barData)) { h = c(labelHeight,mainHeight,labelHeight) } -else { h = c(edgeWidth,mainHeight,edgeWidth) } - -return(list(m=as.matrix(m),w=w,h=h)) -} - - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - -require(ape) - -# PREPARE TREE AND GET TIP ORDER -if (is.character(tree)){ -t<-read.tree(tree) -} -else t<-tree -tl<-ladderize(t) -tips<-tl$edge[,2] -tip.order<-tips[tips<=length(tl$tip.label)] -tip.label.order<-tl$tip.label[tip.order] # for ordering data. note that for tiplabel(), the order is the same as in t$tip (= tl$tip) - - -# PREPARE HEATMAP DATA -if (!is.null(heatmapData)) { - -# read heatmap data and convert to data frame -x<-readMatrix(heatmapData) - -# order rows of heatmap matrix to match tree -y.ordered<-x[tip.label.order,] - -# reorder columns? -if (!is.null(cluster)) { -if (!(cluster==FALSE)) { - -if (cluster=="square" & ncol(y.ordered)==nrow(y.ordered)) { -# order columns to match row order -original_order<-1:nrow(x) -names(original_order)<-rownames(x) -reordered<-original_order[tip.label.order] -y.ordered<-y.ordered[,rev(as.numeric(reordered))] -} - -else { -# cluster columns -if (cluster==TRUE) {cluster="ward"} # set default clustering algorithm -h<-hclust(dist(t(na.omit(y.ordered))),cluster) -y.ordered<-y.ordered[,h$order] -} - -}} # finished reordering columns - -} # finished setting up heatmap data - - -# PREPARE BAR PLOT -if (!is.null(barData)) { -b<-readMatrix(barData) -barData<-b[,1] -names(barData)<-rownames(b) -} - -# PREPARE INFO TO PRINT -if (!is.null(infoFile)) { -info<-readMatrix(infoFile) -info.ordered<-info[rev(tip.label.order),] -} -else {info.ordered=NULL} - - -# PREPARE DISCRETE TRAIT FOR COLOURING NODES AND INFERRING ANCESTRAL STATES -ancestral=NULL -nodeColourSuccess=NULL -if (!is.null(colourNodesBy) & !is.null(infoFile)) { - -if (colourNodesBy %in% colnames(info.ordered)) { -nodeColourSuccess = TRUE -loc1<-info.ordered[,which(colnames(info.ordered)==colourNodesBy)] - -# assign values -tipLabelSet <- character(length(loc1)) -names(tipLabelSet) <- rownames(info.ordered) -groups<-table(loc1,exclude="") -n<-length(groups) -groupNames<-names(groups) - -# set colours -if (is.null(tipColours)){ colours<-rainbow(n) } -else{ colours<-tipColours } - -# assign colours based on values -for (i in 1:n) { -g<-groupNames[i] -tipLabelSet[loc1==g]<-colours[i] -} -tipLabelSet <- tipLabelSet[tl$tip] - -# ancestral reconstruction -if (ancestral.reconstruction) { ancestral<-ace(loc1,tl,type="discrete") } - -}} -# finished with trait labels and ancestral reconstruction - - -# OPEN EXTERNAL DEVICE FOR DRAWING -# open PDF for drawing -if (!is.null(outputPDF)) { -pdf(width=w,height=h,file=outputPDF) -} -# open PNG for drawing -if (!is.null(outputPNG)) { -png(width=w,height=h,file=outputPNG) -} - - -# SET UP LAYOUT FOR PLOTTING -doBlocks <- (!is.null(blockFile) | !is.null(snpFile)) -l <- getLayout(infoFile,infoCols,heatmapData,barData,doBlocks,treeWidth=treeWidth,infoWidth=infoWidth,dataWidth=dataWidth,edgeWidth=edgeWidth,labelHeight=labelHeight,mainHeight=mainHeight,barDataWidth=barDataWidth,blockPlotWidth=blockPlotWidth) -layout(l$m, widths=l$w, heights=l$h) - - -# PLOT TREE -par(mar=rep(0,4)) -tlp<-plot.phylo(tl,no.margin=T,show.tip.label=tip.labels,label.offset=offset,edge.width=lwd,edge.color=edge.color,xaxs="i", yaxs="i", y.lim=c(0.5,length(tl$tip)+0.5),cex=tipLabelSize) - -# colour by trait -if (!is.null(nodeColourSuccess)) { -tiplabels(col= tipLabelSet,pch=16,cex=tip.colour.cex) -if (ancestral.reconstruction) { nodelabels(pie=ancestral$lik.anc, cex=pie.cex, piecol=colours) } -if (legend) { legend(legend.pos,legend=groupNames,fill=colours) } -} - -if (axis) { axisPhylo(axisPos) } - -# PLOT INFO -if (!is.null(infoFile)) { # info is provided - -printCols = TRUE -if (!is.null(infoCols)) { -if (is.na(infoCols)) { -printCols = FALSE -}} - -if (printCols) { - -par(mar=rep(0,4)) - -if (!is.null(infoCols)) {infoColNumbers = which(colnames(info.ordered) %in% infoCols)} -else { infoColNumbers = 1:ncol(info.ordered)} - -plot(NA,axes=F,pch="",xlim=c(0,length(infoColNumbers)+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") - -# plot all info columns -for (i in 1:length(infoColNumbers)) { -j<-infoColNumbers[i] -text(x=rep(i+1,nrow(info.ordered)+1),y=c((nrow(info.ordered)):1),info.ordered[,j],cex=infoCex) -} - -} -} - - -# PLOT HEATMAP -if (!is.null(heatmapData)) { - -if (is.null(heatmapBreaks)) { heatmapBreaks = seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1) } - -# plot heatmap -par(mar=rep(0,4), xpd=TRUE) -image((1:ncol(y.ordered))-0.5,(1:nrow(y.ordered))-0.5, as.matrix(t(y.ordered)),col=heatmap.colours,breaks=heatmapBreaks,axes=F,xaxs="i", yaxs="i", xlab="",ylab="") - -# draw vertical lines over heatmap -if (!is.null(vlines.heatmap)) { -for (v in vlines.heatmap) {abline(v=v, col=vlines.heatmap.col)} -} - -# overlay blocks on heatmap -if (!is.null(heatmap.blocks)) { -for (coords in heatmap.blocks) {rect(xleft=coords[1], 0, coords[2], ncol(y.ordered), col=vlines.heatmap.col, border=NA)} -} - - -# data labels for heatmap -par(mar=rep(0,4)) -plot(NA, axes=F, xaxs="i", yaxs="i", ylim=c(0,2), xlim=c(0.5,ncol(y.ordered)+0.5)) -text(1:ncol(y.ordered)-0.5,rep(0,ncol(x)),colnames(y.ordered), srt=90, cex=colLabelCex, pos=4) - -# scale for heatmap -par(mar=c(2,0,0,2)) -#image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",xlim=c(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T))) -image(as.matrix(seq(min(y.ordered,na.rm=T),max(y.ordered,na.rm=T),length.out=length(heatmap.colours)+1)),col=heatmap.colours,yaxt="n",breaks=heatmapBreaks,axes=F) -axis(1,at=heatmapBreaks[-length(heatmapBreaks)]/max(y.ordered,na.rm=T),labels=round(heatmapBreaks[-length(heatmapBreaks)],heatmapDecimalPlaces)) -} - -# BARPLOT -if (!is.null(barData)) { -par(mar=rep(0,4)) -barplot(barData[tip.label.order], horiz=T, axes=F, xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0.25,length(barData)+0.25),xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),col=barDataCol,border=0,width=0.5,space=1,names.arg=NA) - -# scale for barData plot -par(mar=c(2,0,0,0)) -plot(NA, yaxt="n", xaxs="i", yaxs="i", xlab="", ylab="", ylim=c(0,2), xlim=c((-1)*max(barData,na.rm=T)/20,max(barData,na.rm=T)),frame.plot=F) -} - -# SNPS AND RECOMBINATION BLOCKS -if (doBlocks) { -par(mar=rep(0,4)) -plot(NA,axes=F,pch="",xlim=c(genome_offset,genome_offset+genome_size+1.5),ylim=c(0.5,length(tl$tip)+0.5),xaxs="i",yaxs="i") # blank plotting area - -# plot snps -if (!is.null(snpFile)) { -snps<-read.csv(snpFile,header=F,row.names=1) # in case colnames start with numbers or contain dashes, which R does not like as column headers -snps_strainCols <- snps[1,] # column names = strain names -snps<-snps[-1,] # drop strain names - -for (strain in tip.label.order){ -# print SNPs compared to ancestral alleles in column 1 -s<-rownames(snps)[(as.character(snps[,1]) != as.character(snps[,which(snps_strainCols==strain)])) & (as.character(snps[,which(snps_strainCols==strain)])!=gapChar) & (as.character(snps[,1])!=gapChar)] -y <- which(tip.label.order==strain) -if (length(s)>0) { -for (x in s) { -points(x,y,pch="|",col=snp_colour,cex=0.25) -} -} -} -} - -# plot blocks -if (!is.null(blockFile)){ -blocks<-read.delim(blockFile,header=F) -for (i in 1:nrow(blocks)) { -if (as.character(blocks[i,1]) %in% tip.label.order) { -y <- which(tip.label.order==as.character(blocks[i,1])) -x1 <- blocks[i,2] -x2 <- blocks[i,3] -lines(c(x1,x2),c(y,y),lwd=blwd,lend=2,col=block_colour) -} -} -} - -} # finished with SNPs and recomb blocks - -# CLOSE EXTERNAL DRAWING DEVICE -if (!is.null(outputPDF) | !is.null(outputPNG)) { -dev.off() -} - -# RETURN ordered info and ancestral reconstruction object -if (!is.null(heatmapData)){mat=as.matrix(t(y.ordered))} -else {mat=NULL} -return(list(info=info.ordered,anc=ancestral,mat=mat,strain_order=tip.label.order)) -} diff --git a/shiny_practice/runPlotTree_tabs/server.R b/shiny_practice/runPlotTree_tabs/server.R deleted file mode 100644 index 2871187..0000000 --- a/shiny_practice/runPlotTree_tabs/server.R +++ /dev/null @@ -1,18 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - treeFile <- input$tree - infoFile <- input$info - heatmapFile <- input$heatmap - - if (is.null(treeFile)) - return(NULL) - - plotTree(tree=treeFile$datapath,infoFile=infoFile$datapath,heatmapData=heatmapFile$datapath) - - }) -}) \ No newline at end of file diff --git a/shiny_practice/runPlotTree_tabs/ui.R b/shiny_practice/runPlotTree_tabs/ui.R deleted file mode 100644 index db538a5..0000000 --- a/shiny_practice/runPlotTree_tabs/ui.R +++ /dev/null @@ -1,33 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - tabsetPanel( - - tabPanel("tree", - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', '.nwk', '.tree')) - ), - - tabPanel("metadata", - fileInput('info', 'Choose info file', multiple=F, - accept=c('text/csv', '.csv')) - ), - - tabPanel("heatmap", - fileInput('heatmap', 'Choose heatmap file', multiple=F, - accept=c('text/csv', - '.csv')) - ) - ) - - ), - mainPanel( - plotOutput("Tree", height=2000)) - ) - ) -) \ No newline at end of file diff --git a/shiny_practice/uploadTree2/server.R b/shiny_practice/uploadTree2/server.R deleted file mode 100644 index e7b753c..0000000 --- a/shiny_practice/uploadTree2/server.R +++ /dev/null @@ -1,21 +0,0 @@ -library(shiny) -library(ape) - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - # input$file1 will be NULL initially. After the user selects - # and uploads a file, it will be a data frame with 'name', - # 'size', 'type', and 'datapath' columns. The 'datapath' - # column will contain the local filenames where the data can - # be found. - - inFile <- input$tree - - if (is.null(inFile)) - return(NULL) - - t<-read.tree(inFile$datapath) - plot(t) - }) -}) \ No newline at end of file diff --git a/shiny_practice/uploadTree2/ui.R b/shiny_practice/uploadTree2/ui.R deleted file mode 100644 index 8a8448e..0000000 --- a/shiny_practice/uploadTree2/ui.R +++ /dev/null @@ -1,22 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', - '.nwk', '.tree')) - - fileInput('info', 'Choose info file', multiple=F, - accept=c('text/csv', - '.csv')) - - ), - mainPanel( - plotOutput("Tree", height=2000)) - ) - ) -) \ No newline at end of file diff --git a/shiny_practice/variable_relationships.txt b/shiny_practice/variable_relationships.txt deleted file mode 100644 index 86ab11c..0000000 --- a/shiny_practice/variable_relationships.txt +++ /dev/null @@ -1,127 +0,0 @@ -TO DO: choose colour palettes for node colours - -manually specifying R code for colour palette in heatmap isn't working... - -bar plots are not lined up - -plotting area for blocks isn't working properly - - -INPUTS: - -plotTree<-function(tree,heatmapData=NULL,barData=NULL,infoFile=NULL,blockFile=NULL,snpFile=NULL,gapChar="?",genome_size=5E6,blwd=5,block_colour="black",snp_colour="red",genome_offset=0,colourNodesBy=NULL,infoCols=NULL,outputPDF=NULL,outputPNG=NULL,w,h,heatmap.colours=rev(gray(seq(0,1,0.1))),tip.labels=F,tipLabelSize=1,offset=0,tip.colour.cex=0.5,legend=T,legend.pos="bottomleft",ancestral.reconstruction=F,cluster=NULL,tipColours=NULL,lwd=1.5,axis=F,axisPos=3,edge.color="black",infoCex=0.8,colLabelCex=0.8,treeWidth=10,infoWidth=10,dataWidth=30,edgeWidth=1,labelHeight=10,mainHeight=100,barDataWidth=10,blockPlotWidth=10,barDataCol=2,heatmapBreaks=NULL,heatmapDecimalPlaces=1,vlines.heatmap=NULL,vlines.heatmap.col=2,heatmap.blocks=NULL,pie.cex=0.5) { - - -REQUIRED INPUT, NOT CONDITIONAL: -tree -> require input file in newick format. - -tree options: - -(1) lwd=1.5 -[width of lines in tree] - -(2) edge.color="black" -[colour of tree branches] - -(3) tip.labels=F -print tip labels next to the leaves - if TRUE then can change: - tipLabelSize=1 - offset=0 - -CONDITIONAL RELATIONSHIPS: - -(1) metadata -> if this is checked, then display: - - - input file to select table (to be passed to the function as infoFile=) - - - name of column to use to colour tree tips [optional] - - to be passed to colourNodesBy= - - only valid options are column names in the info file, so ideally would load this file first and then display the column names as a dropdown list to select from) - - => if this is selected, display more options: - -> change size of the leaf node circles by setting tip.colour.cex=0.5 - -> perform ancestral reconstruction? ancestral.reconstruction=F - -> if yes, optionally change pie.cex=0.5 - -> change the default colour panel by setting tipColours= - -> turn off legend (set legend=F) - -> legend.pos - - - by default, if input file is provided, all columns will be printed next to the tree (infoCols=NULL) - - => options: - - select names of columns to display (check boxes? or type list) infoCols=c() - - switch off (set to infoCols=NA) - - -(2) heatmap data -> if this is checked, then display: - - - input file to select datatable (to be passed to the function as heatmapData=) - - - option to change colour scheme (default heatmap.colours=rev(gray(seq(0,1,0.1)))) - - - option to switch on clustering of columns (set cluster=T) - OR - option to switch on ordering of columns according to the tree - (IF the matrix is a square matrix, i.e. with columns names = tree tips as well as - row names = tree tips) (set cluster="square") - - EXPERT OPTIONS - - option to manually supply vector of breakpoints for heatmap values (heatmapBreaks=NULL) - - - - - option to specify decimal places to display in heatmap legend heatmapDecimalPlaces=1 - - - option to change size of column labels (colLabelCex=) - - - option to draw vertical lines after columns - e.g. lines after column 5 and 10, vlines.heatmap=c(5,10) - - set colour for these lines: vlines.heatmap.col=2 - - - manually specify colour scheme - -(3) bar plots -> if this is checked, then display: - - - input file to select table of data to be plotted as barplot (barData=) - - - set colour to use for plotting bar graphs: barDataCol= - -(4) genome blocks -> if this is checked, then display: - - - input file to select table of blocks (blockFile=NULL) - - MUST specify genome size for plotting (genome_size=) [*same as for snps] - - - optionally: - - line width for drawing blocks (blwd=5) - - change colour for blocks (block_colour="black") - -<== DONE ==> - -(5) SNPs -> if this is checked, then display: - - - input file to select table of blocks (snpFile=NULL) - - MUST specify genome size for plotting (genome_size=) [*same as for blocks] - - - optionally: - - character representing unknown bases/baps (gapChar="?") - - change colour for SNPs (snp_colour="red") - - - -CONTROLLING THE RELATIVE SIZES OF THE ELEMENTS: - -WIDTHS (this is the order displayed) -treeWidth=10 -infoWidth=10 -dataWidth=30 -barDataWidth=10 -blockPlotWidth=10 - -HEIGHTS: -mainHeight=100 -labelHeight=10 - -EDGES (TOP, BOTTOM, LEFT, RIGHT) -edgeWidth=1 - diff --git a/shiny_practice/wan/server.R b/shiny_practice/wan/server.R deleted file mode 100644 index eda3157..0000000 --- a/shiny_practice/wan/server.R +++ /dev/null @@ -1,36 +0,0 @@ -library(shiny) -library(ape) -source("plotTree.R") - -### END R PLOTTING CODE - -shinyServer(function(input, output) { - output$Tree <- renderPlot({ - - treeFile <- input$tree - - if (is.null(treeFile)) - return(NULL) - - if (input$chk_metadata) { - infoFile <- input$info - } else { - infoFile <- NULL - } - - if (input$chk_heatmap) { - heatmapFile <- input$heatmap - } else { - heatmapFile <- NULL - } - - if (input$chk_barplot) { - barplotFile <- input$barplot - } else { - barplotFile <- NULL - } - - plotTree(tree=treeFile$datapath, heatmapData = heatmapFile$datapath, infoFile = infoFile$datapath, - barData = barplotFile$datapath) - }) -}) \ No newline at end of file diff --git a/shiny_practice/wan/ui.R b/shiny_practice/wan/ui.R deleted file mode 100644 index 87d3c00..0000000 --- a/shiny_practice/wan/ui.R +++ /dev/null @@ -1,28 +0,0 @@ -library(shiny) -library(ape) - -shinyUI(fluidPage( - titlePanel("Plot tree"), - sidebarLayout( - sidebarPanel( - fileInput('tree', 'Choose tree file', multiple=F, - accept=c('biotree/newick', '.nwk', '.tree')), - - checkboxInput("chk_metadata", "Metadata file", value = FALSE), - - conditionalPanel( - condition = "input.chk_metadata", - fileInput('info', 'Choose metadata file', multiple = FALSE, accept = c('text/csv', '.csv')) - ), - - checkboxInput("chk_heatmap", "Heatmap file", value = FALSE), - conditionalPanel( - condition = "input.chk_heatmap", - fileInput('heatmap', 'Choose heatmap file', multiple = F, accept = c('text/csv', '.csv')) - ) - ), - - mainPanel(plotOutput("Tree", height=2000)) - ) -) -) \ No newline at end of file From d640bdd2dcd04df88afc6ccf99c072f1b72bfe79 Mon Sep 17 00:00:00 2001 From: Yu Wan Date: Sun, 28 Jun 2015 10:24:09 +1000 Subject: [PATCH 2/5] Clearance of files --- tree_example_april2015/.Rhistory | 450 ----------------------------- tree_example_april2015/myplot.pdf | Bin 17544 -> 0 bytes tree_example_april2015/myplot4.pdf | Bin 43487 -> 0 bytes 3 files changed, 450 deletions(-) delete mode 100644 tree_example_april2015/.Rhistory delete mode 100644 tree_example_april2015/myplot.pdf delete mode 100644 tree_example_april2015/myplot4.pdf diff --git a/tree_example_april2015/.Rhistory b/tree_example_april2015/.Rhistory deleted file mode 100644 index 0b3f077..0000000 --- a/tree_example_april2015/.Rhistory +++ /dev/null @@ -1,450 +0,0 @@ -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv",header=T) -d[1:5,1:5] -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv") -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet.csv") -d[1:5,1:5] -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet.csv",row.names=1,header=T) -d[1:5,1:5] -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet.csv",row.names=1,header=F) -write.csv(t(d),file="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv") -write.csv(t(d),file="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv",row.names=F) -d<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv",row.names=1,header=T) -d[1:5,1:5] -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("K","OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv",heatmap.colours=c("grey","red"),dataWidth=20,cluster=F) -dd<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv") -head(dd) -dd[1:5,1:5] -dd<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose.csv",header=T,row.names=1) -image(dd) -image(as.matrix(dd)) -image(as.matrix(dd),col=rev(grey(seq(0,10,1)/10))) -image(as.matrix(dd),col=(grey(seq(0,10,1)/10))) -image(as.matrix(dd),col=rev(grey(seq(0,10,1)/10))) -image(as.matrix(dd),col=(grey(seq(0,10,1)/10))) -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("K","OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData=dd,heatmap.colours=c("grey","red"),dataWidth=20,cluster=F) -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("K","OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose_raxID.csv",heatmap.colours=c("grey","red"),dataWidth=20,cluster=F) -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("K","OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose_raxID.csv",dataWidth=20,cluster=F) -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("K","OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose_raxID.csv",heatmap.colours=(grey(seq(0,10,1)/10)),dataWidth=20,cluster=F) -plotTree(tree,infoFile=info_file,colourNodesBy="K",tip.colour.cex=2,infoCols=c("OC"),treeWidth=10,infoWidth=2,tipColours=c(KL1,KL12,KL15,KL17,KL1a,KL1b,KL1c,KL20,KL25,KL4,KL40),tip.label=T,offset=0.0001,edge.color=c(KL1,KL1,KL12,KL15,KL1a,KL1b,KL25,KL4,KL1)[as.factor(edge_colours)],lwd=2,heatmapData="/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/mapping_final/KTA1_GeneSummary_finalStrainSet_transpose_raxID.csv",heatmap.colours=(grey(seq(0,10,1)/10)),dataWidth=20,cluster=F) -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/ISAba1_insertSites.csv") -abar -head(abar) -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/ISAba1_insertSites.csv",row.names=1) -abar[1:5,1:5] -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/AbaR_detail",row.names=1) -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/AbaR_detail.csv",row.names=1) -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/plotting/AbaR_detail.csv",row.names=1) -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/plotting/AbaR_detail.csv") -head(abar) -nrow(abar) -ncol <- 100# -ns <- 44# -plot(c(0:ncol),0:(ns+1),pch="") -ncol <- 100# -ns <- 44# -plot(c(0,ncol),c(0,ns+1),pch="") -abar<-read.csv("/Users/kat/Documents/acinetobacter/GC1/GC1_paper_july2014/resistance/plotting/AbaR_detail.csv") -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -plot(1,i,pch=16,cex=3,col=abar$AbaR_group[i])# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="") -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,i,pch=16,cex=3,col=abar$AbaR_group[i])# -}# -} -set up plotting frame# -ncol <- 100# -ns <- 44# -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,abar$tree.order,pch=16,cex=3,col=abar$AbaR_group[i])# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,abar$tree.order[i],pch=16,cex=2,col=abar$AbaR_group[i])# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,abar$tree.order[i],pch=16,cex=1,col=abar$AbaR_group[i])# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -} -label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$AbaR_group[i],2,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -} -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$AbaR_group[i],2,ns-i,pch=16,cex=1)# -}# -} -plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$AbaR_group[i],x=2,y=ns-i,pch=16,cex=1)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=2,y=ns-i,pch=16,cex=1)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=1)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=1,cex=0.5)# -}# -} -label with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=0.5)# -}# -} -label AbaR type with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=0.5,col=abar$AbaR_group[i])# -}# -} -add sul1# -sul_col <- 3# -for (i in 1:nrow(abar)) {# -if (abar$SulI_Sul[i] != "-") {# -points(7,ns-i,pch=17,cex=1,col=sul_col)# -}# -} -add sul1# -sul_col <- 3# -for (i in 1:nrow(abar)) {# -if (abar$SulI_Sul[i] != "-") {# -points(7,ns-i,pch=15,cex=1,col=sul_col)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label AbaR type with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=0.5,col=abar$AbaR_group[i])# -}# -}# -# -# add sul1# -sul_col <- 3# -for (i in 1:nrow(abar)) {# -if (abar$SulI_Sul[i] != "-") {# -points(7,ns-i,pch=15,cex=1,col=sul_col)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(1,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label AbaR type with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=4,y=ns-i,pch=16,cex=0.5)# -}# -}# -# -# add sul1# -sul_col <- 3# -for (i in 1:nrow(abar)) {# -if (abar$SulI_Sul[i] != "-") {# -points(7,ns-i,pch=15,cex=1,col=sul_col)# -}# -} -plot(c(0,ncol),c(0,ns+1),pch="")# -# -# plot circle to indicate AbaR presence, colour by main group, label with specific variant# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -points(4,ns-i,pch=16,cex=1,col=abar$AbaR_group[i])# -}# -}# -# -# label AbaR type with number# -for (i in 1:nrow(abar)) {# -if (abar$AbaR_group[i] != "na") {# -text(abar$type[i],x=1,y=ns-i,pch=16,cex=0.5)# -}# -}# -# -# add sul1# -sul_col <- 3# -for (i in 1:nrow(abar)) {# -if (abar$SulI_Sul[i] != "-") {# -points(7,ns-i,pch=15,cex=1,col=sul_col)# -}# -} -aminogly_col <- 4# -for (i in 1:nrow(abar)) {if (abar$Aac3-I_AGly[i] != "-") {# -points(9,ns-i,pch=15,cex=1,col=aminogly_col) } } -aminogly_col <- 4# -for (i in 1:nrow(abar)) {if (abar$Aac3.I_AGly[i] != "-") {# -points(9,ns-i,pch=15,cex=1,col=aminogly_col) } } -for (i in 1:nrow(abar)) {if (abar$AadA.AGly[i] != "-") {# -points(11,ns-i,pch=15,cex=1,col=aminogly_col) } } -head(abar) -for (i in 1:nrow(abar)) {if (abar$AadA_AGly[i] != "-") {# -points(11,ns-i,pch=15,cex=1,col=aminogly_col) } } -90*8+3200 -4000/8 -400*500 -7+9+5+8 -29*50 -360/5 -72+324 -324-72 -72+36 -129+90 -109*2 -132.62*2 -132.62*2*10 -2610/9 -176/2 -install.packages('knitr', dependencies = TRUE) -library(apoe) -library(ape) -library(knitr) -?knit -236/4 -load("/Users/kat/Documents/PROJECTS/CAS_NHMCR_2013/virus_bact_data_221014_yr1paper/virus_bacteria_forKat_22oct.Rdata") -ls() -head(virus_bacteria) -table(virus_bacteria$MPG,virus_bacteria$Category) -14+34 -48/(174+333) -489/(174+333) -4/174 -360/5 -324-72 -324+72 -324+72-360 -4804510-354000-180000 -0.6*0.6 -m <- "/Users/kat/Downloads/VRE_metadataInclClinical_12022015.xlsx\ -\ baseline\ screening.csv" -t <- "/Users/kat/Documents/Efaecium/VRE_Alfred/reddog/run2/CP006620_CP006620_alleles_var_cons0.95_noOutgroups.tree" -source('~/code/holtlab/Rcode/plotTree.R', chdir = TRUE) -getwd() -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST")) -colnames(m) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn2549")) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549")) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Swab.date")) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Swab_date")) -d<-read.csv(m) -head(m) -head(d) -colnames(d) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number")) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community")) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community") -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community",colours=c(2,1)) -plotTree -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1)) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1),tipColourCex=3) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1),tip.colour.cex=3) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1),tip.colour.cex=2) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1),tip.colour.cex=2) -colnames(d) -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549.S.L","Swab_date","Swab.Number","community"),colourNodesBy="community", tipColours =c(2,1),tip.colour.cex=2,"H_admission_to_swab","abtmt") -plotTree(t,infoFile=m,infoCols=c("Study.id","Name.code","MLST","Tn1549.S.L","Swab_date","Swab.Number","community","H_admission_to_swab","abtmt"),colourNodesBy="community", tipColours =c(2,1),tip.colour.cex=2) -694+789+478+742+651+379+600 -60+81+38+10 -4333+ 189 -27+42 -5/6 -0.23*22 -17/23 -17/22 -/5 -96/5 -48/5 -20/4 -96*2 -26*5 -130/48 -5*52 -r<-read.csv("~/Downloads/Aussie conferences (Responses) - Form Responses.csv") -colnames(r) -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.) -lm(r$Invited.talks~r$Contributed.talks..selected.from.abstacts.) -summary(lm(r$Invited.talks~r$Contributed.talks..selected.from.abstacts.)) -cor.test(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.) -cor.test(r$Invited.talks,r$Organisers) -cor.test(r$Contributed.talks..selected.from.abstacts.,r$Organisers) -plot(r$Contributed.talks..selected.from.abstacts.,r$Organisers) -cor.test(r$Invited.talks,r$Organisers) -lm(r$Invited.talks~r$Contributed.talks..selected.from.abstacts.) -cor.test(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.) -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.,pch=16) -abline(coef(lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks))) -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.,pch=16,ylab="Contributed",xlab="Invited") -abline(coef(lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks))) -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.,pch=16,ylab="% Female speakers (Contributed talks)",xlab="% Fmale speakers (Invited talks)") -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.,pch=16,ylab="% Female speakers (Contributed talks)",xlab="% Fmale speakers (Invited talks)",col=2) -abline(coef(lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks))) -text(x=70,y=30,"Correlation=0.5, p=0.03") -text(x=70,y=30,"Correlation=0.5, p=0.03")e -plot(r$Invited.talks,r$Contributed.talks..selected.from.abstacts.,pch=16,ylab="% Female speakers (Contributed talks)",xlab="% Female speakers (Invited talks)",col=2) -text(x=70,y=30,"R2=0.2, p=0.03") -abline(coef(lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks))) -lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks) -summary(lm(r$Contributed.talks..selected.from.abstacts.~r$Invited.talks)) -summary(lm(r$Contributed.talks..selected.from.abstacts.+r$Invited.talks~r$Organisers)) -plot(r$Organisers,r$Contributed.talks..selected.from.abstacts.,pch=16,ylab="% Female speakers (Contributed talks)",xlab="% Female organisers",col=2) -head(r) -14/(14+38) -13/(13+430) -38/(14+38) -430/(13+430) -5/7 -2/7 -9/45 -24+87+46+36 -193-4-15 -140/0.35 -35/2 -3.1*6.9 -install.packages("shiny") -library(shiny) -runExample("01_hello") -source("~/code/plotTree/plotTree.R") -plotTree(tree="tree.nwk",infoFile="info.csv") -plotTree(tree="tree.nwk") -ls() -plotTree(tree="tree.nwk",barData="bar.csv") -plotTree(tree="tree.nwk",barData="bar.csv") -plotTree(tree="tree.nwk",barData="bar.csv",blockFile="blocks.csv"genome_size=5E6) -plotTree(tree="tree.nwk",barData="bar.csv",blockFile="blocks.csv",genome_size=5E6) -plotTree(tree="tree.nwk",barData="bar.csv",blockFile="blocks.csv",genome_size=5E6) -plotTree(tree="tree.nwk",barData="bar.csv",blockFile="blocks.txt",genome_size=5E6) -plotTree(tree="tree.nwk",barData="bar.csv",blockFile="blocks.txt",genome_size=5E6) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E6) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E6) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E7) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E1) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=5) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=10,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=100,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=50,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=20,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=10,blwd=10) -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10) -source("~/code/plotTree/plotTree2.R") -source("~/code/holtlab/Rcode/plotTree2.R") -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10) -?lines -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10,snpFile="alleles.csv") -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10,snpFile="alleles.csv") -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10,snpFile="alleles.csv") -plotTree(tree="tree.nwk",genome_size=5E6,blwd=10,snpFile="alleles.csv") -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5,blwd=10,snpFile="alleles.csv") -plotTree(tree="tree.nwk",blockFile="blocks.txt",genome_size=5E6,blwd=10,snpFile="alleles.csv") -runApp("~/code/plotTree/shiny_practice/reactive/") -library(shiny) -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") -runApp("~/code/plotTree/shiny_practice/reactive/") diff --git a/tree_example_april2015/myplot.pdf b/tree_example_april2015/myplot.pdf deleted file mode 100644 index 2680a25881e4381ea73704f39f225666a3ff6690..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17544 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 EA4|%U{Qv*} diff --git a/tree_example_april2015/myplot4.pdf b/tree_example_april2015/myplot4.pdf deleted file mode 100644 index b37903b2ba8785d59479c3b7aff8b345dfa2d529..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43487 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 OOj_!?Y8jhsj{G0lTmNwY From 15e3a7946bfa5ebe75954edfde61c9798abbd24f Mon Sep 17 00:00:00 2001 From: Yu Wan Date: Sun, 28 Jun 2015 10:32:47 +1000 Subject: [PATCH 3/5] Edition --- .gitignore | 1 + plotTreeShiny/.RData | Bin 53552 -> 0 bytes plotTreeShiny/.Rhistory | 119 +----------------- .../.Rproj.user/ED8AE702/build_options | 4 + .../.Rproj.user/ED8AE702/pcs/files-pane.pper | 9 ++ .../.Rproj.user/ED8AE702/pcs/source-pane.pper | 3 + .../ED8AE702/pcs/windowlayoutstate.pper | 14 +++ .../ED8AE702/pcs/workbench-pane.pper | 4 + .../.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 | 16 +++ .../.Rproj.user/ED8AE702/sdb/prop/BB3849AE | 2 + .../.Rproj.user/ED8AE702/sdb/prop/FA5A19B6 | 2 + ...{01_PlotTree.Rproj => plotTreeShiny.Rproj} | 6 +- 12 files changed, 59 insertions(+), 121 deletions(-) create mode 100644 .gitignore delete mode 100644 plotTreeShiny/.RData create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/build_options create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/pcs/files-pane.pper create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/pcs/workbench-pane.pper create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/BB3849AE create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/FA5A19B6 rename plotTreeShiny/{01_PlotTree.Rproj => plotTreeShiny.Rproj} (62%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..715ad6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/INDEX \ No newline at end of file diff --git a/plotTreeShiny/.RData b/plotTreeShiny/.RData deleted file mode 100644 index c93776ab15d6ad74101f057d08b4f9d80a6e99a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53552 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

*$;)(^276-YW;z?b(e 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 Tx$-zCl73P`BFx?e^S}QCERi?w diff --git a/plotTreeShiny/.Rhistory b/plotTreeShiny/.Rhistory index d9217ac..4b56293 100644 --- a/plotTreeShiny/.Rhistory +++ b/plotTreeShiny/.Rhistory @@ -1,118 +1 @@ -library(shiny) -library(ape) -library(RLumShiny) -source("plotTree.R") -# This is a single-file shiny application -runApp("01_PlotTree") -runApp("bin") -runApp("bin") -sidebarPanel( -) -runApp("bin") -runApp("bin") -sidebarPanel( -numericInput("obs", "Observations:", 10) -), -runApp("bin") -runApp("bin") -source('~/.active-rstudio-document', echo=TRUE) -setwd("G:/01_Research/04_GitHub/01_PlotTree") -), # finished sidebarPanel -df <- read.table(input$info_file$datapath, header = TRUE, sep = ',') -runApp("bin") -library(shiny) -runApp("bin") -), # end of the sidebarPanel -runApp("bin") -runApp("bin") -runApp("bin") -runApp("bin") -runApp("bin") -runApp("bin") -runApp("bin") -runApp("bin") -setwd("G:/01_Research/04_GitHub/01_PlotTree") -runApp("bin") -?runApp -getwd() -runApp(appDir = "G:/01_Research/04_GitHub/01_PlotTree/bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -?file.copy -?file.copy -runApp(appDir = "bin") -runApp(appDir = "bin") -?paste -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -?downloadHandler -runApp(appDir = "bin") -?closure -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -?file.copy -runApp(appDir = "bin") -library(shiny) -library(ape) -library(RLumShiny) -source("plotTree.R") -setwd("G:/01_Research/04_GitHub/01_PlotTree/bin") -library(shiny) -library(ape) -library(RLumShiny) -source("plotTree.R") -runApp(appDir = "bin") -setwd("G:/01_Research/04_GitHub/01_PlotTree") -source("bin/plotTree.R") -runApp(appDir = "bin") -runApp(appDir = "bin") -?radioButtons -?radioButtons -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -png -?png -library(grDevices) -runApp(appDir = "bin") -runApp(appDir = "bin") -?pdf -runApp(appDir = "bin") -runApp(appDir = "bin") -?png -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -library(shiny) -library(ape) -library(RLumShiny) -library(grDevices) -source("plotTree.R") -setwd("G:/01_Research/04_GitHub/01_PlotTree") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") -runApp(appDir = "bin") +setwd("G:/01_Research/Scripts/plotTree/plotTreeShiny") diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/build_options b/plotTreeShiny/.Rproj.user/ED8AE702/build_options new file mode 100644 index 0000000..8bdd3a3 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/build_options @@ -0,0 +1,4 @@ +auto_roxygenize_for_build_and_reload="0" +auto_roxygenize_for_build_package="1" +auto_roxygenize_for_check="1" +makefile_args="" diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/files-pane.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/files-pane.pper new file mode 100644 index 0000000..ac3f7ee --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/files-pane.pper @@ -0,0 +1,9 @@ +{ + "path" : "G:/01_Research/Scripts/plotTree/plotTreeShiny", + "sortOrder" : [ + { + "ascending" : true, + "columnIndex" : 2 + } + ] +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper new file mode 100644 index 0000000..1743e40 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper @@ -0,0 +1,3 @@ +{ + "activeTab" : 0 +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper new file mode 100644 index 0000000..bf2f7e0 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper @@ -0,0 +1,14 @@ +{ + "left" : { + "panelheight" : 686, + "splitterpos" : 289, + "topwindowstate" : "NORMAL", + "windowheight" : 724 + }, + "right" : { + "panelheight" : 686, + "splitterpos" : 434, + "topwindowstate" : "NORMAL", + "windowheight" : 724 + } +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/workbench-pane.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/workbench-pane.pper new file mode 100644 index 0000000..7135db5 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/workbench-pane.pper @@ -0,0 +1,4 @@ +{ + "TabSet1" : 0, + "TabSet2" : 0 +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 new file mode 100644 index 0000000..7bd0a17 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 @@ -0,0 +1,16 @@ +{ + "contents" : "library(shiny)\nlibrary(ape)\nlibrary(RLumShiny)\nsource(\"plotTree.R\")\n\n# Please run this application in an external web browser but not in the built-in browser of shiny\n# Files: bin\\app.R and bin\\plotTree.R\n# Use runApp(appDir = \"bin\") to execute this application\n\n#======================== User interface ========================\n\nui <- fluidPage(\n \n #titlePanel(\"Plot tree\"),\n sidebarLayout(\n sidebarPanel(\n tabsetPanel(\n tabPanel(\"Tree\", \n ### UPLOAD TREE\n br(),\n fileInput('tree_file', 'Upload tree file (nwk)', multiple = FALSE,\n accept = c('biotree/newick','.nwk', '.tree')),\n checkboxInput(\"label_tips\", \"Label tree tips?\", value = FALSE),\n conditionalPanel(\n condition = \"input.label_tips\",\n textInput(\"tip_label_size\", label = \"Text size\", value = \"1\"),\n textInput(\"offset\", label = \"Offset\", value = \"0\")\n ), \n textInput(\"tree_line_width\", label = \"Branch width\", value = \"1.5\"),\n jscolorInput(inputId = \"branch_colour\", label = \"Branch colour:\", value = \"#000000\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n br()\n ), # finished tree tab\t\n \n tabPanel(\"Info\", \n ### METADATA (info file)\n br(),\n fileInput('info_file', 'Upload metadata (CSV)'),\n checkboxInput('chk_info', 'Use metadata', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_info\",\n checkboxInput('print_metadata', 'Print columns', value = FALSE),\n conditionalPanel(\n condition = \"input.print_metadata\",\n selectInput('print_column', 'Metadata columns to print:', c(''), multiple=TRUE)\n ),\n \"--------\",\n selectInput('colour_tips_by', 'Colour tips by:', c('')),\n # options if colouring by tips\n conditionalPanel(\n condition = \"input.colour_tips_by != '(none)'\",\n sliderInput(\"tip_size\", label = \"Tip size\", min = 0.1, max = 20, value = 0.5),\n ### COLOUR PANELS\n checkboxInput(\"legend\", \"Legend for node colours?\", value=TRUE),\n selectInput(\"legend_pos\", label = \"Position for legend\", \n choices = list( \"bottomleft\"=\"bottomleft\", \"bottomright\"=\"bottomright\",\n \"top-left\"=\"topleft\", \"topright\"=\"topright\")\n ), \n \"--------\",\n checkboxInput(\"ancestral\", \"Ancestral state reconstruction?\", value=FALSE),\n sliderInput(\"pie_size\", label = \"Pie graph size\", min = 0.1, max = 20, value = 0.5)\n )\n )\n ),\t# finished metadata tab\t\n \n tabPanel(\"Data\", \n ### HEATMAP DATA\n br(),\n fileInput('heatmap_file', 'Upload heatmap file (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_heatmap', 'Plot heatmap', value = FALSE), \n conditionalPanel(\n condition = \"input.chk_heatmap\", h4(\"Heatmap options\"),\n selectInput(\"clustering\", label = h5(\"Clustering:\"), \n choices = list(\"Select...\" = F, \"Cluster columns by values\" = T, \"Square matrix\"=\"square\"),\n selected = \"Select\"), \n \"--------\",\n # OPTIONALLY DISPLAY COLOUR OPTIONS\n checkboxInput(\"heat_colours_prompt\", \"Change heatmap colour ramp\", value = FALSE),\n conditionalPanel(\n condition = \"input.heat_colours_prompt\", \n jscolorInput(inputId = \"start_col\", label = \"Start colour:\", value = \"FFFFFF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"middle_col\", label = \"Middle colour:\", value = \"FFF94D\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"end_col\", label = \"End colour:\", value = \"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n textInput(\"heatmap_breaks\", label = \"Breaks:\", value = \"100\")\n ),\n #\t\t\t\t\tcheckboxInput(\"heatColoursSpecify\", \"Specify heatmap colours manually\", value=FALSE),\n #\t\t\t\t\tconditionalPanel(\n #\t\t\t\t\t\tcondition = \"input.heatColoursSpecify\",\n #\t\t\t\t\t\ttextInput(\"heatmap_colour_vector\", label = \"R code (vector), e.g. rev(gray(seq(0,1,0.1)))\", value = \"\")\n #\t\t\t\t\t),\n \"--------\",\n textInput(\"heatmap_decimal_places\", label = \"Decimal places to show in heatmap legend:\", value = \"1\"),\n textInput(\"col_label_cex\", label = \"Text size for column labels:\", value = \"0.75\")\n #\t\t\t\t\ttextInput(\"vlines_heatmap\", label = \"y-coordinates for vertical lines (e.g. c(2,5)):\", value = \"\"),\n #\t\t\t\t\tjscolorInput(inputId=\"vlines_heatmap_col\", label=h5(\"Colour for vertical lines:\"), value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ), # finished heatmap options\n \n tabPanel(\"Other\",\n tabsetPanel(\n tabPanel(\"Barplots\",\n br(),\n # bar plots\n fileInput('bar_data_file', 'Upload data for bar plots (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_barplot', 'Plot bar graphs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_barplot\", h5(\"Barplot options\"),\n jscolorInput(inputId = \"bar_data_col\", label = \"Colour for barplots:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ),\n tabPanel(\"Genome blocks\",\n br(),\n # genome blocks\n fileInput('blocks_file', 'Upload genome block coordinates', multiple = F, accept = c('text/tab', '.txt')),\n checkboxInput('chk_blocks', 'Plot genome blocks', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_blocks\", h5(\"Genome block plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"),\n jscolorInput(inputId = \"blocks_colour\", label = \"Colour for blocks:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n sliderInput(\"blwd\", label = \"Block size\", min = 0.1, max = 20, value = 5)\n )\n ),\n \n tabPanel(\"SNPs\",\n br(),\n # snps\n fileInput('snps_file', 'Upload SNP allele table (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_snps', 'Plot SNPs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_snps\", h5(\"SNP plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"), # make this linked to previous conditional \n jscolorInput(inputId = \"snps_colour\", label = \"Colour for SNPs:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n )\n ) #finished tabsetPanels\n ), # finished other data tab\n \n tabPanel(\"Layout\",\n br(),\n h5(\"Relative widths\"),\n textInput(\"tree_width\", label = \"Tree\", value = 10),\n textInput(\"info_width\", label = \"Info columns\", value = 10),\n textInput(\"heatmap_width\", label = \"Heatmap\", value = 30),\n textInput(\"bar_width\", label = \"Bar plots\", value = 10),\n textInput(\"genome_width\", label = \"Genome data (blocks, SNPs)\", value = 10),\n br(),\n h5(\"Relative heights\"),\n textInput(\"main_height\", label = \"Main panels\", value = 100),\n textInput(\"label_height\", label = \"Heatmap labels\", value = 10),\n br(),\n h5(\"Borders\"),\n textInput(\"edge_width\", label = \"Border width/height\", value = 1)\n ),\n \n # Settings and the button for printing\n tabPanel(\"Save\",\n br(), # prints an empty line in the html file that is displayed as the UI\n radioButtons(inputId = \"format\", label = \"Download type:\",\n choices = c(\"PNG\" = \"png\", \"PDF\" = \"pdf\"), selected = \"png\"),\n sliderInput(inputId = \"w\", label = \"width (A4 = 210mm):\", min = 180, max = 1200, value = 210, width = '80%', ticks = FALSE),\n sliderInput(inputId = \"h\", label = \"height (A4 = 297mm):\", min = 180, max = 1200, value = 297, width = '80%', ticks = FALSE),\n textInput(\"file_name\", label = \"File name\", value = \"figure\"), # The default file name is \"figure\".\n downloadButton('downloadButton') # This will generate a new variable 'downloadbutton'\n ) # end of tabPanel \"Save\"\n ), # finish tabsetPanel\n \n ### DRAW BUTTON\n br(),\n actionButton(\"draw_button\", \"Draw!\")\n ), # end of the sidebarPanel\n \n mainPanel(\n plotOutput(\"Tree\", height = 800)\n )\n ) # finished sidebarLayout\n) # end of fluidPage and the ui\n\n#======================== Server =========================\n\nserver <- function(input, output, session) {\n \n # An event observer for changes to INFO CSV file\n observeEvent(input$info_file, \n {\n # read the CSV file and get the column names.\n # re-reading this file repeatedly is inefficient\n df <- read.table(input$info_file$datapath, header = TRUE, sep = ',')\n \n # build a list of values, this is what is required by update methods\n info_cols <- list()\n for (v in colnames(df)) {\n info_cols[v] <- v\n }\n # update the two input widgets using the column names\n \n updateSelectInput(session, inputId = 'colour_tips_by', choices=c('(none)',info_cols[-1]))\n updateSelectInput(session, inputId = 'print_column', choices=c(info_cols[-1]))\n \n # switch on the meta data plotting option\n updateCheckboxInput(session, inputId = 'info_data', value=TRUE)\n }) # end of observeEvent\n\n # An event observer for changes to HEATMAP file\n observeEvent(input$heatmap_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_heatmap', value=TRUE)\n })\t\n \n # An event observer for changes to BAR DATA file\n observeEvent(input$bar_data_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_barplot', value=TRUE)\n })\t\n \n # An event observer for changes to BLOCKS file\n observeEvent(input$blocks_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_blocks', value=TRUE)\n })\t\n \n # An event observer for changes to SNPs file\n observeEvent(input$snps_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_snps', value=TRUE)\n })\n \n ### PLOT THE TREE: defines the main plotting function which will be called by downloadHandler() as well\n doPlotTree <-function() {\n ### ALL VARIABLES PULLED FROM 'input' GO INSIDE HERE\n isolate ({\n \n l <- input$Layout\n t <- input$Tree\n i <- input$Info\n o <- input$Other\n d <- input$Data\n \n tree_file <- input$tree_file$datapath\n \n # tree plotting options\n label_tips <- input$label_tips\n tree_line_width <- as.integer(input$tree_line_width)\n branch_colour <- input$branch_colour\n tip_label_size <- as.integer(input$tip_label_size)\n offset <- as.integer(input$offset)\n \n # metadata variables\n info_file <- input$info_file$datapath\n tip_size <- input$tip_size\n colour_tips_by <- input$colour_tips_by\n if (colour_tips_by == '(none)') {colour_tips_by <- NULL}\n ancestral <- input$ancestral\n pie_size <- input$pie_size\n legend <- input$legend\n legend_pos <- input$legend_pos\n print_column <- input$print_column\n print_metadata <- input$print_metadata\n if (!print_metadata) { print_column <- NA }\n \n # heatmap variables\n heatmap_file <- input$heatmap_file$datapath\n cluster <- input$clustering\n heatmap_decimal_places <- as.integer(input$heatmap_decimal_places)\n col_label_cex <- as.integer(input$col_label_cex)\n vlines_heatmap_col <-input$vlines_heatmap_col\n vlines_heatmap <- input$vlines_heatmap\n \n # \theatColoursSpecify <- input$heatColoursSpecify\n \n #\t\t\tif (heatColoursSpecify) {\n #\t\t\t\theatmap_colours <- input$heatmap_colour_vector\n #\t\t\t}\n #\t\t\telse {\n heatmap_colours <- colorRampPalette(c(input$start_col,input$middle_col,input$end_col),space=\"rgb\")(as.integer(input$heatmap_breaks))\n #\t\t\t}\n \n # barplot variables\n bar_data_file <- input$bar_data_file$datapath\n bar_data_col <- input$bar_data_col\n \n # block plot variables\n blocks_file <- input$blocks_file$datapath\n blocks_colour <- input$blocks_colour\n blwd <- input$blwd\n genome_size <- input$genome_size\n \n snps_file <- input$snps_file$datapath\n snps_colour <- input$snps_colour\n \n # Layout/spacing\n tree_width <- as.numeric(input$tree_width)\n info_width <- as.numeric(input$info_width)\n heatmap_width <- as.numeric(input$heatmap_width)\n bar_width <- as.numeric(input$bar_width)\n genome_width <- as.numeric(input$genome_width)\n main_height <- as.numeric(input$main_height)\n label_height <- as.numeric(input$label_height)\n edge_width <- as.numeric(input$edge_width)\n \n # TRACK DATA TYPES TO PLOT\n chk_heatmap <- input$chk_heatmap\n chk_info <- input$chk_info\n chk_barplot <- input$chk_barplot\n chk_blocks <- input$chk_blocks\n chk_snps <- input$chk_snps\n \n if (is.null(tree_file)) { return(NULL) }\n \n if (!chk_info) { info_file <- NULL } \n else { info_file <- info_file }\n \n if (!chk_heatmap) { heatmap_file <- NULL } \n else { heatmap_file <- heatmap_file }\n \n if (!chk_barplot) { bar_data_file <- NULL } \n else { bar_data_file <- bar_data_file }\n \n if (!chk_blocks) { blocks_file <- NULL } \n else { blocks_file <- blocks_file }\n \n if (!chk_snps) { snps_file <- NULL } \n else { snps_file <- snps_file } \n \n }) # end isolate\n \n # underlying call to plotTree(), drawn to screen and to file\n plotTree(tree = tree_file, \n tip.labels = label_tips, tipLabelSize = tip_label_size, offset = offset,\n lwd = tree_line_width, edge.color = branch_colour,\n infoFile = info_file, infoCols = print_column, \n colourNodesBy = colour_tips_by, tip.colour.cex = tip_size, \n ancestral.reconstruction = ancestral, pie.cex = pie_size, \n legend = legend, legend.pos = legend_pos,\n heatmapData = heatmap_file, cluster = cluster,\n heatmap.colours = heatmap_colours,\n heatmapDecimalPlaces = heatmap_decimal_places, colLabelCex = col_label_cex,\n vlines.heatmap = vlines_heatmap, vlines.heatmap.col = vlines_heatmap_col,\n barData = bar_data_file, barDataCol = bar_data_col,\n blockFile = blocks_file, block_colour = blocks_colour, blwd = blwd,\n genome_size = genome_size,\n snpFile = snps_file, snp_colour = snps_colour,\n treeWidth = tree_width, infoWidth = info_width, dataWidth = heatmap_width,\n barDataWidth = bar_width, blockPlotWidth = genome_width, \n mainHeight = main_height, labelHeight = label_height, edgeWidth = edge_width\n ) \n }\n \n output$Tree <- renderPlot({\n input$draw_button # do not need to reset the draw_button value which increases by every click\n doPlotTree()\n }) # end render plot\n \n # downloads a high-definition plot of the input data\n # This function is called when the download button is clicked\n output$downloadButton <- downloadHandler(\n \n filename = function() {\n # This is the default file name displayed in the download box poped up after clicking the download button.\n # You can change the filename in the download box.\n f <- input$file_name\n if(input$format == \"pdf\"){\n return(paste(f, \".pdf\", sep = \"\"))\n } else {\n return(paste(f, \".png\", sep = \"\"))\n }\n },\n \n content = function(tmp) {\n # tmp: the file name of a non-existent temp file.\n if(input$format == \"pdf\"){\n MM2Inch <- 0.03937 # convert to millimetres to inches because the unit for pdf(..) is inch.\n pdf(tmp, width = as.numeric(input$w) * MM2Inch, height = as.numeric(input$w) * MM2Inch, paper = \"special\") \n # \"special\": the paper size is specified by the width and height; a4r: landscape orientation\n doPlotTree() # redraw the plot\n dev.off()\n } else {\n png(tmp, width = as.numeric(input$w), height = as.numeric(input$w), units = \"mm\", res = 72)\n # res: the resolution is set to 72 ppi\n doPlotTree() # redraw the plot\n dev.off()\n }\n }\n )\n} # end of the function server(..)\n\n#======================== Executes the whole script =========================\n\nshinyApp(ui = ui, server = server)", + "created" : 1435451218770.000, + "dirty" : false, + "encoding" : "UTF-8", + "folds" : "", + "hash" : "4000526187", + "id" : "2504C6D9", + "lastKnownWriteTime" : 1435447656, + "path" : "G:/01_Research/Scripts/plotTree/plotTreeShiny/app.R", + "project_path" : "app.R", + "properties" : { + }, + "source_on_save" : false, + "type" : "r_source" +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/BB3849AE b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/BB3849AE new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/BB3849AE @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/FA5A19B6 b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/FA5A19B6 new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/prop/FA5A19B6 @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/plotTreeShiny/01_PlotTree.Rproj b/plotTreeShiny/plotTreeShiny.Rproj similarity index 62% rename from plotTreeShiny/01_PlotTree.Rproj rename to plotTreeShiny/plotTreeShiny.Rproj index 8e3c2eb..a6b0ae1 100644 --- a/plotTreeShiny/01_PlotTree.Rproj +++ b/plotTreeShiny/plotTreeShiny.Rproj @@ -1,8 +1,8 @@ Version: 1.0 -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default +RestoreWorkspace: Yes +SaveWorkspace: No +AlwaysSaveHistory: No EnableCodeIndexing: Yes UseSpacesForTab: Yes From 6995eb2bd2308a43ec4a07a5a03766a80f1c43b4 Mon Sep 17 00:00:00 2001 From: Yu Wan Date: Mon, 6 Jul 2015 14:42:34 +1000 Subject: [PATCH 4/5] Update --- .../.Rproj.user/ED8AE702/pcs/source-pane.pper | 2 +- .../ED8AE702/pcs/windowlayoutstate.pper | 14 +++++++------- .../.Rproj.user/ED8AE702/saved_source_markers | 1 + .../.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 | 16 ---------------- 4 files changed, 9 insertions(+), 24 deletions(-) create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/saved_source_markers delete mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper index 1743e40..9efb51b 100644 --- a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper @@ -1,3 +1,3 @@ { - "activeTab" : 0 + "activeTab" : -1 } \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper index bf2f7e0..0289683 100644 --- a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper @@ -1,14 +1,14 @@ { "left" : { - "panelheight" : 686, - "splitterpos" : 289, - "topwindowstate" : "NORMAL", - "windowheight" : 724 + "panelheight" : 998, + "splitterpos" : 420, + "topwindowstate" : "HIDE", + "windowheight" : 1036 }, "right" : { - "panelheight" : 686, - "splitterpos" : 434, + "panelheight" : 998, + "splitterpos" : 631, "topwindowstate" : "NORMAL", - "windowheight" : 724 + "windowheight" : 1036 } } \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/saved_source_markers b/plotTreeShiny/.Rproj.user/ED8AE702/saved_source_markers new file mode 100644 index 0000000..2b1bef1 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/saved_source_markers @@ -0,0 +1 @@ +{"active_set":"","sets":[]} \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 deleted file mode 100644 index 7bd0a17..0000000 --- a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/2504C6D9 +++ /dev/null @@ -1,16 +0,0 @@ -{ - "contents" : "library(shiny)\nlibrary(ape)\nlibrary(RLumShiny)\nsource(\"plotTree.R\")\n\n# Please run this application in an external web browser but not in the built-in browser of shiny\n# Files: bin\\app.R and bin\\plotTree.R\n# Use runApp(appDir = \"bin\") to execute this application\n\n#======================== User interface ========================\n\nui <- fluidPage(\n \n #titlePanel(\"Plot tree\"),\n sidebarLayout(\n sidebarPanel(\n tabsetPanel(\n tabPanel(\"Tree\", \n ### UPLOAD TREE\n br(),\n fileInput('tree_file', 'Upload tree file (nwk)', multiple = FALSE,\n accept = c('biotree/newick','.nwk', '.tree')),\n checkboxInput(\"label_tips\", \"Label tree tips?\", value = FALSE),\n conditionalPanel(\n condition = \"input.label_tips\",\n textInput(\"tip_label_size\", label = \"Text size\", value = \"1\"),\n textInput(\"offset\", label = \"Offset\", value = \"0\")\n ), \n textInput(\"tree_line_width\", label = \"Branch width\", value = \"1.5\"),\n jscolorInput(inputId = \"branch_colour\", label = \"Branch colour:\", value = \"#000000\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n br()\n ), # finished tree tab\t\n \n tabPanel(\"Info\", \n ### METADATA (info file)\n br(),\n fileInput('info_file', 'Upload metadata (CSV)'),\n checkboxInput('chk_info', 'Use metadata', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_info\",\n checkboxInput('print_metadata', 'Print columns', value = FALSE),\n conditionalPanel(\n condition = \"input.print_metadata\",\n selectInput('print_column', 'Metadata columns to print:', c(''), multiple=TRUE)\n ),\n \"--------\",\n selectInput('colour_tips_by', 'Colour tips by:', c('')),\n # options if colouring by tips\n conditionalPanel(\n condition = \"input.colour_tips_by != '(none)'\",\n sliderInput(\"tip_size\", label = \"Tip size\", min = 0.1, max = 20, value = 0.5),\n ### COLOUR PANELS\n checkboxInput(\"legend\", \"Legend for node colours?\", value=TRUE),\n selectInput(\"legend_pos\", label = \"Position for legend\", \n choices = list( \"bottomleft\"=\"bottomleft\", \"bottomright\"=\"bottomright\",\n \"top-left\"=\"topleft\", \"topright\"=\"topright\")\n ), \n \"--------\",\n checkboxInput(\"ancestral\", \"Ancestral state reconstruction?\", value=FALSE),\n sliderInput(\"pie_size\", label = \"Pie graph size\", min = 0.1, max = 20, value = 0.5)\n )\n )\n ),\t# finished metadata tab\t\n \n tabPanel(\"Data\", \n ### HEATMAP DATA\n br(),\n fileInput('heatmap_file', 'Upload heatmap file (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_heatmap', 'Plot heatmap', value = FALSE), \n conditionalPanel(\n condition = \"input.chk_heatmap\", h4(\"Heatmap options\"),\n selectInput(\"clustering\", label = h5(\"Clustering:\"), \n choices = list(\"Select...\" = F, \"Cluster columns by values\" = T, \"Square matrix\"=\"square\"),\n selected = \"Select\"), \n \"--------\",\n # OPTIONALLY DISPLAY COLOUR OPTIONS\n checkboxInput(\"heat_colours_prompt\", \"Change heatmap colour ramp\", value = FALSE),\n conditionalPanel(\n condition = \"input.heat_colours_prompt\", \n jscolorInput(inputId = \"start_col\", label = \"Start colour:\", value = \"FFFFFF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"middle_col\", label = \"Middle colour:\", value = \"FFF94D\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"end_col\", label = \"End colour:\", value = \"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n textInput(\"heatmap_breaks\", label = \"Breaks:\", value = \"100\")\n ),\n #\t\t\t\t\tcheckboxInput(\"heatColoursSpecify\", \"Specify heatmap colours manually\", value=FALSE),\n #\t\t\t\t\tconditionalPanel(\n #\t\t\t\t\t\tcondition = \"input.heatColoursSpecify\",\n #\t\t\t\t\t\ttextInput(\"heatmap_colour_vector\", label = \"R code (vector), e.g. rev(gray(seq(0,1,0.1)))\", value = \"\")\n #\t\t\t\t\t),\n \"--------\",\n textInput(\"heatmap_decimal_places\", label = \"Decimal places to show in heatmap legend:\", value = \"1\"),\n textInput(\"col_label_cex\", label = \"Text size for column labels:\", value = \"0.75\")\n #\t\t\t\t\ttextInput(\"vlines_heatmap\", label = \"y-coordinates for vertical lines (e.g. c(2,5)):\", value = \"\"),\n #\t\t\t\t\tjscolorInput(inputId=\"vlines_heatmap_col\", label=h5(\"Colour for vertical lines:\"), value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ), # finished heatmap options\n \n tabPanel(\"Other\",\n tabsetPanel(\n tabPanel(\"Barplots\",\n br(),\n # bar plots\n fileInput('bar_data_file', 'Upload data for bar plots (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_barplot', 'Plot bar graphs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_barplot\", h5(\"Barplot options\"),\n jscolorInput(inputId = \"bar_data_col\", label = \"Colour for barplots:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ),\n tabPanel(\"Genome blocks\",\n br(),\n # genome blocks\n fileInput('blocks_file', 'Upload genome block coordinates', multiple = F, accept = c('text/tab', '.txt')),\n checkboxInput('chk_blocks', 'Plot genome blocks', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_blocks\", h5(\"Genome block plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"),\n jscolorInput(inputId = \"blocks_colour\", label = \"Colour for blocks:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n sliderInput(\"blwd\", label = \"Block size\", min = 0.1, max = 20, value = 5)\n )\n ),\n \n tabPanel(\"SNPs\",\n br(),\n # snps\n fileInput('snps_file', 'Upload SNP allele table (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_snps', 'Plot SNPs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_snps\", h5(\"SNP plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"), # make this linked to previous conditional \n jscolorInput(inputId = \"snps_colour\", label = \"Colour for SNPs:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n )\n ) #finished tabsetPanels\n ), # finished other data tab\n \n tabPanel(\"Layout\",\n br(),\n h5(\"Relative widths\"),\n textInput(\"tree_width\", label = \"Tree\", value = 10),\n textInput(\"info_width\", label = \"Info columns\", value = 10),\n textInput(\"heatmap_width\", label = \"Heatmap\", value = 30),\n textInput(\"bar_width\", label = \"Bar plots\", value = 10),\n textInput(\"genome_width\", label = \"Genome data (blocks, SNPs)\", value = 10),\n br(),\n h5(\"Relative heights\"),\n textInput(\"main_height\", label = \"Main panels\", value = 100),\n textInput(\"label_height\", label = \"Heatmap labels\", value = 10),\n br(),\n h5(\"Borders\"),\n textInput(\"edge_width\", label = \"Border width/height\", value = 1)\n ),\n \n # Settings and the button for printing\n tabPanel(\"Save\",\n br(), # prints an empty line in the html file that is displayed as the UI\n radioButtons(inputId = \"format\", label = \"Download type:\",\n choices = c(\"PNG\" = \"png\", \"PDF\" = \"pdf\"), selected = \"png\"),\n sliderInput(inputId = \"w\", label = \"width (A4 = 210mm):\", min = 180, max = 1200, value = 210, width = '80%', ticks = FALSE),\n sliderInput(inputId = \"h\", label = \"height (A4 = 297mm):\", min = 180, max = 1200, value = 297, width = '80%', ticks = FALSE),\n textInput(\"file_name\", label = \"File name\", value = \"figure\"), # The default file name is \"figure\".\n downloadButton('downloadButton') # This will generate a new variable 'downloadbutton'\n ) # end of tabPanel \"Save\"\n ), # finish tabsetPanel\n \n ### DRAW BUTTON\n br(),\n actionButton(\"draw_button\", \"Draw!\")\n ), # end of the sidebarPanel\n \n mainPanel(\n plotOutput(\"Tree\", height = 800)\n )\n ) # finished sidebarLayout\n) # end of fluidPage and the ui\n\n#======================== Server =========================\n\nserver <- function(input, output, session) {\n \n # An event observer for changes to INFO CSV file\n observeEvent(input$info_file, \n {\n # read the CSV file and get the column names.\n # re-reading this file repeatedly is inefficient\n df <- read.table(input$info_file$datapath, header = TRUE, sep = ',')\n \n # build a list of values, this is what is required by update methods\n info_cols <- list()\n for (v in colnames(df)) {\n info_cols[v] <- v\n }\n # update the two input widgets using the column names\n \n updateSelectInput(session, inputId = 'colour_tips_by', choices=c('(none)',info_cols[-1]))\n updateSelectInput(session, inputId = 'print_column', choices=c(info_cols[-1]))\n \n # switch on the meta data plotting option\n updateCheckboxInput(session, inputId = 'info_data', value=TRUE)\n }) # end of observeEvent\n\n # An event observer for changes to HEATMAP file\n observeEvent(input$heatmap_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_heatmap', value=TRUE)\n })\t\n \n # An event observer for changes to BAR DATA file\n observeEvent(input$bar_data_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_barplot', value=TRUE)\n })\t\n \n # An event observer for changes to BLOCKS file\n observeEvent(input$blocks_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_blocks', value=TRUE)\n })\t\n \n # An event observer for changes to SNPs file\n observeEvent(input$snps_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_snps', value=TRUE)\n })\n \n ### PLOT THE TREE: defines the main plotting function which will be called by downloadHandler() as well\n doPlotTree <-function() {\n ### ALL VARIABLES PULLED FROM 'input' GO INSIDE HERE\n isolate ({\n \n l <- input$Layout\n t <- input$Tree\n i <- input$Info\n o <- input$Other\n d <- input$Data\n \n tree_file <- input$tree_file$datapath\n \n # tree plotting options\n label_tips <- input$label_tips\n tree_line_width <- as.integer(input$tree_line_width)\n branch_colour <- input$branch_colour\n tip_label_size <- as.integer(input$tip_label_size)\n offset <- as.integer(input$offset)\n \n # metadata variables\n info_file <- input$info_file$datapath\n tip_size <- input$tip_size\n colour_tips_by <- input$colour_tips_by\n if (colour_tips_by == '(none)') {colour_tips_by <- NULL}\n ancestral <- input$ancestral\n pie_size <- input$pie_size\n legend <- input$legend\n legend_pos <- input$legend_pos\n print_column <- input$print_column\n print_metadata <- input$print_metadata\n if (!print_metadata) { print_column <- NA }\n \n # heatmap variables\n heatmap_file <- input$heatmap_file$datapath\n cluster <- input$clustering\n heatmap_decimal_places <- as.integer(input$heatmap_decimal_places)\n col_label_cex <- as.integer(input$col_label_cex)\n vlines_heatmap_col <-input$vlines_heatmap_col\n vlines_heatmap <- input$vlines_heatmap\n \n # \theatColoursSpecify <- input$heatColoursSpecify\n \n #\t\t\tif (heatColoursSpecify) {\n #\t\t\t\theatmap_colours <- input$heatmap_colour_vector\n #\t\t\t}\n #\t\t\telse {\n heatmap_colours <- colorRampPalette(c(input$start_col,input$middle_col,input$end_col),space=\"rgb\")(as.integer(input$heatmap_breaks))\n #\t\t\t}\n \n # barplot variables\n bar_data_file <- input$bar_data_file$datapath\n bar_data_col <- input$bar_data_col\n \n # block plot variables\n blocks_file <- input$blocks_file$datapath\n blocks_colour <- input$blocks_colour\n blwd <- input$blwd\n genome_size <- input$genome_size\n \n snps_file <- input$snps_file$datapath\n snps_colour <- input$snps_colour\n \n # Layout/spacing\n tree_width <- as.numeric(input$tree_width)\n info_width <- as.numeric(input$info_width)\n heatmap_width <- as.numeric(input$heatmap_width)\n bar_width <- as.numeric(input$bar_width)\n genome_width <- as.numeric(input$genome_width)\n main_height <- as.numeric(input$main_height)\n label_height <- as.numeric(input$label_height)\n edge_width <- as.numeric(input$edge_width)\n \n # TRACK DATA TYPES TO PLOT\n chk_heatmap <- input$chk_heatmap\n chk_info <- input$chk_info\n chk_barplot <- input$chk_barplot\n chk_blocks <- input$chk_blocks\n chk_snps <- input$chk_snps\n \n if (is.null(tree_file)) { return(NULL) }\n \n if (!chk_info) { info_file <- NULL } \n else { info_file <- info_file }\n \n if (!chk_heatmap) { heatmap_file <- NULL } \n else { heatmap_file <- heatmap_file }\n \n if (!chk_barplot) { bar_data_file <- NULL } \n else { bar_data_file <- bar_data_file }\n \n if (!chk_blocks) { blocks_file <- NULL } \n else { blocks_file <- blocks_file }\n \n if (!chk_snps) { snps_file <- NULL } \n else { snps_file <- snps_file } \n \n }) # end isolate\n \n # underlying call to plotTree(), drawn to screen and to file\n plotTree(tree = tree_file, \n tip.labels = label_tips, tipLabelSize = tip_label_size, offset = offset,\n lwd = tree_line_width, edge.color = branch_colour,\n infoFile = info_file, infoCols = print_column, \n colourNodesBy = colour_tips_by, tip.colour.cex = tip_size, \n ancestral.reconstruction = ancestral, pie.cex = pie_size, \n legend = legend, legend.pos = legend_pos,\n heatmapData = heatmap_file, cluster = cluster,\n heatmap.colours = heatmap_colours,\n heatmapDecimalPlaces = heatmap_decimal_places, colLabelCex = col_label_cex,\n vlines.heatmap = vlines_heatmap, vlines.heatmap.col = vlines_heatmap_col,\n barData = bar_data_file, barDataCol = bar_data_col,\n blockFile = blocks_file, block_colour = blocks_colour, blwd = blwd,\n genome_size = genome_size,\n snpFile = snps_file, snp_colour = snps_colour,\n treeWidth = tree_width, infoWidth = info_width, dataWidth = heatmap_width,\n barDataWidth = bar_width, blockPlotWidth = genome_width, \n mainHeight = main_height, labelHeight = label_height, edgeWidth = edge_width\n ) \n }\n \n output$Tree <- renderPlot({\n input$draw_button # do not need to reset the draw_button value which increases by every click\n doPlotTree()\n }) # end render plot\n \n # downloads a high-definition plot of the input data\n # This function is called when the download button is clicked\n output$downloadButton <- downloadHandler(\n \n filename = function() {\n # This is the default file name displayed in the download box poped up after clicking the download button.\n # You can change the filename in the download box.\n f <- input$file_name\n if(input$format == \"pdf\"){\n return(paste(f, \".pdf\", sep = \"\"))\n } else {\n return(paste(f, \".png\", sep = \"\"))\n }\n },\n \n content = function(tmp) {\n # tmp: the file name of a non-existent temp file.\n if(input$format == \"pdf\"){\n MM2Inch <- 0.03937 # convert to millimetres to inches because the unit for pdf(..) is inch.\n pdf(tmp, width = as.numeric(input$w) * MM2Inch, height = as.numeric(input$w) * MM2Inch, paper = \"special\") \n # \"special\": the paper size is specified by the width and height; a4r: landscape orientation\n doPlotTree() # redraw the plot\n dev.off()\n } else {\n png(tmp, width = as.numeric(input$w), height = as.numeric(input$w), units = \"mm\", res = 72)\n # res: the resolution is set to 72 ppi\n doPlotTree() # redraw the plot\n dev.off()\n }\n }\n )\n} # end of the function server(..)\n\n#======================== Executes the whole script =========================\n\nshinyApp(ui = ui, server = server)", - "created" : 1435451218770.000, - "dirty" : false, - "encoding" : "UTF-8", - "folds" : "", - "hash" : "4000526187", - "id" : "2504C6D9", - "lastKnownWriteTime" : 1435447656, - "path" : "G:/01_Research/Scripts/plotTree/plotTreeShiny/app.R", - "project_path" : "app.R", - "properties" : { - }, - "source_on_save" : false, - "type" : "r_source" -} \ No newline at end of file From d1478d821ae0abc7eab36bc3595bfb2753ba6d13 Mon Sep 17 00:00:00 2001 From: Yu Wan Date: Thu, 12 Nov 2015 23:19:06 +1100 Subject: [PATCH 5/5] update data files --- .../.Rproj.user/ED8AE702/pcs/source-pane.pper | 2 +- .../ED8AE702/pcs/windowlayoutstate.pper | 2 +- .../.Rproj.user/ED8AE702/sdb/per/t/3C7EE37E | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/3C7EE37E diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper index 9efb51b..1743e40 100644 --- a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/source-pane.pper @@ -1,3 +1,3 @@ { - "activeTab" : -1 + "activeTab" : 0 } \ No newline at end of file diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper index 0289683..b63d122 100644 --- a/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper +++ b/plotTreeShiny/.Rproj.user/ED8AE702/pcs/windowlayoutstate.pper @@ -2,7 +2,7 @@ "left" : { "panelheight" : 998, "splitterpos" : 420, - "topwindowstate" : "HIDE", + "topwindowstate" : "NORMAL", "windowheight" : 1036 }, "right" : { diff --git a/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/3C7EE37E b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/3C7EE37E new file mode 100644 index 0000000..dcbe4e5 --- /dev/null +++ b/plotTreeShiny/.Rproj.user/ED8AE702/sdb/per/t/3C7EE37E @@ -0,0 +1,17 @@ +{ + "contents" : "library(shiny)\nlibrary(ape)\nlibrary(RLumShiny)\nsource(\"plotTree.R\")\n\n# Please run this application in an external web browser but not in the built-in browser of shiny\n# Files: bin\\app.R and bin\\plotTree.R\n# Use runApp(appDir = \"bin\") to execute this application\n\n#======================== User interface ========================\n\nui <- fluidPage(\n \n #titlePanel(\"Plot tree\"),\n sidebarLayout(\n sidebarPanel(\n tabsetPanel(\n tabPanel(\"Tree\", \n ### UPLOAD TREE\n br(),\n fileInput('tree_file', 'Upload tree file (nwk)', multiple = FALSE,\n accept = c('biotree/newick','.nwk', '.tree')),\n checkboxInput(\"label_tips\", \"Label tree tips?\", value = FALSE),\n conditionalPanel(\n condition = \"input.label_tips\",\n textInput(\"tip_label_size\", label = \"Text size\", value = \"1\"),\n textInput(\"offset\", label = \"Offset\", value = \"0\")\n ), \n textInput(\"tree_line_width\", label = \"Branch width\", value = \"1.5\"),\n jscolorInput(inputId = \"branch_colour\", label = \"Branch colour:\", value = \"#000000\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n br()\n ), # finished tree tab\t\n \n tabPanel(\"Info\", \n ### METADATA (info file)\n br(),\n fileInput('info_file', 'Upload metadata (CSV)'),\n checkboxInput('chk_info', 'Use metadata', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_info\",\n checkboxInput('print_metadata', 'Print columns', value = FALSE),\n conditionalPanel(\n condition = \"input.print_metadata\",\n selectInput('print_column', 'Metadata columns to print:', c(''), multiple=TRUE)\n ),\n \"--------\",\n selectInput('colour_tips_by', 'Colour tips by:', c('')),\n # options if colouring by tips\n conditionalPanel(\n condition = \"input.colour_tips_by != '(none)'\",\n sliderInput(\"tip_size\", label = \"Tip size\", min = 0.1, max = 20, value = 0.5),\n ### COLOUR PANELS\n checkboxInput(\"legend\", \"Legend for node colours?\", value=TRUE),\n selectInput(\"legend_pos\", label = \"Position for legend\", \n choices = list( \"bottomleft\"=\"bottomleft\", \"bottomright\"=\"bottomright\",\n \"top-left\"=\"topleft\", \"topright\"=\"topright\")\n ), \n \"--------\",\n checkboxInput(\"ancestral\", \"Ancestral state reconstruction?\", value=FALSE),\n sliderInput(\"pie_size\", label = \"Pie graph size\", min = 0.1, max = 20, value = 0.5)\n )\n )\n ),\t# finished metadata tab\t\n \n tabPanel(\"Data\", \n ### HEATMAP DATA\n br(),\n fileInput('heatmap_file', 'Upload heatmap file (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_heatmap', 'Plot heatmap', value = FALSE), \n conditionalPanel(\n condition = \"input.chk_heatmap\", h4(\"Heatmap options\"),\n selectInput(\"clustering\", label = h5(\"Clustering:\"), \n choices = list(\"Select...\" = F, \"Cluster columns by values\" = T, \"Square matrix\"=\"square\"),\n selected = \"Select\"), \n \"--------\",\n # OPTIONALLY DISPLAY COLOUR OPTIONS\n checkboxInput(\"heat_colours_prompt\", \"Change heatmap colour ramp\", value = FALSE),\n conditionalPanel(\n condition = \"input.heat_colours_prompt\", \n jscolorInput(inputId = \"start_col\", label = \"Start colour:\", value = \"FFFFFF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"middle_col\", label = \"Middle colour:\", value = \"FFF94D\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n jscolorInput(inputId = \"end_col\", label = \"End colour:\", value = \"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n textInput(\"heatmap_breaks\", label = \"Breaks:\", value = \"100\")\n ),\n #\t\t\t\t\tcheckboxInput(\"heatColoursSpecify\", \"Specify heatmap colours manually\", value=FALSE),\n #\t\t\t\t\tconditionalPanel(\n #\t\t\t\t\t\tcondition = \"input.heatColoursSpecify\",\n #\t\t\t\t\t\ttextInput(\"heatmap_colour_vector\", label = \"R code (vector), e.g. rev(gray(seq(0,1,0.1)))\", value = \"\")\n #\t\t\t\t\t),\n \"--------\",\n textInput(\"heatmap_decimal_places\", label = \"Decimal places to show in heatmap legend:\", value = \"1\"),\n textInput(\"col_label_cex\", label = \"Text size for column labels:\", value = \"0.75\")\n #\t\t\t\t\ttextInput(\"vlines_heatmap\", label = \"y-coordinates for vertical lines (e.g. c(2,5)):\", value = \"\"),\n #\t\t\t\t\tjscolorInput(inputId=\"vlines_heatmap_col\", label=h5(\"Colour for vertical lines:\"), value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ), # finished heatmap options\n \n tabPanel(\"Other\",\n tabsetPanel(\n tabPanel(\"Barplots\",\n br(),\n # bar plots\n fileInput('bar_data_file', 'Upload data for bar plots (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_barplot', 'Plot bar graphs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_barplot\", h5(\"Barplot options\"),\n jscolorInput(inputId = \"bar_data_col\", label = \"Colour for barplots:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n ),\n tabPanel(\"Genome blocks\",\n br(),\n # genome blocks\n fileInput('blocks_file', 'Upload genome block coordinates', multiple = F, accept = c('text/tab', '.txt')),\n checkboxInput('chk_blocks', 'Plot genome blocks', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_blocks\", h5(\"Genome block plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"),\n jscolorInput(inputId = \"blocks_colour\", label = \"Colour for blocks:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T),\n sliderInput(\"blwd\", label = \"Block size\", min = 0.1, max = 20, value = 5)\n )\n ),\n \n tabPanel(\"SNPs\",\n br(),\n # snps\n fileInput('snps_file', 'Upload SNP allele table (CSV)', multiple = F, accept = c('text/csv', '.csv')),\n checkboxInput('chk_snps', 'Plot SNPs', value = FALSE),\n conditionalPanel(\n condition = \"input.chk_snps\", h5(\"SNP plotting options\"),\n textInput(\"genome_size\", label = \"Genome size (bp):\", value = \"5E6\"), # make this linked to previous conditional \n jscolorInput(inputId = \"snps_colour\", label = \"Colour for SNPs:\", value=\"1755FF\", position = \"bottom\", color = \"transparent\", mode = \"HSV\", slider = T, close = T)\n )\n )\n ) #finished tabsetPanels\n ), # finished other data tab\n \n tabPanel(\"Layout\",\n br(),\n h5(\"Relative widths\"),\n textInput(\"tree_width\", label = \"Tree\", value = 10),\n textInput(\"info_width\", label = \"Info columns\", value = 10),\n textInput(\"heatmap_width\", label = \"Heatmap\", value = 30),\n textInput(\"bar_width\", label = \"Bar plots\", value = 10),\n textInput(\"genome_width\", label = \"Genome data (blocks, SNPs)\", value = 10),\n br(),\n h5(\"Relative heights\"),\n textInput(\"main_height\", label = \"Main panels\", value = 100),\n textInput(\"label_height\", label = \"Heatmap labels\", value = 10),\n br(),\n h5(\"Borders\"),\n textInput(\"edge_width\", label = \"Border width/height\", value = 1)\n ),\n \n # Settings and the button for printing\n tabPanel(\"Save\",\n br(), # prints an empty line in the html file that is displayed as the UI\n radioButtons(inputId = \"format\", label = \"Download type:\",\n choices = c(\"PNG\" = \"png\", \"PDF\" = \"pdf\"), selected = \"png\"),\n sliderInput(inputId = \"w\", label = \"width (A4 = 210mm):\", min = 180, max = 1200, value = 210, width = '80%', ticks = FALSE),\n sliderInput(inputId = \"h\", label = \"height (A4 = 297mm):\", min = 180, max = 1200, value = 297, width = '80%', ticks = FALSE),\n textInput(\"file_name\", label = \"File name\", value = \"figure\"), # The default file name is \"figure\".\n downloadButton('downloadButton') # This will generate a new variable 'downloadbutton'\n ) # end of tabPanel \"Save\"\n ), # finish tabsetPanel\n \n ### DRAW BUTTON\n br(),\n actionButton(\"draw_button\", \"Draw!\")\n ), # end of the sidebarPanel\n \n mainPanel(\n plotOutput(\"Tree\", height = 800)\n )\n ) # finished sidebarLayout\n) # end of fluidPage and the ui\n\n#======================== Server =========================\n\nserver <- function(input, output, session) {\n \n # An event observer for changes to INFO CSV file\n observeEvent(input$info_file, \n {\n # read the CSV file and get the column names.\n # re-reading this file repeatedly is inefficient\n df <- read.table(input$info_file$datapath, header = TRUE, sep = ',')\n \n # build a list of values, this is what is required by update methods\n info_cols <- list()\n for (v in colnames(df)) {\n info_cols[v] <- v\n }\n # update the two input widgets using the column names\n \n updateSelectInput(session, inputId = 'colour_tips_by', choices=c('(none)',info_cols[-1]))\n updateSelectInput(session, inputId = 'print_column', choices=c(info_cols[-1]))\n \n # switch on the meta data plotting option\n updateCheckboxInput(session, inputId = 'info_data', value=TRUE)\n }) # end of observeEvent\n\n # An event observer for changes to HEATMAP file\n observeEvent(input$heatmap_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_heatmap', value=TRUE)\n })\t\n \n # An event observer for changes to BAR DATA file\n observeEvent(input$bar_data_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_barplot', value=TRUE)\n })\t\n \n # An event observer for changes to BLOCKS file\n observeEvent(input$blocks_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_blocks', value=TRUE)\n })\t\n \n # An event observer for changes to SNPs file\n observeEvent(input$snps_file, \n {\n # switch on the heatmap plotting option\n updateCheckboxInput(session, inputId = 'chk_snps', value=TRUE)\n })\n \n ### PLOT THE TREE: defines the main plotting function which will be called by downloadHandler() as well\n doPlotTree <-function() {\n ### ALL VARIABLES PULLED FROM 'input' GO INSIDE HERE\n isolate ({\n \n l <- input$Layout\n t <- input$Tree\n i <- input$Info\n o <- input$Other\n d <- input$Data\n \n tree_file <- input$tree_file$datapath\n \n # tree plotting options\n label_tips <- input$label_tips\n tree_line_width <- as.integer(input$tree_line_width)\n branch_colour <- input$branch_colour\n tip_label_size <- as.integer(input$tip_label_size)\n offset <- as.integer(input$offset)\n \n # metadata variables\n info_file <- input$info_file$datapath\n tip_size <- input$tip_size\n colour_tips_by <- input$colour_tips_by\n if (colour_tips_by == '(none)') {colour_tips_by <- NULL}\n ancestral <- input$ancestral\n pie_size <- input$pie_size\n legend <- input$legend\n legend_pos <- input$legend_pos\n print_column <- input$print_column\n print_metadata <- input$print_metadata\n if (!print_metadata) { print_column <- NA }\n \n # heatmap variables\n heatmap_file <- input$heatmap_file$datapath\n cluster <- input$clustering\n heatmap_decimal_places <- as.integer(input$heatmap_decimal_places)\n col_label_cex <- as.integer(input$col_label_cex)\n vlines_heatmap_col <-input$vlines_heatmap_col\n vlines_heatmap <- input$vlines_heatmap\n \n # \theatColoursSpecify <- input$heatColoursSpecify\n \n #\t\t\tif (heatColoursSpecify) {\n #\t\t\t\theatmap_colours <- input$heatmap_colour_vector\n #\t\t\t}\n #\t\t\telse {\n heatmap_colours <- colorRampPalette(c(input$start_col,input$middle_col,input$end_col),space=\"rgb\")(as.integer(input$heatmap_breaks))\n #\t\t\t}\n \n # barplot variables\n bar_data_file <- input$bar_data_file$datapath\n bar_data_col <- input$bar_data_col\n \n # block plot variables\n blocks_file <- input$blocks_file$datapath\n blocks_colour <- input$blocks_colour\n blwd <- input$blwd\n genome_size <- input$genome_size\n \n snps_file <- input$snps_file$datapath\n snps_colour <- input$snps_colour\n \n # Layout/spacing\n tree_width <- as.numeric(input$tree_width)\n info_width <- as.numeric(input$info_width)\n heatmap_width <- as.numeric(input$heatmap_width)\n bar_width <- as.numeric(input$bar_width)\n genome_width <- as.numeric(input$genome_width)\n main_height <- as.numeric(input$main_height)\n label_height <- as.numeric(input$label_height)\n edge_width <- as.numeric(input$edge_width)\n \n # TRACK DATA TYPES TO PLOT\n chk_heatmap <- input$chk_heatmap\n chk_info <- input$chk_info\n chk_barplot <- input$chk_barplot\n chk_blocks <- input$chk_blocks\n chk_snps <- input$chk_snps\n \n if (is.null(tree_file)) { return(NULL) }\n \n if (!chk_info) { info_file <- NULL } \n else { info_file <- info_file }\n \n if (!chk_heatmap) { heatmap_file <- NULL } \n else { heatmap_file <- heatmap_file }\n \n if (!chk_barplot) { bar_data_file <- NULL } \n else { bar_data_file <- bar_data_file }\n \n if (!chk_blocks) { blocks_file <- NULL } \n else { blocks_file <- blocks_file }\n \n if (!chk_snps) { snps_file <- NULL } \n else { snps_file <- snps_file } \n \n }) # end isolate\n \n # underlying call to plotTree(), drawn to screen and to file\n plotTree(tree = tree_file, \n tip.labels = label_tips, tipLabelSize = tip_label_size, offset = offset,\n lwd = tree_line_width, edge.color = branch_colour,\n infoFile = info_file, infoCols = print_column, \n colourNodesBy = colour_tips_by, tip.colour.cex = tip_size, \n ancestral.reconstruction = ancestral, pie.cex = pie_size, \n legend = legend, legend.pos = legend_pos,\n heatmapData = heatmap_file, cluster = cluster,\n heatmap.colours = heatmap_colours,\n heatmapDecimalPlaces = heatmap_decimal_places, colLabelCex = col_label_cex,\n vlines.heatmap = vlines_heatmap, vlines.heatmap.col = vlines_heatmap_col,\n barData = bar_data_file, barDataCol = bar_data_col,\n blockFile = blocks_file, block_colour = blocks_colour, blwd = blwd,\n genome_size = genome_size,\n snpFile = snps_file, snp_colour = snps_colour,\n treeWidth = tree_width, infoWidth = info_width, dataWidth = heatmap_width,\n barDataWidth = bar_width, blockPlotWidth = genome_width, \n mainHeight = main_height, labelHeight = label_height, edgeWidth = edge_width\n ) \n }\n \n output$Tree <- renderPlot({\n input$draw_button # do not need to reset the draw_button value which increases by every click\n doPlotTree()\n }) # end render plot\n \n # downloads a high-definition plot of the input data\n # This function is called when the download button is clicked\n output$downloadButton <- downloadHandler(\n \n filename = function() {\n # This is the default file name displayed in the download box poped up after clicking the download button.\n # You can change the filename in the download box.\n f <- input$file_name\n if(input$format == \"pdf\"){\n return(paste(f, \".pdf\", sep = \"\"))\n } else {\n return(paste(f, \".png\", sep = \"\"))\n }\n },\n \n content = function(tmp) {\n # tmp: the file name of a non-existent temp file.\n if(input$format == \"pdf\"){\n MM2Inch <- 0.03937 # convert to millimetres to inches because the unit for pdf(..) is inch.\n pdf(tmp, width = as.numeric(input$w) * MM2Inch, height = as.numeric(input$w) * MM2Inch, paper = \"special\") \n # \"special\": the paper size is specified by the width and height; a4r: landscape orientation\n doPlotTree() # redraw the plot\n dev.off()\n } else {\n png(tmp, width = as.numeric(input$w), height = as.numeric(input$w), units = \"mm\", res = 72)\n # res: the resolution is set to 72 ppi\n doPlotTree() # redraw the plot\n dev.off()\n }\n }\n )\n} # end of the function server(..)\n\n#======================== Executes the whole script =========================\n\nshinyApp(ui = ui, server = server)", + "created" : 1442378666405.000, + "dirty" : false, + "encoding" : "UTF-8", + "folds" : "", + "hash" : "4000526187", + "id" : "3C7EE37E", + "lastKnownWriteTime" : 1435447656, + "path" : "G:/01_Research/Scripts/plotTree/plotTreeShiny/app.R", + "project_path" : "app.R", + "properties" : { + }, + "relative_order" : 1, + "source_on_save" : false, + "type" : "r_source" +} \ No newline at end of file