No plotly_events firing by reactless custom component

Hello,

I am trying to create a custom Streamlit component using TypeScript only (I cannot use React as it has a bit different plotly chart style than plotlyjs).

I went to the famous streamlit-plotly-events repo to seek inspiration and I was quite successful in putting my component together.

import { Streamlit, RenderData } from "streamlit-component-lib"
import Plotly from 'plotly.js-dist-min'
import * as d3 from 'd3'

const m_plot_div = document.createElement("div")
const m_plot = document.body.appendChild(m_plot_div)

m_plot.setAttribute("id","m_plot");

function onRender(event: Event): void {
  const data = (event as CustomEvent<RenderData>).detail
  var j = JSON.parse(data.args.props)
  
  Plotly.newPlot(
    m_plot.id,
    j.data,
    j.layout
  )


  document.getElementById(m_plot.id)?.addEventListener(
    "click",
    (e:Event) => console.log("1a")
  );
  
    document.getElementById(m_plot.id)?.addEventListener(
    "plotly_click",
    (e:Event) => console.log("1b")
  );


  d3.select(".plotly").on('click', function(this, event) {
    console.log("2a");
  })

  d3.select("#m_plot").on('plotly_click', function(this, event) {
    console.log("2b");
  })

  Streamlit.setFrameHeight()
}

Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRender)

Streamlit.setComponentReady()

Streamlit.setFrameHeight()

I then display my component in Python as

from streamlit_plotly_m import streamlit_plotly_m

...

streamlit_plotly_m(props=fig.to_json())

The chart looks fine. However the issue is I am unable to catch plotly_click events. They are simply not firing.

I should see “1b” or “2b” displayed in the console, but I only see “1a” and “2a”.

In React we can create the plot and assign the onclick callback as react-plotly plot already has onClick argument. plotly-js does not allow anything like that.

Could anyone please point me in the right direction?

Thanks a lot!

RJ

Well, actually the React componenrt also does not fire any plotly_click events.

import {
  Streamlit,
  StreamlitComponentBase,
  withStreamlitConnection,
} from "streamlit-component-lib"
import React, { ReactNode } from "react"
import Plot from 'react-plotly.js';
import Plotly from 'plotly.js';

class StreamlitPlotlyMyReact extends StreamlitComponentBase {
  public render = (): ReactNode => {
    const plot_obj = JSON.parse(this.props.args["plot_obj"]);
   
    return (
      <Plot
        data={plot_obj.data}
        layout={plot_obj.layout}
        onClick={this.plotlyEventHandler}
      />
    )

  }

  private plotlyEventHandler = (data: any) => {
    console.log('>>> data', data);
  }
}

Ok, the problem was in the fact I misunderstood TypeScript errors and did not attach the event listener to the correct element.

The trick is to first declare m_plot as

const m_plot: any = document.body.appendChild(m_plot_div)

and then you can simply

m_plot.on('plotly_click', function(e: any) { ... } )

Easy as that.

Rookie mistake. Case closed.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.