Javascript event data

from @chriddyp on Plotly ecosystem explanation , the plotly.py library is rendered using the same underlying javascript library, “plotly.js”.

I see that in plotly.js, there is the potential for hover events. However, aside from a FigureWidget (which requires jupyter), I’m not finding examples of using events in plotly.py.

Since the py library uses the same underlying js library, is it possible to build custom javascript on my webpage to capture event data from the plotly chart that was generated? For instance – if a user hovers over an image, or clicks in the chart – can I use a click event listener to capture x-axis, or y-axis value, or series name, or anything about the chart? If so, I would like to see an example or two that would help me out. if I add a click event listener to my webpage, and click in the chart – i just see target as ‘svg’. – Even tags that are generated via the plotly html do not seem to be accessible or interactive on the webpage.

Thanks,

1 Like

Hello @allsyntax,

There are ways to call functions based upon user interactions with python. But, if you are exporting to html, that would be an issue.

Yes, you can add event listeners to the plotly events.

I am generating the plot in python, and exporting to html. I am not using Dash. I would just like to capture interactive data from my plotly chart that was generated via python, and placed in the HTML document. Maybe it’s possible to do via javascript - even if the chart was originally created from python?

That is pure JavaScript, not using dash.

To do it:

figure.addEventListener(“plotly_click”, function() {console.log(this)})

Where figure is the div that you want to listen to.

I agree. But I don’t see a way to get chart data. Even this, for example, will not function:

document.getElementsByClassName("plotly-graph-div js-plotly-plot").addEventListener("click", function(e) {
   print("you clicked the plot");
  });

    function print(msg) {
        document.getElementById("console").innerHTML += msg+"<br>";
    }

When I put the plotly chart to HTML, this is a piece of the starting HTML (it’s lengthy). Am I referencing the correct DIV?

<div> 
<div class="plotly-graph-div js-plotly-plot" id="765c45f6-ab38-471a-9c03-18196e0bc437" style="height:100%; width:100%;">
<div class="plot-container plotly">
<div class="user-select-none svg-container" style="position: relative; width: 100%; height: 450px;">
<svg class="main-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="863.984" height="450" style="background: white;">
<defs id="defs-9193e6"><g class="clips">
<clipPath id="clip9193e6xyplot" class="plotclip">
<rect width="801" height="352"></rect></clipPath>
<clipPath class="axesclip" id="clip9193e6x">
<rect x="58" y="0" width="801" height="450"></rect></clipPath><clipPath class="axesclip" id="clip9193e6y">
<rect x="0" y="25" width="863.984" height="352"></rect></clipPath><clipPath class="axesclip" id="clip9193e6xy">
<rect x="58" y="25" width="801" height="352"></rect></clipPath></g>
<g class="gradients"></g></defs><g class="bglayer"><rect class="bg" x="58" y="25" width="801" height="352" style="fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;"></rect></g><g class="draglayer cursor-crosshair"><g class="xy"><rect class="nsewdrag drag" data-subplot="xy" x="58" y="25" width="801" height="352" style="fill: transparent; stroke-width: 0; pointer-events: all;"></rect><rect class="nwdrag drag cursor-nw-resize" data-subplot="xy" x="38" y="5" width="20" height="20" style="fill: transparent; stroke-width: 0; pointer-events: all;"></rect><rect class="nedrag drag cursor-ne-resize" data-subplot="xy" x="859" y="5" width="20" height="20" style="fill: transparent; stroke-width: 0; pointer-events: all;"></rect>

And even provided this worked, how could I fetch any chart data? Such as x-axis value or y-axis value where the user clicked? Or an attribute from a trace or image they clicked on?

Try plotly_selectedData or plotly_clickData.

I think first, I need to demonstrate the ability for JS to recognize the chart- and I’m not able to do that so far.

When plotly generates the HTML, it includes the chart HTML, and then JS at the end. I noticed, it doesn’t identify the chart as cleanly as “myDiv” in the plotly.js examples. Instead - here is the first few lines of the auto-generated JS that follows the HTML:

<script type ="text/javascript">
window.PLOTLYENV = window.PLOTLYENV || {};
if (document.getElementById("0a1fcd19-8e02-4e67-81b3-8a9f4d36785d")) {
	Plotly.newPlot("0a1fcd19-8e02-4e67-81b3-8a9f4d36785d", [{

Notice this unique ID code. It’s different each time the chart is generated.

Also, I’m wondering if the code for events needs to be on the python side, so it’s bundled with the html+js — or if I’ll be able to get it to work in my html page after the chart code is inserted.

It should work at any point in time because you are adding an event listener, as long as the chart uses plotly, it shouldn’t be an issue.

I don’t know if you can alter the div id, but you should always know the path of the element. You can use jquery to query it, or use a query path.

Here, this what I got:

<script>
$(document).ready( function () {
    console.log('adding listenters')
    $('.js-plotly-plot')[0].on('plotly_click', function(data) {console.log(data)})
})
</script>

To use jquery, include this in your head:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Result:

To use this, you will need to be using write_html vs to_html.


You can use straight JS as well:

document.getElementsByClassName('js-plotly-plot')[0].on('plotly_click', function(data) {console.log(data)})

Thanks, this is helpful! If I print (data), I get:

[object Object]

Is there a map somewhere that shows how to reference data within the data object? for instance, data.x does not show value at x. Instead, undefined

1 Like

You’re hunting after data.points. :wink:

1 Like

Strangely, I still see: [Object Object] why is it doing that?

Which one are you using?

Trying a bit of everything:

data.points
data.points[0]
data.points.x
data.points[0].x
data.points[0].xaxis
JSON.stringify(data)

While chart is detected, and hover and click listeners are firing, nothing yet seems to get me inside the data.

Hmm, maybe you need to delay the addition.

Which version of the code are you trying, jquery or javascript?

Here’s what I’m doing. I read that there’s a built-in way to add JS to bundle with the chart, specifically for js event handling called post_script. So I define the post script js, and pass along with the creation and that all seems to work. You can also control the name of the DIV, so I’m now defining that as well:

   post_js = """
    $(document).ready( function () {
        print('adding listenters')
        $('.js-plotly-plot')[0].on('plotly_hover', function(data) {
           print('test2:'+data.points)
        })
    })
    """
    myFig = fig.to_html(full_html=False, include_plotlyjs=False, div_id="js-plotly-plot", post_script=post_js)

Dont try to convert it to a string, lol. :smiley:

If you want it to be a string, you need to do this:

print('test2:'+JSON.stringify(data.points))

I don’t necessarily want it to be a string, I just need to access the value and work with the data. When i use JSON.stringify() then the event doesn’t fire anymore.

Weird.

Just print it without the string part.

console.log(data.points)

Ok, this gets me some progress. Here’s a clip what I see. It appears to include everything on the series clicked. Now i need to try to get data for the point that was clicked. like the x-axis value.