Dash ClickPoint Callback to Modify Data

Hello,

I am working with Dash and a Plotly Scatterplot, and I am looking to use a callback to allow the user to click points on the scatterplot, and in turn this click action inverts the boolean associated with that point. I am using a pandas DataFrame with three columns, the X and Y locations as well as a column for true/false state of each point, which controls the color of the points. I am having trouble placing arguments within the definition “display_click_data”. Any help on how to do this would be appreciated.

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.express as px
from dash.dependencies import Input, Output
import numpy as np

start of the sample data colleciton

a = [False, True]
truefalse = pd.DataFrame(np.random.choice(a,size=4))
truefalse.columns = [‘truefalse’]

geometry = pd.DataFrame(np.random.randint(0,100,size=(4,2)), columns=list(‘XY’))

df = geometry.join([truefalse])

end of the sample data collection

this is the code for the styling of the dash interface

the dataframe needed ends here and begins with the layout and development of the visualization of the data

sliderlist = [‘hourlydata1’,‘hourlydata2’,‘hourlydata3’,‘hourlydata4’,‘hourlydata5’,‘hourlydata6’,‘hourlydata7’,‘hourlydata8’,‘hourlydata9’,‘hourlydata10’,‘hourlydata11’,‘hourlydata12’,‘annualdata’]
sliderlistdf = pd.DataFrame(sliderlist, columns=[‘slidernames’])

slidervalues = [1,2,3,4,5,6,7,8,9,10,11,12,13]
slidervaluesdf = pd.DataFrame(sliderlist, columns=[‘slidervalues’])

external_stylesheets = [‘https://codepen.io/chriddyp/pen/bWLwgP.css’]

app = dash.Dash(name, external_stylesheets=external_stylesheets)

fig = px.scatter(df, x=“X”, y=“Y”, color=“truefalse”)

app.layout = html.Div([
dcc.Graph(id=‘graph-with-slider’, figure=fig),
dcc.RangeSlider(
id=‘month-slider’,
min=1,
max=12,
value=[1,12],
marks={
1: ‘January’,
2: ‘February’,
3: ‘March’,
4: ‘April’,
5: ‘May’,
6: ‘June’,
7: ‘July’,
8: ‘August’,
9: ‘September’,
10: ‘October’,
11: ‘November’,
12: ‘December’
},
step=None,
updatemode=‘drag’
),
dcc.RangeSlider(
id=‘timeofday-slider’,
min=0,
max=23,
value=[0,23],
marks={
0: ‘12AM’,
1: ‘1AM’,
2: ‘2AM’,
3: ‘3AM’,
4: ‘4AM’,
5: ‘5AM’,
6: ‘6AM’,
7: ‘7AM’,
8: {‘label’: ‘8AM’, ‘style’: {‘color’: ‘#f50’}},
9: ‘9AM’,
10: ‘10AM’,
11: ‘11AM’,
12: {‘label’: ‘12PM’, ‘style’: {‘color’: ‘#66cc00’}},
13: ‘1PM’,
14: ‘2PM’,
15: ‘3PM’,
16: ‘4PM’,
17: ‘5PM’,
18: {‘label’: ‘6PM’, ‘style’: {‘color’: ‘#f50’}},
19: ‘7PM’,
20: ‘8PM’,
21: ‘9PM’,
22: ‘10PM’,
23: ‘11PM’
},
step=None,
updatemode=‘drag’
),
html.Div([
dcc.Markdown("""
Click Data

    Click on points in the graph.
"""),
    html.Pre(id='click-data'),
], className='three columns')

])

@app.callback(
Output(‘graph-with-slider’, ‘figure’),
[Input(‘month-slider’, ‘value’), Input(‘timeofday-slider’, ‘value’)]
)

this callback and definition should just handle the True/False state of the point list (which will then be used

to retrieve the data from MongoDB)

@app.callback(
Output(‘click-data’, ‘children’),
Input(‘graph-with-slider’, ‘clickData’))

def display_click_data(clickData):
index = clickData[‘points’][0][‘pointIndex’]
#modify the dataframe and invert the boolean HERE
print(clickData)

#the order of the inputs in the definition is the same order as the callback, regardless of name
def update_figure(selected_time):
rangelow = 0
rangehigh = df.to_numpy().max()

fig = px.scatter(df, x="X", y="Y", color="shadestate", range_color=[rangelow, rangehigh])

fig.update_layout(transition_duration=500,
                  title = "Test Plot",
                  )

fig.update_layout(clickmode='event+select')

fig.update_layout({'plot_bgcolor': 'rgba(0,0,0,0)'})

fig.update_yaxes(
    scaleanchor = 'x',
    scaleratio = 1,
  )

return fig

if name == ‘main’:
app.run_server(debug=True)