'Plotly JS graph_div.on is not a function

TL;DR - the .on event listner in Plotly JS seems to be undefined, therefore I can't setup any interactive graph features.

Details:

Using Ploty JS in a Flask project, I am creating several graphs as div's in a boostrap grid and then filling them with graphs from a element. The graphs are plottings four different features of a audio waveform with timestamps, plus the waveform, so I would like to synchronize the axis zooms across the four charts. enter image description here

The HTML for this page looks like this:


<script src="{{ url_for('static', filename='js/d3.v7.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/jquery-3.3.1.slim.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/plotly-2.9.0.js') }}"></script>

...

<div class="row">
    <div class="col-6">
        <div id="zcs_plot" style="width:auto; height:225px;"></div>
        <div id="energy_plot" style="width:auto; height:225px;"></div>
    </div>
    <div class="col-6">
        <div id="centroid_plot" style="width:auto; height:225px;"></div>
        <div id="spectrogram_plot" style="width:auto; height:225px;"></div>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <div id="audio_plot" style="width:auto; height:225px;"></div>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <audio style="width: 100%" controls>
            <!--source src="{{wav_json}}" type="audio/wav"-->
            <source src="{{url_for('soundserve', day=file_day, hour=file_hour, file=file_file)}}"
                    type="audio/wav">
        </audio>
    </div>
</div>

Using the example code from Plotly's website (https://plotly.com/javascript/zoom-events/), and refining based on the example in this post (How do I synchronize the zoom level of multiple charts with Plotly.js?) it looks like I need to use the .on() event listener from Plotly in the JS.

<script type="text/javascript">
    console.log(Plotly.version)
    console.log(d3.version)

    //ZCS
    var zcs_plot = document.getElementById('zcs_plot');
    data = d3.json("{{ url_for('zcs_stat', day=file_day, hour=file_hour, file=file_file) }}").then(
        json => {
            const data = json.data;
            var layout = {
                title: {text: "Zero Crossings (per sec)", font:{color: "#F0F0F0"}},
                xaxis:{gridcolor:'#252525', gridwidth: 1, tickfont: {color: "#F0F0F0"} },
                yaxis:{gridcolor:'#252525', gridwidth: 1, tickfont: {color: "#F0F0F0"} },
                showlegend: false,
                margin: {t: 30, b: 40, l: 30, r: 5},
                paper_bgcolor: "black",
                plot_bgcolor: "black"
            }
            plt = Plotly.newPlot(zcs_plot,
                data,
                layout,
                {displayModeBar: false}
            );
            }
        ).catch(error => {
            console.error(error);
        }
    );

    //...^^that is repeated for the other 4 graphs as well

    zcs_plot.on('plotly_relayout',
    function(eventdata){
        alert( 'ZOOM!' + '\n\n' +
            'Event data:' + '\n' +
             JSON.stringify(eventdata) + '\n\n' +
            'x-axis start:' + eventdata['xaxis.range[0]'] + '\n' +
            'x-axis end:' + eventdata['xaxis.range[1]'] );
    });
    //...the production version of this will loop over each plots and then update all, but for TS this should work

</script>

However, when I try to run this page, I get the following error in the web console:

(index):294 Uncaught TypeError: zcs_plot.on is not a function
    at (index):294:16
(anonymous) @ (index):294

and the page doesn't exhibit the expected response when I zoom the graph.

I also looked at this post: Plotly javascript. 'plotly_click' gets on is not a function, which appears to be almost the exact same problem, but I can't even make the accepted solution there work either. Possibly something has changed that didn't get updated in the Docs.

Note: btw I have tried linking the source JS directly from the CDNs as a web url instead of using a locally downloaded version, same results. I'm using local downloads because ultimately this app will be deployed in a location with poor to no internet service.



Solution 1:[1]

Plotly adds the "on" function to the div once the chart is initialized. Your chart is initialized asynchronously in a callback after getting the data from a json file. Your zcs_plot.on() is most likely called before the chart is even there. In order to prevent this, you should call zcs_plot.on() in the callback after Plotly.newPlot().

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mit