Search code examples
rplotly

How to turn the color scale in Plotly r to log scale


I am trying to have a logarithmic scale for the color bar in R, any ideas on how I can do it?

My code:

TEST_DATAFRAME = read.table(TEST_FILE, sep="\t",skip=2, header=T)
PROD_DATAFRAME = read.table(PROD_FILE, sep="\t",skip=2, header=T)

PARAMETER = "Vf_High"
LST_RESIDUAL <- PROD_DATAFRAME[PARAMETER] - TEST_DATAFRAME[PARAMETER]
PARAM_DATAFRAME <- data.frame("NEW_MEASUREMENT" = TEST_DATAFRAME[PARAMETER], 
                              "OLD_MEASUREMENT" = PROD_DATAFRAME[PARAMETER], 
                              "RESIDUAL" = LST_RESIDUAL)

colnames(PARAM_DATAFRAME) <- c("NEW_MEASUREMENT","OLD_MEASUREMENT","RESIDUAL")

p <- plot_ly(PARAM_DATAFRAME, x = ~OLD_MEASUREMENT, y = ~NEW_MEASUREMENT, color=~RESIDUAL,  colorscale = "Log",
             hovertext = paste("<b>New Measurement :</b>", PARAM_DATAFRAME$NEW_MEASUREMENT,
                               "<br><b>Old Measurement :</b>", PARAM_DATAFRAME$OLD_MEASUREMENT,
                               "<br><b>Residual :</b>" , PARAM_DATAFRAME$RESIDUAL)) %>% add_markers()

#p <- layout(p, color = list(type = "log"))
p

this is my current output:

enter image description here

I also tried the following code:

TEST_DATAFRAME = read.table(TEST_FILE, sep="\t",skip=2, header=T)
PROD_DATAFRAME = read.table(PROD_FILE, sep="\t",skip=2, header=T)

PARAMETER = "Vf_High"
LST_RESIDUAL <- PROD_DATAFRAME[PARAMETER] - TEST_DATAFRAME[PARAMETER]
PARAM_DATAFRAME <- data.frame("NEW_MEASUREMENT" = TEST_DATAFRAME[PARAMETER], 
                              "OLD_MEASUREMENT" = PROD_DATAFRAME[PARAMETER], 
                              "RESIDUAL" = abs(LST_RESIDUAL))

colnames(PARAM_DATAFRAME) <- c("NEW_MEASUREMENT","OLD_MEASUREMENT","RESIDUAL")

brks <- pretty(range(PARAM_DATAFRAME$RESIDUAL))
gg <- ggplot(PARAM_DATAFRAME, aes(NEW_MEASUREMENT, OLD_MEASUREMENT, color = RESIDUAL)) +
  geom_point() +
  scale_colour_gradient(
    low = "blue", high = "red",
    trans = "log", breaks = brks, labels = brks) +
  theme_minimal()

ggplotly(gg)

this is the result:

enter image description here

How can I give it legible labelling? I want to configure the color bar as the following:

enter image description here


Solution

  • You could use ggplot to generate the logarithmic colour scale and then have plotly::ggplotly turn the ggplot grob into a plotly object.

    Since you don't provide reproducible sample data, here is an example based on mtcars

    brks <- pretty(range(mtcars$disp))
    gg <- ggplot(mtcars, aes(mpg, wt, colour = disp)) +
        geom_point() +
        scale_colour_gradient(
            low = "blue", high = "red",
            trans = "log", breaks = brks, labels = brks) +
        theme_minimal()
    
    ggplotly(gg)
    

    enter image description here


    Update

    In response to your comment, here is a minimal reproducible example.

    First we generate some sample data

    set.seed(2018)
    df <- data.frame(
        x = 1:100,
        y = 1:100 + rnorm(100),
        val = 10^seq(-5, 2, length.out = 100))
    

    We then define suitable breaks

    brks <- 10^seq(floor(log10(min(df$val))), ceiling(log10(max(df$val))), by = 1)
    

    Generate ggplot grob

    gg <- ggplot(df, aes(x, y, colour = val)) +
        geom_point() +
        scale_colour_gradient(
            low = "blue", high = "red",
            trans = "log",
            breaks = brks,
            labels = brks) +
        theme_minimal()
    

    Finally show as plotly object

    ggplotly(gg)
    

    enter image description here


    Without using ggplotly

    To achieve the same without the ggplotly detour, use the colorbar argument within marker to define tick spacings and labels.

    # Determine range of log10-scale
    rg <- range(log10(df$val))
    
    # Plot
    plot_ly(
        df, 
        x = ~x, y = ~y, 
        type = "scatter",
        mode = "markers",
        marker = list(
            color = ~log10(val),
            colorbar = list(
                tickmode = "array",
                ticktext = 10^seq(floor(rg[1]), ceiling(rg[2])),
                tickvals = seq(floor(rg[1]), ceiling(rg[2])))))
    

    enter image description here