class: center, middle, inverse, title-slide .title[ # Interactive visualization ] .author[ ### MACS 40700
University of Chicago ] --- class: inverse, middle # For today/Tuesday: ```r # install bslib and dependencies, if necessary # install.packages(c("bslib", "curl", "bsicons")) usethis::use_course("MACS40700/shiny-sep") ``` --- ## Announcements * Tuesday: Last wrap on bslib/dashboards * 3/11 final due!! --- ### Agenda: * Build on last class * More on layouts, including tabsets * Small discussion of themes * Prep for dashboards --- # Building on our successes <img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWFtZzRtYmFlOHo0MnM1NWV1NjV4bTNyYTVzMnU1b3M5YTdxdm43aSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/izspP6uMbMeti/giphy.gif" width="80%" style="display: block; margin: auto;" /> --- # Sandbox party time `usethis::use_course("MACS40700/shiny-sep")` ``` r ui <-fluidPage() server <- function(input, output) { select_data <- reactive({ data("starwars") # a bit random: star wars dataset starwars[0:input$num,] # plot the first (selected) rows }) output$myplot <-renderPlot({ hist(select_data()$birth_year, # make it into a histogram main = "Histogram of Birth year", xlab = "birth year", col = "orchid") }) } shinyApp(ui = ui, server = server) ``` --- ## More on layouts: We've previously worked in a somewhat standard layout: panels on the side and main -- everything is on one page. * How to divide the page * How to --- ## Fluidity: dynamic page adjustment If you want to use the column grid system (and adjust width based on item size), you can use fluidRow. This is our prior example: Prior example: ``` r ui <- fluidPage( theme = shinytheme("superhero"), # Application title titlePanel( h1("First level title", align = "center")), sidebarLayout( sidebarPanel( sliderInput( inputId = "num", label = "How many observations? Choose a number from 0 to 87", min = 1, max = 87, value = 20)), mainPanel( plotOutput("myplot")), position = c("right")) ) ``` --- ## fluidRow usecase ``` r ui <- fluidPage( theme = shinytheme("superhero"), # Application title titlePanel( h1("First level title", align = "center")), sidebarLayout( sidebarPanel( sliderInput( inputId = "num", label = "How many observations? Choose a number from 0 to 87", min = 1, max = 87, value = 20)), * mainPanel(fluidRow(h2("A little about my plot")), * fluidRow( plotOutput("myplot"))), position = c("right") ) ``` --- ## fluidRow + columns You can further subdivide your space using columns: ``` r ui <- fluidPage( theme = shinytheme("superhero"), # Application title titlePanel( h1("First level title", align = "center")), sidebarLayout( sidebarPanel( sliderInput( inputId = "num", label = "How many observations? Choose a number from 0 to 87", min = 1, max = 87, value = 20)), mainPanel(fluidRow( column(4, * h2("A little about my plot")), * column(6, h3("and more stuff goes here"))), * fluidRow( plotOutput("myplot"))), position = c("right") ) ) ``` https://shiny.posit.co/r/reference/shiny/0.14/column.html https://mastering-shiny.org/action-layout.html --- #Fillable and fluid <img src="https://shiny.posit.co/r/articles/build/layout-guide/pages.png" width="80%" style="display: block; margin: auto;" /> --- # Exercise: * Test out a different theme * Add this plot under the prior plot and fix the color issue :) ``` r output$myplot2 <-renderPlot({ ggplot(select_data(), aes(x = fct_infreq(eye_color))) + geom_bar(col = "orchid") + labs( title = "Bar plot of eye color", x = "Eyecolor") }) ``` --- ## More sophisticated layouts <iframe src="https://shiny.posit.co/r/layouts/" width="80%" height="400px" data-external="1"></iframe> --- ## Tabsets You might also want to have tabs in some way. Here is the generic code: ```r ui <- fluidPage tabsetPanel( tabPanel("name", input(details)), tabPanel("n2", input(details)), ) ) ``` --- ## Tabsets: incorporation Most likely, you will want to have tabs within a sidebar of some type. In that case, you can fold the tabset into where you would like them: ```r ui <- fluidPage( sidebarLayout( sidebarPanel( tabsetPanel( tabPanel("name", input(details)), tabPanel("n2", input(details)), ), main panel() ) ) ``` --- ## Tabsets working example ``` r ui <- fluidPage( theme = shinytheme("superhero"), # Application title titlePanel( h1("First level title", align = "center")), sidebarLayout( sidebarPanel( textOutput("panel"), tabsetPanel( tabPanel("Import data", fileInput("file", "Data", buttonLabel = "Upload..."), ), tabPanel("Set parameters", textInput("delim", "Delimiter (leave blank to guess)", ""), ), tabPanel("Visualise results", sliderInput( inputId = "num", label = "How many observations? Choose a number from 0 to 87", min = 1, max = 87, value = 20)), tabPanel("Inputs", numericInput("skip", "Rows to skip", 0, min = 0), numericInput("rows", "Rows to preview", 10, min = 1)) ), width = 4), mainPanel( fluidRow( column(4, h2("A little about my plot")), column(8, h3("and more stuff goes here"))), fluidRow( plotOutput("myplot"))), position = "right")) ``` --- ## example, cont'd ``` r server <- function(input, output) { } shinyApp(ui = ui, server = server) ``` --- # Building out your sidebar Can place any number of items there: * Static tabs: `tabName` * Dynamic info: `renderMenu` and `sidebarMenuOutput` * No sidebar!: `dashboardSidebar(disable = TRUE)` --- # Body: Where and how to place things * Truly sketch out what it will look like * Consider your goals --- # Building from ui and server files * Put all ui elements in file -- need ui to be last object * put all server elements in file -- need server to be last object --- # How to decide to build * Overall complexity * Purpose of design * Length of use --- # Sample example: Separate Files ``` usethis::use_course("MACS40700/shiny-sep") ``` --- class: middle, center # Dashboards --- ## bslib, fluidPage vs alternatives Everything we've done so far has been with fluidPage. R/Shiny runs on `bootstrap` and using fluidPage runs a pior version of boostrap while bslib runs the curent version. * INCOMING: NEW VOCABULARY! --- ## Vocab basics * `title`: * `page_*`: what kind of page you want (sidebar, fillable, etc.) * `card`: items you are putting in * `layout`: --- ## bslib demo `bslib::bs_theme_preview()` --- # Fancying up a header: application In sandbox, test out adding a dropdown menu: ```r header <- dashboardHeader(dropdownMenu( )) sidebar <- dashboardSidebar() body <- dashboardBody() dashboardPage(header, sidebar, body) ``` --- # SKETCH IT OUT! Let't try a left sidebar, and a three-plot layout --- # Start: penguins and packages Inspo: https://rstudio.github.io/bslib/articles/dashboards/index.html Goal: https://jclip.shinyapps.io/penguin-dash/ -- Packages: ```r library(tidyverse) library(palmerpenguins) library(gghighlight) library(shiny) library(bslib) data(penguins, package = "palmerpenguins") ``` --- # specify UI + server ```r ui <- page_sidebar( title = "Penguins dashboard", sidebar = color_by, layout_columns(cards[[1]], cards[[2]]), cards[[3]] ) ``` --- # filtering ```r color_by <- varSelectInput( "color_by", "Color by", penguins[c("species", "island", "sex")], selected = "species" ) ``` --- ## UI: plots/items ```r cards <- list( card( full_screen = TRUE, card_header("Bill Length"), plotOutput("bill_length") ), card( full_screen = TRUE, card_header("Bill depth"), plotOutput("bill_depth") ), card( full_screen = TRUE, card_header("Body Mass"), plotOutput("body_mass") ) ) ``` --- # Server: Two main kind of plots, so specify two plot 'types': ```r server <- function(input, output) { gg_plot <- reactive({ ggplot(penguins) + geom_density(aes(fill = !!input$color_by), alpha = 0.5) + theme_minimal(base_size = 16) + scale_fill_discrete(h = c(0,190)) + theme(axis.title = element_blank(), legend.position = "bottom") }) gg_plot_h <- reactive({ ggplot(penguins) + geom_point(aes(x = flipper_length_mm, y=body_mass_g, color = !!input$color_by))+ gghighlight() + facet_wrap(vars(!!input$color_by)) + scale_color_discrete(h = c(0,190)) + theme_minimal(base_size = 16) + theme(axis.title = element_blank(), legend.position = "bottom") }) output$bill_length <- renderPlot(gg_plot() + aes(bill_length_mm)) output$bill_depth <- renderPlot(gg_plot() + aes(bill_depth_mm)) output$body_mass <- renderPlot(gg_plot_h()) } ``` --- ## Alternative: split it out: ```r gp1<-ggplot(penguins) + theme_minimal(base_size = 16) + scale_fill_discrete(h = c(0,190)) + theme(axis.title = element_blank(), legend.position = "bottom") ``` --- ## Then server ```r server <- function(input, output) { gg_plot <- reactive({gp1+ geom_density(aes(fill = !!input$color_by), alpha = 0.5) }) gg_plot_h <- reactive({ gp1 + geom_point(aes(x = flipper_length_mm, y=body_mass_g, color = !!input$color_by))+ gghighlight() + facet_wrap(vars(!!input$color_by)) }) output$bill_length <- renderPlot(gg_plot() + aes(bill_length_mm)) output$bill_depth <- renderPlot(gg_plot() + aes(bill_depth_mm)) output$body_mass <- renderPlot(gg_plot_h())} ``` --- # Finally, launch ```r shinyApp(ui, server) ``` --- center: middle, center # Code for these: `usethis::use_course("MACS40700/bslib-ex")` --- # Additional Skills: * Incorporating css files * Building from ui and server files * Brushing --- # CSS files vs packages * [Great jumping off point](https://shiny.posit.co/r/articles/build/css/) * `fresh` package can be helpful also * put custom css in subfolder named `www` --- # Example ```css /* app-specific css */ .main-header .logo { font-family: "Georgia", Times, "Times New Roman", serif; font-weight: bold; font-size: 24px; } body { background-color: #ffefc8; color: #8300a5; /* text color */ } .irs--shiny .irs-bar, .irs--shiny .irs-single { border: #8300a5; background: #8300a5; } ) /* Make text visible on inputs */ .shiny-input-container { color: #8300a5; } ``` --- # Recap * Shiny can be wonderful * Work outside the app for plots * Shiny can be not wonderful * Dashboard vs shiny: think about workload --- class: center, middle, inverse # Work time --- # Learning Objectives *By the end of the course, students will be able to:* 1. Understand the principles of designing and creating effective data visualizations. 2. Evaluate, critique, and improve upon one’s own and others’ data visualizations based on how good a job the visualization does for communicating a message clearly and correctly. 3. Post-process and refine plots for effective communication. 4. Use visualizations for evaluating statistical models and for statistical inference. 5. Master using R and a variety of modern data visualization packages to create data visualizations. 6. Work reproducibly individually and collaboratively using Git and GitHub. --- # What we did * Assignments on github (items 5 and 6) * In-class applications and analysis (items 1,2, 3, 4) * Final project (items 1-6) --- # How we did it * Build a community of inquiry -- can offer feedback and critique * Strong engagement * Challenging ourselves to think through beyond the superficial * Continuing to build, scaffold, and refine --- # Looking ahead: evaluations Role of evaluations to help understand how the course contributes to your learning. * Please fill them out! * Be specific! * NO: 'I didn't like this class' * YES: 'I didn't like this class because I wanted more assignments' * Think about elements that were/not helpful for learning -- I tried to build a course that would meet people where they were with their level of experience and allow them to deepen their skillset in a meaningful way --- class: center, inverse, middle # GOOD LUCK!