# My first… web application with Shiny

December 11, 2013
By

(This article was first published on Milano R net, and kindly contributed to R-bloggers)

It was several time I was thinking about developing a web application with R and Shiny.

In these days I realize my first application with Shiny. You can find it at http://spark.rstudio.com/nsturaro/pyramid0/

The idea is very simple: I plot a population pyramid for Italy. Data refers to year 2002 through 2011. Ages can be aggregated into classes, specifying the width of classes.

A Shiny application is defined by two R files: ui.R and server.R. As the names suggest, ui.R contains definition of the application interface, while server.R contains definition of the computation behind.

Let see the scripts.

ui.R contains the shiny package requirements and then call the shinyUI() function. Inside this function, the pageWithSidebar() function is used to specify which layout should be used. Finally, three elements are built, by just as many functions: headerPanel() contains the main title, sidebarPanel() defines the sidebar and mainPanel() defines the main content of the web page.

The sidebar panel contains two sliders and some custom HTML codes useful to put the company logo. The main panel contains only the plot.

This is the full code:

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25  require(shiny)   shinyUI(pageWithSidebar(   ### Application title headerPanel("Italian population between 2002 and 2011"),   ### Sidebar with sliders and HTML sidebarPanel( # Slider: choose class width sliderInput("ampiezza", "Class width (years):", min=1, max=10, value=5), # Slider: choose year sliderInput("anno", "Year:", min=2002, max=2011, value=2011, format = "0000", animate = TRUE), # HTML info div(style = "margin-top: 30px; width: 200px; ", HTML("Developed by")), div(style = "margin-top: 10px; ", HTML("")), div(style = "margin-top: 30px;", HTML("Source: ISTAT - Istituto Nazionale di Statistica")) ),   ### Main Panel mainPanel( # Show the plot plotOutput("pyramid", height="600px") ) ))

On the other side, server.R contains the R code to produce the pyramid plot. Code that read input values and return output ought be wrapped in a function, contained in the shinyServer() function.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66  # Load libraries library(pyramid)   # Set working directory (to run code within RStudio) #setwd("ShinyApps/pyramid")   # Load data load("data.Rdata")   # Define useful functions roundAny = function(x, accuracy, f = round) {f(x/accuracy) * accuracy}       ### Main shinyServer function shinyServer(function(input, output) {   ### Plot output: pyramid output$pyramid <- renderPlot({ # Define data column from slider input col = input$anno - 2002 + 1   # Class widths from slider input agg = rep(1:1000, length.out = nrow(pop$MALES), each = input$ampiezza)   # Build data frame with current year and class widths df = data.frame( M = tapply(pop$MALES[, col], INDEX = agg, FUN = sum), F = tapply(pop$FEMALES[, col], INDEX = agg, FUN = sum) )   # Given the class width, data frame with highest value dfMax = data.frame( M = tapply(pop$MALES[, ncol(pop$MALES)], INDEX = agg, FUN = sum), F = tapply(pop$FEMALES[, ncol(pop$FEMALES)], INDEX = agg, FUN = sum) )   # Age classes labels lab = seq(from = 0, to = 1000, by = input$ampiezza)[1:nrow(df)] if(input$ampiezza == 1) { row.names(df) = lab } else { row.names(df) = paste(lab, lab+input$ampiezza-1, sep = " - ") } row.names(df)[nrow(df)] = paste0(lab[nrow(df)], "+") # Graphical parameter (adjusted for class width) val.Cadj = -0.01 val.Cstep = 1 if(input$ampiezza == 1) {val.Cadj = -0.030; val.Cstep = 3} if(input$ampiezza == 2) {val.Cadj = -0.025; val.Cstep = 2} if(input$ampiezza == 3) {val.Cadj = -0.020} if(input\$ampiezza == 4) {val.Cadj = -0.015}   # Data scale ord = nchar(max(dfMax)) - 1 df = df/(10^ord) if(ord == 6) {val.Laxis = seq(0, roundAny(max(dfMax)/(10^ord), 0.5, ceiling), by = 0.5); val.main = "(millions)"} if(ord == 5) {val.Laxis = seq(0, roundAny(max(dfMax)/(10^ord), 1, ceiling), by = 1); val.main = "(thousands x 100)"}   # Finally, draw the plot pyramid(df, Cstep = val.Cstep, Cadj = val.Cadj, AxisFM = "g", Laxis = val.Laxis, main = paste("Population", val.main))   }) })