When we include graphics inside a Shiny application, all the elements that are seen can be handled within a reactive context. Taking the same previous example, in the following code, you will see how to use reactivity inside graphical parameters.
In this case, a fixed color is assigned to every species, so the color assignment can be done outside the reactive context. In this case, we will be doing it inside global.R
because the inputs in UI.R
are going to be defined as the levels of iris$Species
, as it was explained in Chapter 4, Shiny Structure – Reactivity Concepts:
global.R# Load Data data(iris) #Assign color by Species iris$color <- sapply(iris$Species, function(x) switch(as.character(x), setosa = "red", versicolor = "green", virginica = "blue"))
UI.R
has two types of inputs; firstly, the species (within checkboxGroupInput
) and secondly, the variables in the horizontal and vertical axes respectively. For the purpose of simplicity, the first part has been hardcoded. However, it could have been rewritten similar to the solution implemented for selectInput()
where the variable names from the iris
object were directly taken:
library(shiny) # Starting line shinyUI(fluidPage( # Application title titlePanel("Reactiveparameters in the application"), # Sidebar sidebarLayout( sidebarPanel( #Species selection checkboxGroupInput("species","Select the species to plot:", levels(iris$Species), selected= levels(iris$Species)), selectInput("xvar","Select the variable on the horizontal axis",names(iris)[1:4]), selectInput("yvar","Select the variable on the vertical axis",names(iris)[1:4])), #The plot created in server.R is displayed mainPanel( plotOutput("custom.plot") ) ) ))
It is in server.R
, however, where the most important processes are done in order to have a fully flexible graph that can adapt to any variable combination and can still plot graphs with identical layout:
library(shiny) #initialization of server.R shinyServer(function(input, output) { iris.sset <- reactive(subset(iris,Species %in% input$species)) species.color <- reactive(unique(iris.sset()[,5:6])) #Plot generation output$custom.plot <- renderPlot({ title <- paste0(input$xvar,"/",input$yvar," dispersion graph") plot(iris.sset()[[input$xvar]],iris.sset()[[input$yvar]], col=iris.sset()$color, pch = 16,main= title, xlab =input$xvar, ylab=input$yvar,cex=0.8) #Horizontal Position for legend min.x <- min(iris.sset()[[input$xvar]]) max.x <- max(iris.sset()[[input$xvar]]) x.diff <- max.x - min.x x.pos <- min.x + x.diff * 0.8 #Vertical Position for legend min.y <- min(iris.sset()[[input$yvar]]) max.y <- max(iris.sset()[[input$yvar]]) y.diff <- max.y - min.y y.pos <- min.y + y.diff * 0.2 #Legend creation legend(x.pos,y.pos,legend=species.color()[,1], pch=16, col=species.color()[,2],cex=0.7) }) })
Firstly, two reactive objects are created: iris.sset
, which is clearly a subset by species and secondly, a small species.color
dataset, which is mainly a deduplicated combination of species and color and used in the legend.
After this, the plot is rendered. In this case, the title object is dynamically built by pasting the variable names to the rest of the title together. In the plotting title, the object is passed to the main
argument.
In the plot
call, the variables selected for the horizontal and vertical axes are called with a double bracket. The reason for this is that as input$xvar
and input$yvar
are character strings, so they cannot be used to access the corresponding selected variables by writing something as iris.sset()$input$var
or anything similar to this.
As it was explained in Chapter 2, First Steps towards Programming in R, data frames are special types of lists. As lists, their objects can be accessed not only by the $
operator but also by index number or character string within double brackets. Sometimes both are equivalent but in this case, using the $
operator would have implied excessive complex coding.
For the positions of the horizontal and vertical axes, the range of the variable is calculated and after this, these positions are defined as the minimum value for the variable along with the range multiplied by a coefficient. As we want the legend near the bottom right corner, the coefficient in the horizontal axis is 0.8
(nearer to 1
than to 0
) and 0.2
on the vertical axis (nearer to 0
than to 1
). If the positions were hardcoded, the legend would move according to the selected variables because the axes would change whenever another variable is selected.
For the legend, the species.color()
subset generated before is called where legend
takes the first column of values and col
takes the second one. Although this could have been coded differently, this solution guarantees that the color and species in the legend match correctly, independent of how the data is internally organized.
You may have realized at this stage that even with R's most basic graphical package, the possibilities of creating fully customized graphics within a Shiny application are endless.