“Exposure, the effective laying open of the data to display the unanticipated, is to us a major portion of data analysis.” … John Tukey and Martin Wilk (1966)
Because loon is an interactive visualization system, this introduction is meant as a “hands on” tutorial. Not all interactions are from the command line (programmatic). Suggestions for interactions will also be given and questions that draw attention to the outcome of interactions.
After completing the tutorial, there are numerous other examples of using loon which can be explored. These include
l_plot()
are described
in the help topic ?l_plot_arguments
R
help(package = "loon")
pages for
loon
, or alternatively online via as
l_web()
demo(package = "loon")
. These are especially useful because
the source code for creating them appears in the console, andl_help()
or
R
manual only as l_web()
.Here, we will walk through some of the basic functionality.
l_plot()
the basic loon
plotBegin with a simple scatterplot of the quakes
data from
R
l_plot(x = quakes$long,
y = quakes$lat,
xlabel = "longitude",
ylabel = "latitude",
title = "Tonga trench earthquakes")
This prints the above information on the loon plot (more on this later) and causes two windows to appear.
One is the scatterplot:
and the other a “loon inspector”:
For the moment we’ll focus mainly on the scatterplot.
The loon scatterplot is highly interactive and can be directly manipulated using the mouse. Several interactions are immediately available.
In what follows, images of a two button mouse (left is primary, right secondary) with a scroll wheel will be used to indicate the interaction. The colour red indicates selection, arrows and double images suggest movement, and any modifier keys are shown in the body of the mouse.
To pan the plot, select the plot interior with the right (or secondary) mouse button and move the mouse (with the button still down). The direction of panning can be constrained by holding down the named modifier keys while panning.
Try it. Select anywhere on the scatterplot and move it
Question: How did the inspector change in response to each movement?
Reproduce these movements on the smaller “World View” plot appearing at the top of the inspector.
How does the larger scatterplot change?
Another way to dynamically focus on different parts of the plot is by zooming, using scrolling:
To try it, note that there is a small cluster of 16 points towards the top left of the scatterplot.
On the scatterplot,
zoom in and out and move the plot around until only these 16 points appear in the scatterplot
use the restricted horizontal and vertical zooming so that the same 16 points occupy as much of the scatterplot’s space as possible
Question: How has the inspector changed in response?
On the inspector click on the button titled plot
. What
happened?
Using zooming and panning on the “World View”
There are two ways to directly select points on the scatterplot using the mouse: either by selection (one at a time or multiple selections) or by “sweep selection” as shown below:
To try this out, on the scatterplot (which should contain only 16 points)
Question: How has the inspector changed?
Now try a holding the left mouse button down and move the mouse.
This is called sweeping or sweep selection and allows us to sweep out a contiguous area of the plot.
Check: The 16 points should now be separated by colour into 4 groups and by glyph shape into 2 groups.
Question: How has the inspector changed?
You will have already discovered how to colour selected points from the inspector. You can now use the inspector to select points by colour:
By the above experimentation, you will have already discovered how the inspector is used to change the loon plot.
For example, try checking the “guides” box on the inspector to place a background grid of guide lines on the loon plot. Unchecking removes the guide lines.
The loon inspector consists of several component pieces.
At the top is the “World View” which shows a miniature version of the whole of the current plot, what is displayed there, and what is active.
Below the “World View” are a few tabs. The default (and most used) one is the “Analysis” tab where common interactions are separated into three regions: the “Plot”, the “Select”, and the “Modify” systems.
Try (in order) the following interactions between the inspector and the plot:
Check: You should have a scatterplot of open circles with three clusters of points in red, blue, and orange
You should have a scatterplot of open circles with three clusters of points in red, blue, and orange.
Use the functionality of the loon inspector to (in order)
You should now have four different coloured groups or clusters.
For fun, in the inspector
<Shift>
keyQuestion: What is going on? When might this functionality be useful?
When done, turn the selection back to the defaults:
That is,
Shift selection works with any mix of
Exercise: Try out different combinations of the above selections.
For a variety of reasons, we sometimes want to (temporarily) move points in a scatterplot.
From the inspector:
move
modifications on the configuration of the selected
pointsFrom the scatterplot, selected points may be moved by hand
<Ctrl>-<Left-button>
<Shift><Ctrl><Left-button>
For example:
More colours can be added directly by clicking on the +
or the +5
in the colour modification section of the
inspector.
+5
twice adds 10 new coloursThe loon system default list of colours get be found programmatically:
[1] "gray60" "#A6CEE3" "pink" "#B2DF8A" "#FDBF6F" "#FFFF99"
Note:
loon colours are 6 hexadecimal digits in length and can be a
named R
colour
being constrained to tcl/tk colours, no alpha level is available at this time in loon
R
has a similar set of base colours that is default
for all its graphics devices:
[1] "black" "#DF536B" "#61D04F" "#2297E6" "#28E2E5" "#CD0BBC"
like the R
palette, the loon inspector palette
persists.
At the beginning of a loon session (that is,
immediately after executing library(loon)
) you might choose
to change the default palette for the inspector to something that suits
your tastes/problem.
Note: There may be unintended side effects to changing the inspector colours after a plot (and hence the inspector) has been created so this should be avoided.
A variety of functions exist to change an inspector’s palette of colours:
l_setColorList_baseR() # base R palette
l_setColorList_ColorBrewer("Set2") # colorblind friendly choice from ColorBrewer
l_setColorList_hcl(luminance = 80) # set of hcl colours
l_setColorList_ggplot2() # ggplot2's palette
l_setColorList_loon() # default loon palette
l_setColorList(l_colRemoveAlpha(rainbow(5))) # any set of colours without alpha
To change the palette
l_setColorList_loon()
returns the inspector to the
default loon colour palette.
The plot itself is a (tcl) data structure and can be assigned to an
R
variable.
Either at construction (the preferable way):
# loon graphics (note that the result is assigned to p)
p <- l_plot(x = quakes$long, y = quakes$lat,
xlabel = "longitude", ylabel = "latitude",
title = "Tonga trench earthquakes")
or, if (as we did) you forgot to do that or reassigned something else
to that variable (more likely), by accessing the plot from its
tcl
string:
Note that this string ".l0.plot"
appears on the right
side of the window title of an l_plot
.
Do this and assign your plot to p
. You might have to
look at the window to get the string if you have created more than one
l_plot()
.
Were we to now print p
we get the string name of the plot, but with a class attribute. This
is the value of p
and provides us access
to a very rich data structure, but one whose values reside in
tcl
.
For example, we can access this value and, like plots from
lattice
or ggplot2
produce a grid
data structure that can then be displayed as a grid
graphic
in R
.
The simplest way to achieve this is to use the generic R
function plot()
Note that this will always reflect the current state of the loon plot. In this way, you can get snapshots of the loon plot after any interaction.
Exercise: Try this. Change p
by direct
manipulation in loon
and repeat.
This allows the visual representation of a loon
plot to
be displayed at any time.
There are names
associated with a loon plot indicating
its contents or states:
[1] "glyph" "itemLabel" "showItemLabels" "linkingGroup" "linkingKey" "zoomX"
These features of p
can be directly accessed the
[]
function.
For example,
[1] TRUE
A more meaningful example might be identify groups with the colours
of the points.
This could be done simply as follows
unique_cols <- unique(p['color'])
group1 <- p['color'] == unique_cols[1]
# Number in group 1 (e.g. as you might have -- here from saved colours)
sum(group1)
lat long depth mag stations
1 -20.42 181.62 562 4.8 41
2 -20.62 181.03 650 4.2 15
4 -17.97 181.66 626 4.1 19
5 -20.42 181.96 649 4.0 11
10 -17.47 179.59 622 4.3 19
11 -21.44 180.69 583 4.4 13
Alternatively, a function could be written to save the groups as a list of logical vectors (one for each group):
getGroups <- function(loonplot){
# make sure it is an "l_plot"
if (!is(loonplot, "l_plot")) stop("loonplot must be an l_plot")
# use color to identify groups
unique_cols <- unique(loonplot['color'])
lapply(unique_cols,
FUN = function(col){loonplot['color'] == col}
)
}
myGroups <- getGroups(p) # returns groups identified by unique colour in p
nGroups <- length(myGroups) # number of groups
group1 <- myGroups[[1]] # each group is an element of the list myGroups
Similarly, other point symbol characteristics
(e.g. size
, glyph
) might be used to define
groups. This is particularly handy when these are first determined
interactively.
In addition to accessing the state values of a loon plot using
[]
, its values may also be set using []
. For
example, try these:
p["showGuides"] <- TRUE
p["size"] <- sample(1:30, size = length(p["x"]), replace = TRUE)
for (i in 1:length(myGroups)) {
p["selected"] <- myGroups[[i]]
Sys.sleep(1)
}
p["selected"] <- FALSE
# something a little more involved for up to 6 groups
myCols <- c("firebrick", "steelblue", "purple",
"orange", "grey10", "grey80")
for (i in 1:length(myGroups)) {
p["color"][myGroups[[i]]] <- myCols[i]
}
# something crazy
for (j in 1:10) {
p["xTemp"] <- p["x"] + runif(length(p["x"]), min = -0.5, max = 0.5)
Sys.sleep(0.1)
}
# putting locations and size back
p["xTemp"] <- p["x"]
p["size"] <- 4
loon
plots are actually a little richer still. The
scatterplot is only one possible layer in a plot. It could have many
more, each layer having different geometric objects.
For example, we can add a map to the current loon plot
p
.
First get the relevant map:
It is added as a “layer” to the loon plot
l_layer(p, NZFijiMap,
label = "New Zealand and Fiji",
color = "forestgreen",
index = "end")
loon layer "New Zealand and Fiji" of type polygons of plot .l0.plot
[1] "layer0"
Try this out.
As can be seen in the world view, much of the map is outside of the plot display (shown as the black-bordered rectangle in the world view).
Now play with the scaling buttons in the loon inspector.
Adding the map allows us to see the effect of all three plot scaling choices available in the inspector.
The effect is best seen on the world view:
Note that the plot in the world view matches that of the actual plot. Also the aspect ratio changes with the scaling.
The map is added as a layer, which can be seen by selecting the “Layers” tab in the inspector:
This allows a lot of interaction with the layers - for example changing their display order, making some of them invisible, grouping layers, and so on.
l_plot()
is like base graphics
plot()
loon
’s l_plot()
syntax
intentionally resembles that of plot()
from the base graphics
package:
# Base graphics
plot(x = quakes$long, y = quakes$lat,
xlab = "longitude", ylab = "latitude",
main = "Tonga trench earthquakes")
# loon graphics
l_plot(x = quakes$long, y = quakes$lat,
xlabel = "longitude", ylabel = "latitude",
title = "Tonga trench earthquakes")
The arguments to l_plot()
provide initial values to each
named state. Note that the argument names in l_plot
are
slightly different.
In result, however, loon plots are quite different
l_plot()
returns a data structure;
plot()
does not
loon
plot is highly interactive
In loon, the function plot.loon()
is a
method of the base plot()
generic function
that turns the loon plot (as the first argument of
plot.loon()
) into a grid object and plots it on the current
R
graphics device.
l_hist()
the loon
histogramAs seen earlier, the quakes
data has some other variates
in addition to the latitude and longitude of the quakes.
Before starting, make sure that you have the four groups coloured in
the loon plot p
as described earlier. If you don’t, then
colour them again now.
Let’s consider a histogram of the depth
of each
earthquake.
Note that the inspector has changed. There is a different inspector for each type of base loon plot.
Exercise:
yshows: density
Now that we have both a scatterplot and a histogram, we can explore one of the most important features of an interactive data visualization system like loon.
linkingGroup
The principal feature of loon plots which effect the linking of
displays is the setting of a common linkingGroup
.
On the histogram inspector, where it says linking group, select the text “none” and replace it with “quakes”
On the scatterplot inspector, if you do the same you will now be prompted to either “push” or “pull”. Select “push”.
NOTE: Programmatically, we might have tried to set the linking group directly on the plot as
but this would have resulted in an error. The
problem is that the synchronization must be set at the same time to
determine where the linked states are to be drawn from. To effect this,
the loon command l_confiure()
must be used whenever
two or more states are to be set simultaneously. The
correct programmatic setting of the “linkingGroup” is
l_configure(h, linkingGroup = "quakes", sync = "push")
l_configure(p, linkingGroup = "quakes", sync = "pull")
This causes h
to push its linked states to the “quakes”
group and p
to pull them from the “quakes” group. (In this
example, “pull” could have been used in both cases and is generally
recommended.)
brush the scatterplot and observe the effects in the histogram
brush the histogram and observe the effects in the scatterplot
could also set colours programmatically on the histogram. Here we colour the histogram bars so that those earthquakes that are deepest are darkest.
Arbitrarily many plots may be created and linked in loon.
Consider, for example, adding two more histograms to the same
linkingGroup
. Note that the linking is done at creation and
that the synchronization is by default a “pull”.
h_mag <- l_hist(x = quakes$mag,
linkingGroup = "quakes",
showStackedColors = TRUE,
yshows = "density",
xlabel = "magnitude")
h_stations <- l_hist(x = quakes$stations,
linkingGroup = "quakes",
showStackedColors = TRUE,
yshows = "density",
xlabel = "Number of stations reporting")
Brush to show the relationship between magnitude of the earthquake and the number of stations reporting.
Alternatively, we could look at a linked scatterplot of these two
variates and explore their relationship conditional on
depth
p_mag_stations <- l_plot(x = quakes$mag,
y = quakes$stations,
showGuides = TRUE,
glyph = "ccircle",
linkingGroup = "quakes",
xlabel = "Magnitude",
ylabel = "Number of stations reporting")
Brushing any one of these plots will cause the other plots to highlight in response.
Note that selection effectively shows the relations in one plot conditional upon the values actively being selected (e.g. brushed) in another.
linkingKey
Observations in a loon
plot are uniquely identified (for
the purpose of linking) by their linkingKey
. Pardon the pun
but this is the key to linking in loon
.
For the most part, the default linking is all that you ever need
do.
Trouble may arise, however, if you want to link two different plots that
were created with different data frames whose rows do not match row for
row. For example, one data.frame
might be a re-ordering of
the rows of the other. Or, it might be a subset of the rows of the
other.
In either case, to have linking work properly the
linkingKey
of the plots associated with the two data frames
need to be managed.
For example,
new_order <- sample(1:nrow(quakes), nrow(quakes), replace = FALSE)
some_quakes <- sample(1:nrow(quakes), 100, replace = FALSE)
quakes_linkingKey <- p["linkingKey"]
p_new <- with(quakes[new_order, ], l_plot(long, lat, title = "quakes reordered",
linkingGroup = "quakes", linkingKey = quakes_linkingKey[new_order]))
p_subset <- with(quakes[some_quakes, ], l_plot(long, lat, title = "quakes reordered",
linkingGroup = "quakes", linkingKey = quakes_linkingKey[some_quakes]))
The new plots p_new
and p_subset
will link
correctly with all the rest.
Rather than the default values, the linkingKey
can be
any vector of unique strings used in any newly created plot as above. Of
course, not using the default linking keys from loon
may
require a little more care in management from the user.
l_plot3D
Given that the quakes
data has three spatial dimensions
(long
, lat
, and depth
), it would
be natural to view this in a three dimensional scatterplot.
# First, scale the data
scaled_quakes <- l_scale3D(quakes)
p_mag_stations <- l_plot3D(x = scaled_quakes$long,
y = scaled_quakes$lat,
z = scaled_quakes$depth,
showGuides = TRUE,
linkingGroup = "quakes",
title = "Three dimensional plot of quakes")
Select the plot, type r
to turn on the
rotation mode
. Press the down arrow on the keyboard until
the darkest points (deepest quakes) are at the bottom of the display.
Press r
again to turn off the rotation mode.
Selecting the plot, the key r
toggles the rotation mode;
arrow keys rotate the plot vertically and horizontally. In
rotation mode
the plot may also be rotated free hand using
the mouse. When rotation mode
is toggled off (with the key
r
), the plot can again be brushed et cetera as with any
l_plot
. See help("l_plot3D")
for more
details.
NOTE Many methods exist for visualizing higher
dimensional data in loon
. For e.g. see
help("l_navgraph")
, help("l_pairs")
, or
help("l_serialaxes")
. See also the online manual
l_web()
.
Miscellaneous other topics on and sources of working and programming
with loon
.
Being able to get and set the plot contents means that it is possible
to capture different plot states as grobs
. There are a
variety of ways to see how you might put loon
to use.
There are of course many smaller examples available through the
loon
’s R
documentation available via
and more complex examples and more general discussion via
loon
’s online web documentation
Other vignettes have been developed to cover a range of topics. These currently include:
An example exploratory analysis: “Visible minorities in Canadian cities” available via
This illustrates a variety of loon
features including
map layers, parallel coordinate axes, and radial axes glyphs in the
context of an exploratory analysis of the distribution of visible
minorities in 33 Canadian cities.
New interactive graphics in loon
in a teaching
example: “Smoothers and Bone Mineral Density” available via
This illustrates how to create new interactions in loon
through more general bindings. This is done by developing a teaching
tool for explaining how smoothing works. The example data set is
bone
from the loon.data
package.
Some suggestions on integrating loon
plots into an
Rmarkdown document: “Loon in RMarkdown” via
There are numerous demos in loon whose source code might be examined
for more examples of using loon
. To see them all
The range is quite broad. For example,
### teaching demos
demo("l_regression", package = "loon") # lots using the Old Faithful geyser
demo("l_regression_influential", package = "loon") # change points change the regression fit
### gapminder
demo("l_us_and_them", package = "loon") # basic demo
demo("l_us_and_them_slider", package = "loon") # year selected on a slider
demo("l_us_and_them_choropleth", package = "loon") # world map and linked with a scatterplot
### the spatial package sp
demo("l_polygons_sp", package = "loon") # layer polygons with class sp
### layering and custom layouts
demo("l_layers") # demonstrate layer types
demo("l_layout") # custom layout widgets
demo("l_widgets") # inspector and plot in one window
### novel brushing and linking
demo("l_knn") # brushing by k nearest points in some subspace
demo("l_us_and_them_choropleth") # many to one linking
### high dimensional data and dimensionality reduction
demo("l_ng_images_frey_LLE") # navigation graphs, image data, LLE
demo("l_ng_dimred") # comparing dimension reduction methods
The code that appears in the console after the demo can be examined
and reused to create your own loony loon
code.
zenplots
This package is available on CRAN.
Provides a means for compact layout of alternating 1d
(e.g. histograms) and 2d (e.g. scatterplots) plots. In will layout base
graphics
plots, grid
graphics plots, and
loon
plots.
It is similar to pairs
plots but allows many many more
plots to be displayed. From the introductory vignette:
“A zenplot can show the same information as a pairs plot but with two important display differences.
First, the matrix organization of the pairs layout is replaced by the “zig-zag” layout of zenplot. Second, the number of plots produced is about half that of a pairs plot allowing each plot in a zenplot to be given more visual space.”
loon
extensions -
loon.<specialty>
packagesThere are/will be other packages available which build on
loon
. Those developed by us are typically prefixed with
loon
(e.g. loon.ggplot
)
These will typically be on CRAN when ready, but development versions
are accessible from our great northern diver
github
repositories. For example,
There you can see related packages as well as what is coming up.
Graphics in the grid
package are built up from graphical
objects or grobs
.
In loon
, the functions grid.loon()
and
loonGrob()
construct grobs
from loon plots
which can then be used as any other grob
in
grid
For example, when transformed to grid
, the loon plot
p
structure becomes a gTree
in
grid
.
This simply produces the grid data structure corresponding to the
current state of the loon plot p
, as can be seen from
listing its contents:
The grob gp
could now be used with all the functionality
of the grid
package.
Note that all of the elements of a loon plot appear in the grob,
either explicitly or, if they were not drawn in the loon plot, as an
empty grob
containing the relevant arguments to drawing
them.
Another function in loon to help that is the grid.loon()
function
will display p
as a grid
graphic … and all
that entails.