Black Lives Matter. Please consider donating to Black Girls Code today.

Copy pointer data to clipboard

I’m writing my js code to implement the customized feature to copy the data for a selected (by click the point) plotted point to the clipboard. For example, if the selected point reflect the data (x=1,y=3), a string such as ‘x=1, y=3’ is automatically copied to the clipboard.
I read https://plot.ly/javascript/plotlyjs-events/ and understand that calling myPlot.on will register a callback for a specific plotly event such as ‘click’, ‘hover’ etc. I implemented my own callback as following (with taking the example code from plot.ly/dash), but it ended up with that my code wasn’t get called when the point is clicked. After some debugging work, it turns out that the myPlot.on was called too earlier and it has to been called after the point when the plot chart has finish rendering in the window. After calling myPlot.on at a later point, my callback gets called correctly when the point is clicked.
But when I did some interactive operation on the user interface e.g. select a different value in a dropdown list which result in the whole plot being updated. My ‘plotly_click’ callback doesn’t take effect again. I’m wondering whether I’m doing the right thing to achieve my objective or I’m lost in a wrong direction.
I am using dash version 0.17.7 and dash_core_components version 0.5.1

myPlot.on('plotly_click', function(data){
      for(var i=0; i < data.points.length; i++){
        annotate_text = 'x = '+data.points[i].x +
                      'y = '+data.points[i].y.toPrecision(4);
        copyTextToClipboard(annotate_text)
        annotation = {
          text: annotate_text,
          x: data.points[i].x,
          y: parseFloat(data.points[i].y.toPrecision(4))
        }

        annotations =  [];
        annotations.push(annotation);
        Plotly.relayout('indicator-graphic',{annotations: annotations})

        try {
          var successful = document.execCommand('copy');
          var msg = successful ? 'successful' : 'unsuccessful';
          console.log('Copying text command was ' + msg);
        } catch (err) {
          console.log('Oops, unable to copy');
        }
    }
  })

Hey @kfyao

Good question. It seems like 1 of 2 things could be happening here:
1 - When the Graph updates, Plotly.newPlot is called: https://github.com/plotly/dash-core-components/blob/master/src/components/Graph.react.js#L69. This might reset the event listeners. In the Graph component, we add the event listeners after every newPlot call just in case.
2 - The Graph component sets its own event listeners here: https://github.com/plotly/dash-core-components/blob/master/src/components/Graph.react.js#L81-L106. Those might be overriding your event listeners. There might be a way to add event listeners without destroying the ones that already exist.

I haven’t verified either of these claims yet but that’s what I suspect is going on.

If (1) is true, then I’m not sure how we can enable hooks like yours into the code.

One solution that might work for you is to create your own react-based implementation of Graph.react.js includes the copy-and-paste behaviour that you’re looking for you. You could fork dash-core-components and use the exsting Graph.react.js as a starting point.

@chriddyp

Thanks for the reply. That direct me well.

For 2, I think plotly has a nice mechanism to manage multi event listener for a same event here: https:////github.com/plotly/plotly.js/blob/master/dist/plotly-finance.js#L11129-L11138 (file too big to show) Multi event listener will be added to event listener array there.

Yeah, as I checked, each time the Plotly.newPlot is call, the event listeners are reset. This is done here: https://github.com/plotly/plotly.js/blob/master/src/plot_api/plot_api.js#L64 and relevant code here: https://github.com/plotly/plotly.js/blob/master/src/lib/events.js#18

So looks like for short term, I may want to customize the Graph.react.js to achieve my goal.