From 3037d6e3ef393a2289a7207848c7d59f61fccede Mon Sep 17 00:00:00 2001 From: Tanushree Tunstall Date: Mon, 5 Sep 2022 16:05:36 +0100 Subject: [PATCH] msa dashboard --- drug-target/global.R | 341 +++++++++++++++++++++++++++++++++++++++++++ index.html | 1 + msa/.global.R.swp | Bin 0 -> 16384 bytes msa/global.R | 301 ++++++++++++++++++++++++++++++++++++++ msa/server.R | 0 msa/ui.R | 0 6 files changed, 643 insertions(+) create mode 100644 msa/.global.R.swp create mode 100644 msa/global.R create mode 100644 msa/server.R create mode 100644 msa/ui.R diff --git a/drug-target/global.R b/drug-target/global.R index 437d523..ea08946 100644 --- a/drug-target/global.R +++ b/drug-target/global.R @@ -316,3 +316,344 @@ consurf_colours = c( , "9" = rgb(0.63,0.16,0.37) ) +if (interactive()){ + options(shiny.launch.browser = FALSE) # i am a big girl and can tie my own laces + options(shiny.port = 8000) # don't change the port every time + options(shiny.host = '0.0.0.0') # This means "listen to all addresses on all interfaces" + options(width=120) + options(DT.options = list(scrollX = TRUE)) + + ui=dashboardPage(skin="purple", + dashboardHeader(title = "Drug/Target Explorer"), + + dashboardSidebar( + sidebarMenu( id = "sidebar", + selectInput( + "switch_target", + label="Switch to New Target", + choices = c( + "alr", + "embb", + "gid", + "katg", + "pnca", + "rpob" + ), + selected="embb"), + menuItem("LogoP SNP", tabName="LogoP SNP"), + menuItem("Lineage Sample Count", tabName="Lineage Sample Count"), + menuItem("Site SNP count", tabName="Site SNP count"), + menuItem("Stability SNP by site", tabName="Stability SNP by site"), + menuItem("DM OM Plots", tabName="DM OM Plots"), + menuItem("Correlation", tabName="Correlation"), + menuItem("Lineage Distribution", tabName="Lineage Distribution"), + menuItem("Consurf", tabName="Consurf"), + menuItem("LogoP OR", tabName="LogoP OR"), + menuItem("LogoP ED", tabName="LogoP ED"), + menuItem('Stability count', tabName='Stability count'), + + # These conditionalPanel()s make extra settings appear in the sidebar when needed + conditionalPanel( + condition="input.sidebar == 'LogoP SNP'", + textInput( + "omit_snp_count", + "Omit SNPs", + value = c(0), + placeholder = "1,3,6" + ) + ), + # NOTE: + # I *think* we can cheat here slightly and use the min/max from + # merged_df3[['position']] for everything because the various + # dataframes for a given gene/drug combination have the + # same range of positions. May need fixing, especially + # if we get/shrink the imported data files to something + # more reasonable. + conditionalPanel( + condition=" + input.sidebar == 'LogoP SNP'|| + input.sidebar == 'Stability SNP by site' || + input.sidebar == 'Consurf' || + input.sidebar == 'LogoP OR' || + input.sidebar == 'Site SNP count'", + sliderInput( + "display_position_range" + , "Display Positions" + , min=1, max=150, value=c(1,150) # 150 is just a little less than the smallest pos_count + ) + ), + conditionalPanel( + condition="input.sidebar == 'LogoP ED'", + sliderInput( + "display_position_full_range" + , "Display Positions" + , min=1, max=150, value=c(1,150) + ) + ), + + + conditionalPanel( + condition=" + input.sidebar == 'LogoP SNP' || + input.sidebar == 'LogoP OR' || + input.sidebar == 'LogoP ED'", + selectInput( + "logoplot_colour_scheme", + label="Logo Plot Colour Scheme", + choices = logoPlotSchemes, + selected="chemistry" + ) + ), + #conditionalPanel( + # condition="input.sidebar == 'LogoP SNP' || input.sidebar == 'LogoP ED'|| input.sidebar == 'Consurf'", + # numericInput( + # "table_position" + # , "Table Position", value=1 + # ) + #), + conditionalPanel( + condition="input.sidebar == 'Correlation'", + selectInput( + "corr_method", + label="Correlation Method", + choices = list("spearman", + "pearson", + "kendall"), + selected="spearman" + ) + ), + conditionalPanel( + condition="input.sidebar == 'Correlation'", + numericInput( + "corr_lig_dist" + , "Ligand Distance Cutoff (Å)", value=1 + ) + ), + + conditionalPanel( + condition="input.sidebar == 'Correlation'", + checkboxGroupInput( + "corr_selected", + "Parameters", + choiceNames = c( + "DeepDDG", + "Dynamut2", + "FoldX", + "ConSurf"#, + #"dst_mode" + ), + choiceValues = c( + "DeepDDG", + "Dynamut2", + "FoldX", + "ConSurf"#, + #"dst_mode" + ), + selected = c( + "DeepDDG", + "Dynamut2", + "FoldX", + "ConSurf"#, + #"dst_mode" + ) + ) + ), + + conditionalPanel( + condition="input.sidebar == 'DM OM Plots'", + selectInput( + "dm_om_param", + label="Stability Parameter", + choices = keys(dm_om_map), + selected="SNAP2") + ), + # colour_categ + conditionalPanel( + condition="input.sidebar == 'Stability SNP by site'", + selectInput( + "stability_snp_param", + label="Stability Parameter", + choices = stability_boxes_df$stability_type, + selected="Average") + ), + conditionalPanel( + condition="input.sidebar == 'Stability SNP by site'", + checkboxInput("reorder_custom_h", + label="Reorder by SNP count", + FALSE) + ), + conditionalPanel( + condition="input.sidebar.match(/^Lineage.*/)", + checkboxInput("all_lineages", + label="All Lineages", + FALSE) + ), + # an example of how you can match multiple things in frontend JS + conditionalPanel( + condition="input.sidebar == 'LogoP SNP' || + input.sidebar =='Stability SNP by site' || + input.sidebar =='Consurf' || + input.sidebar =='LogoP OR' || + input.sidebar =='LogoP ED'", + actionButton("clear_ngl", + "Clear Structure") + ), + conditionalPanel( + condition="input.sidebar == 'LogoP SNP' || + input.sidebar =='Stability SNP by site' || + input.sidebar =='Consurf' || + input.sidebar =='LogoP OR' || + input.sidebar =='LogoP ED'", + actionButton("test_ngl", + "Test NGLViewR") + )#, + + # downloadButton("save", + # "Download Plot" + # ) + # actionButton( + # "reload_target", + # label="Reload Target\nData (slow!)" + # ) + + ) + ), + body <- dashboardBody( + + tabItems( + tabItem(tabName = "dashboard", + h2("Dashboard tab content") + ), + + tabItem(tabName = "widgets", + h2("Widgets tab content") + ) + ), + # creates a 'Conditional Panel' containing a plot object from each of our + # ggplot plot functions (and its associated data frame) + fluidRow(column(width=12, + lapply(plot_functions_df$tab_name, + function(x){ + + plot_function=plot_functions_df[ + plot_functions_df$tab_name==x, + "plot_function"] + + plot_df=plot_functions_df[ + plot_functions_df$tab_name==x, + "plot_df"] + cat(paste0('\nCreating output: ', x)) + generate_conditionalPanel(x, plot_function, plot_df) + + } + ) + ) + ), + #### fluidRow()s for "Stability Count" in the sidebar #### + fluidRow( + conditionalPanel( + condition=" + input.sidebar == 'LogoP SNP' || + input.sidebar =='Stability SNP by site' || + input.sidebar =='Consurf' || + input.sidebar =='LogoP OR' || + input.sidebar =='LogoP ED'", + column(NGLVieweROutput("structure"), + width=3 + ) + ), + conditionalPanel( + condition=" + input.sidebar == 'LogoP SNP' || + input.sidebar == 'Stability SNP by site' || + input.sidebar == 'Site SNP count' || + input.sidebar == 'Consurf' || + input.sidebar == 'LogoP OR' || + input.sidebar == 'LogoP ED'", + column( + DT::dataTableOutput('table'), + width=9 + ) + ) + ) + ) + ) + + server = function(input, output) { + observeEvent({ + input$combined_model + input$combined_data + input$combined_training_genes + input$score_dropdown + input$resample_dropdown + input$drug_dropdown + input$split_dropdown + + },{ + combined_model = input$combined_model + selection = input$score_dropdown + resampler = input$resample_dropdown + selected_drug = input$drug_dropdown + selected_split = input$split_dropdown + combined_data = input$combined_data + combined_training_genes = input$combined_training_genes + + selected_gene = combo[combo$drug == selected_drug,'gene'] + + # hide stuff if selected + if(combined_model == "combined") { + #if(combined_model == TRUE) { + + hide("split_dropdown") + hide("resample_dropdown") + show("combined_data") + show("combined_training_genes") + filedata = paste0(combined_training_genes, + 'genes_logo_skf_BT_', + selected_gene, + '_', + combined_data + ) + print(filedata) + + print('doing COMBINED plot') + output$plot <- renderPlot(makeplot(loaded_files[[filedata]], + selection, + "none", # always 'none' for combined plot + gene = combo[drug==selected_drug,"gene"], + combined_training_genes = combined_training_genes, + display_combined = TRUE, + ) + ) + # e.g. + # makeplot(loaded_files$`5genes_logo_skf_BT_pnca_actual`, "MCC", "none" , gene = 'foo', combined_training_genes = '1234', display_combined = TRUE) + } else { + show("split_dropdown") + show("resample_dropdown") + hide("combined_data") + hide("combined_training_genes") + filedata = paste0(combo[drug==selected_drug,"gene"], + '_baselineC_', + selected_split + ) + print(filedata) + print("doing GENE plot") + output$plot <- renderPlot(makeplot(loaded_files[[filedata]], + selection, + resampler, + gene = combo[drug==selected_drug,"gene"], + display_combined = FALSE, + ) + ) + + + } + # 6genes_logo_skf_BT_gid_complete + + # filedata example for combined: 6genes_logo_skf_BT_embb_actual + # 6genes_logo_skf_BT_embb_combined + }) + } + app <- shinyApp(ui, server) + runApp(app) +} \ No newline at end of file diff --git a/index.html b/index.html index 7beb795..f52a41c 100644 --- a/index.html +++ b/index.html @@ -98,6 +98,7 @@

Drug/Gene Target explorer

ML/AI model explorer

+

Multiple Sequence Alignment explorer

diff --git a/msa/.global.R.swp b/msa/.global.R.swp new file mode 100644 index 0000000000000000000000000000000000000000..ae9e8879f79391105bfdea6961d738a231b74d85 GIT binary patch literal 16384 zcmeHNU5wmT6~2%r{53SRC{G|R9@?F$X1z1B+23lB3fWDfOcIoAqM|6WJocR#vmV>{ zdiF0;v^6zzd>zrtnZCkdP`N5K;kEJU|5^tw1OsA%0%?m&$jpukFd~&ZMY| z5W-GA@7#0FJ@?%2o_lRyyVJOK?gC#nTMWku#@>12q;q~{gT4HocQ7fEenj%S9KG0% z`XUhKaLY`FflO@QH@#qAt&b^(b3HGaJ8jE;C$wW%&JCnJ*Ym@U?VFePRVf7}10@58 z!N4%-&MqInI^SwG$X&&FFMr_vtB2va^ieWUGEg#5GEg#5GEg#5GEg#5GVnjbKoT8c zA4jZj)bU=|f8Q|n_f>t|)bbl+`XjnLo5{6<%#RkAe@X^Q21*7>21*7>21*7>21*7> z21*7>21*7>2L1~S*e+vd(e8`%ppN(d+4KMH`xyH<@O|K0z&C-XfQNtz@Wk60`{{AU zW`WP%%h;dZ#@KD(72wCf^T5}EF9V+eo&W;i25=r&0v-bH2cCH=W1j+S;5cv;c=|1j zMZkIBFK=e-55RAMUjx4ao&!DyJPw=&e)lHEUIM-fd=dCO&;s5C{P7rLzW{y)JPUjQ zSOu1WCE(q_caI`QU+B0xw8J+_fDcjXa{X`6!IZ@p7Yq$S|gib0^%1{4iNvrL)zGJ-6z6f#rn5 zAh9};<$Bv9mR_<~-RWA}c3h_>ESLzpCuE(Qrdg|lj-pD{pJ-S^gQ*)t(Gy8EveA=9 zb+>MiOKYcVfJM$z4+q=$%7(0^v(^QjG&=BbM_j17k;e8otMH9;k6l<_rvhOm|(~seE)-d$4mNGA}LJ&KG%J)@l_63^2NK_T%AJ*2=weJ8*f{QKAgh2OTf4 zi84lu2ycgu?eh(tg;FgvY5I7`V4G6*j6*762+M2qfRO3M%u{6i)gI#8EY7LT~D|cnwlX~{LdSM zto6QYO^E0h8jFSPnvUGAB6&PtSY1q0yUzO%r>houNFx}vAn9lsp0cc&lkxVPT7+h? z@L@^OU%Dms9MZszhdm_2oXRZ{B$x#|m<<#?NHAJfw`Hm*RCcA27UVVa=$i*bk4{aE z9r}^TQTn&z4%Ny)fg{n0G0GOAI`w;psBk{sNvc4s8#Njo;sldbCC$K&u3slEZrosg zXsc1Q((eL`B~Woi`5uMQ(8tWt=`brJ;b8C`{_toPa4hCBU+FlfHII($FAe2b3hRYE z&kmHc&Q8cwteqR@+M8#Ya?QOiuTl+D>|z2)x>Dp0FjZ5dw3RG>QwER%7UV{Kml&mE zq-thr9GqkqJn5vVXSvyzm2L6z&Z6)t2iX&u<)W|IkgACQmI2jn~eEr?ciu^tLwJ+!O0ydI{`aY#ztdi3gxoP>Q-5Rs$-A|fw6Xw!uj*jk-4nI1- z`}(7E!Z^0vt~Hpq4n4+E->*N?fxyD+BG%Snb6I#k#3<+gV^PlEElQ-N42Q8JvYYt{ z%W(V3+06@B%|F>#o;R*Lro0!wPR+#@#>GM!LeOyYqB*&`ldmIW4N`)i0In z3!p5nfTq59fKLEj;4JVka4+zC#QP%fBjASs z#s30O9wh@M10@3`10@3`10@3`1OHD9(9Q|&vR4e+BI|Xk4Rdk6-Y}bsIL$9NixAZ4ArAnp>3&f>9n+ z1lU@mR|0efj}!fB{luuWeqx`rej+1UKao$ZpEw#?KXELzeqttQ{lq*X{S;~|^gKsf zIvKfEd;QvaJEge7UEyFSO}(e_#kTP2rI(c47uYqz;~4qge`INGxOTi1#!laJPw7`D z2O6us8JQv5Z$lC|RUB!%d1JDj;u>!`di?~iakiRMOx3U%3Et-6Wz006YW!7)Bwn?} zLIkZTZdEoJkqw^6bXo)|F^$aWv=CH^8+bt?WTM;}`NW`>l0?wU0!)o`A{l$a$F@Df wJea9`l(xMPwPWF8b7i7wIz|IK4#QwV$MX@2{NZ2{J1|OzM{_>KZhUP11r53?(f|Me literal 0 HcmV?d00001 diff --git a/msa/global.R b/msa/global.R new file mode 100644 index 0000000..92e2cc4 --- /dev/null +++ b/msa/global.R @@ -0,0 +1,301 @@ +library(shinycssloaders) +library(DT) +library(NGLVieweR) +library(hash) + +load_target_globals=function(target){ + cat(paste0("Reloading Target: ", target)) + source(paste0("/srv/shiny-server/git/LSHTM_analysis/config/", target, ".R")) # load per-target config file + + invisible(assign(paste0(target, "_merged_df3"), read.csv(paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/",target,"-merged_df3.csv")), envir = .GlobalEnv)) + invisible(assign(paste0(target, "_merged_df2"), read.csv(paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/",target,"-merged_df2.csv")), envir = .GlobalEnv)) + invisible(assign(paste0(target, "_corr_df_m3_f"), read.csv(paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/",target,"-corr_df_m3_f.csv")), envir = .GlobalEnv)) + invisible(assign(paste0(target, "_lin_lf"), read.csv(paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/",target,"-lin_lf.csv")), envir = .GlobalEnv)) + invisible(assign(paste0(target, "_lin_wf"), read.csv(paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/",target,"-lin_wf.csv")), envir = .GlobalEnv)) + lapply( + c( + "duet", + "mcsm_lig", + "foldx", + "deepddg", + "dynamut2", + "consurf", + "snap2", + "provean", + "dist_gen", + "mcsm_ppi2"#, + #"mcsm_na" + ), function(x){ + wf_filename=paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/", tolower(gene), "-wf_", x ,".csv") + wf_var=paste0("wf_",x) + if (file.exists(wf_filename)){ + invisible(assign(wf_var,read.csv(wf_filename), envir = .GlobalEnv)) # FILTH + } + lf_filename=paste0("/srv/shiny-server/git/Misc/shiny_dashboard/data/", tolower(gene), "-lf_", x ,".csv") + lf_var=paste0(target, "_lf_",x) + if (file.exists(lf_filename)){ + invisible(assign(lf_var,read.csv(lf_filename), envir = .GlobalEnv)) # FILTH + } + } + ) +} +# populate target-specific *_unified_msa vars +load_msa_global=function(gene){ + drug=target_map[[gene]] + in_filename_msa = paste0(tolower(gene), "_msa.csv") + infile_msa = paste0("/srv/shiny-server/git/Data/", drug, "/output/", in_filename_msa) + print(infile_msa) + msa1 = read.csv(infile_msa, header = F) + msa_seq = msa1$V1 + + infile_fasta = paste0("/srv/shiny-server/git/Data/", drug, "/input/", tolower(gene), "2_f2.fasta") + print(infile_fasta) + msa2 = read.csv(infile_fasta, header = F) + wt_seq = msa2$V1 + + target_name=paste0(gene, '_unified_msa') + #print(target_name) + invisible(assign(target_name, list(msa_seq = msa_seq, wt_seq = wt_seq), envir = .GlobalEnv)) +} + +#### Local Functions #### +# Generate a conditionalPanel() for a given graph function and sidebar name combination +generate_conditionalPanel = function(tab_name, plot_function, plot_df){ + # e.g.: list("lin_count_bp_diversity", "Lineage diversity count") + cond=paste0("input.sidebar == '", tab_name, "'") + conditionalPanel(condition=cond, box( + title=tab_name + , status = "info" + , width=NULL + , plotOutput(plot_function + , click = "plot_click") %>% withSpinner(color="#0dc5c1") + # , plotOutput(plot_function, click = "plot_click") + ) + ) +} + +# FIXME: passing in the per-plot params is broken +lin_sc=function(x, all_lineages = F, ...){ + lf_var = get(paste0(x,"_lin_lf")) + wf_var = get(paste0(x,"_lin_wf")) + cowplot::plot_grid(lin_count_bp_diversity(wf_var, all_lineages, ...), lin_count_bp(lf_var, all_lineages, ...)) +} + + +options(shiny.port = 8000) +options(shiny.host = '0.0.0.0') # This means "listen to all addresses on all interfaces" +options(shiny.launch.browser = FALSE) +options(width=120) +options(DT.options = list(scrollX = TRUE)) + + +################ STATIC GLOBALS ONLY ############## +# never quite sure where "outdir" gets set :-| + +# using dataframes instead of lists lets us avoid use of map() +plot_functions_df=data.frame( + tab_name=c( + "LogoP SNP", + "Lineage Sample Count", + "Site SNP count", + "Stability SNP by site", + "DM OM Plots", + "Correlation", + "Lineage Distribution", + "Consurf", + "LogoP OR", + "LogoP ED" + ), + plot_function=c( + "LogoPlotSnps", + "lin_sc", + "site_snp_count_bp", + "bp_stability_hmap", + "lf_bp2", + "my_corr_pairs", + "lineage_distP", + "wideP_consurf3", + "LogoPlotCustomH", + "LogoPlotMSA" + ), + plot_df=c( + "mutable_df3" , + "lin_lf", + "mutable_df3", + "merged_df3" , + "lf_duet" , + "corr_df_m3_f", + "merged_df2", + "merged_df3", + "merged_df2", + "unified_msa" + ) +) + +stability_boxes_df=data.frame( + outcome_colname=c("duet_outcome", + "foldx_outcome", + "deepddg_outcome", + "ddg_dynamut2_outcome", + "mcsm_na_outcome", + "mcsm_ppi2_outcome", + "snap2_outcome", + "consurf_outcome", + "avg_stability_outcome"), + stability_type=c( + "DUET", + "FoldX", + "DeepDDG", + "Dynamut2", + "mCSM-NA", + "mCSM-ppi2", + "SNAP2", + "Consurf", + "Average" + ), + stability_colname=c( + "duet_scaled", + "foldx_scaled", + "deepddg_scaled", + "ddg_dynamut2_scaled", + "mcsm_na_scaled", + "mcsm_ppi2_scaled", + "snap2_scaled", + "consurf_scaled", + "avg_stability_scaled" + ) +) + +table_columns = c( + "position", + "mutationinformation", + "sensitivity", + "ligand_distance", + "avg_lig_affinity", + "avg_lig_affinity_outcome", + "avg_stability", + "avg_stability_outcome", + "or_mychisq", + "maf", + "snap2_outcome", + "consurf_outcome", + "provean_outcome", + "rsa", + "kd_values" , + "rd_values" +) + +logoPlotSchemes <- list("chemistry" + , "taylor" + , "hydrophobicity" + , "clustalx") +dm_om_methods = c("DUET ΔΔG" + , "Consurf" + , "Deepddg ΔΔG" + , "Dynamut2 ΔΔG" + , "FoldX ΔΔG" + , "Ligand affinity (log fold change)" + , "mCSM-NA affinity ΔΔG" + , "SNAP2") +dm_om_map = hash(c( + "DUET ΔΔG" + , "Consurf" + , "Deepddg ΔΔG" + , "Dynamut2 ΔΔG" + , "FoldX ΔΔG" + , "Ligand affinity (log fold change)" + , "mCSM-NA affinity ΔΔG" + , "SNAP2" +), c( + "lf_duet" + ,"lf_consurf" + ,"lf_deepddg" + ,"lf_dynamut2" + ,"lf_foldx" + ,"lf_mcsm_lig" + ,"lf_mcsm_na" + ,"lf_snap2" +) +) +#### target_map: handy gene/drug mapping hash #### +target_map = hash( + c( + "alr", + "gid", + "embb", + "pnca", + "rpob", + "katg"), + c( + "cycloserine", + "streptomycin", + "ethambutol", + "pyrazinamide", + "rifampicin", + "isoniazid") +) + +# load E V E R Y T H I N G +lapply(c( + "alr", + "embb", + "gid", + "katg", + "pnca", + "rpob" +),function(x){ + invisible(load_target_globals(x)) + invisible(load_msa_global(x)) # turn off to speed up start time at the expense of "LogoP ED" +} +) + +consurf_palette1 = c("0" = "yellow2" + , "1" = "cyan1" + , "2" = "steelblue2" + , "3" = "cadetblue2" + , "4" = "paleturquoise2" + , "5" = "thistle3" + , "6" = "thistle2" + , "7" = "plum2" + , "8" = "maroon" + , "9" = "violetred2") + +consurf_palette2 = c("0" = "yellow2" + , "1" = "forestgreen" + , "2" = "seagreen3" + , "3" = "palegreen1" + , "4" = "darkseagreen2" + , "5" = "thistle3" + , "6" = "lightpink1" + , "7" = "orchid3" + , "8" = "orchid4" + , "9" = "darkorchid4") + +# decreasing levels mess legend +# consurf_colours_LEVEL = c( +# "0" = rgb(1.00,1.00,0.59) +# , "9" = rgb(0.63,0.16,0.37) +# , "8" = rgb(0.94,0.49,0.67) +# , "7" = rgb(0.98,0.78,0.86) +# , "6" = rgb(0.98,0.92,0.96) +# , "5" = rgb(1.00,1.00,1.00) +# , "4" = rgb(0.84,0.94,0.94) +# , "3" = rgb(0.65,0.86,0.90) +# , "2" = rgb(0.29,0.69,0.75) +# , "1" = rgb(0.04,0.49,0.51) +# ) + +consurf_colours = c( + "0" = rgb(1.00,1.00,0.59) + , "1" = rgb(0.04,0.49,0.51) + , "2" = rgb(0.29,0.69,0.75) + , "3" = rgb(0.65,0.86,0.90) + , "4" = rgb(0.84,0.94,0.94) + , "5" = rgb(1.00,1.00,1.00) + , "6" = rgb(0.98,0.92,0.96) + , "7" = rgb(0.98,0.78,0.86) + , "8" = rgb(0.94,0.49,0.67) + , "9" = rgb(0.63,0.16,0.37) +) + + diff --git a/msa/server.R b/msa/server.R new file mode 100644 index 0000000..e69de29 diff --git a/msa/ui.R b/msa/ui.R new file mode 100644 index 0000000..e69de29