Dash layout issue when using Rows and Colums in Bootstrap Components - layout

I am trying to create a simple dashboard layout and just cannot get it to work. It involves having two rows of different heights in one column on the left and then one big column on the right. So I have managed to do it but I cannot get column 1, to be flush against 2 and 3, I have tried everything but I am new to this.
Here is the code:
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.title = " Dashboard"
app.layout = dbc.Container(
[
dbc.Row([
dbc.Col(html.Div([
dbc.Row([dbc.Col(html.Div(html.B('2')),style={'height': '80px',"border":"1px black solid"},width=3)]),
dbc.Row([dbc.Col(html.Div(html.B('3')),style={'height': '900px',"border":"1px black solid"},width=3)]),
])),
dbc.Col(html.Div(html.B('1'), style={'height': '100%',"border":"1px black solid"})),
])
], fluid = True)

It seems the key is to use html.div, here is the solution.
from dash import Dash, html
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
[
dbc.Row(
[
dbc.Col(
[
html.Div("2", style={"height": 80}, className="border"),
html.Div("3", style={"height": 900}, className="border"),
],
width=3,
),
dbc.Col(html.Div("1", className="vh-100 border")),
],
className="g-0",
)
],
fluid=True, )
if __name__ == "__main__":
app.run_server(debug=True)

Related

scatter plot with Dash

I am coding a Dash page to plot some data for myself.
I want to have some dynamic features on some of my plots.
On my dash I have one dropdown, one pie chart and one scatter chart.
Here is my code:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
app = dash.Dash()
app.layout = html.Div([
html.Label(['Select the Type:']),
dcc.Dropdown(
id='type_filter',
options=[{'label': i, 'value': i} for i in df.Type.unique()],
value='All'
),
dcc.Graph(
id='allocation_chart'
),
dcc.Graph(
id='allocation_history_chart'
),
])
#app.callback(
Output('allocation_chart','figure'),
[
Input('type_filter', 'value')
]
)
def update_allocation(type_):
if type_ == 'All':
filtered = df
else:
mask = df['Type'] == type_
filtered = df.loc[mask]
data = [
go.Pie(
labels=filtered['Asset'],
values=filtered['Total']
)
]
return {
'data': data,
'layout': go.Layout(title='Asset Allocation by Type')
}
#app.callback(
Output('allocation_history_chart','figure'),
[
Input('type_filter','value')
]
)
def update_allocation_history(type_):
if type_ == 'All':
filtered = df_index
else:
mask = df['Type'] == type_
filtered = df_index.loc[mask]
data = go.Figure()
for ticker in filtered.index:
data.add_trace(
go.Scatter(
x = filtered.loc[ticker].index,
y = filtered.loc[ticker],
name = ticker
)
)
return {
'data': [data],
'layout': go.Layout(title='History of Asset')
}
if __name__ == '__main__':
app.run_server()
here is the Dash:
Here is the scatter chart ran in my Notebook:
Everything is working - Dash is running well, i can see the dropdown and the pie chart - except the scatter chart - the second one.
I absolutely don't understand why because when I run the scatter chart in my Notebook it's working pretty well.
If you have any idea, don't hesitate.

Capture which items are displayed on Python Plotly Express chart based on legend selection

DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
Streamlit, version 1.12.2
plotly==5.10.0
I have a Plotly Express px.scatter chart being generated in a Streamlit page. The different data points available to be shown are set by the color= parameter in ...
fig = px.scatter(x=df[x_column_name],
y=df[y_column_name],
color=df[color_column_name])
Which data (color) points are actually shown on the chart can be selected in the legend (see images.)
Is there a way to detect in the code (via the fig or something else) which data points (colors) have actually been selected in the legend to appear on the chart? I.e. In the example pictures, for the Streamlit (Python) code to know that only DMP, OTP, and BP are currently being seen on the plotly chart?
All selected
None selected
DMP, OTP, BP selected
FULL CODE
def control_chart_by_compound(df,
x_column_name,
y_column_name,
color_column_name,
chart_width = 800,
marker_line_width = 1,
standard_deviation = False,
stddev_colors = ["#CCFF00","#FFCC99","#FF9966"],
average = False,
average_color = "green",
custom_marker_lines = [],
custom_marker_lines_colors = []
):
if custom_marker_lines_colors == []:
custom_marker_lines_colors = CSS_blues()
fig = px.scatter(x=df[x_column_name],
y=df[y_column_name],
color=df[color_column_name],
width=chart_width,
labels={
"x": x_column_name,
"y": y_column_name,
color_column_name: "Compounds"
},
)
# Adds buttons select or deselect all amongst the legend (default the compounds as different colors)
fig.update_layout(dict(updatemenus=[
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=["visible", "legendonly"],
label="Deselect All compounds",
method="restyle"
),
dict(
args=["visible", True],
label="Select All compounds",
method="restyle"
)
]),
pad={"r": 10, "t": 10},
showactive=False,
x=1,
xanchor="right",
y=1.1,
yanchor="top"
),
]
))
if average != False:
fig.add_hline(y=np.average(df[y_column_name]),
line_color=average_color,
line_width=marker_line_width,
line_dash="dash")
# Add zero hline
fig.add_hline(y=0, line_color="gainsboro")
### Standard deviations
if standard_deviation != False:
stddev = df[y_column_name].std()
for idx, color in enumerate(stddev_colors):
fig.add_hline(y=stddev * (idx+1), line_color=color, line_width=marker_line_width,)
fig.add_hline(y=-stddev * (idx+1), line_color=color, line_width=marker_line_width,)
for idx, line in enumerate(custom_marker_lines):
fig.add_hline(y=line, line_color=custom_marker_lines_colors[idx], line_width=marker_line_width,)
fig.add_hline(y=-line, line_color=custom_marker_lines_colors[idx], line_width=marker_line_width,)
# Background to clear
fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})
fig.update_layout(xaxis=dict(showgrid=False),
yaxis=dict(showgrid=False))
return fig

A nonexistent object was used in an Input of a Dash callback

I'm new in Plotly/Dash. I'm trying to build a sentiment analysis Dashboard.
I would like to represent the "sentiment" in a graph (realtime data: from a table) I reached my fist goal so far:
I choose: trump in my SQL.
#app.callback(
Output("live-graph", "figure"),[Input('sentiment_term', 'value'), Input('graph-update', 'n_intervals')]
)
#Output("wind-speed", "figure")
#Input("wind-speed-update", "n_intervals")
#Input("sentiment_term", "value")
#Input("graph-update", "n_intervals")]
def gen_wind_speed(self, sentiment_term):
conn = sqlite3.connect('twitter.db')
c = conn.cursor()
df = pd.read_sql("SELECT * FROM sentiment WHERE tweet LIKE '%trump%' ORDER BY unix DESC LIMIT 1000", conn)
df.sort_values('unix', inplace=True)
df['sentiment_smoothed'] = df['sentiment'].rolling(int(len(df)/5)).mean()
df.dropna(inplace=True)
X = df.unix.values[-100:]
Y = df.sentiment_smoothed.values[-100:]
data = plotly.graph_objs.Scatter(
x=X,
y=Y,
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(X),max(X)]),
yaxis=dict(range=[min(Y),max(Y)]),)}
Now as second goal I would like to generate (just beside the graph) a table with the data (in this case twits) used in the graph.
But when I add the table I got:
A nonexistent object was used in an Input of a Dash callback. The id of this object is recent-table-update and the property is n_intervals. The string ids in the current layout are: [live-graph, sentiment_term, graph-update, bin-slider, bin-auto, bin-size, wind-histogram, recent-tweets-table]
Which I don´t understand since I used the same Input/Output "logic" that before
Complete code,, apologizes if it does´t look organized enough
import os
import pathlib
import numpy as np
import pandas as pd
import datetime as dt
import dash
import dash_core_components as dcc
import dash_html_components as html
import sqlite3
import plotly
import plotly.graph_objs as go
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output, State
from scipy.stats import rayleigh
conn = sqlite3.connect('twitter.db', check_same_thread=False)
app_colors = {
'pageBackground': '#272B30',
'background': '#0C0F0A',
'text': '#6699ff',
'sentiment-plot':'#41EAD4',
'volume-bar':'#6699ff',
'someothercolor':'#80aaff',
'papercolor':'#1E2022',
'plotcolor':'#262626',
'fillcolor':'#ff6666',
'gridcolor': '#737373',
'backgroundTableHeaders': '#001133',
'backgroundTableRows': '#002266'
}
POS_NEG_NEUT = 0.1
MAX_DF_LENGTH = 100
GRAPH_INTERVAL = os.environ.get("GRAPH_INTERVAL", 5000)
app = dash.Dash(
__name__,
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
)
server = app.server
app_colorsor = {"graph_bg": "#082255", "graph_line": "#007ACE"}
app.layout = html.Div(
[
# header
html.Div(
[
html.Div(
[
html.H4("Twitter STREAMING", className="app__header__title"),
html.P(
"This app continually queries a SQL database and displays live charts of twitter sentiment analysis.",
className="app__header__title--grey",
),
],
className="app__header__desc",
),
html.Div(
[
html.Img(
src=app.get_asset_url("twitter_logo.png"),
className="app__menu__img",
)
],
className="app__header__logo",
),
],
className="app__header",
),
html.Div(
[
#Plot sentiment
html.Div(
[
html.Div(
[html.H6("Plot sentiment", className="graph__title")]
),
dcc.Graph(
id="live-graph",
animate=False
),
dcc.Input(
id="sentiment_term",
value="twitter",
type="text"
),
dcc.Interval(
id="graph-update",
interval=1*1000,
n_intervals=0
),
],
className="two-thirds column container",
),
html.Div(
[
# Recent tweets table
html.Div(
[
html.Div(
[
html.H6(
"Recent tweets table",
className="graph__title",
)
]
),
html.Div(
[
dcc.Slider(
id="bin-slider",
min=1,
max=60,
step=1,
value=20,
updatemode="drag",
marks={
20: {"label": "20"},
40: {"label": "40"},
60: {"label": "60"},
},
)
],
className="slider",
),
html.Div(
[
dcc.Checklist(
id="bin-auto",
options=[
{"label": "Auto", "value": "Auto"}
],
value=["Auto"],
inputClassName="auto__checkbox",
labelClassName="auto__label",
),
html.P(
"# of Bins: Auto",
id="bin-size",
className="auto__p",
),
],
className="auto__container",
),
#it says wind because I got it from a wind direction Dash template
dcc.Graph(
id="wind-histogram",
figure=dict(
layout=dict(
plot_bgcolor=app_colorsor["graph_bg"],
paper_bgcolor=app_colorsor["graph_bg"],
)
),
),
],
className="graph__container first",
),
# Table that I would like to add
html.Div(
[
html.H6(
"Recent tweets table",
className="graph__title",
)
]
),
html.Div(id="recent-tweets-table", children=[
html.Thead(html.Tr( children=[], style={'color': app_colorsors['text']})),
html.Tbody([html.Tr(children=[], style={'color': app_colorsors['text'],
'background-color': app_colors['backgroundTableRows'],
'border':'0.2px', 'font - size':'0.7rem'}
],
className='col s12 m6 l6', style={'width':'98%', 'margin-top':30, 'margin-left':15,
'margin-right':15,'max-width':500000}
),
],
className="one-third column histogram__direction",
),
],
className="app__content",
),
],
className="app__container",
)
dcc.Interval(
id='recent-table-update',
interval=2*1000,
n_intervals=0),
#def get_current_time():
#now = dt.datetime.now()
#total_time = (now.hour * 3600) + (now.minute * 60) + (now.second)
#return total_time
def df_resample_sizes(df, maxlen=MAX_DF_LENGTH):
df_len = len(df)
resample_amt = 100
vol_df = df.copy()
vol_df['volume'] = 1
ms_span = (df.index[-1] - df.index[0]).seconds * 1000
rs = int(ms_span / maxlen)
df = df.resample('{}ms'.format(int(rs))).mean()
df.dropna(inplace=True)
vol_df = vol_df.resample('{}ms'.format(int(rs))).sum()
vol_df.dropna(inplace=True)
df = df.join(vol_df['volume'])
return df
#app.callback(
Output("live-graph", "figure"),[Input('sentiment_term', 'value'), Input('graph-update', 'n_intervals')]
)
#Output("wind-speed", "figure")
#Input("wind-speed-update", "n_intervals")
#Input("sentiment_term", "value")
#Input("graph-update", "n_intervals")]
def gen_wind_speed(self, sentiment_term):
conn = sqlite3.connect('twitter.db')
c = conn.cursor()
df = pd.read_sql("SELECT * FROM sentiment WHERE tweet LIKE '%trump%' ORDER BY unix DESC LIMIT 1000", conn)
df.sort_values('unix', inplace=True)
df['sentiment_smoothed'] = df['sentiment'].rolling(int(len(df)/5)).mean()
df.dropna(inplace=True)
X = df.unix.values[-100:]
Y = df.sentiment_smoothed.values[-100:]
data = plotly.graph_objs.Scatter(
x=X,
y=Y,
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],'layout' : go.Layout(xaxis=dict(range=[min(X),max(X)]),
yaxis=dict(range=[min(Y),max(Y)]),)}
def generate_table(df, max_rows=20):
return html.Table(className="responsive-table",
children=[
html.Thead(
html.Tr(
children=[
html.Th(col.title()) for col in df.columns.values],
style={'color': app_colorsors['text'],
'background-color': app_colorsors['backgroundTableHeaders']}
)
),
html.Tbody(
[
html.Tr(
children=[
html.Td(data) for data in d
], style={'color': app_colorsors['text'],
'background-color': quick_color(d[2]),
'border':'0.2px', 'font - size':'0.7rem'}
)
for d in df.values.tolist()])
]
)
#app.callback(Output("recent-tweets-table", "children"),[Input('sentiment_term','value'), Input('recent-table-update', 'n_intervals')]
)
def update_recent_tweets(self, sentiment_term):
genTable = html.Table()
try:
conn = sqlite3.connect('twitter.db')
df = pd.read_sql("SELECT UnixTime, Tweet, Polarity FROM %s ORDER BY UnixTime DESC LIMIT 20" % (RunConfig.tableName), conn)
if len(df)>0:
df['Date'] = pd.to_datetime(df['UnixTime'], unit='ms')
df = df.drop(['UnixTime'], axis=1)
df = df[['Date', 'Tweet', 'Polarity']]
df.Polarity = df.Polarity.round(3)
genTable = generate_table(df, max_rows=10)
except Exception as e:
with open('errors.txt','a') as f:
f.write("update_recent_tweets: " + str(e))
f.write('\n')
return genTable
if __name__ == "__main__":
app.run_server(debug=True)
I think the problem is that you are introducing a non-existing (not yet) element in the callback as input. The element is the 'recent-table-update' which doesn't exist until you update the table. To avoid this you should introduce it in the callback as a State (it doesn't trigger the callback and the code will not break). More info: link
Here is your code:
#app.callback(
Output("recent-tweets-table", "children"),
[Input('sentiment_term','value'),
Input('recent-table-update', 'n_intervals')]
)
Here is my suggested code:
#app.callback(
Output("recent-tweets-table", "children"),
Input('sentiment_term','value'),
State('recent-table-update', 'n_intervals')
)

error somewhere in the code while adding colorscale in dash barplot

I have written some code to represent a barplot with a colorscale, in dash. The expected result looks something like this but with only one dropdown menu
https://brandatastudio.shinyapps.io/visualization-practica/
, therefore I wrote the following code:
#!/usr/bin/env python
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.offline as pyo
import plotly.graph_objs as go
import pandas as pd
from dash.dependencies import Input, Output
app = dash.Dash()
datause = pd.read_csv("datawind.csv" , sep = ",")
app.layout = html.Div([
dcc.Graph(
id = 'barplot1'),
dcc.Dropdown(
id="dropmenu" ,
options=[{'label' : i , 'value' : i } for i in datause.columns.values
],
value='Total Investment ($ Millions)')
],
)
#app.callback(Output(component_id = 'barplot1', component_property = 'figure'),
[Input(component_id = 'dropmenu' , component_property = 'value')])
def update_figure(dropmenuinput):
potato = dropmenuinput
return {
'data': [
go.Bar(
x = datause["State"],
y = datause[potato],
mode = 'markers',
marker = {
"color" : datause[potato],
"colorbar" : dict(title = "hola"),
"colorscale" : 'Viridis'
})],
'layout': go.Layout(
title = "pene"
,xaxis={'title': "state"},
yaxis ={'title' : potato}) }
if __name__ == '__main__':
app.run_server(debug=True)
Instead, the obtained results ends up looking like this
After testing and retesting, I discover that the main error of the code seems to be in this section
mode = 'markers',
marker = dict(
size=16,
color = datause['Total Investment ($ Millions)'],
colorbar = dict(title = "hola"),
colorscale = 'Viridis'
))]
If I remove that section of the code, the dashboard looks something like it should, without the colorscale of course.
So, the question is, what is failing in my insertion of the colorscale? I have been checking different posts of how to add them
https://community.plot.ly/t/add-a-colorbar-to-scatter-plot-in-python/13349
https://plot.ly/python/colorscales/#custom-contour-plot-colorscale
and I find no examples applied to dash dashboard, or barplots, only here can I hope to find help.
Notes: Heres is the information regarding to the enviroment and packages affecting:
chardet==3.0.4
click==6.7
Cython==0.28.2
dash==0.21.0
dash-core-components==0.22.1
dash-html-components==0.10.0
dash-renderer==0.12.1
decorator==4.3.0
nbformat==4.4.0
numpy==1.14.2
pandas==0.22.0
pandas-datareader==0.6.0
plotly==2.5.1
python-dateutil==2.7.2
pytz==2018.4
requests==2.18.4
urllib3==1.22
Werkzeug==0.14.1
Here is the dataset Iḿ using https://drive.google.com/open?id=1Cr74jKf2FHDA7XVAblQX3d9_dVHfXyVG
The only problem I see is the line
mode = 'markers',
inside the go.Bar. If you go to the reference you will see that Bar traces do not have this attribute. If it still doesn't work I suggest updating plotly, as version 3 was a major upgrade to the library (actually I would recommend updating even if it works).
Here is a minimal example from a notebook:
trace = go.Bar(
x = [1, 2, 3, 4],
y = [1, 2, 3, 4],
marker = {
"color" : [1, 2, 3, 4],
"colorbar" : dict(),
"colorscale" : 'Viridis',
"showscale": True
}
)
I have had a similar issue when adding a color scale to a Map using Dash and the way I resolved this was by finding out the underlying colour schemes by running the code:
import plotly.express as px
print(px.colors.sequential.Plasma)
['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921']
Then my command in Dash is:
"colorscale":[[0.0,'#0d0887'], [0.1,'#46039f'], [0.2,'#7201a8'], [0.3,'#9c179e'], [0.4,'#bd3786'], [0.5,'#d8576b'], [0.6,'#ed7953'], [0.7,'#fb9f3a'], [0.8,'#fdca26'], [1.0,'#f0f921']]

Plotly Dash Graph With Multiple Dropdown Inputs Not Working

I’m trying to create a time-series Dash line graph that has multiple interactive dropdown user input variables. I would ideally like each of the dropdown inputs to allow for multiple selections.
While I’m able to create the drop down menus successfully, the chart isn’t updating like I’d like. When I allow the dropdowns to have multiple selections, I get an error that arrays are different lengths. And when I limit the dropdowns to one selection, I get an error that [‘Vendor_Name’] is not in index. So this may be two separate problems.
Graph that doesn’t work:
Snippet of Excel data imported into DF
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
#import plotly.graph_objs as go
df = pd.read_csv("Data.csv", sep = "\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format = '%Y-%m')
cols = ['Product_1', 'Product_2', 'Product_3']
vendor = df['Vendor'].unique()
app = dash.Dash('Data')
app.layout = html.Div([
html.Div([
html.Div([
html.Label('Product'),
dcc.Dropdown(
id = 'product',
options = [{
'label' : i,
'value' : i
} for i in cols],
multi = True,
value = 'Product_1'
),
]),
html.Div([
html.Label('Vendor'),
dcc.Dropdown(
id = 'vendor',
options = [{
'label' : i,
'value' : i
} for i in vendor],
multi = True,
value = 'ABC')
,
]),
]),
dcc.Graph(id = 'feature-graphic')
])
#app.callback(Output('feature-graphic', 'figure'),
[Input('product', 'value'),
Input('vendor', 'value')])
def update_graph(input_vendor, input_column):
df_filtered = df[df['Vendor'] == input_vendor]
##also tried setting an index because of the error I was getting. Not sure if necessary
df_filtered = df_filtered.set_index(['Vendor'])
traces = []
df_by_col = df_filtered[[input_column, 'YearMonth']]
traces.append({
'x' :pd.Series(df_by_col['YearMonth']),
'y' : df_by_col[input_column],
'mode' : 'lines',
'type' : 'scatter',
'name' :'XYZ'}
)
fig = {
'data': traces,
'layout': {'title': 'Title of Chart'}
}
return fig
if __name__ == '__main__':
app.run_server(debug=False)
Thanks in advance for helping! Still new-ish to Python, but very excited about Dash’s capabilities. I’ve been able to create other graphs with single inputs, and have read through documentation.
Here is the approach I followed: (editing common example available in google with my approach):
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
all_options = {
'America': ['New York City', 'San Francisco', 'Cincinnati'],
'Canada': [u'Montréal', 'Toronto', 'Ottawa']
}
app.layout = html.Div([
dcc.Dropdown(
id='countries-dropdown',
options=[{'label': k, 'value': k} for k in all_options.keys()],
value='America', #default value to show
multi=True,
searchable=False
),
dcc.Dropdown(id='cities-dropdown', multi=True, searchable=False, placeholder="Select a city"),
html.Div(id='display-selected-values')
])
#app.callback(
dash.dependencies.Output('cities-dropdown', 'options'),
[dash.dependencies.Input('countries-dropdown', 'value')])
def set_cities_options(selected_country):
if type(selected_country) == 'str':
return [{'label': i, 'value': i} for i in all_options[selected_country]]
else:
return [{'label': i, 'value': i} for country in selected_country for i in all_options[country]]
if __name__ == '__main__':
app.run_server(debug=True)
Workaround here is: When there is single input present in parent dropdown, the value is in string format. But for multiple values, it comes in list format.
This code also work perfectly and gets updated automatically even when you click on cross option to remove any selected option.
Note: I have used 'placeholder' attribute instead of defining default value for it as it made no sense in this case. But you can also update the value dynamically in similar way.
1 input data
The data as it is in the csv is hard to loop.
And I would argue that it is the main reason your code does not work,
because you seem to understand the fundamental code structure.
Having put on my SQL glasses I think you should try to get it to sth like
Date, Vendor, ProductName, Value
2 callback input types change
multi is tricky because it changes switches between returning a str if only 1 item is selected and list if more than one is selected
3 callback return type
you code returns a dict but the callback declared figure as the return type
but here is the code with debugging traces of print() and sleep()
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import time
df = pd.read_csv("Data.csv", sep="\t")
df['YearMonth'] = pd.to_datetime(df['YearMonth'], format='%Y-%m')
products = ['Product_1', 'Product_2', 'Product_3']
vendors = df['Vendor'].unique()
app = dash.Dash('Data')
app.layout = html.Div([
html.Div([
html.Div([
html.Label('Product'),
dcc.Dropdown(
id='product',
options=[{'label' : p, 'value' : p} for p in products],
multi=True,
value='Product_1'
),
]),
html.Div([
html.Label('Vendor'),
dcc.Dropdown(
id='vendor',
options=[{'label': v, 'value': v} for v in vendors],
multi=True,
value='ABC'
),
]),
]),
dcc.Graph(id='feature-graphic', figure=go.Figure())
])
#app.callback(
Output('feature-graphic', 'figure'),
[Input('product', 'value'),
Input('vendor', 'value')])
def update_graph(input_product, input_vendor):
# df_filtered[['Product_1', 'YearMonth']]
if type(input_product) == str:
input_product = [input_product]
if type(input_vendor) == str:
input_vendor= [input_vendor]
datasets = ['']
i = 1
for vendor in input_vendor:
df_filtered = df[df['Vendor'] == vendor]
for product in input_product:
datasets.append((df_filtered[['YearMonth', 'Vendor', product]]).copy())
datasets[i]['ProductName'] = product
datasets[i].rename(columns={product: 'Value'}, inplace=True)
i += 1
datasets.pop(0)
print(datasets)
traces = ['']
for dataset in datasets:
print(dataset)
time.sleep(1)
traces.append(
go.Scatter({
'x': dataset['YearMonth'],
'y': dataset['Value'],
'mode': 'lines',
'name': f"Vendor: {dataset['Vendor'].iloc[0]} Product: {dataset['ProductName'].iloc[0]}"
}))
traces.pop(0)
layout = {'title': 'Title of Chart'}
fig = {'data': traces, 'layout': go.Layout(layout)}
return go.Figure(fig)
if __name__ == '__main__':
app.run_server()
quick and dirty disclosure:
If you handle the 1. issue it will dramatically simplify everything.
So I'd try to isolate the pd.DataFrame() juggling out of the callback and into the upper I/O part.
1) don't use counters in for loops
2) my variable names aren't the best either
3) the following style is caveman's python and there must be a better way:
traces = ['']
traces.append(this_and_that)
traces.pop(0)
Generally:
using print(input_variable) and print(type(input_variable))
gets my wheels most of the time out of the mud.
after all
you should notice that each trace got its individual name which will show up in the legend. Clicking on the name in the legend will add or remove the trace without the need for#app.callback()

Resources