rgraphicsplotlyheatmap

Hover text for multiple heatmap traces in an R plotly plot


This is something of a follow-up question from this one. Ultimately, I have a plotly plot that seems to be treating separate traces as the same and producing unexpected behavior. I'm trying to figure out how to get it to treat them as separate traces.

I have a heatmap in which I'm plotting separate traces for the upper and lower triangles. Thanks to that previous answer, I have the plot looking more or less how I want it:

library(tidyverse)
library(plotly)

# generate some sample data (somewhat clunkily)
# x and y column are all unique combinations of the words "one" through "four"
# v1 and v2 columns contain random data with different ranges
f <- combn(c("one","two","three","four"),2) %>%
  t() %>%
  as.data.frame() %>%
  rename(x=1,y=2) %>%
  mutate(v1 = rnorm(n(),5), v2 = rnorm(n(), 200, sd=55)) %>%
  arrange(x,y) %>%
  mutate(
    x = factor(x,c("one","two","three","four")),
    y = factor(y,c("four","three","two","one"))
  )

lwr_scale <- list(list(0,"black"),list(1,"red"))
upr_scale <- list(list(0,"white"),list(1,"green"))



f %>%
  plot_ly() %>% 
  add_trace(
    type = "heatmap",
    x = ~x,
    y = ~y,
    z = ~v1,
    colorscale = lwr_scale
  ) %>%
  add_trace(
    type="heatmap",
    x = ~y,
    y = ~x,
    colorscale = upr_scale,
    z = ~v2
  )

plotly plot

The issue I'm running into now is that plotly seems to treat both traces as the same or somehow overlapping, since you'll note that both colorbars show both variable names (v1/v2). Additionally, the hover text for the bottom-left triangle says "trace 1: NaN", but it works fine in the upper-right triangle (e.g., "trace 1: 2.252"):

enter image description here

I haven't been able to reproduce this using any other trace type, so I'm assuming it's either something specific to heatmaps or to the way my dataset is organized. How can I get plotly to recognize these as separate traces?

Update: apparently if I set hoverongaps=TRUE, then it'll show the correct hovertext, but the plot treats the entire top row of the upper triangle as gaps (this is apparently true with or without hoverongaps set), and won't show hover text for those cells. Closer, but not quite there...


Solution

  • This turned out to be happening because the first trace had no entries for y == "one", and so plotly considered the entire top row to contain gaps. My hacky solution for this was to add NA's for that whole row, and it seems to have fixed the issue:

    library(tidyverse)
    library(plotly)
    
    # generate some sample data (somewhat clunkily)
    # x and y column are all unique combinations of the words "one" through "four"
    # v1 and v2 columns contain random data with different ranges
    f <- combn(c("one","two","three","four"),2) %>%
      t() %>%
      as.data.frame() %>%
      rename(x=1,y=2) %>%
      mutate(v1 = rnorm(n(),5), v2 = rnorm(n(), 200, sd=55)) %>%
      arrange(x,y) %>%
      mutate(
        x = factor(x,c("one","two","three","four")),
        y = factor(y,c("four","three","two","one"))
      )
    
    lwr_scale <- list(list(0,"black"),list(1,"red"))
    upr_scale <- list(list(0,"white"),list(1,"green"))
    
    
    # get factor level for the top row
    last_l <- last(levels(f$y))
    top_row <- f %>%
      # get entries for x == last_l
      filter(x == last_l) %>%
      # swap x and y
      mutate(temp=y,y=x,x=temp) %>%
      select(-temp) %>%
      # set numeric columns to NA
      mutate(across(where(is.numeric),~NA))
    
    # add dummy rows back to original dataset
    f <- bind_rows(f,top_row)
    
    f %>%
      plot_ly(hoverongaps=FALSE) %>% 
      add_trace(
        type = "heatmap",
        x = ~x,
        y = ~y,
        z = ~v1,
        colorscale = lwr_scale
      ) %>%
      add_trace(
        type="heatmap",
        x = ~y,
        y = ~x,
        colorscale = upr_scale,
        z = ~v2
      )
    

    et voila:

    enter image description here