Plotly: Annotate outliers with sample names in boxplot

plotly samples
python boxplot example
plotly histogram labels
what is plotly
plotly trellis
plotly api
interactive plotly
plotly pandas

I am trying to create a boxplot with ggplot and plotly with the dataset airquality where Month is on the x-axis and Ozone values are on y-axis. My aim is to annotate the plot so that when I hover over the outlier points it should show the Sample name in addition to the Ozone value:

library(tidyverse)
library(plotly)
library(datasets)
data(airquality)

# add months
airquality$Month <- factor(airquality$Month,
                           labels = c("May", "Jun", "Jul", "Aug", "Sep"))

# add sample names
airquality$Sample <- paste0('Sample_',seq(1:nrow(airquality)))

# boxplot
p <- ggplot(airquality, aes(x = Month, y = Ozone)) +
  geom_boxplot()
p <- plotly_build(p)
p

Here is the plot that's created:

By default, when I hover over each of the boxes, it shows the basic summary stats of the x-axis variable. However, what I would also like to see is what the outlier samples are. For e.g. when hovering over May, it shows the outlier value 115 but it does not show that it is actually Sample_30.

How can I add the Sample variable to the outlier points so it shows both the outlier value as well as the sample name?


We can almost get it like this:

library(ggplot2)
library(plotly)
library(datasets)
data(airquality)
# add months
airquality$Month <- factor(airquality$Month,
                           labels = c("May", "Jun", "Jul", "Aug", "Sep"))
# add sample names
airquality$Sample <- paste0('Sample_',seq(1:nrow(airquality)))
# boxplot
gg <- ggplot(airquality, aes(x = Month, y = Ozone)) +
  geom_boxplot()
ggly <- ggplotly(gg)
# add hover info
hoverinfo <- with(airquality, paste0("sample: ", Sample, "</br></br>", 
                                     "month: ", Month, "</br>",
                                     "ozone: ", Ozone))
ggly$x$data[[1]]$text <- hoverinfo
ggly$x$data[[1]]$hoverinfo <- c("text", "boxes")

ggly

Unfortunately, the hovering does not work for the first box plot...

Box Plots | Python, If a column name is given as x argument, a box plot is drawn for each value of x . If "outliers", only the sample points lying outside the whiskers are shown. A box plot is a statistical representation of numerical data through their quartiles. The ends of the box represent the lower and upper quartiles, while the median (second quartile) is marked by a line inside the box. For other statistical representations of numerical data, see other statistical charts. Box Plot with plotly.express¶


I've managed to achieve this with Shiny.

library(plotly)
library(shiny)
library(htmlwidgets)
library(datasets)

# Prepare data ----
data(airquality)
# add months
airquality$Month <- factor(airquality$Month,
                           labels = c("May", "Jun", "Jul", "Aug", "Sep"))
# add sample names
airquality$Sample <- paste0('Sample_', seq(1:nrow(airquality)))

# Plotly on hover event ----
addHoverBehavior <- c(
  "function(el, x){",
  "  el.on('plotly_hover', function(data) {",
  "    if(data.points.length==1){",
  "      $('.hovertext').hide();",
  "      Shiny.setInputValue('hovering', true);",
  "      var d = data.points[0];",
  "      Shiny.setInputValue('left_px', d.xaxis.d2p(d.x) + d.xaxis._offset);",
  "      Shiny.setInputValue('top_px', d.yaxis.l2p(d.y) + d.yaxis._offset);",
  "      Shiny.setInputValue('dx', d.x);",
  "      Shiny.setInputValue('dy', d.y);",
  "      Shiny.setInputValue('dtext', d.text);",
  "    }",
  "  });",
  "  el.on('plotly_unhover', function(data) {",
  "    Shiny.setInputValue('hovering', false);",
  "  });",
  "}")

# Shiny app ----
ui <- fluidPage(
  tags$head(
    # style for the tooltip with an arrow (http://www.cssarrowplease.com/)
    tags$style("
               .arrow_box {
                    position: absolute;
                  pointer-events: none;
                  z-index: 100;
                  white-space: nowrap;
                  background: rgb(54,57,64);
                  color: white;
                  font-size: 14px;
                  border: 1px solid;
                  border-color: rgb(54,57,64);
                  border-radius: 1px;
               }
               .arrow_box:after, .arrow_box:before {
                  right: 100%;
                  top: 50%;
                  border: solid transparent;
                  content: ' ';
                  height: 0;
                  width: 0;
                  position: absolute;
                  pointer-events: none;
               }
               .arrow_box:after {
                  border-color: rgba(136, 183, 213, 0);
                  border-right-color: rgb(54,57,64);
                  border-width: 4px;
                  margin-top: -4px;
               }
               .arrow_box:before {
                  border-color: rgba(194, 225, 245, 0);
                  border-right-color: rgb(54,57,64);
                  border-width: 10px;
                  margin-top: -10px;
               }")
  ),
  div(
    style = "position:relative",
    plotlyOutput("myplot"),
    uiOutput("hover_info")
  )
)

server <- function(input, output){
  output$myplot <- renderPlotly({
    airquality[[".id"]] <- seq_len(nrow(airquality))
    gg <- ggplot(airquality, aes(x=Month, y=Ozone, ids=.id)) + geom_boxplot()
    ggly <- ggplotly(gg, tooltip = "y")
    ids <- ggly$x$data[[1]]$ids
    ggly$x$data[[1]]$text <- 
      with(airquality, paste0("<b> sample: </b>", Sample, "<br/>",
                              "<b> month: </b>", Month, "<br/>",
                              "<b> ozone: </b>", Ozone))[ids]
    ggly %>% onRender(addHoverBehavior)
  })
  output$hover_info <- renderUI({
    if(isTRUE(input[["hovering"]])){
      style <- paste0("left: ", input[["left_px"]] + 4 + 5, "px;", # 4 = border-width after
                      "top: ", input[["top_px"]] - 24 - 2 - 1, "px;") # 24 = line-height/2 * number of lines; 2 = padding; 1 = border thickness
      div(
        class = "arrow_box", style = style,
        p(HTML(input$dtext), 
          style="margin: 0; padding: 2px; line-height: 16px;")
      )
    }
  })
}

shinyApp(ui = ui, server = server)

geom_boxplot | ggplot2, How to make a box plot in ggplot2. Examples of box plots in R that are grouped, colored, and display the underlying Outliers. library(plotly) set.seed(123) df  The dots away from the whiskers seem not to be able to be labelled with text such as sample ID. Can this be fixed? I'm using ggplotly on a ggplot2 boxplot. Labelling points in a scatterplot is easy in comparison.


I found solution on https://github.com/ropensci/plotly/issues/887

Try to make this kind of code !

 library(plotly)

 vals <- boxplot(airquality$Ozone,plot = FALSE)
 y <- airquality[airquality$Ozone > vals$stats[5,1] | airquality$Ozone < vals$stats[1,1],]

plot_ly(airquality,y = ~Ozone,x = ~Month,type = "box") %>% 
   add_markers(data = y, text = y$Day)

Allow Annotation of Boxplot Outliers · Issue #887 · ropensci/plotly , with text such as sample ID. Can this be fixed? I'm using ggplotly on a ggplot2 boxplot. Labelling points in a scatterplot is easy in comparison. Box Plots in R How to make an interactive box plot in R. Examples of box plots in R that are grouped, colored, and display the underlying data distribution. New to Plotly? Plotly is a free and open-source graphing library for R.


plotly.graph_objects.Box, If "outliers", only the sample points lying outside the whiskers are shown. 9.5, 10, 10.25, 11.5, 12, 16, 20.90, 22.3, 23.25], name="All Points", fig.​update_layout(title_text="Box Plot Styling Outliers") fig.show(). How to make a D3.js-based box plot in javascript. Seven examples of box plots in javascript that are grouped, colored, and display the underlying data distribution.


Chart::Plotly::Trace::Box, How to make a box plot in ggplot2. Examples of box plots in R that are grouped, colored, and display the underlying Outliers. library(plotly) set.seed(123) df  New to Plotly? Plotly is a free and open-source graphing library for R. We recommend you read our Getting Started guide for the latest installation or upgrade instructions, then move on to our Plotly Fundamentals tutorials or dive straight in to some Basic Charts tutorials .


boxpoints – If “outliers”, only the sample points lying outside the whiskers are Attributes such as trace name , graph, axis and colorbar title.text , annotation text​  library (plotly) set.seed (123) df <-diamonds [sample (1: nrow (diamonds), size = 1000),] # This is how it needs to be done in ggplot p <-ggplot (df, aes (color, price)) + stat_boxplot (geom = 'errorbar') + geom_boxplot + ggtitle ("Add horizontal lines to whiskers using ggplot2") # Note that plotly will automatically add horozontal lines to the whiskers p <-ggplot (df, aes (cut, price, fill = cut)) + geom_boxplot + ggtitle ("Add horizontal lines to whiskers using ggplot2") fig <-ggplotly (p) fig