admin管理员组

文章数量:1221395

I am using plotly for R and plotting a stacked plot for a common x variable and multiple y variables, each having their own y axis. Currently, the graph shows the all the y variable hover values for a particular x value.

  1. I would like to show the hover values at another x value, while the previous hover is also visible.

  2. How can I make changes to the y ranges of the stacked plot to show more ticks?

I have the following code below

Create a function for a stacked plot

plotly_stacked <- function(df, x_colName, cols){
      
      DF <- df[, cols] %>%
        tidyr::gather(variable, value, -x_colName ) %>%
        transform(id = as.integer(factor(variable)))
    
      DF$variable<- factor( DF$variable, levels = unique( DF$variable))
      
      p <- plot_ly(data = DF, x = ~get(names(DF[1])) , y = ~value, color = ~variable, colors = "Dark2",
                   yaxis = ~paste0( "y",sort(id, decreasing = F))) %>%
        
        add_lines() %>%
        layout(
         xaxis = list(
           title = ""), 
          legend = list(
                  orientation = "h",   
                  xanchor = "center",  
                  x = 0.5)) %>%
        plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE)
      
      return(p)
    }
    

Create a data frame

df <- data.frame(
      Time = c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
               1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2),
      a = c(0.01,0.02,0.03,0.04,0.05,0.06,0.07,
            0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,
            0.19,0.2),
      b = c(0.001,0.002,0.003,0.004,0.005,0.006,
            0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015,
            0.016,0.017,0.018,0.019,0.02),
      c = c(1e-04,2e-04,3e-04,4e-04,5e-04,6e-04,
            7e-04,8e-04,9e-04,0.001,0.0011,0.0012,0.0013,0.0014,
            0.0015,0.0016,0.0017,0.0018,0.0019,0.002)
    )
 

json code for making the hover appear for all variables at the same time

#Create a vector of labels
labels <- c("xy", paste0("xy", 2: 2)) # for 4 y variables, change this from 2:4


# Convert the labels to a JSON array
labels_json <- jsonlite::toJSON(labels)

# Define the JavaScript function
js_code <- sprintf(
  'function(el, x){el.on("plotly_hover", function(d) {
    Plotly.Fx.hover(el.id, {xval: d.xvals[0]}, %s);
  })}',
  labels_json
)

Plot the variables

plotly_stacked(df, "Time",  c( "Time" ,"a", "b", "c"))|>
  layout(hovermode = "x") |>
  htmlwidgets::onRender(js_code)

I am using plotly for R and plotting a stacked plot for a common x variable and multiple y variables, each having their own y axis. Currently, the graph shows the all the y variable hover values for a particular x value.

  1. I would like to show the hover values at another x value, while the previous hover is also visible.

  2. How can I make changes to the y ranges of the stacked plot to show more ticks?

I have the following code below

Create a function for a stacked plot

plotly_stacked <- function(df, x_colName, cols){
      
      DF <- df[, cols] %>%
        tidyr::gather(variable, value, -x_colName ) %>%
        transform(id = as.integer(factor(variable)))
    
      DF$variable<- factor( DF$variable, levels = unique( DF$variable))
      
      p <- plot_ly(data = DF, x = ~get(names(DF[1])) , y = ~value, color = ~variable, colors = "Dark2",
                   yaxis = ~paste0( "y",sort(id, decreasing = F))) %>%
        
        add_lines() %>%
        layout(
         xaxis = list(
           title = ""), 
          legend = list(
                  orientation = "h",   
                  xanchor = "center",  
                  x = 0.5)) %>%
        plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE)
      
      return(p)
    }
    

Create a data frame

df <- data.frame(
      Time = c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
               1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2),
      a = c(0.01,0.02,0.03,0.04,0.05,0.06,0.07,
            0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,
            0.19,0.2),
      b = c(0.001,0.002,0.003,0.004,0.005,0.006,
            0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015,
            0.016,0.017,0.018,0.019,0.02),
      c = c(1e-04,2e-04,3e-04,4e-04,5e-04,6e-04,
            7e-04,8e-04,9e-04,0.001,0.0011,0.0012,0.0013,0.0014,
            0.0015,0.0016,0.0017,0.0018,0.0019,0.002)
    )
 

json code for making the hover appear for all variables at the same time

#Create a vector of labels
labels <- c("xy", paste0("xy", 2: 2)) # for 4 y variables, change this from 2:4


# Convert the labels to a JSON array
labels_json <- jsonlite::toJSON(labels)

# Define the JavaScript function
js_code <- sprintf(
  'function(el, x){el.on("plotly_hover", function(d) {
    Plotly.Fx.hover(el.id, {xval: d.xvals[0]}, %s);
  })}',
  labels_json
)

Plot the variables

plotly_stacked(df, "Time",  c( "Time" ,"a", "b", "c"))|>
  layout(hovermode = "x") |>
  htmlwidgets::onRender(js_code)
Share Improve this question asked Feb 6 at 19:41 ACEACE 3351 gold badge3 silver badges13 bronze badges 3
  • "I would like to show the hover values at another x value, while the previous hover is also visible." Can you maybe give a desired result in form of an image or a more detailed description? What do you mean with that? 2. is simply just add yaxis = list(nticks=20) to your layout. Replace 20 with number of y-ticks. – dog Commented Feb 6 at 21:20
  • 1 Hi, what I meant was showing another set of hover data at a different x value, while retaining the hover display for the previous x value. As an example, the graph you have shows the hover values for x = 0.9, I want to show the hover values for say x = 1.8 on the same plot, while also showing the hover values at x = 0.9 – ACE Commented Feb 7 at 21:57
  • Got it, I made something similar. I am sure, you can adapt this to fit your needs. – dog Commented Feb 7 at 23:39
Add a comment  | 

1 Answer 1

Reset to default 0
  1. "show hover on multiple x-positions". Yes, we can store previously hovered coords and print annotations (y-values) to all previously hovered x values. The code is highly customized. If you double click the graph, all annotations are removed. I hope, this is what you wanted and it makes you happy.
  2. Simply add yaxis = list(nticks=20) to your layout. Replace 20 with number of y-ticks.

Code

library(plotly)

plotly_stacked <- function(df, x_colName, cols){
  
  DF <- df[, cols] %>%
    tidyr::gather(variable, value, -x_colName ) %>%
    transform(id = as.integer(factor(variable)))
  
  DF$variable<- factor( DF$variable, levels = unique( DF$variable))
  
  p <- plot_ly(data = DF, x = ~get(names(DF[1])) , y = ~value, color = ~variable, colors = "Dark2",
               yaxis = ~paste0( "y",sort(id, decreasing = F))) %>%
    
    add_lines() %>%
    layout(
      xaxis = list(
        title = ""), 
      legend = list(
        orientation = "h",   
        xanchor = "center",  
        x = 0.5),
      yaxis = list(nticks=20)) %>% # adjust ticks as needed
    plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE)
  
  return(p)
}

df <- data.frame(
  Time = c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
           1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2),
  a = c(0.01,0.02,0.03,0.04,0.05,0.06,0.07,
        0.08,0.09,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18,
        0.19,0.2),
  b = c(0.001,0.002,0.003,0.004,0.005,0.006,
        0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015,
        0.016,0.017,0.018,0.019,0.02),
  c = c(1e-04,2e-04,3e-04,4e-04,5e-04,6e-04,
        7e-04,8e-04,9e-04,0.001,0.0011,0.0012,0.0013,0.0014,
        0.0015,0.0016,0.0017,0.0018,0.0019,0.002)
)

# Define the JavaScript function
js_code <- 
  'function(el, x) {
  var previouslyHovered = [];
  var annotations = [];
  
  el.on("plotly_hover", function(d) {
    var xval = Math.round(d.points[0].x * 10) / 10;
    var curveIndex = d.points[0].curveNumber;
    
    // Hover on all subplots
    Plotly.Fx.hover(el.id, {xval: d.xvals[0]}, ["xy","xy2","xy3"]);
    if (!previouslyHovered.includes(xval)) {
      previouslyHovered.push(xval);
      
      // Get data for all traces at this x-value
      var traces = el.data;
      var yaxes = ["y", "y2", "y3"];
      
      for(var i = 0; i < traces.length; i++) {
        var trace = traces[i];
        var xIndex = trace.x.indexOf(xval);
        if(xIndex !== -1) {
          var yval = Math.round(trace.y[xIndex] * 10000) / 10000;
          
          // Create annotation for each subplot
          var annotation = {
            x: xval,
            y: yval,
            yref: i > 0 ? `y${i + 1}` : "y",
            text: yval.toString(),
            showarrow: false,
            ax: 0,
            ay: -20,
            yaxis: yaxes[i], // Specify which y-axis this annotation belongs to
            font: {
              size: 10
            }
          };
          
          annotations.push(annotation);
        }
      }
      
      // Update the plot with all new annotations
      Plotly.relayout(el.id, {annotations: annotations});
    }
  });
  
  // Add double-click handler to clear annotations
  el.on("plotly_doubleclick", function() {
    previouslyHovered = [];
    annotations = [];
    Plotly.relayout(el.id, {annotations: []});
  });
}'


plotly_stacked(df, "Time",  c( "Time" ,"a", "b", "c"))|>
  layout(hovermode = "x") |>
  htmlwidgets::onRender(js_code)

本文标签: