UI and Server - Input / Output Flow
When I started writing code on R Shiny1 applications, one of the topics was quite unusual for me and took some time to comprehend the mechanics behind: the switches between UI and server in terms of object creation and using those objects later.
So, I’ve put them on some sketches and tried to explain what’s really happening as much as I understand.
1 - The UI (User interface)
User interface is a very common term in programming : a blank canvas which you add some objects and content to show your users and also a place to get some inputs from them.
I won’t talk about the layout of the UI in this post but let’s say we have this kind of layout below:
We have some sliders, a dropdown to choose something, a text box to write something and also a graph and a table.
Ask yourself before going further: Can you recognize which objects are related to get some input from user and which are outputs generated by server?
A view from a real shiny app below:
As you can imagine, left side is more about what we enter as a user and right side is about seeing the results of the machine’s work behind.
2- Inputs in Code
In shiny apps, on the server side, there are 3 main objecs:
input
output
session
We will talk about the inputs and outputs only in this article.
As you see in previous image, we have different kinds of input styles such as selection, just empty text box, slider etc. Since these are parts of UI, we are placing those object inside our UI object in the code.
How they look like in the code? Just as below:
<- fluidPage(
ui textInput('a', 'Enter some text', '...')
When we add this line, we are storing the value entered to this text box called “name” inside an object called “input”.
Why? Because we will use this entry as an input in our operations.
Ok, we created a link between text box and our “input” object and called this “a”.
What’s next?
Now we need to use them in server to generate some output.
Before the output, let’s put our input somewhere in the server area then we will figure out how to use it.
<- fluidPage(
ui
textInput('a', 'Enter some text', '...')
)
<- function(input, output, session) {
server
$a
input
}
2- Outputs in Code
We are calling the “a” from “input” object to server but server doesn’t know yet what to do with it.
We can use this text in many kinds of operations like using in a sentence, to filtering some data or even just showing as just it is. R calls this operation as “rendering”.
How do we render it? With the “render” functions like “renderText”.
<- fluidPage(
ui #Inputs
textInput('a', 'Enter Name', '...')
)
<- function(input, output, session) {
server renderText({ input$a })
}
A Small Break for “Rendering”
What did we do exactly when we “render” this? Why do we even need this operation?
Because, shiny apps running as “HTML” , but we are creating a code in R. Someone needs to translate this language to HTML and with this translation, your chrome or safari will be able to understand this language! 🤖👾
As you see, our few lines of code in R, being converted by “R-Studio” to a much longer HTML code and in this snapshot, you don’t even see the “CSS” file which organizes the layout of the objects.
I’m adding this here just to remind you that we are working on the “R” layer of our app.
Whenever we render our app, there is some code conversion from R to HTML. That’s why, to keep things clean and not messed up, Rstudio always ask “should I save this file before running the app?”. Notice that, it doesn’t ask the same thing when you are working on R environment.
You can click on the check box and make it automatized also. But, the wording is meaningful: “build”. It’s taking your R code and building a website with it.
Break is Over
So, now, our server rendered our text as HTML but how are we going to show it to user? That’s where we come to our object “output”.
To be able to use something in UI, we need to put it inside the “output” object.
Let’s create an object called “x” as an output and put it inside the output object:
<- function(input, output, session) {
server $x <- renderText({
output$a
input
}) }
After creating “x” in the output by💲sign, now we managed to store our “a” from inputs, as “rendered” format in the outputs.
We can go back to UI and now use this output by “textOutput” function this time.
<- fluidPage(
ui #Inputs
textInput('a', 'Enter some text', '...'),
#Adding some shine
print("This is what you entered if you already forgot:"),
# Outputs
textOutput('x')
)
<- function(input, output, session) {
server $x <- renderText({
output$a
input
})
}
shinyApp(ui = ui, server = server)
How does it look like?
So what did we do while generating the output? Let’s have a look:
Conclusion and Summary
In summary, this is simply our flow in the code and actions:
I think this concept is the core of the communication between UI and server when we write R code. This also reflects how you code in shiny apps. As you see in the red arrows, we are going back and forth between UI and the server. This is something very different than what we do in general R coding.
This is also showing that, when R-studio builds our app, it’s creating the UI and server relations in different order than what we write in the R code. Why I’m saying this? Because, think about the code below:
<- fluidPage(
ui # Defining the input text
textInput('a','Enter some text'),
# Defining what to show
textOutput('x')
)
The function calls for something called “x” but “x” doesn’t exist yet! If we would be running as a straight forward logic, it would give and error and say “hey, there is no such thing as x”.
Yet… Here is what it does then we put it:
> textOutput('x')
<div id="x" class="shiny-text-output"></div>
Now it makes more sense. Because we see that, the output functions are simply tagging our objects in the dedicated html class and that’s all. It’s going to be come this area if server creates something called “x” inside our output box.
In other words, they are simply creating an address for things to come and classifying the address even before they come. (In our case, it’s telling “something as text format is coming here”) Then whenever asked to the server, server just provides whatever that “x” is.
It was quite interesting for me to figure out how this works. Yet, of course, I’m just scratching the surface.
I hope this is also helpful to somebody else to understand these mechanics behind.
Stay with peace!😇
Footnotes
If you never heard of shiny, check this out: https://shiny.rstudio.com/gallery/↩︎