class: center, middle, inverse, title-slide # Enriching the Vocabulary
of R Graphics ### Paul Murrell --- class: chapter-slide # R Draws a Tooltip ??? I only recently discovered that 'shiny' allows me to write R code to respond to *direct* mouse interaction with a plot. This allows me to draw the response to mouse actions using R code, e.g., I can draw a tooltip with R! Demonstrate the tooltip example live by running ... ``` rmarkdown::run("../../../Shiny/tooltip.Rmd") ``` --- ## I Know What You are Thinking *Damn!* *Why do those tooltips look so good?* ??? The most important technology used in that tooltip example is the 'shiny' package, which handles the user input (mouse hover) and calls back to R so that the tooltip (and the highlighted points) can be added to the plot (and makes sure the plot is redrawn). But this talk is going to focus on a less important detail: how to draw the tooltip. --- ## A Close-Up of the Tooltip .center[ ![A close-up of the tooltip](close-up.svg) ] ??? This is a close up of the feature of the plot that we are going to focus on. Just in case you missed it, I will point out some important details about this tooltip and explain how changes to R 4.2.0 make it possible for us to achieve this result. --- ## A Close-Up of the Tooltip * The tooltip is semitransparent **in a special way**. * The tooltip shadow is a **weird shape**. * We can see the plot through the tooltip, but not the tooltip's own shadow. The tooltip shadow is a **really weird shape**. --- class: chapter-slide # Simple graphics with R ??? We will now look at how we might go about drawing that tooltip, starting with just "simple" R graphics. --- ## A Tooltip Suppose we have a function that can create a tooltip ... ```r tooltip <- textBubble(textGrob("gears: 5", gp=gpar(fontace = "bold")), * gp = gpar(col = 1, fill = 2)) ``` ... and we use it to create an **opaque** tooltip. ??? This is just normal R graphics. Well, if by "normal" we mean 'grid' graphics to draw a rectangle with rounded corners, plus a polygon for the "pointer" at the bottom, and 'gridGeometry' to combine them into a single "balloon" shape, with a text label on top, all within a series of viewports to make the drawing simpler. --- ## A Tooltip .center[ ![A close-up of a solid version of the tooltip](close-up-solid.svg) ] ??? This is an opaque version of the tooltip, without any shadow. --- ## A Semitransparent Tooltip What happens if we make that tooltip **semitransparent**? ```r tooltip <- textBubble(textGrob("gears: 5", gp=gpar(fontace = "bold")), * gp = gpar(col = adjustcolor(1, alpha = .5), * fill = adjustcolor(2, alpha = .5))) ``` ??? One of the things we want is to be able to see through the tooltip. It is easy to change the colours that we draw with to semitransparent colours. --- ## A Semitransparent Tooltip .center[ ![A close-up of a semitransparent version of the solid version of the tooltip](close-up-semi.svg) ] ??? With semitransparent colours, the tooltip no longer completely obscures the plot. We can see shadowy data symbols beneath the tooltip. --- ## I Know What You are Thinking *Damn!* *Why do I feel a bit ick?* ??? However, there are some nasty details in the result. Where the text overlaps the tooltip, we have to look through both the text and the tooltip. This is also true where the border of the tooltip overlaps the fill of the tooltip. --- ## A Semitransparent Tooltip * The text is **a little bit too red**. * The border has **two levels of semitransparency**. --- ## A Semitransparent Tooltip .center[ ![An extreme close-up of a semitransparent version of the solid version of the tooltip](extreme-close-up-semi.svg) ] ??? This extreme close up shows that, where the border of the tooltip overlaps the fill of the tooltip, we get a more opaque red than either the fill itself or where the border does not overlap the fill. --- class: chapter-slide # Advanced graphics with R ??? We will now look at how some new features in R graphics allow us to take control of some of these fine details and produce the final tooltip. --- ## Masks From R 4.1.0, we can use **alpha masks**. A mask can be used to make subsequent drawing **semitransparent** (wherever the mask is semitransparent). ```r mask <- rectGrob(gp = gpar(col = NA, * fill = rgb(0, 0, 0, .8))) *maskvp <- viewport(mask = mask) ``` ??? Rather than specifying a semitransparent colour for individual shapes, we can specify an "alpha mask" that makes everything that we draw semitransparent. --- ## Groups From R 4.2.0, we can draw **isolated groups**. A group is drawing that occurs in isolation before being added to the main image. ```r tooltip <- textBubble(textGrob("gears: 5", gp=gpar(fontace = "bold")), * gp = gpar(col = 1, fill = 2)) ``` ```r *tooltipGroup <- groupGrob(tooltip, vp = maskvp) ``` The group is **drawn opaque** and then the mask makes **the drawn group semitransparent**. ??? Rather than drawing each shape one at a time on top of previous drawing, we can compose several shapes together first, as a "group", and then add them on top of previous drawing. If we add a mask, then the whole group is made semitransparent before it is added on top of previous drawing. --- ## A Group Tooltip (with a Mask) .center[ ![A close-up of a group version of the tooltip, with a mask](close-up-group.svg) ] ??? This produces a see-through tooltip without any of the artifacts that we saw earlier, when we drew without using a group and a mask. --- ## A Group Tooltip (with a Mask) * The border is a **single semitransparent red**. * The text is the **same red as the border**. --- ## A Group Tooltip (with a Mask) .center[ ![An extreme close-up of a group version of the tooltip, with a mask](extreme-close-up-group.svg) ] ??? This extreme close up shows that the opaque border has been drawn on top of the opaque fill, as a separate group, and then the result has been made semitransparent and added on top of the plot. --- ## A Shadow for the Tooltip Suppose we have a function that can create a tooltip shape without the text ... ```r ghost <- bubble(gp = gpar(col = "grey", fill = "grey")) ``` ??? We now move on to the tooltip shadow, starting with just the outline outline of the tooltip, filled in grey. This is just normal drawing with R. --- ## A Shadow for the Tooltip .center[ ![A close-up of a grey version of the tooltip shape](close-up-bubble.svg) ] --- ## Affine Transformations From R 4.2.0, we can **transform** groups. If we **define** a group in one viewport and **use** it in another, the group is **scaled** and **translated** based on the difference in location and size between the viewports. ```r ghost <- bubble(gp = gpar(col = "grey", fill = "grey")) *grid.define(ghost, name = "ghost") *squashvp <- viewport(height = .5) *shadow <- useGrob("ghost", vp = squashvp) ``` ??? Another thing we can do when drawing a group is to separate the group "definition" from the group "use". If we define group in one (viewport) context and use it in a different (viewport) context, we can induce a transformation of the group. We can define something to draw and then transform it for drawing. --- ## A Squashed Shadow .center[ ![A close-up of a grey version of the tooltip shape that has been squashed vertically](close-up-bubble-squashed.svg) ] ??? In this case, we use the group in a viewport that is half the height of the viewport where we defined the group, so the drawing is vertically squashed. --- ## Affine Transformations We can also specify a **shear** transformation. ```r ghost <- bubble(gp = gpar(col = "grey", fill = "grey")) grid.define(ghost, name = "ghost") squashvp <- viewport(height = .5) shear <- function(...) { * viewportTransform(..., shear = groupShear(1)) } *shadow <- useGrob("ghost", vp = squashvp, trans = shear) ``` ??? We can also specify details of the transformation that is applied when we use a group, including adding skew and/or flipping the group. --- ## A Sheared Shadow .center[ ![A close-up of a grey version of the tooltip shape that has been sheared](close-up-bubble-sheared.svg) ] ??? This gives us the weird shape of the shadow. --- ## Compositing Operators From R 4.2.0, we can use **compositing operators** to draw a **source** composited on a **destination** within a group. ```r *groupShadow <- groupGrob(ghost, "clear", shadow) ``` The "clear" operator erases the destination wherever the source overlaps the destination (and does not draw the source at all). ??? Another thing that we can do with a group is to combine drawing using a compositing operator other than the default "over" operator. We can control how drawing is combined within a group BEFORE it gets added to the main image. --- ## An Occluded Shadow .center[ ![A close-up of a grey version of the tooltip shape that has been cleared](close-up-bubble-cleared.svg) ] ??? In this case, we combine the original tooltip outline with the squashed and skewed shadow using a "clear" operator, which removes the shadow wherever it is overlapped by the original tooltip outline (indicated by the dotted line). --- ## A Shadow (with a Mask) .center[ ![A close-up of a grey version of the tooltip shape that has been masked](close-up-bubble-masked.svg) ] ??? This gives us the really weird shape of the tooltip. Here we have drawn the result using a mask so that the final shadow is see-through. --- ## A Close-Up of the Tooltip .center[ ![A close-up of the tooltip](close-up.svg) ] ??? And here we have the final result: An opaque group drawn with an alpha mask, plus a squashed and sheared group combined with another opaque group using a "clear" operator, also drawn with an alpha mask. --- ## Summary From R 4.2.0, we can ... * draw isolated groups. * apply affine transformations on groups. * use different compositing operators within groups. ... (as long as we use the right graphics device). ??? This is a small lie. Although most of that summary is true, the tooltip example presented in these slides requires some bug fixes that will only be part of R 4.2.1. The "right graphics device" is currently the `pdf()` device or any of the Cairo-based devices, e.g., `svg()`. --- ## Addendum * The 'ggblend' package is already making these facilites available for 'ggplot2' ! [https://mjskay.github.io/ggblend/](https://mjskay.github.io/ggblend/) ??? Another package that is making use of groups already is the 'piecepackr' package.