class: middle, inverse, title-slide .title[ # Introduction to Shiny, Session 1 ] .subtitle[ ##
Bioinformatics Resource Center - Rockefeller University ] .author[ ###
http://rockefelleruniversity.github.io/RU_course_template/
] .author[ ###
brc@rockefeller.edu
] --- class: inverse, center, middle # Set Up <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Materials All prerequisites, links to material and slides for this course can be found on github. * [RU_shiny](https://rockefelleruniversity.github.io/RU_shiny/) Or can be downloaded as a zip archive from here. * [Download zip](https://github.com/rockefelleruniversity/RU_shiny/zipball/master) --- ## Course materials Once the zip file in unarchived. All presentations as HTML slides and pages, their R code and HTML practical sheets will be available in the directories underneath. * **r_course/presentations/slides/** Presentations as an HTML slide show. * **r_course/presentations/singlepage/** Presentations as an HTML single page. * **r_course/presentations/r_code/** R code in presentations. * **r_course/exercises/** Practicals as HTML pages. * **r_course/answers/** Practicals with answers as HTML pages and R code solutions. --- ## Set the Working directory Before running any of the code in the practicals or slides we need to set the working directory to the folder we unarchived. You may navigate to the unarchived RU_Course_help folder in the Rstudio menu. **Session -> Set Working Directory -> Choose Directory** or in the console. ``` r setwd("/PathToMyDownload/RU_shiny-master/r_course") # e.g. setwd("~/Downloads/RU_shiny-master/r_course") ``` --- ## Course outline - Session 1 - + Shiny basics + app layouts + app theming - Session 2 - + Input types + basic reactivity + interactive plots + downloading files from apps - Session 3 - + uploading files and conditional UIs + observers + publishing apps + basic debugging --- ## What is Shiny? Why do we use it? Shiny allows us to **make powerful web applications** with only R code, **without the need to learn HTML, JavaScript, or CSS**. Deeper knowledge of these other languages can certianly be used with Shiny to improve your apps, but its not necessary. This allows us to use the analytical tools that are the strengths or R, like statistics and visualization, when making these apps and dashboards. There are many use cases that depend on the developer's needs, but Shiny apps can be really useful in transforming common code workflows into user friendly dashboards or displaying and interacting with databases. While Shiny was developed in R, and this is what we will cover in this course, there is now support for Shiny in Python (since 2023). While Shiny for Python is not as far along as for R (fewer community driven tools available), this will likely change in the future. --- ## Basic components of Shiny app A shiny app consists of the user interface (UI) and the server function - the UI object defines what will be seen on the page - the server function contains code that combines R code with inputs (eg info from user, databases, or files) and provides instructions for generating outputs - the Shiny R package builds the shiny app from the the UI object and server function <img src="imgs/shiny_ui_server.png"height="300" width="800"> Neth, H. (2025) *Introduction to Data Science* (https://bookdown.org/hneth/i2ds/) --- ## Shiny - how to get started A Shiny app is generally contained within one R script to define the UI object and the server function. ``` r library(shiny) library(bslib) ui = page_fluid( textOutput(outputId = "app_info") ) server = function(input, output) { output$app_info = renderText("Our first app!") } shinyApp(ui = ui, server = server) ``` <img src="imgs/first_app.png"height="400" width="500"> --- ## Shiny - how to get started When you run the *shinyApp* function, your RStudio console will be busy and you'll see a message with a URL. This is the port within your computer that the app is running. <img src="imgs/listening_app.png"height="100" width="400"> A window should pop up automatically showing the app. You can also copy and paste this address into a browser to open an instance of the app. To close the app and free up the console, you can: - click on the console to hit the *ESC* button or Ctrl+C - click on the *Stop* button on the top right corner of the console --- ## Shiny - how to get started Shiny is well integrated into R Studio and there are a few additional features that make running apps easier. If you open a blank R script and add the shiny template code (see previous slide), once you save the file you should see a button in the upper right corner of the script that says *Run App*. This will automatically launch the app. <img src="imgs/runApp_button_pp.png"height="200" width="800"> --- ## Shiny - how to get started Pretty much any Shiny app will start with the code below. Just paste this code into a fresh R script to get started. TIP: Open a new R script, type *shinyapp*, then hit Shift+Tab, and the template will appear. Boiler plate Shiny app code: ``` r library(shiny) ui <- page_fluid() server <- function(input, output, session) { } shinyApp(ui, server) ``` --- ## Shiny - how to get started How that app is launched (e.g. in browser or a window within RStudio) can be changed by the dropdown that is part of the *Run App* button <img src="imgs/runApp_dropdown.png"height="200" width="800"> --- ## Shiny - how to get started .pull-left[ You can also start a new app by opening a new file in R Studio and selecting the *Shiny Web App* option. The *Application name* you enter will be the name of a newly created directory that contains the app.R file and your Shiny app. ] .pull-right[ <img src="imgs/shiny_file_dropdown.png"height="400" width="350"> ] --- ## Shiny basics .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) ui = page_fluid( textOutput(outputId = "app_info"), br(), tags$b("Bold text in UI object"), br(), tableOutput(outputId = "table_in") ) server = function(input, output) { output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` </div> ] .pull-right[ Let's look at a very basic app. <img src="imgs/basic.png"height="300" width="400"> ] --- ## Shiny basics - packages and global code .pull-left[ ``` r *library(shiny) *library(bslib) *data <- data.frame(col1 = 1:3, * col2 = 4:6) ui = page_fluid( textOutput(outputId = "app_info"), br(), tags$b("Bold text in UI object"), br(), tableOutput(outputId = "table_in") ) server = function(input, output) { output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` ] .pull-right[ The top part of a Shiny R script contains any packages that a required, and any global code/variables. - The code that is in this section will only be run once when the app is initialized, and cannot be updated once the app starts. - The variables from this section are in the global environment, and can be used in the server function. - If an app is deployed in a server, the global environment is only loaded once and shared between users. Can help if data is large. ] --- ## Shiny basics - UI object .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) *ui = page_fluid( * textOutput(outputId = "app_info"), * * br(), * tags$b("Bold text in UI object"), * * br(), * tableOutput(outputId = "table_in") *) server = function(input, output) { output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` ] .pull-right[ The UI object sets up what the user sees on the page. Websites use HTML to set up the structure of the page, CSS for styling, and JavaScript for interactivity. The beauty of Shiny is that you can fully use R (or Python) code to utilize HTML, CSS, and JavaScript in the UI, while using R or Python behind the scenes for the server logic. The UI object is a series of R functions that generates HTML code (see below). ``` r print(as.character(ui)) ``` ``` ## [1] "<div class=\"container-fluid\">\n <div id=\"app_info\" class=\"shiny-text-output\"></div>\n <br/>\n <b>Bold text in UI object</b>\n <br/>\n <div id=\"table_in\" class=\"shiny-html-output shiny-table-output\"></div>\n</div>" ``` ] --- ## Shiny basics - rendering outputs .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) ui = page_fluid( * textOutput(outputId = "app_info"), br(), tags$b("Bold text in UI object"), br(), tableOutput(outputId = "table_in") ) server = function(input, output) { * output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` ] .pull-right[ The *Output* functions from Shiny will hold a space on the page for an HTML element in the UI object. Using the 'outputId' argument, outputs are paired with a *render* function in the server that will determine the contents of this element based on R code run in the server function. Here, we simply render some text to fill the output in the UI, but later on we will see how we can fill these UI components in a **reactive** manner, which is where the power of Shiny is apparent. ] --- ## Shiny basics - HTML helper functions .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) ui = page_fluid( textOutput(outputId = "app_info"), * br(), * tags$b("Bold text in UI object"), * * br(), tableOutput(outputId = "table_in") ) server = function(input, output) { output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` ] .pull-right[ As we mentioned, the UI object translates R functions into HTML code. Shiny has many helper functions that allow us to insert common HTML elements, or tags, into our app. A glossary of Shiny tags is [here](https://shiny.posit.co/r/articles/build/tag-glossary/). Common tags have their own function, such as *br()* (creates a line break), while others are available using the *tags* object, like *tags$b()* in our example (makes text bold). [HTML can be used](https://shiny.posit.co/r/articles/build/html-tags/) in Shiny in a variety of potentially complex ways, including as raw HTML. ] --- ## Shiny basics - server function .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) ui = page_fluid( textOutput(outputId = "app_info"), br(), tags$b("Bold text in UI object"), br(), tableOutput(outputId = "table_in") ) *server = function(input, output) { * output$app_info <- renderText("Rendered in server!") * * output$table_in <- renderTable(data) } ``` ``` r shinyApp(ui = ui, server = server) ``` ] .pull-right[ The server function takes the inputs from the UI object, and using R code will generate the output objects that are displayed in the UI. As the app runs the UI is then monitoring the *output* object to update the UI components. Here we simply use text or a table that are hard coded, but the main use of Shiny is the ability to use very complex R code in the server to react to user actions and dynamically create outputs. We will start getting into reactivity in Session 2. ] --- ## Shiny basics - launch app .pull-left[ ``` r library(shiny) library(bslib) data <- data.frame(col1 = 1:3, col2 = 4:6) ui = page_fluid( textOutput(outputId = "app_info"), br(), tags$b("Bold text in UI object"), br(), tableOutput(outputId = "table_in") ) server = function(input, output) { output$app_info <- renderText("Rendered in server!") output$table_in <- renderTable(data) } ``` ``` r *shinyApp(ui = ui, server = server) ``` ] .pull-right[ The last part of a Shiny app is to run the *shinyApp* function. This function does a lot, and it's not that important to know specifics to use Shiny, but it runs the app in the browser (or in RStudio) while using the UI object and server function to handle the interactions between inputs and outputs. ] --- ## Shiny resources for inputs and outputs The Shiny [cheatsheet](https://shiny.posit.co/r/articles/start/cheatsheet/) is a great resource demonstrating built-in input and output options <img src="imgs/cheat_sheet.png"height="500" width="700"> --- ## Shiny app folder structure You can run a Shiny app as we have from RStudio as a stand alone file. But once your apps get more complex and you have more support files that the app uses, you'll contain it in its own directory. There's a convention when setting up that folder as follows: <img src="imgs/app_structure.png"height="200" width="550"> Then once you have this folder, you can use the *runApp* function from Shiny with the path to the folder (e.g. `runApp("/path/to/app")`), and it will launch the app with access to all of these support files. --- class: inverse, center, middle # Build our own RNAseq app <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Adding global variables to app Let's start building a real app of our own. This is the section outside the UI and server where we define global variables or functions. We read in a data frame that contains RNAseq differential expression results. ``` r library(shiny) library(bslib) library(dplyr) # read in table de_table <- read.csv("data/shP53_vs_control_DEG.csv") de_table$negLog10_pval <- -log10(de_table$pvalue) # view table (would not be part of shiny script) head(de_table, 3) ``` ``` ## ID Symbol baseMean log2FoldChange lfcSE stat pvalue ## 1 ENSG00000002745 WNT16 1531.822 -3.766480 0.08955896 -42.05587 0 ## 2 ENSG00000026025 VIM 1578.109 5.556894 0.12318261 45.11103 0 ## 3 ENSG00000104419 NDRG1 6651.576 -3.614629 0.07273378 -49.69671 0 ## padj negLog10_pval ## 1 0 Inf ## 2 0 Inf ## 3 0 Inf ``` --- ## App with datatable from DT package We are going to use the DT package to show the table in our app. This provides a very interactive table out of the box with little extra work. We add the table using the *dataTableOutput* function in the UI, which is paired with the *renderDataTable* function in the server. ``` r *library(DT) ui = page_fluid( textOutput(outputId = "app_info"), * DT::dataTableOutput(outputId = "de_data") ) server = function(input, output) { output$app_info = renderText("This is an app showing differential gene expression data") * output$de_data = renderDataTable(datatable(de_table)) } ``` --- ## App with datatable from DT package ``` r shinyApp(ui = ui, server = server) ``` <img src="imgs/addDT.png"height="375" width="750"> --- ## Customize datatable The DT package allows for a lot of customization of the html datatable. [This link](https://rstudio.github.io/DT/) shows some of the capabilities. Below we will add custom filters on top of each column and round the values to improve the appearance. ``` r server = function(input, output) { output$app_info = renderText("This is an app showing differential gene expression data") output$de_data = renderDataTable({ * datatable(de_table, * filter = 'top') %>% * formatRound(columns = c("baseMean", "log2FoldChange", "lfcSE", "stat"), digits = 3) %>% * formatSignif(columns = c("pvalue", "padj"), digits = 3) }) } ``` --- ## Customize datatable ``` r shinyApp(ui = ui, server = server) ``` <img src="imgs/customizeDT.png"height="350" width="750"> --- ## Other options for displaying tables - [rhandsontable](https://jrowen.github.io/rhandsontable/) - based on javascript handsontable + an excel like table that is easily editable by the user - [reactable](https://glin.github.io/reactable/) - based on java script React Table + similar to DT, depends on use case. --- ## Add plots to app Add an MA plot and a Volcano plot to the page. First add the outputs to the UI object ``` r ui = page_fluid( textOutput(outputId = "app_info"), dataTableOutput(outputId = "de_data"), * plotOutput("ma_plot"), * plotOutput("volcano_plot") ) ``` --- ## Add plots to app Then make the server function containing the *render* functions that tell shiny how to make the outputs from the IU object. ``` r library(ggplot2) server = function(input, output) { output$app_info = renderText("This is an app showing differential gene expression data") output$de_data = renderDataTable({ datatable(de_table,filter = 'top') %>% formatRound(columns = c("baseMean", "log2FoldChange", "lfcSE", "stat"), digits = 3) %>% formatSignif(columns = c("pvalue", "padj"), digits = 3) }) * output$ma_plot = renderPlot({ * ggplot(de_table, aes(x = baseMean, y = log2FoldChange)) + geom_point() + * scale_x_log10() + xlab("baseMean (log scale)") + theme_bw() * }) * output$volcano_plot = renderPlot({ * ggplot(de_table, aes(x = log2FoldChange, y = negLog10_pval)) + geom_point() + theme_bw() * }) } ``` --- ## Add plots to app ``` r shinyApp(ui = ui, server = server) ``` <img src="imgs/addPlots.png"height="500" width="450"> --- class: inverse, center, middle # App layouts <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Tidy up app appearance with cards bslib has many functions that allow customizing the formatting of the page. NOTE: Older Shiny versions don't use bslib and used similar, but slightly different functions to set up page that you'll likely see on forums (fillPage, fluidPage, etc) - they still work just fine! Here we add ['cards'](https://rstudio.github.io/bslib/articles/cards/index.html), which are boxes that allow grouping of UI components. The basic arguments of the *card* function will be the a call to the *card_header* function, and the rest of the unnamed arguments being UI elements to go into the card body. ``` r ui <- page_fillable( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"), plotOutput("ma_plot")), card(card_header("Volcano plot"), plotOutput("volcano_plot")) ) ``` --- ## Tidy up app appearance with cards ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/addCards.png"height="450" width="400"> --- ## Collapsable cards with accordions We can add the ability to hide certain boxes with accordions from the bslib package. By default only the top accordion is open, but the *accordian* function has an argument 'open' that allows you to select which are when the app is started. ``` r ui <- page_fillable( accordion( accordion_panel(title = "Table of DE results", dataTableOutput(outputId = "de_data")), accordion_panel(title = "MA plot", plotOutput("ma_plot")), accordion_panel(title = "Volcano plot", plotOutput("volcano_plot")) ) ) ``` --- ## Collapsable boxes with accordions ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/accordion.png"height="450" width="900"> --- ## Multiple rows The 'col_widths' argument of the *layout_columns* function will control with width of the column. The bootstrap grid system is made up of 12 columns. A numeric vector is provided with widths for each card. Once the elements combined width goes above 12, then the elements are wrapped to the next row. ``` r ui <- page_fillable( layout_columns( card(card_header("Table of DE results", dataTableOutput(outputId = "de_data"))), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))), col_widths = c(12,6,6) ), ) ``` --- ## Multiple rows ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/multiple_rows.png"height="450" width="600"> --- ## Nested rows within a column More complicated layouts can be achieved by nesting *layout_columns* functions. Here we add a tall card as a new row below the table and then nest the plots within this row next to the card. ``` r ui <- page_fillable( layout_columns( col_widths = 12, card(card_header("Table of DE results", dataTableOutput(outputId = "de_data")))), layout_columns( col_widths = c(6, 6), card(card_header("This is a tall box")), layout_columns( col_widths = c(12,12), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))) ) ), ) ``` --- ## Nested rows within a column ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/nested.png"height="450" width="500"> --- ## Page layout options While we have been using the *page_fillable* function to build the UI, there are three main functions from bslib for slightly differnet page layout strategies: - **page_fillable** - UI components will be in a grid format that will automatically fill the whole page (both vertically and horizontally). - **page_fluid** - UI components will be in a grid format that will extend to fill the whole width of the webpage. - **page_fixed** - UI components will be in a grid format that has a fixed width that will vary depending on the settings of the device. <img src="imgs/page_layouts.png"height="200" width="600"> Image from the Posit tutorials (https://shiny.posit.co/r/articles/build/layout-guide/) --- ## Fillable page (used thus far) ``` r *ui <- page_fillable( layout_columns( card(card_header("Table of DE results", dataTableOutput(outputId = "de_data"))), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))), col_widths = c(12,6,6) ) ) ``` --- ## Fillable page (used thus far) ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` The cards do not fill the screen horizontally and dynamically, but when the window is not big enough, the cards ajust and add scroll bars so you have access to the whole table or plot not matter what. <img src="imgs/fillable_page.png"height="350" width="900"> --- ## Fixed page ``` r *ui <- page_fixed( layout_columns( card(card_header("Table of DE results", dataTableOutput(outputId = "de_data"))), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))), col_widths = c(12,6,6) ) ) ``` --- ## Fixed page ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` The cards do not fill the screen horizontally as there is padding on each side and the cards are a fixed height. When the window is not big enough, you need to scroll down to see the plots on the bottom of the page. <img src="imgs/fixed_page.png"height="350" width="900"> --- ## Fluid page ``` r *ui_fluid <- page_fluid( layout_columns( card(card_header("Table of DE results", dataTableOutput(outputId = "de_data"))), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))), col_widths = c(12,6,6) ) ) ``` --- ## Fluid page ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` The cards fill the screen horizontally and dynamically, but are a fixed height. When the window is not big enough, you need to scroll down to see the plots on the bottom of the page. <img src="imgs/fluid_page.png"height="350" width="900"> --- class: inverse, center, middle # Value boxes and sidebars <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Value boxes [Value boxes](https://rstudio.github.io/bslib/articles/value-boxes/index.html) are another common UI element from the *bslib* package and are nice ways to show key numbers or information that you want to highlight for the user. - the 'value' argument in a value box will be the most prominent text - the 'title' argument goes above the value and other unnamed arguments go below. - the color can be set by the 'theme' argument, which can be made with *value_box_theme* or use special [bootstrap](https://bootswatch.com/) themes (will see this later) - the 'showcase' argument can simply be an icon (see ?icon page) or can get more complex and [show a plot](https://rstudio.github.io/bslib/articles/value-boxes/index.html#expandable-sparklines) ``` r ui <- page_fluid( layout_columns( layout_columns( * value_box(title = "Number of genes that go up:", value = 2000, "Adjusted p-value < 0.05", showcase = icon("arrow-up"), theme = value_box_theme(bg = "#22b430")), * value_box(title = "Number of genes that go down:", value = 1000, "Adjusted p-value < 0.05", showcase = icon("arrow-down"), theme = value_box_theme(bg ="#c34020" )), col_widths = c(12,12) ), card(card_header("Table of DE results", dataTableOutput(outputId = "de_data"))), col_widths = c(3,9)) ) ``` --- ## Value boxes Here we just hard code in numbers to show in the value boxes, but this will obviously be more useful if this number can repsond to user activity. This is something we will do later on. ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/valueboxes.png"height="350" width="600"> --- ## Add a sidebar to a card Sidebars are retractable areas that can be useful in adding information or eventually add user inputs for a specific part of the app. Here we add a sidebar only to the card that contains the table. The *layout_sidebar* function is used to set this up within the card. By default, layout_* elements will be fillable, here its demonstrated that this can be set to FALSE if desired. ``` r ui <-page_fluid( layout_columns( card(card_header("Table of DE results"), * layout_sidebar(sidebar = sidebar("Sidebar ONLY for table", width = 400), * dataTableOutput(outputId = "de_data"), * fillable = FALSE)), card(card_header("MA plot",plotOutput("ma_plot"))), card(card_header("Volcano plot",plotOutput("volcano_plot"))), col_widths = c(12,6,6) ) ) ``` --- ## Add a sidebar to a card ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/card_sidebar.png"height="400" width="900"> --- ## Add a sidebar to the page Sidebars can also be added to the whole page of the app by using the *page_sidebar* function in a similar manner to the other page_* functions used thus far. Page sidebars will remain static as you scroll up and down the page. They are often nice for user inputs or information that you always want the user to see. ``` r ui <- page_sidebar( title = "RNAseq tools", * sidebar = sidebar( * "This is a sidebar for the whole page", * width = 300, * ), layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") ) ) ``` --- ## Add a sidebar to the page ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/sidebar.png"height="450" width="550"> --- class: inverse, center, middle # Mutli-page apps <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Use a navbar layout for multi-page app Oftentimes we want a multi-page layout where the user can click through tabs to see pages with different types of data or information. This can be done using the *page_navbar* function coupled with child *nav_panel* functions that contain the UI elements for each page. ``` r *ui <- page_navbar( title = "RNAseq tools", * nav_panel(title = "DE Analysis", layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") )), * nav_panel(title = "Next steps", "The next step in our analysis will be...") ) ``` --- ## Use a navbar layout for multi-page app ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/nav_bar_sidebyside.png"height="375" width="900"> --- ## Navbar menu We can easily add a menu on the right hand side of our navbar as well with key links or information. The *nav_spacer* function will push the menu to the right hand side of the page, and the *nav_menu* function can contain multiple *nav_item* objects to comprise the list. ``` r ui <- page_navbar( title = "RNAseq tools", nav_panel(title = "DE Analysis", layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") )), nav_panel(title = "Next steps", "The next step in our analysis will be..."), * nav_spacer(), * nav_menu( * title = "Links", align = "right", * nav_item( * tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!",href = "https://rockefelleruniversity.github.io/", target = "_blank")), * nav_item( * tags$a(shiny::icon("arrow-right"), "More about posit",href = "https://posit.co/", target = "_blank")) * ) ) ``` --- ## Use a navbar layout for multi-page app ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/navbar_menu.png"height="450" width="550"> --- ## Add sidebars to a multi-page app Sidebars are easily integrated into the *page_navbar* set up. The 'sdiebar' argument of the *page_navbar* function will add the same sidebar to every page of the app. ``` r ui <- page_navbar( title = "RNAseq tools", * sidebar = sidebar("The same sidebar on every page...", width = 500), nav_panel(title = "DE Analysis", layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") )), nav_panel(title = "Next steps", "The next step in our analysis will be...") ) ``` --- ## Add sidebars to a multi-page app ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/navbar_sidebar_same.png"height="300" width="900"> --- ## Add sidebars to select tabs Sidebars can also be added to some pages and not others by using the *layout_sidebar* function. For example, a *layout_sidebar* object within a *nav_panel* function will only put that sidebar on that panel/page. ``` r ui <- page_navbar( title = "RNAseq tools", nav_panel(title = "DE Analysis", * layout_sidebar( * sidebar = sidebar("The side bar is only on this page...", width = 500), * layout_columns( * card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), * card(card_header("MA plot"),plotOutput("ma_plot")), * card(card_header("Volcano plot"),plotOutput("volcano_plot")), * col_widths = c(12,6,6), row_heights = c("750px", "500px")) * ), ), nav_panel(title = "Next steps", "The next step in our analysis will be...") ) ``` --- ## Add sidebars to select tabs ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/navbar_specific_page.png"height="300" width="900"> --- class: inverse, center, middle # Themes <html><div style='float:left'></div><hr color='#EB811B' size=1px width=720px></html> --- ## Themes It's easy to modify the look of the app using the bslib package. The *page_sidebar* function (and other payout functions) has a 'theme' argument that takes a *bs_theme* object. bslib has builtin themes that can be easily used. The themes can be previewed (here)[https://bootswatch.com/], and the string to use in the 'bootswatch argument' of the *bs_theme* function can be picked from the vector returned by *bootswatch_themes()* ``` r bootswatch_themes() ``` ``` ## [1] "cerulean" "cosmo" "cyborg" "darkly" "flatly" "journal" ## [7] "litera" "lumen" "lux" "materia" "minty" "morph" ## [13] "pulse" "quartz" "sandstone" "simplex" "sketchy" "slate" ## [19] "solar" "spacelab" "superhero" "united" "vapor" "yeti" ## [25] "zephyr" ``` --- ## Themes - Cerulean ``` r ui <- page_navbar( title = "RNAseq tools", * theme = bs_theme(version = 5, bootswatch = "cerulean"), nav_panel( title = "DE Analysis", layout_sidebar( sidebar = sidebar("This is a sidebar", width = 300), layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") ) ) ), nav_panel(title = "Next steps","The next step in our analysis will be..."), nav_spacer(), nav_menu(title = "Links", align = "right", nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank")) ) ) ``` --- ## Themes - Cerulean ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/cerulean.png"height="450" width="550"> --- ## Themes - Darkly ``` r ui_darkly <- page_navbar( title = "RNAseq tools", * theme = bs_theme(version = 5, bootswatch = "darkly"), nav_panel( title = "DE Analysis", layout_sidebar( sidebar = sidebar("This is a sidebar", width = 300), layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") ) ) ), nav_panel(title = "Next steps","The next step in our analysis will be..."), nav_spacer(), nav_menu(title = "Links", align = "right", nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank")) ) ) ``` --- ## Themes - Darkly ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/darkly.png"height="450" width="550"> --- ## Custom themes A big benefit of the *bs_theme* function is the ability to highly customize the app theme. This can be done with the arguments to the function, or with additional CSS. We use custom CSS to modify the header of the cards throughout the app and manually set the main color options. ``` r custom_css <- " .card-header { background-color: #d3dff1; border-bottom: 2px solid #273449; } " # Create theme with custom CSS custom_theme <- bs_theme( version = 5, bg = "white", fg = "#273449", primary = "#5886b2", secondary = "#95a5a6", success = "#18bc9c", info = "#3498db", warning = "#f39c12", danger = "#e74c3c", preset = "bootstrap", "navbar-bg" = "#5886b2" ) |> bs_add_rules(custom_css) ``` --- ## Custom themes This custom theme object can then be used in the 'theme' argument of *page_sidebar*. ``` r ui <- page_navbar( title = "RNAseq tools", * theme = custom_theme, nav_panel( title = "DE Analysis", layout_sidebar( sidebar = sidebar("This is a sidebar", width = 300), layout_columns( card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")), card(card_header("MA plot"),plotOutput("ma_plot")), card(card_header("Volcano plot"),plotOutput("volcano_plot")), col_widths = c(12,6,6), row_heights = c("750px", "500px") ) ) ), nav_panel(title = "Next steps","The next step in our analysis will be..."), nav_spacer(), nav_menu(title = "Links", align = "right", nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank")) ) ) ``` --- ## Themes ``` r #same server function as previous shinyApp(ui = ui, server = server) ``` <img src="imgs/custom_theme.png"height="450" width="550"> --- ## Time for an exercise! Exercises for Session 1 are [here](../../exercises/exercises/shiny_exercise1_exercise.html) --- ## Answers to exercise Answers can be found [here](../../exercises/answers/shiny_exercise1_answers.html) R code for solutions can be found [here](../../exercises/answers/shiny_exercise1_answers.R)