Consider the following artificially generated dataset:
<- data.frame(A = c(19, 19, 25, 62, 34,
data 58, 62, 40, 24, 60,
70, 40, 40, 34, 26),
B = c(68, 63, 63, 13, 55,
78, 14, 14, NA, 28,
NA, 55, 57, 40, 78) )
There are 15 observations in the dataset; variable A
is complete (has no missing values), whereas variables B
and C
are missing 2 and 0 observations, respectively.
ggplot
to loon
transformationggplot
and its statesBegin with a ggplot
defined using the interactive grammar extension:
<- ggplot(data,
ggp mapping = aes(x = A, y = B)) +
ggtitle("Some title") +
geom_point(color = "grey", size = 5) +
linking(linkingGroup = "my plots")
plot(ggp)
Information on the ggplot
corresponding to loon
states is had using ggplot_build()
# get the ggplot data corresponding to loon "states"
<- ggplot_build(ggp)$data[[1]]
ggp_states
ggp_states#> x y PANEL group shape colour size fill alpha stroke
#> 1 19 68 1 -1 19 grey 5 NA NA 0.5
#> 2 19 63 1 -1 19 grey 5 NA NA 0.5
#> 3 25 63 1 -1 19 grey 5 NA NA 0.5
#> 4 62 13 1 -1 19 grey 5 NA NA 0.5
#> 5 34 55 1 -1 19 grey 5 NA NA 0.5
#> 6 58 78 1 -1 19 grey 5 NA NA 0.5
#> 7 62 14 1 -1 19 grey 5 NA NA 0.5
#> 8 40 14 1 -1 19 grey 5 NA NA 0.5
#> 9 24 NA 1 -1 19 grey 5 NA NA 0.5
#> 10 60 28 1 -1 19 grey 5 NA NA 0.5
#> 11 70 NA 1 -1 19 grey 5 NA NA 0.5
#> 12 40 55 1 -1 19 grey 5 NA NA 0.5
#> 13 40 57 1 -1 19 grey 5 NA NA 0.5
#> 14 34 40 1 -1 19 grey 5 NA NA 0.5
#> 15 26 78 1 -1 19 grey 5 NA NA 0.5
Note that some of the x
and y
values are NA
, representing missing values.
loon
plot and its statesNow construct the loon
plot from this ggplot
:
<- loon.ggplot(ggp)
lp plot(lp)
The loon
plot looks slightly different:
loon
plot.Plots in loon
have more constrained layouts than those in ggplot2
, since focus is primarily on interactive as opposed to publication quality graphics.
Some differences (e.g., colour) are also because loon
is based on Tcl
for drawing primitives.
Plot states in loon
are accessible using []
and the name of the state. Values are assigned in the same way. Names of interactively changeable states in loon
are
names(lp)
#> [1] "glyph" "itemLabel" "showItemLabels" "linkingGroup"
#> [5] "linkingKey" "zoomX" "zoomY" "panX"
#> [9] "panY" "deltaX" "deltaY" "xlabel"
#> [13] "ylabel" "title" "showLabels" "showScales"
#> [17] "swapAxes" "showGuides" "background" "foreground"
#> [21] "guidesBackground" "guidelines" "minimumMargins" "labelMargins"
#> [25] "scalesMargins" "x" "y" "xTemp"
#> [29] "yTemp" "color" "selected" "active"
#> [33] "size" "tag" "useLoonInspector" "selectBy"
#> [37] "selectionLogic"
# and accessed with [] as in
"title"]
lp[#> [1] "Some title"
(See also ?l_info_states
.)
Some, like x
, y
, and color
, are n-dimensional states whose values correspond to those on individual observations. These may be changed using the [] <-
notation as well.
Because loon
plots exclude observations missing values in any its n-dimensional states, the loon
plot will have fewer observations than the corresponding ggplot
, even though the same number of points may be plotted. The actual number of observations in the loon
plot is
"n"]
lp[#> [1] 13
which is less than the number of observations recorded in the ggplot
structure (namely nrow(ggp_states) =
15).
Differences between ggplot
structure and loon
plot structure (and how these affect the visualizations) is worth exploring in a little more detail. A better understanding will be helpful when transforming back and forth between the two.
In R
the point symbol plotted is associated with a numerical code pch
. In loon
the point symbol is a glyph, identified by a string.
$shape
ggp_states#> [1] 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19
"glyph"]
lp[#> [1] "circle" "circle" "circle" "circle" "circle" "circle" "circle" "circle"
#> [9] "circle" "circle" "circle" "circle" "circle"
As with other plot “states”, there is not always a glyph
in loon
that matches a pch
in R
. Values of pch
with no counterpart in loon
will map to the default glyph
in loon
.
Size is another plot state that differs between ggplot
and loon
.
$size
ggp_states#> [1] 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
"size"]
lp[#> [1] 26.78116 26.78116 26.78116 26.78116 26.78116 26.78116 26.78116 26.78116
#> [9] 26.78116 26.78116 26.78116 26.78116 26.78116
The point size
in loon
identifies the approximate area of the point symbol, so when transforming from ggplot
to loon
, the size
parameter of the ggplot
is transformed to an integer value in loon
that tries to match the area of the point in ggplot
.
Comparing the plots, the points are slightly different "grey"
in one plot than in the other.
This is because the two plots have different values stored as their colour state:
$colour
ggp_states#> [1] "grey" "grey" "grey" "grey" "grey" "grey" "grey" "grey" "grey" "grey"
#> [11] "grey" "grey" "grey" "grey" "grey"
"color"]
lp[#> [1] "#808080808080" "#808080808080" "#808080808080" "#808080808080"
#> [5] "#808080808080" "#808080808080" "#808080808080" "#808080808080"
#> [9] "#808080808080" "#808080808080" "#808080808080" "#808080808080"
#> [13] "#808080808080"
First, there is a slight difference between what R
regards as "grey"
and what Tcl
(used by loon
) regards as "grey"
. Several other named colours in R
also differ slightly from those in Tcl
and hence in loon
. R
colours whose name is the same as that in Tcl
but whose colour is different are only the following: (See ?tkcolors
in loon
for more information.)
Second, loon
plot colour values are strings of twelve hexadecimal digits, as in tk
(e.g., see ?tkcolors
); in contrast, the ggplot
are either strings corresponding to the named R
colours (see ?grDevices::colors
in R
) or to six hexadecimal digits (two for each of the red, green, and blue components).
Twelve hex digit colours are turned into six hex digits using the loon
function hex12to6()
. To convert the R
named colours to six hex digits, the following function can be used.
<- function(x) {
tohex sapply(x, function(xi) {
<- as.vector(col2rgb(xi))
crgb rgb(crgb[1], crgb[2], crgb[3], maxColorValue = 255)
})}
So, comparing the two "grey"
colours, the ggplot
has the R
hex colour tohex("grey") =
#BEBEBE and the loon
plot has Tcl
hex colour (converted to hex 6) hex12tohex6(lp["color"][1]) =
#808080, which are clearly different RGB values.
The loon
plot does not include the missing data
nrow(ggp_states) == lp["n"]
#> [1] FALSE
# Compare
$y
ggp_states#> [1] 68 63 63 13 55 78 14 14 NA 28 NA 55 57 40 78
"y"]
lp[#> [1] 68 63 63 13 55 78 14 14 28 55 57 40 78
Note that, absent the missing NA
s, the order of the points is identical.
Default linking keys in loon
are from "0"
to "n-1"
where "n"
is the number of rows in the original data set.
Here nrow(data) =
15. Note that this "n"
is not the number of points actually plotted because loon
drops the missing data, unlike ggplot
.
The linking keys reflect this missingness:
"linkingKey"]
lp[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
which is missing "8"
and "10"
. Note also that lp["n"] =
13 is the number of points plotted in the loon
plot.
Some care needs to be taken when dealing with linking, especially when there is missing data.
See the vignette Linking and the loon
vignette Logical Queries for more information.
loon
to ggplot
transformationA ggplot
from the loon
plot will not have access to the original information.
<- loon.ggplot(lp)
ggp_lp_1 ggp_lp_1
Note that, though a ggplot
, the position of the title is now centred. This is because the objective of the transformation is to create a ggplot
that looks as much like the original loon
plot as possible.
ggplot
statesTo try to reflect the look of the loon
plot, the states of the ggplot
are different from those of the original ggplot
ggp
.
<- ggplot_build(ggp_lp_1)$data[[1]]
ggp_lp_1_states
ggp_lp_1_states#> colour size x y PANEL group shape fill alpha stroke
#> 1 #808080 5 19 68 1 1 19 NA NA 0.5
#> 2 #808080 5 19 63 1 1 19 NA NA 0.5
#> 3 #808080 5 25 63 1 1 19 NA NA 0.5
#> 4 #808080 5 62 13 1 1 19 NA NA 0.5
#> 5 #808080 5 34 55 1 1 19 NA NA 0.5
#> 6 #808080 5 58 78 1 1 19 NA NA 0.5
#> 7 #808080 5 62 14 1 1 19 NA NA 0.5
#> 8 #808080 5 40 14 1 1 19 NA NA 0.5
#> 9 #808080 5 60 28 1 1 19 NA NA 0.5
#> 10 #808080 5 40 55 1 1 19 NA NA 0.5
#> 11 #808080 5 40 57 1 1 19 NA NA 0.5
#> 12 #808080 5 34 40 1 1 19 NA NA 0.5
#> 13 #808080 5 26 78 1 1 19 NA NA 0.5
<- loon.ggplot(ggp_lp_1) lp_ggp_lp_1
Perform some interactive changes, including selecting some points
<- lp["x"] > 50 &lp["y"] > 13
selection "selected"] <- selection
lp[<- lp["x"] == 34
colorMeRed "color"][colorMeRed] <- "red" lp[
loon.ggplot()
Linking problems can arise whenever a ggplot
constructed from a loon
plot is then made interactive again.
Suppose a loon
plot, like lp
, is turned into a ggplot
(typically, after some interactive changes) via loon.ggplot()
, and the resulting new ggplot
is then itself turned into another interactive plot. The new interactive plot will not necessarily share the same linking information as the original.
This is because the second interactive plot will have the default values of linkingGroup
, linkingKey
and linked display states; these values are lost in the transfer from the first interactive plot to the ggplot
. That is,
the linking group is not automatically carried over to the second interactive plot
the linked states are not automatically carried over to the second interactive plot
the default linking keys in the second interactive plot are "0"
, …, "n-1"
where n
is the number of observations that were displayed in the first plot.
So, provided the first interactive plot has the default linking keys (and was built with complete data; i.e., no data was missing at creation), then the linking keys will match.
An important special case is when some observations were selected in the first interactive plot at the time the ggplot
is created. In this case, the linking keys will typically not match.
For example,
# Get a ggplot from the loon plot
<- loon.ggplot(lp) ggp_lp
The interactive lp
and the new ggplot
ggp_lp
appear as follows. The left plot, lp
, is an interactive loon
plot and the magenta points are selected. The right plot, ggp_lp
, is a static ggplot
which has no selected
state and the magenta points are simply points having that colour (and appear as that in the ggplot
legend).
In an interactive plot, selected points are visually emphasized in two ways:
When transferring that to a ggplot
, the selected points appear with the highlight colour and the data order is changed in the ggplot
so that they appear on top of all other points in the display. If, instead, the argument selectedOnTop = FALSE
is given to loon.ggplot()
call, then the order of points will not be changed in the ggplot
. This is strongly recommended whenever the ggplot
will later be turned into an interactive plot; this will allow the linking to match more easily with the original interactive plot.
To see the effect of this (and of missing values) on linking, suppose an interactive plot is created from the ggplot
ggp_lp
:
# The loon plot from the resulting ggplot
<- loon.ggplot(ggp_lp) lp_ggp_lp
Compare the linking keys of this plot with the original:
# The original loon plot has linking keys
"linkingKey"]
lp[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
# And the loon plot from the derived ggplot
"linkingKey"]
lp_ggp_lp[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12"
Clearly, these are not the same and will match observations correctly ("0"
to "7"
), some incorrectly ("9"
, "11"
, and "12"
), and some not at all ("8"
, "13"
, and "14"
).
The difference is that lp
was created with data missing values corresponding to the missing linking keys "8"
and "10"
. This information was not available on the ggplot
ggp_lp
so that the new loon
plot would be created with the default values "0"
to "12"
. The result is that some points will be wrongly linked between lp
and lp_ggp_lp
.
The selected points in lp
(highlighted magenta) will cause reordering in ggp_lp
and hence in lp_ggp_lp
. This too will cause problems in linking and other states of the new lp_ggp_lp
. For example, the two point orders can be seen in the respective values of their "x"
:
# The original point order
"x"]
lp[#> [1] 19 19 25 62 34 58 62 40 60 40 40 34 26
# The new plot's order
"x"]
lp_ggp_lp[#> [1] 19 19 25 62 34 40 40 40 34 26 58 62 60
This makes problems for matching the correct observations.
Other states are also changed because of the transition from loon
plot to ggplot
to loon
plot. In particular, the "color"
and "selected"
states will not match.
# Original selected
"selected"]
lp[#> [1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE
#> [13] FALSE
# the new plot has nothing selected
"selected"]
lp_ggp_lp[#> [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [13] FALSE
This is for two reasons. First the selected points of lp
changed to colour in ggp_lp
and so the selected points from lp
could not be transferred to lp_ggp_lp
. The colours in lp_ggp_lp
will not match those of. Second, the new plot has not (yet) joined the same linking group as the original.
# Original selected
"color"]
lp[#> [1] "#808080808080" "#808080808080" "#808080808080" "#808080808080"
#> [5] "#FFFF00000000" "#808080808080" "#808080808080" "#808080808080"
#> [9] "#808080808080" "#808080808080" "#808080808080" "#FFFF00000000"
#> [13] "#808080808080"
# the new plot has nothing selected
"color"]
lp_ggp_lp[#> [1] "#808080808080" "#808080808080" "#808080808080" "#808080808080"
#> [5] "#FFFF00000000" "#808080808080" "#808080808080" "#808080808080"
#> [9] "#FFFF00000000" "#808080808080" "#FFFF0000FFFF" "#FFFF0000FFFF"
#> [13] "#FFFF0000FFFF"
When observations are also highlighted in the original loon
plot, as in lp
, a little more care needs to be taken with respect to the linking keys. The problem is that in constructing the ggplot
, the data has to be reordered to ensure that the selected highlighted points appear on top of the other points in the ggplot
.
Care needs to be taken to manage the linking keys when moving from the static ggplot
to the interactive loon
plot. This information can be added when the interactive plot is created, as arguments to loon.ggplot()
as follows.
# Add the linking information when creating the interactive plot
<- loon.ggplot(ggp_lp,
lp_ggp_l1_lk linkingKey =lp["linkingKey"],
linkingGroup = "NA example")
# Now compare
"linkingKey"]
lp_ggp_l1_lk[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
# to the original loon plot
"linkingKey"]
lp[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
Alternatively, the grammar could have been used as in
# Add the linking information when creating the interactive plot
<- loon.ggplot(ggp_lp +
lp_ggp_l1_ggk linking(linkingGroup = "NA example",
linkingKey =lp["linkingKey"]))
# Again compare
"linkingKey"]
lp_ggp_l1_ggk[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
# to the original loon plot
"linkingKey"]
lp[#> [1] "0" "1" "2" "3" "4" "5" "6" "7" "9" "11" "12" "13" "14"
Of course, all this depends on the user knowing where to find the correct linking information.
Comparing the three different interactive plots shows how information can be lost, as well as how it can be maintained, when translating from interactive to static ggplot
back to an interactive loon
plot.