Recreating a shiny app

Recreating a shiny app

Here we demonstrate how to reproduce a basic shiny application with ambiorix: a simple app which at the click of a button fits a polynomial to randomly generated data, this is visualised with plotly.

Shiny

library(shiny)
library(plotly)

ui <- fluidPage(
  h1("Shiny"),
  actionButton("randomize", "Randomize"),
  plotlyOutput("chart")
)

server <- function(input, output){
  output$chart <- renderPlotly({
    input$randomize

    df <- list(
      x = 1:100,
      y = runif(100)
    )

    model <- loess(y ~ x, data = df)
    augmented <- broom::augment(model)

    augmented %>% 
      plot_ly(x = ~x, y = ~y, type = 'scatter', mode = 'lines') %>% 
      add_lines(y = ~.fitted)
  })
}

shinyApp(ui, server)

The ui consists of a button and the plotlyOutput.

In the server we place input$randomize in the renderPlotly function so it retriggers that expression.

Ambiorix

One could reproduce this with ambiorix in numerous ways. It could be done à la shiny: using the websocket to send a message to the server when the plot is clicked and have the server respond with the chart configuration but we shall go a different way.

We can build an endpoint that returns the randomize loess and, in JavaScript bind the button to a function that fetches this endpoint and produces the chart.

The back can be fairly simple the homepage (/) sends an HTML file (which we’ll create right after this). We also create the endpoint that generates the random data, runs loess and sends a JSON response.

# app.R
library(ambiorix)

app <- Ambiorix$new()

# homepage
app$get("/", \(req, res){
  res$send_file("home.html")
})

app$get("/randomize", \(req, res){

  df <- list(
    x = 1:100,
    y = runif(100)
  )

  model <- loess(y ~ x, data = df)
  augmented <- broom::augment(model)

  data <- list(
    x = augmented[["x"]],
    y = augmented[["y"]],
    fitted = augmented[[".fitted"]]
  )
  res$json(data)
})

app$start()

Then in HTML we import plotly from the CDN in the head, add a button which runs the JavaScript function randomize() that fetches the data from the /randomize endpoint and generates the chart.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>  
</head>
<body>
  <h1>Ambiorix</h1>
  <button onclick="randomize()">Normalize</button>
  <div id="chart"></div>
  <script>
    randomize = function(){
      fetch("/randomize")
        .then(response => response.json())
        .then(data => {
          var trace1 = {
            x: data.x,
            y: data.y,
            type: 'line'
          };

          var trace2 = {
            x: data.x,
            y: data.fitted,
            type: 'line'
          };

          var data = [trace1, trace2];

          Plotly.newPlot('chart', data);
        });
    }
  </script>
</body>
</html>