Making a really simple web app in R

I made (now defunct) web app that displayed public data on monthly average food prices in New Zealand. The app was really simple — it just presented food items for selection from a menu of categories and showed some simple stats and a graph using the price data for a selected item.

The app was intended to be used on a phone in a context (shopping) where people don’t have much ability to concentrate. So it needed to be simple and fast. Since the app showed the same information for each item, I decided to use R to generate a whole bunch of static html files, one for each food item.

I briefly tried to use knitr and pandoc to produce the html files in R via a template, but they seemed to add a lot of unnecessary stuff to the html output and I didn’t have the patience to get things looking like I wanted. So I made my own quick and dirty “framework” for producing this app in R by generating html directly from the data.

Three functions

My “framework” is really just three simple functions that aid the process of generating html files via iterating over a dataset. It’s not particularly pretty but it seems to work.

First, output_html takes a character vector (content) and sandwiches it between a header and footer of static html. The header contains links to the CSS stylesheets, etc. The footer just closes the body and html tags, though it could contain other stuff.

output_html <- function(content, output_filename) {
  template_header <- read_file(paste0(template_dir, “header.html”))
  template_footer <- read_file(paste0(template_dir, “footer.html”))
  output <- paste(template_header, content, template_footer, sep = “\n”)
  write_file(output, paste0(html_dir, output_filename))
}

The idea is that you create content from a subset of a dataset (e.g. the price data for one food item), write the output to an html file, and repeat for the next subset.

The next function isbuild_content. This barely qualifies to be a function as it’s just a slightly modified paste() function. This allows us to use magrittr’s %>% operator to build up html content piece by piece in a slightly cleaner way than by using paste() directly.

build_content <- function(current = NULL, new) {
  return(paste(current, new, sep = “\n”))
}

So you can chain a bunch of build_content() calls together with %>% and have a kind of coherent way to generate html content from some data.

Finally, wrap_html_tag() takes a character vector and wraps an opening and closing html tag (e.g. <p> and </p>) around it, with an optional vector of parameters to add things like CSS classes. This too is just a fancy paste():

wrap_html_tag <- function(x, tag, params = NULL) {
  output <- paste0(“<”, tag)
  if (!is.null(params)) {
    output <- paste(output, paste(params, collapse = “ “))
  }
  output <- paste0(output, “>”, x, “</”, tag, “>”)
  return(output)
}

And that’s it really. The rest of the app just iterates through the food price dataset to produce static html for the menus and detail views using combinations of the functions above.

Making good CSS

CSS has always confused and frustrated me me. I found the Pure CSS modules helped a lot to make things look how I wanted on desktop and mobile browsers.

Back to home