Introduction to loon.shiny

Zehao Xu


Overview of the three packages



The shiny R package simplifies the creation of interactive analysis web pages.

A shiny application is composed of two components, a ui (user interface) and a server function. This ui/server pair are passed as arguments to the shinyApp function that creates a shiny app. The ui (user interface) creates the layout of the app, guiding its users about the analysis by determining the objects that appear and how they can be manipulated on such application. The server function reacts to modifications on the ui, defining the logic of the app. As the user interacts with the page, the server function reacts to make changes in the display.


The loon R package provides an interactive visualization toolkit for unconstrained, unscripted, and open-ended data exploration. It is intended for data analysts themselves.

An important part of loon’s interactivity is the loon inspector which can can make changes specialized to different loon plots. Typically, the loon inspector has a single instance. The inspector will adapt its display to whichever of the different base loon graphics (scatterplots, graphs, histograms, serial axe plots, etc) is its focus (e.g., the graphic display that last received a mouse or window focus event.

For loon users, it is a challenge to provide a curated analysis that is still somewhat interactive. Snapshots of different steps of the analysis are easily accommodated via RMarkdown, etc. but interaction is not.


Loon.shiny transforms loon widgets to appear (with their inspector) in a shiny web app.

The idea behind the implementation: In loon.shiny, loon widgets are transformed to static loonGrobs created by the R base grid package to provide low-level, general purpose graphics functions. Note that, a loonGrob contains all elements of a loon plot even some not drawn contents, i.e. deactivated elements, hidden layers. All these essential contents are stored inside an empty grob possessing the argument values necessary to draw them. When the server function is fired, the interactivity is realized by editing and redisplaying these loonGrobs.

Basic Usage

Consider the classic iris data set.

# Loon scatterplot
p <- with(iris,
  l_plot(x = Petal.Width, 
         y = Sepal.Width, 
         color = Species)
# Modify glyph to radial axes glyph.
p['glyph'] <- l_glyph_add_serialaxes(p, data = iris)
# Fit a linear regression on each group (species)
for(s in unique(iris$Species)) {
  # sub data set
  subdata <- iris %>%
    filter(Species == s)
  # fitted line
  fit <- lm(Sepal.Width ~ Petal.Width, data = subdata)
  x <- subdata$Petal.Width
  pred <- predict(fit, interval = "confidence")
  ord <- order(x)
  # Loon pipe model (connected with %T>%)
  # Check ```help(`%T>%`)``` for more details
  p <- p %T>% 
    # fitted line
    l_layer_line(x = x[ord], 
                 y = pred[, "fit"][ord], 
                 color = "firebrick",
                 linewidth = 1.5,
                 index = "end") %T>%
    # confidence interval
    l_layer_line(x = c(x[ord], rev(x[ord]), x[ord][1]),
                 y = c(pred[, "lwr"][ord], rev(pred[, "upr"][ord]), pred[, "lwr"][ord][1]),
                 color = "grey50",
                 linewidth = 2,
                 index = "end")
loon.shiny(p, plotRegionWidth = "400px")

The left panel is a scatterplot which receives mouse can be utilized for direct manipulations. The right panel is an inspector, mainly for indirect manipulations. Compared with the loon one, it is different that is composed of a world view window and six buttons (Plot, Linking, Select, Modify, Layer and Glyph). Each channel will be popped up by pressing the corresponding button. Due to very limited layout space, such design can make the inspector look fresh.

There are several noticeable difference here:

Compound Plots

Arbitrarily many plots may be created and linked in loon. Package loon.shiny successfully inherits such facility.

Following graph illustrates compound plots. The three graphs are histogram of variable Sepal.Length, scatterplot of Sepal.Width versus Sepal.Length and swapped histogram of variable Sepal.Width (from top to bottom, from left to right). They are colored by species and linked each other.

p1 <- l_plot(iris, linkingGroup = "iris", 
             showLabels = FALSE)
p2 <- l_hist(iris$Sepal.Length, linkingGroup = "iris",
             showLabels = FALSE, 
             showStackedColors = TRUE)
p3 <- l_hist(iris$Sepal.Width, color = iris$Species, 
             linkingGroup = "iris", 
             showLabels = FALSE,  swapAxes = TRUE, 
             showStackedColors = TRUE)
loon.shiny(list(p1, p2, p3), 
           layout_matrix = matrix(c(2,NA,1,3), nrow = 2, byrow = TRUE),
           plotRegionWidth = "400px")

Inspector Activation

Loon inspector is a singleton which means there is only one instance of it. Each kind of graphics (scatterplots, graphs, histograms, serial axes plots, etc) has its own specified inspector. The shown one depends on which display receives the last mouse gesture input or window focus event. However, such design in shiny can be very complex. Instead, we build a navigation bar menu. The inspector can be switched by toggling tabpanel on the bar menu or the last mouse gesture (<double click>) input.


If we brush on any of these plots, the corresponding elements on the rest will be highlighted instantaneously. Linking status can be checked via linking panel.