Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add event back to python #19

Closed
nathalieguillemain opened this issue Oct 3, 2021 · 6 comments
Closed

Add event back to python #19

nathalieguillemain opened this issue Oct 3, 2021 · 6 comments
Assignees

Comments

@nathalieguillemain
Copy link

It would be great if events could be sent back to python to add some interactions on graphs

events = {"click": "function(params, echarts) {console.log(params);Streamlit.setComponentValue(params)}"}

something = st_pyecharts(b, events=events)
st.text(something)

I understand that Streamlit object is no longer available after component has been rendered.
May be the onclick could be defined as the default behavior of the component ?

Thanks

@andfanilo
Copy link
Owner

Hey @nathalieguillemain !

I understand that Streamlit object is no longer available after component has been rendered.

You explained the problem perfectly :( what I could eventually try is a st_echarts_clickable maybe with a default behavior of returning the params of any clicked object back to Python. That's interesting.

Could you maybe describe your use case for this so I have a basic idea of what you're trying to accomplish?

Have a nice day?
Fanilo

@andfanilo andfanilo self-assigned this Oct 4, 2021
@nathalieguillemain
Copy link
Author

Hello Fanilo,

  b = (
        Bar()
            .add_xaxis(["Microsoft", "Amazon", "IBM", "Oracle", "Google", "Alibaba"])
            .add_yaxis(
            "2017-2018 Revenue in (billion $)", [21.2, 20.4, 10.3, 6.08, 4, 2.2]
        )
            .set_global_opts(
            title_opts=opts.TitleOpts(
                title="Top cloud providers 2018", subtitle="2017-2018 Revenue"
            ),
            toolbox_opts=opts.ToolboxOpts(),
        )
    )

    events = {"click": "function(params, echarts) {console.log(params.name);console.log(params)}"}

    something = st_pyecharts(b, events=events)

In this example, when I click on a bar in the graph the params contains
params.name="Microsoft"
paramvalue=21.2
...
DataIndex=1
...

So I can now update another graph selecting Microsoft (dataIndex is more usefull) in a dataset giving a hability to drilling into the data. Such as I can do in Tableau Software

If "something = st_pyecharts(b, events=events)" would give the param object as a Dict it would be very userfull

Thank you very much

@flunardelli
Copy link

Hi, @nathalieguillemain looks like we have the same problem.
I think I found a simple way to do that. It's a small hack but can avoid some headaches while @andfanilo is thinking of a better solution.
Here we go:

  1. locate the HTML component template streamlit_echarts are using - index.html
    ex: /.venv/lib/python3.8/site-packages/streamlit_echarts/frontend/build/index.html

  2. Put these lines before </body>

<script>      
  function sendMessageToStreamlitClient(type, data) {
    var outData = Object.assign({
      isStreamlitMessage: true,
      type: type,
    }, data);
    window.parent.postMessage(outData, "*");
  }

  // The `data` argument can be any JSON-serializable value.
  function sendDataToPython(data) {
    sendMessageToStreamlitClient("streamlit:setComponentValue", data);
  }
</script>
  1. Change your app.py
events = {
   "click": "function(params) { console.log(params); delete params.event; sendDataToPython({value:params});"
}
r = st_pyecharts(c,  width=9000, height=640, events=events, key='chart') 
st.write(json.dumps(r))
  • without the 'key' parameter, I'm couldn't return values.
  • JS events are tricky for cloning or converting to string, so I removed them from the echart's 'params' return.

Hope this helps.
PS: You can blame that guy ;) ->
https://discuss.streamlit.io/t/code-snippet-create-components-without-any-frontend-tooling-no-react-babel-webpack-etc/13064

@andfanilo
Copy link
Owner

That's a nice workaround @flunardelli :) feel free to post it back to the Forum post, will definitely help other users!

Still need to push a fix as this solution I suppose will not work on Streamlit Sharing 🤔

PS: Thiago's Streamlit hidden hacks, it's like manipulating Streamlit internals 😆

@flunardelli
Copy link

flunardelli commented Oct 11, 2021

thx @andfanilo
I just realise that we can use a much simpler approach ...

events = {
   "click": "function(p){console.log(p); delete p.event; window.parent.postMessage({isStreamlitMessage:!0,type:'streamlit:setComponentValue','value':p},'*');}"
} 

and probably it will work on Streamlit cloud/share...

best.

@andfanilo
Copy link
Owner

andfanilo commented Dec 12, 2021

Starting 0.4.0, any value returned inside the event method is sent back to Streamlit. If no return values nor events are provided, all works the same.

events = {"click": "function(params) {console.log(params);return params.name}"}

something = st_pyecharts(b, events=events)
st.text(something)

Thanks @brightxml for the contribution 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants