################################################################################ # # # Example: New York air quality measurements 1973 # An R dataset # # ################################################################################ # # # # This data is available from the datasets package of R and contains # daily air quality measurements taken in New York, from May to September 1973. # data(airquality) summary(airquality) # There are several NAs representing missing data and dates # have numerical values. # # The dates can easily be made more meaningful airquality$Date <- with(airquality, as.Date(paste("1973", Month, Day, sep = "-"))) airquality$Weekday <- factor(weekdays(airquality$Date), levels = c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")) airquality$Month <- factor(month.abb[airquality$Month], levels = month.abb[unique(airquality$Month)]) # # airquality now contains more information # View(airquality) summary(airquality) ################################################################################ # # A GRAMMAR of INTERACTIVE GRAPHICS # ################################################################################# # # # library(diveR) # # Or, if diveR was not installed, library(loon.ggplot) # # # The function l_ggplot() # lgp <- l_ggplot(airquality, mapping = aes(x = Wind, y = Ozone)) + ggtitle("Air quality in New York (1973)") + geom_point() # # What is this? # class(lgp) # # An l_ggplot? A kind of ggplot? # # # To see any ggplot, ggplot2 SPECIALIZES # the plot function in R # plot(lgp) # # The ggplot2 documentation ?plot.ggplot # says the top-level print function also displays the ggplot. # (the source code is identical! ... at this time) # # # What if the l_ggplot is printed? # lgp # # Printing produces an INTERACTIVE loon plot!!! # # To access the interactive plot, as before # use the function l_getFromPath() # # E.g., if this was the first loon plot produced in # this session, then it would be ".l0.ggplot" lp <- l_getFromPath(".l0.ggplot") # The correct string appears both when lgp was first printed. # It also appears in the title bar of the interactive window, # following the string "path: " # # Printing lp is the same as printing any loon plot lp # A static version of the interactive plots is had as before plot(lp) # Note that this is not quite the same as plot(lgp) # the ggplot version. # # - The former tries to appear exactly as the interactive plot # (or as close as it can get) # - The latter produces the original ggplot constructed by the # grammar. # ######################################## # # the loon-ggplot duality # ######################################## # # Using l_ggplot() in place of ggplot() # extends the graphics grammar of ggplot2 # to produce interactive loon plots. # # - use l_ggplot() in place of ggplot() # # - plotting an l_ggplot produces a static ggplot display # printing an l_ggplot produces an interactive loon display. # # - the l_ggplot is NOT the interactive loon plot; # it is an enhanced ggplot AND can be augmented just as # any other ggplot. # # changes to the ggplot have NO EFFECT on the interactive plot # E.g., plot(lgp + geom_smooth()) # - changing the interactive plot has NO EFFECT # on the l_ggplot # # E.g., Make whatever changes you like interactively # to the plot lp. plot(lp) # # Alternatively, changes could be made programmatically. # # E.g., # Change glyph aesthetics of ALL points # lp["color"] <- "lightgrey" lp["glyph"] <- "ctriangle" # closed triangle lp["size"] <- 10 # proportional to area in loon # Could change the scaling (magnify or zoom in and out) for (mag in rep(c(0.8, 1, 1.2), times = 5)){ lp["zoomX"] <- mag lp["zoomY"] <- mag Sys.sleep(0.1) # slow down to see effect } # Settle on lp["zoomX"] <- 1.2 lp["zoomY"] <- 1.2 # # Similarly, change the location of the plot xlocs <- seq(min(lp["x"]), median(lp["x"]), length.out = 10) ylocs <- seq(min(lp["y"]), median(lp["y"]), length.out = 10) for (i in 1:length(xlocs)){ lp["panX"] <- xlocs[i] lp["panY"] <- ylocs[i] Sys.sleep(0.1) # slow down to see effect } # and back xlocs <- rev(xlocs) ylocs <- rev(ylocs) for (i in 1:length(xlocs)){ lp["panX"] <- xlocs[i] lp["panY"] <- ylocs[i] Sys.sleep(0.1) # slow down to see effect } # Settle on lp["panX"] <- 7 lp["panY"] <- 0 # Plotting lgp and lp plot(lgp) # the l_ggplot plot(lp) # the l_plot # # Only the loon plot (lp) reflects the changes. # # NOTE: a ggplot version of the current interactive plot # can be had: loon.ggplot(lp) # # and used like any ggplot gp <- loon.ggplot(lp) gp + geom_smooth() # Similarly, lgp behaves like an INTERACTIVE ggplot # lgp + geom_smooth() # which produces a NEW interactive plot. # # NOTE: # - Used ALL the information in the original lgp # NONE of the changes in the interactive lp # # 0. Open the layers tab of the new plot. # # - show the polygon of the confidence (se) region as well, # - move the model layer up above the smooths. # # NOTE: # These two plots can be LINKED: # # 1. Go to the inspector for the original plot lp # (with all the changes) # # - type in # airquality # as its linking group (hit enter/return) # # # 2. Focus the inspector on the new plot (just created) # (looks like the original lgp + geom_smooth() ) # # - change its linking group to "airquality" # (select from the linking group menu) # - choose "PULL" when asked to synchronize. # # What changed? # What did not? # # 3. Select all of the points in the new plot and # colour them light blue (from the inspector) # # # ######################################## # # SUMMARY on the loon-ggplot duality # # - l_ggplots # # - contain info to produce BOTH ggploys AND loon plots # - plot them to get a ggplot # - print them to get a loon plot # # - can be incrementally changed as can any ggplot # - e.g., ... + geom_smooth() # # - loon.ggplot() is a bridge between the two # - applied to a loon plot returns a ggplot # - applied to a ggplot returns a loon plot # ######################################## # # Extending the grammar to interaction # ######################################## # # # LINKING # # lgp_temp <- l_ggplot(airquality, mapping = aes(x = Date, y = Temp)) + ggtitle("Daily Temperatures") + geom_point() + geom_line() + linking(linkingGroup = "airquality") # # An interactive plot # lgp_temp # Again, the loon plot was not assigned to a variable. # # - could have done so by instead evaluating # # lp_temp <- loon.ggplot(lgp_temp) # # - otherwise it would have to be assigned as before # # lp_temp <- l_getFromPath(".l3.ggplot") # Use whatever number appears instead # # # Question: # Why are there two different colours of points? # # What are the black points? # # # Note: Displaying the ggplot does not use linked information plot(lgp_temp) # # # # 1. In the loon plot, make the black points # # - pink # - the same size as the other points # # # 2. Select any point and move it around the display # # What happens to the lines? # # # # 3. Open the layers tab in the inspector # # How are the lines implemented? # Move the scatterplot to the top. # # How might the l_ggplot have been constructed so # that the scatterplot was on top? # # # # The linking can be forced by sync = "push" # WARNING: ALL linked states will be pushed # l_ggplot(airquality, mapping = aes(x = Wind, y = Temp)) + ggtitle("Wind effect on temperatures") + geom_smooth() + geom_point() + # <- note order linking(linkingGroup = "airquality", sync = "push") # # So, if you PUSH, be careful you set all the linked states # to be as you want them (following ggplot grammar) # # Close the last plot and try # l_ggplot(airquality, mapping = aes(x = Wind, y = Temp)) + ggtitle("Wind effect on temperatures") + geom_smooth() + geom_point(pch = 21, size = 4, fill = "grey") + linking(linkingGroup = "airquality", sync = "push") # Question: What would you conclude about the dependence # of temperature on wind? # # A barplot # l_ggplot(airquality, mapping = aes(x = Month)) + geom_bar() + ggtitle("Months of measurements") + linking(linkingGroup = "airquality") # # # 1. Bring the following plots to the top # "Wind effect on temperature" scatterplot # "Months of measurements" barplot/histogram # # Use sweeping to determine: # - which months have highest temperatures? # lowest temperatures? # highest wind? # lowest wind? # # # # 2. Bring "Air quality in New York (1973)" to the top # with # "Months of measurements" barplot/histogram # # Use sweeping to determine: # - which months have highest ozone? # lowest ozone? # # # 3. Select all the points in "Air quality in New York (1973)" # # - what do the unselected parts of the # "Months of measurements" barplot represent? # - do any of these appear in the # "Wind effect on temperature" scatterplot? # # # LINKING # ... there are a couple of more arguments to linking() # See ?linking # ######################################## ######################################## # # All of the ggplot grammar should work # # E.g., l_ggplot(data = airquality, mapping = aes(x = Wind, y = Temp, fill = Month)) + ggtitle("Wind effect on temperatures") + geom_smooth(col = "grey") + geom_point(pch = 21, size = 3) + # <- note order linking(linkingGroup = "airquality", sync = "push") + facet_wrap(~Month, ncol = 1) # # NOTE: Now have ggplot default colours everywhere :-( # # Might want to change the selection colour if working # with ggplot colours: l_userOptions() l_userOptionDefault("select-color") l_setOption("select-color", "yellow") # Now try selections # # Can always set it back # l_setOption("select-color", l_userOptionDefault("select-color")) # # # # # # Question: What would you NOW conclude about the dependence # of temperature on wind? # # And so on # ######################################## ######################################## # # Hover labels # # Three dimensional scatterplots, # # ######################################## # # # All loon interactive plots have pop up # "tool tips" which appear whenever the # mouse hovers over that point # (and showItemLabels is TRUE/itemLabels is checked) # # In loon, these are just character vectors # (one string for each case) hoverLabels <- with(airquality, paste0(" ", # Just adding space for my large mouse pointer icon Weekday, "\n", paste(Month, Day, "1973")) ) l_ggplot(data = airquality, mapping = aes(x = Wind, y = Temp, z = Ozone)) + geom_point() + scale_multi() + # scales the data to a box as well as transforms ?scale_multi linking(linkingGroup = "airquality") + hover(itemLabel = hoverLabels, showItemLabels = TRUE) # On the plot # # 1. Press the letter key. # - what happened? # # You are now in "Rotation Mode" # # Press the key again. # You are now NOT in "Rotation Mode" # # 2. Put the plot into "Rotation Mode" # # Press the RIGHT ARROW key. Hold it down. # Release the key. # What has happened to the axis labels? # # Press the UP ARROW key. Hold it down. # Release the key. # What has happened to the axis labels? # # Using the DOWN ARROW and then the LEFT ARROW # Try and return the data cloud to its original position. # # TURN OFF rotation mode. # # 3. On the INSPECTOR, near the bottom, # there is a NEW "move" button just for 3D plots. # It is supposed to be a 3D axis. # # Press the axis button. What happened? # This is ALWAYS available. # # 4. Turn ON rotation mode. # # 5. With the LEFT mouse button pressed, move the data cloud # # NOTE that brushing and sweeping are not available # in rotation mode. # # 6. With the RIGHT mouse button pressed, move the data cloud. # # Move it away from the axes. # # 7. Rotate the data cloud. # NOTE the centre of rotation. # # 8. Click on the axes button in the inspector. # How does the data cloud change? # # Scale to plot. # # 9. Turn off rotation. # # # The equivalent in loon would be # with(l_scale3D(airquality), # scale the data to a box l_plot3D(x = Wind, y = Temp, z = Ozone, linkingGroup = "airquality", itemLabel = hoverLabels, showItemLabels = TRUE, showScales = TRUE) ) # # ######################################## # # HOMEWORK: For something completely different, look at this # pure loon code: # # data(SCmolecule) # See ?SCmolecule for more info # # with(SCmolecule, # l_plot3D(x, y, z, # col = residue, # size = mass, # linkingGroup = "molecule")) # l_hist(SCmolecule$residueName, # swapAxes = TRUE, linkingGroup = "molecule") # # 1. See if you can isolate the DNA segments. # # # 2. Rewrite the above code using the grammar # # ######################################## ######################################## # # Extending the grammar to match loon # ######################################## # # ################# # # E.g. to accommodate arbitrary glyphs # (to match loon) # # In loon, anything you can draw in R can be # a glyph library(png) img_path <- "diver.png" img_path <- list.files(file.path(find.package(package = 'diveR'), "help/figures"), full.names = TRUE) diver <- readPNG(img_path) l_ggplot(airquality, mapping = aes(x = Date, y = Temp)) + ggtitle("Daily Temperatures") + geom_line() + geom_image_glyph(images = diver, units = "native") + linking(linkingGroup = "airquality") + hover(itemLabel = hoverLabels, showItemLabels = TRUE) # These could have been different images for each point # # 1. Make the window for that plot short and wide # # 2. Centre your mouse over the left most month/colour. # Do NOT press any mouse button but position the # mouse in the centre of that colour and keep it there. # # Now press and hold the key and SCROLL so as # to stretch the plot horizontally. # When only that first month's of data appears in the # plot, stop scrolling. # # 3. By mouse movement, # pan across this time series from the left most values # to the right most values. # # Observe how the temperature series changes over time. # # - when is it lowest? highest? # - when is it most variable? least variable? # - where is it smoothly changing # # ################# # # E.g., Using pipes and parallel coordinates # library(tidyverse) airquality %>% select(Ozone, Solar.R, Wind, Temp) %>% na.omit() %>% # <--- should not be necessary (bug) l_ggplot(mapping = aes(Wind = Wind, Temp = Temp, Ozone = Ozone, Solar.R = Solar.R)) + geom_path() + linking(linkingGroup = "airquality") + coord_serialaxes() # Added by ggmulti # # The above is still a little buggy in loon.ggplot. # # # # Using loon alone instead: # airquality %>% select(Ozone, Solar.R, Wind, Temp) %>% l_serialaxes(axesLayout = "parallel", linkingGroup = "airquality", linewidth = 2, itemLabel = hoverLabels, showItemLabels = TRUE) -> pc_plot # # And pc_plot could be programmatically modified # pc_plot["axesLayout"] <- "radial" plot(pc_plot) loon.ggplot(pc_plot) ######################################## # # Some plots (presently) outside # the grammar # ######################################## l_pairs(airquality, linkingGroup = "airquality", showHistograms = TRUE) # Really want a different colour for selection # with ggplot default colours l_setOption("select-color", "yellow") ######################################## # # Main interactive grammar clauses # ######################################## # # The interactive grammar adds five new # kinds of clauses to the grammar. # # 1. linking() ... ?linking # 2. hover() ... ?hover # 3. selection() ... ?selection - logic, style, and cases # 4. active() ... ?active - points, and which layer is active # 5. zoom() ... ?zoom - scaleTo different regions # # # Additionally, any and all of the above can be accommodated # in a single "super" clause # # 6. interactivity() ... ?interactivity - all of the above at once. # # ######################################## # # FINALLY ... did not need l_ggplot() at all! # # just use ggplot() with the above clauses # ######################################## # gg <- ggplot(data = airquality, mapping = aes(x = Date, y = Solar.R, fill = Month, size = Wind^2)) + ggtitle("Solar radiation over time") + geom_line(size = 1, col = "grey") + geom_point(pch = 21) + linking(linkingGroup = "airquality", sync = "push") + hover(itemLabel = hoverLabels, showItemLabels = TRUE) + active(active = ~Month != "Jun") + selection(selected = ~Solar.R > 200) gg # Shows no legend since this can change interactively plot(gg) # Shows no effect of interaction # # Return the selection colour to its original default colour l_setOption("select-color", l_userOptionDefault("select-color")) # ################################################################################