rplotlyhtmlwidgetsonrender

Line width related to x and y values (rather than pixel size) - htmlwidgets plotly R


I am aiming to make a plot using the onRender() function from the htmlwidgets package in which a user can click on a point and a gray line is drawn. I am trying to make the thickness of the gray line set to a variable.

I have a tentative MWE working as shown below. However, I currently have a problem. Basically, the width of the line changes depending on the resizing of the image and/or browser. This creates a problem because some of the dots change from being inside or outside the gray line depending on the changing line width (as a result of the image or browser resizing). However, whether the dots are inside or outside the gray line has a meaning that I need to keep consistent.

As a result, I am trying to designate the thickness of the line as a value that is relative to the x and y axis values (and not to the pixel values on the screen that can change size). I am hoping this would create a consistent gray line width that does not change relative to the dots even if the user resized the image or browser. Is this something can be accomplished in the onRender() function?

library(plotly)
library(broom)
library(htmlwidgets)

dat <- mtcars
dat$mpg <- dat$mpg * 10
maxVal = max(abs(dat))
maxRange = c(-1*maxVal, maxVal)

# Specify line width
ciVal = 100

p <- ggplot(data = dat, aes(x=disp,y=mpg)) + geom_point(size=0.5) + coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2]))

ggplotly(p) %>%
  onRender("
           function(el, x, data) {
            el.on('plotly_click', function(e) {

              var trace1 = {
                 x: [0, 600],
                 y: [0, 600],
                 mode: 'lines',
                 line: {
                   color: 'gray',
                   width: 2*data.ciVal
                 },
                 opacity: 0.5
              }

              Plotly.addTraces(el.id, trace1);
           })
          }
          ", data = list(dat=dat, ciVal=ciVal))

Note: This question is an additional tweak to a previous question I asked (Changing line thickness and opacity in scatterplot on onRender() htmlWidgets in R).


Solution

  • Instead of having one line with varying width, you could have a two lines which mark the borders and fill the space in between (fill: 'tonexty'). The line will therefore always resize depending on your axis range and your zoom.

    Normal zoom Zoom in

    library(plotly)
    library(htmlwidgets)
    
    dat <- mtcars
    dat$mpg <- dat$mpg * 10
    maxVal = max(abs(dat))
    maxRange = c(-1*maxVal, maxVal)
    
    p <- ggplot(data = dat, aes(x=disp,y=mpg)) + geom_point(size=0.5) + coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2]))
    
    ggplotly(p) %>%
      onRender("
               function(el, x, data) {
               el.on('plotly_click', function(e) {
    
               var trace1 = {
                 x: [0, 500],
                 y: [450, 50],
                 mode: 'lines',
                 line: {
                   color: 'gray',
                   width: 2
                 },
                 opacity: 0.5
               }
               var trace2 = {
                 x: [0, 500],
                 y: [250, -150],
                 mode: 'lines',
                 fill: 'tonexty',
                 line: {
                   color: 'gray',
                   width: 2
                 },
                 opacity: 0.5
               }
               Plotly.addTraces(el.id, trace1);
               Plotly.addTraces(el.id, trace2);
    
               })
               }
               ", data = list(dat=dat, ciVal=ciVal))