Hello,
I have a dataframe of 4 columns. I have the below code, which uses dynamic callbacks to add/remove charts. col1 and col2 are numeric, col3 is category, and col4 is also numeric.
In my plot, I want to have col4 on the y-axis, col1 and col2 on the x-axis, and col3 as the highlighted background.
I have added the highlighted background using fig.add_shape. If you run my code, it should work well. But I have two issues.
Before I select col1 or col2 from the dropdown menu, the highlighted backgrounds are placed on the chart. I want to trigger them, and show them on the chart after parameter selection.
To highlight the plot, I had used fig.add_vrect or fig.add_hrect, but I couldn’t override the lines on the highlighted sections and the color of the lines looked bad, so I start using fig.add_shape.
Also, how I can fix colors for the lines? Right now, the first selected parameter from the dropdown menu is going to be blue and the second parameter is red. I want to have my col1 always in one defined color, and col2 in another fixed color.
Thanks in advance.
from dash import Dash, html, dcc, Output, Input, State, MATCH, ALL
import plotly.express as px
import pandas as pd
import numpy as np
import dash_bootstrap_components as dbc
df={'col1':[12,15,25,33,26,33,39,17,28,25],
'col2':[35,33,37,36,36,26,31,21,15,29],
'col3':['A','A','A','A','B','B','B','B','B','B'],
'col4':[1,2,3,4,5,6,7,8,9,10]
}
df = pd.DataFrame(df)
app = Dash(__name__, external_stylesheets=[dbc.themes.SUPERHERO])
app.layout = html.Div([
html.Div(children=[
html.Button('add Chart', id='add-chart', n_clicks=0)
]),
html.Div(id='container', children=[])
])
@app.callback(
Output('container', 'children'),
[Input('add-chart', 'n_clicks'),
Input({'type': 'remove-btn', 'index': ALL}, 'n_clicks')],
[State('container', 'children')],
prevent_initial_call=True
)
def display_graphs(n_clicks, n, div_children):
ctx = dash.callback_context
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]
elm_in_div = len(div_children)
if triggered_id == 'add-chart':
new_child = html.Div(
id={'type': 'div-num', 'index': elm_in_div},
style={'width': '25%',
'display': 'inline-block',
'outline': 'none',
'padding': 5},
children=[
dcc.Dropdown(id={'type': 'feature-choice',
'index': n_clicks},
options=df.columns.values[0:2],
multi=True,
clearable=True,
value=[]
),
dcc.Graph(id={'type': 'dynamic-graph',
'index': n_clicks},
figure={}
),
html.Button("Remove", id={'type': 'remove-btn', 'index': elm_in_div})
]
)
div_children.append(new_child)
return div_children
if triggered_id != 'add-chart':
for idx, val in enumerate(n):
if val is not None:
del div_children[idx]
return div_children
@app.callback(
Output({'type': 'dynamic-graph', 'index': MATCH}, 'figure'),
[Input({'type': 'feature-choice', 'index': MATCH}, 'value')]
)
def update_graph(X):
if X is None:
raise PreventUpdate
Xmin = df[X].min().min()
Xmax = df[X].max().max()
# to find the height of y-axis(col4)
col4_max = df['col4'].max()
col4_min = df['col4'].min()
fig1 = px.line(df, x=X, y='col4')
fig1.update_layout({'height': 600,
'legend': {'title': '', 'x': 0, 'y': 1.06, 'orientation': 'h'},
'margin': {'l': 0, 'r': 20, 't': 50, 'b': 0},
'paper_bgcolor': 'black',
'plot_bgcolor': 'white',
}
)
fig1.update_yaxes(range=[col4_max, col4_min], showgrid=False)
fig1.update_xaxes(showgrid=False)
categ_col3 = df.col3.dropna().unique()
colors = ['#54FF9F', '#87CEFF']
for (i,j) in zip(categ_col3, colors):
index_min = df.loc[df.col3 == i].index[0]
index_max = df.loc[df.col3 == i].index[-1]
if index_min == 0:
cat_min = df['col4'][index_min]
else:
cat_min = df['col4'][index_min-1]
cat_max = df['col4'][index_max]
fig1.add_shape(type="rect", x0=Xmin, y0=cat_min, x1=Xmax, y1=cat_max,
fillcolor=j, layer='below', opacity=0.5,
)
return fig1
if __name__ == '__main__':
app.run_server(debug=True)```