Hi i am coding a Sunburst chart in python Plotly with Dash. Sunburst v1
when i go deeper in the leafs Sunburst v2 in first leaf and update the graph i get back to the top rootSunburst v3 after update.
can i start already in leaf? Or maybe simulate the clicks after the graph updates.
I already got the path, id with clickData. Thanks
Edit:clickData Output I can read the information when i click on Point in the Sunburstgraph. There has to be a way to start the sunburst again at this point right? Added some shortened code.
data_sunburst = pd.DataFrame.from_dict(namedict, orient='index',columns=['name','weight','Art', 'tp', 'impact', 'parent_key', 'child_list'])
app = dash.Dash(__name__) ##Starte Dash
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
app.layout = html.Div([
html.H4(id="title",
style={
'textAlign': 'left'}
),
html.Div([
html.H5("Focus CM"),
dcc.RadioItems(
id='focus_cm',
options=[
{'label': "True", 'value': "True"},
{'label': "False", 'value': "False"}],
value="False"
)]),
html.Div([
html.H5("Show T/B"), #color some areas
dcc.RadioItems(
id='show_tb',
options=[
{'label': "Show", 'value':"True"},
{'label': "Dont", 'value':"False" }],
value="False"
)]),
html.Br(),
dcc.Graph(id='sunburst'),
html.Div([
dcc.Markdown("""
**Click Data**
Click on points in the graph.
"""),
html.Pre(id='click-data', style=styles['pre']),
], className='three columns'),
])
#app.callback(
Output('click-data', 'children'),
Output('title', 'children'),
Input('sunburst', 'clickData'))
def display_click_data(clickData):
click_path = "test"
if clickData:
click_path = clickData["points"][0]["id"]
percentEntry = (clickData["points"][0]).get("percentEntry") ##Show all when returning to root
parent = (clickData["points"][0]).get("parent")
if percentEntry == 1 and parent == "test":
click_path = "test"
title = f"Selected from Sunburst Chart: {' '.join(click_path)}"
return json.dumps(clickData, indent=2), title
#app.callback(
Output('sunburst', 'figure'),
Input('show_tb', 'value'))
def update_graph(show_tb_input):
global focus_cm, show_tb, tp_dict
if show_tb_input == "True":
show_tb = True
else:
show_tb =False
tp_dict = {"bsp": C_BSP, "wm": C_WM}
colors = set_colors_for_sunburst(namedict) ## set color when Show T/B input True;False
fig = go.Figure(go.Sunburst( ## Build fig; Can i build already in Point from clickData?
ids=data_sunburst.index,
labels=data_sunburst.name,
parents=data_sunburst.parent_key,
values=data_sunburst.weight,
branchvalues="total",
marker=dict(colors=colors),
insidetextorientation="auto",
))
fig.update_layout(
grid=dict(columns=2, rows=1),
margin=dict(t=0, l=0, r=0, b=0))
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=True)
Easy solution:
Sunburst Object has paramenter level:
level – Sets the level from which this trace hierarchy is rendered. Set level to '' to start from the root node in the hierarchy. Must be an “id” if ids is filled in, otherwise plotly attempts to find a matching item in labels.
Related
I’m trying to return name of points when clicking on Scatter Plot points but it just return one. How can I do to return multiple value when clicking multiple points. Below is my sample code:
from dash import Dash, html, dcc, Input, Output
import pandas as pd
import plotly.express as px
PCA_table=pd.read_excel('https://github.com/hoatranobita/Jobs/blob/main/PCA_table.xlsx?raw=true')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
options=PCA_table.columns.unique(),
value='PC1',
id='crossfilter-xaxis-column',
)],style={'width': '49%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
options=PCA_table.columns.unique(),
value='PC2',
id='crossfilter-yaxis-column'
)], style={'width': '49%', 'float': 'right', 'display': 'inline-block'})
], style={'padding': '10px 5px'}),
html.Div([
dcc.Graph(
id='crossfilter-indicator-scatter',
clickData={'points': [{'hovertext': '184A1'}]}
)], style={'width': '49%', 'display': 'inline-block', 'padding': '0 20'}),
html.Div([
html.Div(id='x-time-series'),
], style={'display': 'inline-block', 'width': '49%'}),
])
#app.callback(
Output('crossfilter-indicator-scatter', 'figure'),
Input('crossfilter-xaxis-column', 'value'),
Input('crossfilter-yaxis-column', 'value'))
def update_graph(xaxis_column_name, yaxis_column_name):
fig = px.scatter(PCA_table,x=PCA_table[xaxis_column_name],
y=PCA_table[yaxis_column_name],
color=PCA_table['Labels'],
labels=PCA_table['Columns'],
hover_name=PCA_table['Columns'])
fig.update_layout(clickmode='event')
fig.update_layout(margin={'l': 40, 'b': 40, 't': 10, 'r': 0}, hovermode='closest')
return fig
#app.callback(
Output('x-time-series', 'children'),
Input('crossfilter-indicator-scatter', 'clickData'))
def update_y_timeseries(clickData):
click_name = clickData['points'][0]['hovertext']
return html.Span(click_name)
if __name__ == '__main__':
app.run_server(debug=False,port=1111)
As you see, I want to return click_name as multiple values not just one.
I’ve read about clickevent but still not get it. Thank you.
Use clickmode='event+select' to enable accumulation and to handle both click and selection events by listening for one single event (selectedData).
If layout.clickmode = 'event+select', selection data also accumulates
(or un-accumulates) selected data if you hold down the shift button
while clicking.
You can also set dragmode='select' if you want to modebar to be ready for selecting points (default mode is 'zoom').
fig.update_layout(
clickmode='event+select',
dragmode='select',
margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
hovermode='closest'
)
Now in the callback, use selectedData instead of clickData :
#app.callback(
Output('x-time-series', 'children'),
Input('crossfilter-indicator-scatter', 'selectedData'),
prevent_initial_call=True)
def update_y_timeseries(selectedData):
selection= [p['hovertext'] for p in selectedData['points']]
return html.Span(', '.join(selection))
I want to make interactive dashboard using 'callback'. The final goal is to make dashboard graph to change when person click the polygon of the map. But i don't know how to make 'id' for each polygon.Can anybody help solving this problem? Below is the code.
for idx, sigun_dict in enumerate(state_geo1['features']):
sigun_id = sigun_dict['properties']['new_code']
sigun_nmm = df.loc[(df.new_code == sigun_id), 'SGG'].iloc[0]
A_R = df.loc[(df.new_code == sigun_id), 'A_R'].iloc[0]
txt = f'<b><h4>{sigun_nmm}</h4></b>A_R:{A_R}<br>'
state_geo1['features'][idx]['properties']['tooltip1'] = txt
import plotly.express as px
for Type in Types:
trace1.append(go.Choroplethmapbox(
geojson=state_geo1,
locations=df['new_code'].tolist(),
z=df[Type].tolist(),
text=suburbs,
featureidkey='properties.new_code',
colorscale=color_deep,
colorbar=dict(thickness=20, ticklen=3),
zmin=0,
zmax=df[Type].max() + 0.5,
visible=False,
subplot='mapbox1',
hovertemplate = "<b>%{text}</b><br><br>"+
"value: %{z}<br>"+
"<extra></extra>"))
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "인구감소지역 지원방안"
app.layout = html.Div([
html.Div(children=[
html.H1(children='한국 인구감소지역 지원방안',
style={"fontSize":"48px"},
className="header-title"
),
html.P(
children="한국 인구감소지역의 대표 지표들과 지역에 따른 분포 지도",
className="header-description"
),
dcc.Graph(
id='example-graph-1',
figure=fig
),
html.Div(children='''
본 대시보드는 지방행정연구원의 지원으로 작성되었음
''')
]),
html.Div([
dash_table.DataTable(
id='datatable_id',
data=df.to_dict('records'),
columns=[
{"name":i, "id": i, "deletable":False, "selectable":False} for i in df.columns
],
editable=False,
filter_action="native",
sort_action="native",
sort_mode="multi",
row_selectable="multi",
row_deletable=False,
selected_rows=[],
page_action="native",
page_current=0,
page_size=6,
],
className='row'),
])
i want to make the graph to change when person click the polygon of the map. But don't know how to create the id for that.
app = Dash(__name__)
colors = {
'background': '#ededed',
'text': '#0b1710'
}
fig = px.scatter(df, x="AverageTime", y="Machine",
size="Jobs", color="Category", hover_name="MaxTime",
log_x=False, log_y=False, size_max=70, labels={
"AverageTime": "Average time since last update(min)",
"Machine": "Machine code",
"MaxTime": "Longest time since last update(min)",
"Category": "Department",
}, title="Vision Labs Orders Movement Tracking")
app.layout = html.Div([
dcc.Graph(
id='graph',
figure=fig
)
])
fig.update_layout(
plot_bgcolor=colors['background'],
paper_bgcolor=colors['background'],
font_color=colors['text'],
autosize=True,
height=900
)
if __name__ == '__main__':
app.run_server(debug=True)
to
This is my current code for better understanding. If I knew how to fetch data needed to filter the table by clicking on the point I would be able to establish that in pure python probably
I am new to python Dash. I am trying to create a dashboard with a dropdown menu and a map. By the selecting a value in the dropdown menu, the map will be updated with a new html map.
Here is the code:
dropdown_list = [{'label': 'MSFT', 'value': 'MSFT'},
{'label': 'IBM', 'value': 'IBM'}]
app.layout = html.Div(
children=[
html.Div(className='row',
children=[
html.Div(className='three columns div-user-controls',
children=[
html.Div(
children=[
dcc.Dropdown(id='selector', options=dropdown_list,
multi=False, value=dropdown_list[0]['value'],
style={'backgroundColor': '#1E1E1E'}
),
],
style={'color': '#1E1E1E'})
]
),
html.Div(className='nine columns div-for-charts bg-grey',
children=[
html.Iframe(id='map', style={'border': 'none'}, width='100%', height='750')
])
])
])
## Callback for timeseries price
#app.callback(Output('map', 'srcDoc'),
[Input('selector', 'value')])
def update_map(dropdown_values):
for vv in dropdown_values:
if vv == 'MSFT':
return open(html_file1, 'r').read()
elif vv == 'IBM':
return open(html_file2, 'r').read()
else:
return dash.no_update
The map, however, does not show up and is not updated. Can anyone give me some hints on this? Thank you in advance.
I have found the issue. In the dropdown menu, since multi=False, there will be only one value in the input of the callback function: dropdown_values. So there is no need to loop through a list and match the value.
Below is the corrected callback function
#app.callback(Output('map', 'srcDoc'),
[Input('selector', 'value')])
def update_map(dropdown_values):
if dropdown_values == 'MSFT':
return open(html_file1, 'r').read()
elif dropdown_values == 'IBM':
return open(html_file2, 'r').read()
else:
return dash.no_update
I'm making a webapp using Python and Dash, this webapp includes a choropleth map of the world with data based on the selected year. I want to be able to change the year and with that also update the map to match that year. I prefer to do this with the Dash slider, although any other way I would appreciate as well.
I've tried updating other graphs such as line charts with the text input, and that worked, but when i changed it to a choropleth map it stopped updating. It now only creates the map but updates on it don't show up. I've put some print text in the update function and it confirmed that it is actually called when I change the input, but the graph just doesn't update.
The layout:with the dcc.input i want to update the html.Div 'my-div'
app.layout = html.Div( children=[
html.H1(
children='UN Sustainable Development goal: Poverty',
style={
'textAlign': 'center',
'color': colors
}
),
dcc.Input(id='my-id',value='30', type='text'),
html.Div(id='my-div')
,
daq.Slider(
id='my-daq-slider',
min=1,
max=sliderlength,
step=1,
),
html.Div(id='slider-output')
], style={
'textAlign': 'center'
})
The update part
#app.callback(
Output('my-div', 'children'),
[Input('my-id', 'value')])
def update_output_div(input_value):
return dcc.Graph(
id='my-div',
figure={'data': [go.Choropleth(
locations = df_pov['Country Code'],
z = df_pov.iloc[:,int(input_value)],
text = df_pov['Country Name'],
autocolorscale = True,
reversescale = False,
marker = go.choropleth.Marker(
line = go.choropleth.marker.Line(
color = 'rgb(180,180,180)',
width = 0.5
)),
colorbar = go.choropleth.ColorBar(
tickprefix = '%',
title = '% below 1.90$ '),
)],
'layout': go.Layout(
title = go.layout.Title(
text = list(df_pov)[int(input_value)]
),
geo = go.layout.Geo(
showframe = False,
showcoastlines = False,
projection = go.layout.geo.Projection(
type = 'equirectangular'
)
),
annotations = [go.layout.Annotation(
x = 0.55,
y = 0.1,
xref = 'paper',
yref = 'paper',
text = 'Source: Kaggle',
showarrow = False
)]
)
}
)
What i expected: for the choropleth to update when changing the text input, or slider input.
Actual: the map gets created once ( with the same function that should update it), but doesn't update.
Dash doesn't like new components being loaded in like this. Try initializing your graph by adding an empty graph to the layout like this:
html.Div(id='my-div', children=[
dcc.Graph(
id='my-graph-id',
figure=dict(
data=[],
layout={},
),
)
])
With the graph already on the page, you would have to change the callback so that it updates the figure prop of the Graph instead of the children of the div.
Also, you have multiple IDs that are the same. Dash doesn't like that. Make sure every ID is unique. If all of this still does not work, I may need to ask you to post some more details so I can help further. Good luck!