Search code examples
rplotlyboxplot

Cannot plot scatter points on top of box plot in plotly using R


I am trying to plot scatter data on top of a box plot using Plotly. For this case I need to specify the quantiles manually. When I run the reprex below I get this error

Error in eval(expr, data, expr_env) : object 'lower_fence' not found

I would like the scatter data to have the same colour scheme as the box plot but the problem happens whether or not I add the colouring scheme. Essentially I am just trying to add in the outlier points that you get in a normal box plot where the quantiles are computed by plotly.

Any ideas how I can do this?

library(plotly)

# create presomputed quantiles
stats_df <- data.frame(
  site = c("site 2", "site 1", "site 3", "site 4"),
  site_type = c("b_type", "b_type", "a_type", "c_type"),
  lower_fence = c(1, 1.5, 2,  2.5),
  q1 = c(2, 3, 4, 5),
  median = c(6, 6.5, 7, 7.5),
  q3 = c(7, 8, 9, 10),
  upper_fence = c(11, 12, 13, 14)
)

# create box plot
fig <- plot_ly(
  data = stats_df,
  x = ~factor(site),
  color = ~ factor(site_type),
  colors = c("purple", "yellow", "red"),
  type="box",
  lowerfence = ~ lower_fence,
  q1 = ~ q1,
  median = ~ median,
  q3 = ~ q3,
  upperfence = ~ upper_fence)


# create scatter data
filtered_df_sub <- stats_df <- data.frame(
  site = c("site 2", "site 1", "site 3", "site 4"),
  site_type = c("b_type", "b_type", "a_type", "c_type"),
  value = c(1,2,3,4)
)

# add scatter points
fig <- fig %>% 
  add_trace(
    data = filtered_df_sub,
    x = ~factor(site),  # Use the same x variable for consistency
    y = ~value,  # Original values for scatter points
    color = ~ factor(site_type),
    colors = c("purple", "yellow", "red"),
    type = "scatter",
    mode = "markers",
    showlegend = FALSE  # Hide legend for scatter points if desired
  )

# add axis labels
fig <- fig %>%
        layout(title = "Box Plot with Precomputed Statistics",
               yaxis = list(title = "Value"),
               xaxis = list(title = "Sites"))

fig

Solution

  • This is not a bug - it is expected behaviour.

    You can simply set inherit = FALSE for your add_trace call. This prevents plotly from inheriting attributes from the initial plot_ly() call. E.g. lowerfence = ~ lower_fence which is not part of the data you are providing to add_trace.

    library(plotly)
    
    # create presomputed quantiles
    stats_df <- data.frame(
      site = c("site 2", "site 1", "site 3", "site 4"),
      site_type = c("b_type", "b_type", "a_type", "c_type"),
      lower_fence = c(1, 1.5, 2,  2.5),
      q1 = c(2, 3, 4, 5),
      median = c(6, 6.5, 7, 7.5),
      q3 = c(7, 8, 9, 10),
      upper_fence = c(11, 12, 13, 14)
    )
    
    # create box plot
    fig <- plot_ly(
      data = stats_df,
      x = ~factor(site),
      color = ~ factor(site_type),
      colors = c("purple", "yellow", "red"),
      type="box",
      lowerfence = ~ lower_fence,
      q1 = ~ q1,
      median = ~ median,
      q3 = ~ q3,
      upperfence = ~ upper_fence)
    
    
    # create scatter data
    filtered_df_sub <- stats_df <- data.frame(
      site = c("site 2", "site 1", "site 3", "site 4"),
      site_type = c("b_type", "b_type", "a_type", "c_type"),
      value = c(1,2,3,4)
    )
    
    # add scatter points
    fig <- fig %>% 
      add_trace(
        data = filtered_df_sub,
        x = ~factor(site),  # Use the same x variable for consistency
        y = ~value,  # Original values for scatter points
        color = ~ factor(site_type),
        colors = c("purple", "yellow", "red"),
        type = "scatter",
        mode = "markers",
        showlegend = FALSE,  # Hide legend for scatter points if desired
        inherit = FALSE
      )
    
    # add axis labels
    fig <- fig %>%
      layout(title = "Box Plot with Precomputed Statistics",
             yaxis = list(title = "Value"),
             xaxis = list(title = "Sites"))
    
    fig