Skip to main content

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>