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

[feature requert] get click data or hover data #5

Closed
Liripo opened this issue Nov 1, 2023 · 3 comments
Closed

[feature requert] get click data or hover data #5

Liripo opened this issue Nov 1, 2023 · 3 comments

Comments

@Liripo
Copy link

Liripo commented Nov 1, 2023

Hello:
like plotly, It would be nice if clickData could be included.
I have a simple example, https://github.com/Liripo/dash-vega/blob/434f9cb7465d894262a7d4c862584eca9f33590a/src/lib/fragments/Vega.react.js#L21-L33

@Liripo
Copy link
Author

Liripo commented Nov 1, 2023

At the same time, I am also interested in getting the click events of the coordinate axis and legend, but I don’t know how to implement it.

@binste
Copy link
Collaborator

binste commented Nov 1, 2023

Hi Liripo, I haven't seen dash-vega before, seems like we were developing something similar! :)

So far in dash-vega-components, if you want to capture any kind of events in your chart, you would define a parameter in Altair which captures this event and give the parameter a name. You can then pass the parameter name to signalsToObserve and read the data out of signalData. While this doesn't offer click or hover events out of the box, it's way more flexible.

Clicks on scatter plot

For example, if you have a scatter plot and want to get click data, you can do:

import json

import altair as alt
import pandas as pd
from dash import Dash, Input, Output, callback, dash_table, dcc, html

import dash_vega_components as dvc

app = Dash(
    __name__, external_stylesheets=["https://codepen.io/chriddyp/pen/bWLwgP.css"]
)


app.layout = html.Div(
    [
        html.H1("Example", id="header1"),
        dvc.Vega(id="chart1", signalsToObserve=["selected_points"]),
        dcc.Markdown(id="chart1-params"),
    ]
)


@callback(Output("chart1", "spec"), Input("header1", "children"))
def create_chart(_):
    # generate fake data
    source = pd.DataFrame(
        {
            "x": [1, 2],
            "y": [5, 4],
        }
    )

    selector = alt.selection_point(fields=["x", "y"], name="selected_points")

    return (
        alt.Chart(source)
        .mark_circle(size=50)
        .encode(x="x", y="y")
        .add_params(selector)
        .to_dict()
    )


@callback(
    Output("chart1-params", "children"),
    Input("chart1", "signalData"),
    prevent_initial_call=True,
)
def display_altair_width_params(params):
    return format_json(params)


def format_json(json_data):
    return "```json\n" + json.dumps(json_data, indent=2) + "\n```"


if __name__ == "__main__":
    app.run_server(debug=True)
Screen.Recording.2023-11-01.at.18.45.28.mov

I first click on each point individually and then I use Shift+Click to select both.

If you add on="mouseover" to the selector, the callback is triggered instead when you hover over a point.

selector = alt.selection_point(fields=["x", "y"], name="selected_points", on="mouseover")

Interactive legend

Another example with an interactive legend:

import json

import altair as alt
import pandas as pd
from dash import Dash, Input, Output, callback, dash_table, dcc, html
from vega_datasets import data

import dash_vega_components as dvc

app = Dash(
    __name__, external_stylesheets=["https://codepen.io/chriddyp/pen/bWLwgP.css"]
)


app.layout = html.Div(
    [
        html.H1("Example", id="header1"),
        dvc.Vega(id="chart1", signalsToObserve=["legend_selection"]),
        dcc.Markdown(id="chart1-params"),
    ]
)


@callback(Output("chart1", "spec"), Input("header1", "children"))
def create_chart(_):
    source = data.unemployment_across_industries.url

    selection = alt.selection_point(
        fields=["series"], bind="legend", name="legend_selection"
    )

    return (
        alt.Chart(source)
        .mark_area()
        .encode(
            alt.X("yearmonth(date):T").axis(domain=False, format="%Y", tickSize=0),
            alt.Y("sum(count):Q").stack("center").axis(None),
            alt.Color("series:N").scale(scheme="category20b"),
            opacity=alt.condition(selection, alt.value(1), alt.value(0.2)),
        )
        .add_params(selection)
        .to_dict()
    )


@callback(
    Output("chart1-params", "children"),
    Input("chart1", "signalData"),
    prevent_initial_call=True,
)
def display_altair_width_params(params):
    return format_json(params)


def format_json(json_data):
    return "```json\n" + json.dumps(json_data, indent=2) + "\n```"


if __name__ == "__main__":
    app.run_server(debug=True)
Screen.Recording.2023-11-01.at.18.48.31.mov

I'm working with the Plotly Dash team on adding some examples to their documentation to make these things easier. You can also find more information on parameters in Altair here.

Does this answer your question?

@Liripo
Copy link
Author

Liripo commented Nov 3, 2023

Thank you very much for your help, the examples are very helpful.

@Liripo Liripo closed this as completed Nov 3, 2023
@binste binste pinned this issue Nov 3, 2023
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

2 participants