Search code examples
rggplot2ggplotly

ggplot2 fill not converting ggplotly color mapping correctly


I'm trying to convert a ggplot2 image using ggplotly(), but it's not converting correctly. My ggplot image takes in two lines all of the time, and has a color variable for the geom_line component and a fill variable for the geom_point component.

Here is my code for the strictly the basic ggplot part:

test_data1 = data.frame(
  filter = "Filter 1",
  time = seq(as.Date("2017-01-01"), as.Date("2017-03-01"), "days"),
  ovr_perc = rnorm(n = 60, mean = 8, sd = 2),
  neg_perc = rnorm(n = 60, mean = 6, sd = 2),
  count = sample(50:250,60,replace=T)
)

test_data2 = data.frame(
  filter = "Filter 2",
  time = seq(as.Date("2017-01-01"), as.Date("2017-03-01"), "days"),
  ovr_perc = rnorm(n = 60, mean = 20, sd = 6),
  neg_perc = rnorm(n = 60, mean = 6, sd = 2),
  count = sample(50:250,60,replace=T)
)

test_data = rbind(test_data1, test_data2)

p = ggplot(test_data, aes(x=time, y=ovr_perc, group = factor(filter)))  +
  geom_line(aes(color=factor(filter))) +
  geom_point(aes(fill=neg_perc, size = count), shape=21) +
  scale_fill_gradient2(low = "darkgreen", mid = "yellow", high = "red1", 
                       midpoint = 5, limits = c(0, 10), oob = squish) +
  scale_colour_manual(values = c("pink", "green")) +
  theme_classic() 
p

The image should look something like this, which is almost exactly how I want it to look:

enter image description here

However, when I try adding the ggplotly code to get the tooltip feature, it turns into this:

ggplotly(p)

enter image description here

The entire color scheme on each of the points is gone. How can I change this so it keeps the same color scale from the ggplot image to the ggplotly image?


Solution

  • As noted in the open bug report linked above, geom_point's aesthetic mapping for fill doesn't work properly, while color works fine. According to the bug report, the problem goes away in the package's dev version, but if you don't have easy access to that (neither do I), the following works, at least on my end:

    library(dplyr)
    library(plotly)
    
    p2 <- ggplot(test_data, aes(x=time, y=ovr_perc, linetype = filter))  +
      geom_line(data = . %>% filter(filter == "Filter 1"),
                colour = "pink") +
      geom_line(data = . %>% filter(filter == "Filter 2"),
                colour = "green") +
      geom_point(aes(color = neg_perc, size = count)) +
      scale_color_gradient2(low = "darkgreen", mid = "yellow", high = "red1", 
                           midpoint = 5, limits = c(0, 10), oob = squish) +
      scale_linetype_manual(values = c("solid", "solid"),
                            guide = guide_legend(override.aes = list(
                              color = c("pink", "green")
                            ))) +
      theme_classic(); p2
    
    ggplotly(p2)
    

    Explanations:

    1. This uses color rather than fill for geom_point, which works fine.

    2. The lines are plotted in separate geom_line layers, with their colours specified directly, outside aes().

    3. The lines' linetype is mapped inside aes(), to force the creation of a legend for each filter value, while the actual mapping specified in scale_linetype_manual sets both lines to be solid.

    ggplotly result