Aplicaciones Web en R con Shiny

Inspirados en el tutorial de Paul Hiemstra Tutorial: creating webapps with R using Shiny vamos a construir una aplicación Shiny que muestre los precios de instrumentos financieros tomando la información de Google mediante el paquete quantmod.

Introducción

Desde que Internet se hace popular y proliferan las formas de conectarse, tanto desde la empresa como desde el hogar y ahora de forma masiva a través de los dispositivos móviles, es muy común que cada empresa e inclusive las personas utilizan las páginas web para mostrar y compartir información útil. Estas aplicaciones han evolucionado ya que hoy en día son cada vez más dinámicas, es por ello que se denominan Aplicaciones Web.

Desde el punto de vista tecnológico existen muchas opciones para construir Aplicaciones Web y diversas arquitecturas Cliente-Servidor que facilitan este proceso, sin embargo, nos interesa transitar el camino para construir Aplicaciones Web desde R utilizando el paquete Shiny.

Normalmente es necesario contar con un programador que conozca sobre las tecnologías Web como HTML5/JavaScript/CSS3, sin embargo, es posible construir Aplicaciones Web dinámicas e interactivas mediante las facilidades que ofrece Shiny sin requerir mucho conocimiento sobre las tecnologías Web.

RStudio ha hecho grandes esfuerzos por facilitar el acceso y usabilidad de R como lenguaje y en este sentido ha promovido la creación de nuevos paquetes para manejar documentación y también crear contenido Web. En esa misma línea también crearon el paquete shiny.

Las funciones de este paquete se ocupan de la comunicación entre el Cliente y el Servidor utilizando la programación reactiva (Reactive), además genera el HTML5/JavaScript/CSS necesario para construir las Aplicaciones Web. Es por ello que los analistas de datos ahora cuentan con una herramienta que les permite darle vida a sus estudios ya que pueden construir una Aplicación Web con parámetros y variables dinámicas que permiten interactuar con los datos y ver diferentes resultados sin necesidad de programar.

Aplicaciones Web

Una Aplicación Web está compuesta por contenido (estático y dinámico) que es consumido por el navegador (Browser) de su preferencia. Usualmente las interacciones con la Aplicación Web generan llamadas a un Servidor que la procesa y devuelve un resultado que se despliega en el navegador.

Se suele separar entre Interfaz de Usuario (UI o Front o Frontend) y el Servidor (Back o Backend). En este caso la interfaz de usuario es una Aplicación cliente que corre (se ejecuta) y muestra sus resultados en el navegador, la aplicación servidor corre (se ejecuta) y genera sus resultados en un servidor acondicionado para tal fin, usualmente en la nube, es decir, en internet.

El proceso usual es que el usuario abre el navegador de su preferencia y señala la dirección de la página, al especificar la dirección, el navegador se conecta al servidor y obtiene el contenido que se ejecuta en el navegador. En la medida que el usuario interactua con la Aplicación Web, se generan nuevas llamadas al servidor, usualmente para solicitar alguna información, el servidor recibe la llamada, la procesa y genera un resultado que luego el navegador del usuario recibe y muestra en pantalla con el formato apropiado.

Aplicaciones Web Shiny/R

Las Aplicaciones Web Shiny funcionan de la misma forma que una Aplicación Web hecha en otras tecnologías, con la ventaja de que R y el paquete Shiny se encargan de generar todo el código necesario para facilitar la creación de una Aplicación Web, sin necesidad de entender en detalle el funcionamiento de las tecnologías Web. Shiny ofrece muchas funciones que generan código HTML para mostrar elementos en una página Web y al mismo tiempo ofrece un modelo de interacción con los componentes de la página para hacerla interactiva y dinámica.

Una aplicación Shiny está conformada por un archivo app.R o dos archivos ui.R y server.R. Es decir, se puede hacer una aplicación Shiny partiendo de un solo archivo con todo el código o se puede partir de dos archivos que separan los aspectos de la interfaz de los aspectos centralizados (servidor).

  • app.R es el archivo que contiene tanto los elementos de la interfaz como del servidor.
  • ui.R es el archivo donde se especifican los elementos de la interfaz y la disposición de dichos elementos en la pantalla.
  • server.R es el archivo donde se programa la lógica del servidor y se genera el contenido dinámico que depende de las interacciones con la pantalla.

Shiny se encarga de generar el HTML/JavaScript y además ofrece toda la lógica de manejo de los eventos que se producen en pantalla (clicks a botones, cambios de menú, etc), cuando cambia un parámetro en pantalla, Shiny también se encarga de comunicarse con el servidor enviando el nuevo valor del parámetro y el servidor procesa la llamada, genera el resultado y lo envía al cliente. Toda esta lógica la ofrece Shiny y el analista sólo se debe enfocar en lo que va a aparecer en pantalla y lo que se debe generar cada vez que el usuario hace algún cambio. El analista se concentra en programar en R para generar su Aplicación Web interactiva y dinámica.

Elementos de la interfaz del usuario (interactivo)

Vamos a explorar cómo se programa una aplicación Shiny utilizando un archivo y luego utilizando dos archivos.

Aplicación en un archivo - app.R

Una aplicación típica Shiny incluye el paquete shiny y especifica dos objetos ui y server (estos objetos pueden tener cualquier nombre). Luego llamamos la función shinyApp() especificando los objetos ui y server respectivamente.

library(shiny)
ui <- fluidPage()

server <- function(input, output) {}

shinyApp(ui = ui, server = server)

El ejecutar el código previo en la cónsola de R o RStudio pueden ver una página Web vacía. En el objeto ui está todo el código HTML necesario para mostrar la información en la pantalla y los componentes y parámetros que la hacen interactiva. En el objeto server se encuentra definida la lógica que se ejecuta cada vez que el usuario hace un cambio o una interacción en pantalla.

Como ejemplo vamos a ejecutar los comandos siguientes:

> # Primero incluimos el paquete shiny
> library(shiny)
> # Luego ejecutamos la función que genera
> fluidPage()
<div class="container-fluid"></div>
> 

Podemos ver que la función fluidPage() genera código HTML. El analista no se preocupa por esto, shiny se ocupa de generar el código de la Aplicación Web.

Un ejemplo más elaborado de la interfaz considera la inclusión de un título mediante la función titlePanel(), la creación de una pantalla con una barra lateral y un panel principal, mediante las funciones sidebarPanel() y mainPanel() respectivamente. Ambos componentes se colocan dentro de la llamada a la función sidebarLayout() que genera una página dividida en una barra lateral y un panel principal.

> fluidPage(
+     titlePanel("título"),
+     
+     sidebarLayout(
+         sidebarPanel("panel lateral"),
+         mainPanel("panel principal")
+     )
+ )
<div class="container-fluid">
  <h2>título</h2>
  <div class="row">
    <div class="col-sm-4">
      <form class="well">panel lateral</form>
    </div>
    <div class="col-sm-8">panel principal</div>
  </div>
</div>
> 

Vamos a agregar los elementos en la página para permitir al usuario seleccionar una acción del mercado americano de una lista para luego mostrar la gráfica de precios en el panel principal.

Primero vamos a agregar un título y la selección de la acción mediante la función selectInput(). Le recomendamos consultar la ayuda en línea mediante el comando ?selectInput.

En sidebarPanel() se agregan los elementos que van en el Panel separados por coma como sigue:

sidebarPanel(elemento1, elemento2, elemento3,...)

Para colocar un texto sencillamente se agrega el texto entre comillas y luego el selectInput() con las opciones para seleccionar algunas de las acciones como sigue:

    sidebarPanel("Seleccione la acción que desea consultar",
                 selectInput('accion', 
                             label = 'Acción', 
                             choices = c("Apple"="AAPL", "Cisco"="CSCO",
                                         "IBM"="IBM", "Facebook"="FB",
                                         "Twitter"="TWTR", "Microsoft"="MSFT",
                                         "Google"="GOOG"))),

Luego en el Panel principal vamos a agregar un texto descriptivo, un título con h1(), texto en un párrafo con p() y el gráfico con plotOutput().

mainPanel("Gráfico de Acciones del Mercado de Valores Americano",
          h1('Gráficos de Precios'),
          p('A continuación se muestra la gráfica del precio de la acción seleccionada.'),
          plotOutput('grafico'))

Se puede apreciar que dentro del Panel principal, también se colocan los elementos que aparecen en pantalla en una lista separada por comas.

El código de la aplicación con la interfaz de acuerdo a la descripción queda como sigue:

library(shiny)
library(quantmod)

ui<-fluidPage(
  titlePanel("Mercados con R"),
  sidebarLayout(
    sidebarPanel("Seleccione la acción que desea consultar",
                 selectInput('accion', 
                             label = 'Acción', 
                             choices = c("Apple"="AAPL", "Cisco"="CSCO",
                                         "IBM"="IBM", "Facebook"="FB",
                                         "Twitter"="TWTR", "Microsoft"="MSFT",
                                         "Google"="GOOG"))),
    mainPanel("Gráfico de Acciones del Mercado de Valores Americano",
              h1('Gráficos de Precios'),
              p('A continuación se muestra la gráfica del precio de la acción seleccionada.'),
              plotOutput('grafico'))
  )
)

server<-function(input, output) {}

shinyApp(ui=ui, server=server)

Ya esta es una Aplicación Web Shiny que sólo genera la interfaz del usuario pero no tiene ninguna lógica del lado del servidor.

Elementos del servidor (dinamismo)

En el servidor queremos generar el gráfico basándonos en la selección que realizó el usuario. La forma en la cual se relacionan las interacciones o cambios de los usuarios con los resultados, es mediante las variables input y output.

En la interfaz hemos creado una variable input en la llamada a selectInput() denominada accion. En esta variable está almacenada la acción seleccionada. La forma de acceder a este valor desde el servidor es mediante la expresión input$accion. Adicionalmente hemos creado una variable de salida en la llamada a plotOutput() denominada grafico, este es un gráfico que se genera en el servidor mediante la expresión output$grafico. Es decir, que en el servidor utilizados los input$ para generar los output$.

A la variable output$grafico debemos asignarle un gráfico en R. Esto se realiza mediante la función renderPlot(). Hay varias funciones de tipo renderXX para generar diversos tipos de salida. En este caso sólo queremos generar un gráfico.

Dentro de la llamada a renderPlot() el primer argumento es una expresión, es decir, una secuencia de comandos de R que producen el resultado esperado, en este caso un gráfico.

Para generar el gráfico vamos a usar las funciones del paquete quantmod. Lo primero que debemos hacer es incluir este paquete en nuestro programa mediante library(quantmod). El código base es el siguiente:

server<-function(input, output) {
  output$grafico <- renderPlot({
    # Código que genera el gráfico partiendo de la variable input$accion
  })
}

Ahora vamos a utilizar getSymbols() para obtener los datos de este año 2017, desde google y luego dibujamos un gráfico de velas mediante la función candleChart() como se puede apreciar a continuación:

server<-function(input, output) {
  output$grafico <- renderPlot({
    stockdata <- getSymbols(input$accion, src="google", from = "2017-01-01",
                       to = "2017-08-18", auto.assign = FALSE)
    candleChart(stockdata, name=input$accion)
  })
}

Le hemos pasado algunos parámetros adicionales que puede consultar mediante el comando ?getSymbols.

El código del programa completo queda como sigue:

library(shiny)
library(quantmod)

ui<-fluidPage(
  titlePanel("Mercados con R"),
  sidebarLayout(
    sidebarPanel("Seleccione la acción que desea consultar",
                 selectInput('accion', 
                             label = 'Acción', 
                             choices = c("Apple"="AAPL", "Cisco"="CSCO",
                                         "IBM"="IBM", "Facebook"="FB",
                                         "Twitter"="TWTR", "Microsoft"="MSFT",
                                         "Google"="GOOG"))),
    mainPanel("Gráfico de Acciones del Mercado de Valores Americano",
              h1('Gráficos de Precios'),
              p('A continuación se muestra la gráfica del precio de la acción seleccionada.'),
              plotOutput('grafico'))
  )
)

server<-function(input, output) {
  output$grafico <- renderPlot({
    stockdata <- getSymbols(input$accion, src="google", from = "2017-01-01",
                       to = "2017-08-18", auto.assign = FALSE)
    candleChart(stockdata, name=input$accion)
  })
}

shinyApp(ui=ui, server=server)

Ahora tenemos un Aplicación Web en Shiny/R que muestra una lista de acciones del mercado americano y al ser seleccionada alguna de ellas, es decir el usuario interactua con la Aplicación Web, la aplicación (del lado del servidor) muestra un gráfico de precios de dicha acción utilizando el paquete quantmod.

Aplicación en dos archivos

Partiendo de la apliación que hemos construido, si queremos separar el código de la interfaz del usuario y el código del lado del servidor quedaría de la forma siguiente:

  • ui.R
library(shiny)

shinyUI(fluidPage(
  titlePanel("Mercados con R"),
  sidebarLayout(
    sidebarPanel("Seleccione la acción que desea consultar",
                 selectInput('accion', 
                             label = 'Acción', 
                             choices = c("Apple"="AAPL", "Cisco"="CSCO",
                                         "IBM"="IBM", "Facebook"="FB",
                                         "Twitter"="TWTR", "Microsoft"="MSFT",
                                         "Google"="GOOG"))),
    mainPanel("Gráfico de Acciones del Mercado de Valores Americano",
              h1('Gráficos de Precios'),
              p('A continuación se muestra la gráfica del precio de la acción seleccionada.'),
              plotOutput('grafico'))
  )
))
  • server.R
library(shiny)
library(quantmod)

shinyServer(function(input, output) {
  output$grafico <- renderPlot({
    stockdata <- getSymbols(input$accion, src="google", from = "2017-01-01",
                       to = "2017-08-18", auto.assign = FALSE)
    candleChart(stockdata, name=input$accion)
  })
})

Como se puede apreciar no hay muchas diferencias excepto por el uso de las funciones shinyUI() y shinyServer(), además ya no es necesario utilizar la función shinyApp().

Copyright © 2014-2018 Synergy Vision. Los artículos del Corpus se comparten bajo los términos de la licencia Creative Commons con Reconocimiento, Propósito no comercial, Compartir contenido similar, 4.0 Internacional (CC BY-NC-SA 4.0).

Citar el artículo.