Interactive Graph
Add Index as Customdata
express
- custom_data
- assign data in one or more columns to each record
- combine with "color" to assign customdata to each record
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
fig = px.scatter(df, x="x", y="y", color="fruit", custom_data = ['label'])
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='hover-data')
])
@app.callback(
Output('hover-data', 'children'),
Input('basic-interactions', 'hoverData'))
def display_hover_data(hoverData):
return json.dumps(hoverData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
graph object
- customdata
- assign a list of data to the records in a specific trace
- use the different lists of data to different traces
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
fig = go.Figure()
temp = df[df['fruit'] == 'apple']
trace = go.Scatter(x = temp['x'], y = temp['y'], mode='markers', customdata = temp.index)
fig.add_trace(trace)
temp = df[df['fruit'] == 'orange']
trace = go.Scatter(x = temp['x'], y = temp['y'], mode='markers', customdata = temp.index)
fig.add_trace(trace)
temp = df[df['fruit'] == 'mango']
trace = go.Scatter(x = temp['x'], y = temp['y'], mode='markers', customdata = temp.index)
fig.add_trace(trace)
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='hover-data')
])
@app.callback(
Output('hover-data', 'children'),
Input('basic-interactions', 'hoverData'))
def display_hover_data(hoverData):
return json.dumps(hoverData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Mode
clickmode, determines the mode of single click interactions
- event (default), emits the "plotly_click" event, not select the clicked data point
- select, select the clicked data point, not emit the "plotly_click" event
- event+select, emits the "plotly_click" event, and select the clicked data point
- none, not emits the "plotly_click" event, not select the clicked data point
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
fig = px.scatter(df, x="x", y="y", color="fruit", custom_data = ['label'])
fig.update_layout(clickmode='event+select')
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_click_data(clickData):
return json.dumps(clickData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
dragmode, determines the mode of drag interactions
- select and lasso, select the record points, return points and range
- zoom (default), zoom the selected area, no return
- pan, drag the plot, no return
- orbit and turntable, apply to 3D traces
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
fig = px.scatter(df, x="x", y="y", color="fruit", custom_data = ['label'])
fig.update_layout(dragmode = "select")
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'selectedData'))
def display_selected_data(selectedData):
return json.dumps(selectedData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
hovermode, determines the mode of hover interactions
- closet (default), a single hoverlabel will appear for the "closest" point within the "hoverdistance"
Interactive Information
hoverData, data when mouse is hovered
clickData, data selected by clicking
selectedData, data selected with box select or lasso select
relayoutData, click and drag on the graph to zoom or click on the zoom buttons in the graph's menu bar, or click on legend items
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
temp = df[df['Country Name'] == 'Canada']
df = temp[temp['Indicator Name'] == 'CO2 emissions (metric tons per capita)']
def get_fig(data):
fig = go.Figure(go.Scatter(x=data['Year'], y=data['Value']))
return fig
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=get_fig(df)
),
html.Pre(id='output'),
html.Pre(id='output2'),
])
@app.callback(
Output('output2', 'children'),
Input('basic-interactions', 'hoverData'),
Input('basic-interactions', 'clickData'),
Input('basic-interactions', 'selectedData'))
def display_selected_data(hoverData, clickData, selectedData):
return str(hoverData)+'\n'+str(clickData)+'\n'+str(selectedData)
@app.callback(
Output('output', 'children'),
Output('basic-interactions', 'figure'),
Input('basic-interactions', 'relayoutData'),
State('basic-interactions', 'figure'))
def display_relayout_data(relayoutData, fig):
if not relayoutData:
raise PreventUpdate
if 'autosize' in relayoutData.keys():
print('autosize')
if 'xaxis.autorange' in relayoutData.keys():
return json.dumps(relayoutData, indent=2), get_fig(df)
print('reset')
if 'xaxis.range[0]' in relayoutData.keys():
xl = relayoutData['xaxis.range[0]']
xr = relayoutData['xaxis.range[1]']
yl = relayoutData['yaxis.range[0]']
yr = relayoutData['yaxis.range[1]']
df_selected = df.loc[(df.Year > xl) & (df.Year < xr) & (df.Value > yl) & (df.Value < yr)]
return json.dumps(relayoutData, indent=2), get_fig(df_selected)
return json.dumps(relayoutData, indent=2), get_fig(df)
if __name__ == '__main__':
app.run_server(debug=True)
Scatter
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
fig = px.scatter(df, x="x", y="y", color="fruit", custom_data = ['label'])
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'relayoutData'))
def display_relayout_data(relayoutData):
return json.dumps(relayoutData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({
"x": [1,2,1,2, 1],
"y": [1,2,3,4, 5],
"label": ['s1', 's2', 's3', 's4', 's5'],
"fruit": ["apple", "apple", "orange", "orange", "mango"]
})
df.index = ['r1', 'r2', 'r3', 'r4', 'r5']
fig = go.Figure()
trace = go.Scatter(x = df['x'], y = df['y'], mode='markers', customdata = df.index)
fig.add_trace(trace)
fig.update_layout(clickmode='event+select', dragmode = "lasso")
fig.update_traces(marker_size=20)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'selectedData'))
def display_selected_data(selectedData):
if selectedData:
indices = [p['customdata'] for p in selectedData['points']]
temp = df.loc[indices]
return temp.to_string()
return json.dumps(selectedData, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Pie
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
fig = px.pie(df, values='pop', names='country', custom_data = ['country'], title='Population of European continent')
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['label']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
fig = go.Figure()
trace = go.Pie(values = df['pop'], labels = df['country'])
fig.add_trace(trace)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
#if data:
#country = data['points'][0]['label']
#return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Histogram
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
df = px.data.tips()
fig = px.histogram(df, x="total_bill", nbins=40)
fig.update_layout(bargap=0.1)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
df = px.data.tips()
fig = go.Figure()
trace = go.Histogram(x = df["total_bill"])
fig.add_trace(trace)
fig.update_layout(bargap=0.1)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
return df.iloc[data['points'][0]['pointNumbers']].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Bar
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
fig = px.bar(df, x='country', y='pop')
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['label']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
df.loc[df['pop'] < 2.e6, 'country'] = 'Other countries'
fig = go.Figure()
trace = go.Bar(x = df['country'], y = df['pop'])
fig.add_trace(trace)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
#return df.iloc[data['points'][0]['pointNumbers']].to_string()
country = data['points'][0]['label']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Line
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder().query("continent=='Americas'")
fig = px.line(df, x="year", y="lifeExp", color='country', markers=True, custom_data=['country', 'year'])
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['customdata'][0]
year = data['points'][0]['customdata'][1]
return df.loc[(df['country'] == country) & (df['year'] == year)].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Box
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder()
fig = px.box(df, x = 'country', y="lifeExp")
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['x']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder()
fig = go.Figure()
trace = go.Box(x = df['country'], y = df['lifeExp'])
fig.add_trace(trace)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['x']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Violin
# Plotly Express
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder()
fig = px.violin(df, x = ['country'], y="lifeExp")
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['x']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
# Graph Objective
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder()
fig = go.Figure()
trace = go.Violin(x = df['country'], y = df['lifeExp'])
fig.add_trace(trace)
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig
),
html.Pre(id='output')
])
@app.callback(
Output('output', 'children'),
Input('basic-interactions', 'clickData'))
def display_selected_data(data):
if data:
country = data['points'][0]['x']
return df[df['country'] == country].to_string()
return json.dumps(data, indent=2)
if __name__ == '__main__':
app.run_server(debug=True)
Cross Interaction between Graphs
import json
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
app = dash.Dash(__name__)
df = px.data.gapminder()
sub_operation = False
app.layout = html.Div([
dcc.Graph(
id='g1',
),
dcc.Graph(
id='g2',
),
html.Pre(id='output1'),
])
def get_g1_plot(data):
fig = go.Figure()
trace = go.Scatter(x = data['lifeExp'], y = data['gdpPercap'], mode='markers')
fig.add_trace(trace)
return fig
def get_g2_plot(data):
fig = go.Figure()
trace = go.Pie(values = data['pop'], labels = data['continent'])
fig.add_trace(trace)
return fig
def data_screened(data, data_g1, data_g2, sub):
temp = data
if data_g1 and 'xaxis.range[0]' in data_g1:
xl = data_g1['xaxis.range[0]']
xr = data_g1['xaxis.range[1]']
yl = data_g1['yaxis.range[0]']
yr = data_g1['yaxis.range[1]']
temp = temp.loc[(temp.lifeExp > xl) & (temp.lifeExp < xr) & (temp.gdpPercap > yl) & (temp.gdpPercap < yr)]
if data_g2 and sub:
country = data_g2['points'][0]['label']
temp = temp[temp['continent'] == country]
return temp
@app.callback(
Output('g1', 'figure'),
Output('g2', 'figure'),
Output('output1', 'children'),
Input('g1', 'relayoutData'),
Input('g2', 'clickData')
)
def display_selected_data(data_g1, data_g2):
ctx = dash.callback_context
global sub_operation
if data_g1:
# auto selection
if 'xaxis.range[0]' not in data_g1:
# operations by clicking reset button
if 'xaxis.autorange' in data_g1:
# reset operation
if sub_operation:
sub_operation = False
return get_g1_plot(df), get_g2_plot(df), str(df.shape)
# click operation on pie chart
else:
sub_operation = True
temp = data_screened(df, data_g1, data_g2, sub_operation)
return get_g1_plot(temp), get_g2_plot(temp), temp.to_string()
# click operation following auto selection
if data_g2:
sub_operation = True
temp = data_screened(df, data_g1, data_g2, sub_operation)
return get_g1_plot(temp), get_g2_plot(temp), temp.to_string()
# intial auto selection
sub_operation = False
return get_g1_plot(df), get_g2_plot(df), str(df.shape)
# select operation on scatter plot
if ctx.triggered[0]['prop_id'].split('.')[0] == 'g1':
temp = data_screened(df, data_g1, data_g2, sub_operation)
return get_g1_plot(temp), get_g2_plot(temp), temp.to_string()
# click operation on pie chart
if ctx.triggered[0]['prop_id'].split('.')[0] == 'g2':
sub_operation = True
temp = data_screened(df, data_g1, data_g2, sub_operation)
return get_g1_plot(temp), get_g2_plot(temp), temp.to_string()
# initial state
return go.Figure(), go.Figure(), 'Plotting ...'
if __name__ == '__main__':
app.run_server(debug=True)
Reference