3/08/2016

Custom interactive CSS/HTML tooltips with ggplot, shiny and R (ggvis like).


Working on data set visualization with R and shiny for Facebook data insights, we've faced a serious problem with some, one would say "simple feature".

"Hovering on plot data, shall display popover (tooltip) with the user picture, active link, short description and some other data".

First we've tried ggvis library. It was very promising and the tooltips worked like a charm.
However, very soon we've found out that library is not mature enough and leads to problems with plot interactions i.e.  zooming - to get rid of marque artifacts we would have to patch the library with some custom JS and other "fixes". This way looked "quick and dirty" so we've decided to explore the possibilities of well known and mature ggplot. If it's possible to display the data we need in "panel", let's fetch the panel with needed HTML data and play with it's position and look. The final solution is as follows:

Tooltips are managed by combination of shiny+ggplot hover functionality and CSS styles.
By setting hover argument of 'plotOutput' we can access  hover data from the server side, as an ordinary input.

Hover input is a list with:
  • position of cursor ON the image; 
  • domain - that is values of variables at the plotting area edges; 
  • range - that is position of plotting area edges in pixels relative to whole image element.

Additionally for ggplot mappings are returned.

To create tooltip first we need to identify position of the cursor inside the image element. We do it by calculating distances from left and top edge of image element from hover data. Then we create tooltip, in this app it is 'wellPanel' with required informations inside, and 'position' property set  to 'absolute' and set 'left' and 'top' properties to calculated values.

However, 'absolute' position is defined as relative to the nearest positioned ancestor. Because we want to position tooltip inside the image, we need to put both 'plotOutput' with image and 'uiOutput' with tooltip content inside additional 'div' element with 'position' property set to 'relative'.

We don't set top, left etc. for this element, so the actual position of the image doesn't change - it's edges are identical as previously, so we can use 'div' (for positioning tooltip) as substitute for image.

You can find full, working, simplified code snippet here: https://gitlab.com/snippets/16220

Special thanks to Bartek Chroł for help with developing this idea!!

ggplot with fully customised tooltip



3 comments:

  1. Many thanks for this bit of code! I looked for a simple way to add a tooltip and this is the simplest (no need to install additional packages and I can style the well as much as I want). I'd make some changes to your code, though:

    1) I prefer to use a small well instead of a regular well so to the wellPanel( ………. ) function call, I added class = "well-sm"

    2) No need to use actual HTML, I prefer to use Shiny tags. So instead of the HTML bit for the well's style, we can place

    tags$b("Car:"), rownames(point), br(),
    tags$b("mpg:"), point$mpg, br(),
    tags$b("hp:"), point$hp), br(),
    tags$b("Distance from left:"), left_px, tags$b(", from top:"), top_px

    ReplyDelete
    Replies
    1. Thx for the comment, glad it helped you. We've also spent quite a moment looking for something simple and straightforward before this idea.

      Delete
  2. This is excellent, impressive!
    I have been using Plotly as an add-on to ggplot but it gets a little clumsy. I am switching over.
    ...Usman Suleman

    ReplyDelete