I'm trying to deploy some app in dash but, although the dropdowns appears correcty, the plots are not getting called.
I already tried a lot of different things, but it always goes to a white referencial...
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import numpy as np
import pandas as pd
import plotly.graph_objs as go
import plotly.express as px
import plotly.io as pio
from plotly.colors import n_colors
from plotly.subplots import make_subplots
df = pd.read_csv('movies.csv', encoding = "ISO-8859-1")
df.columns = df.columns.str.capitalize()
###################### APP ############################
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div([
dcc.Graph(id = 'our_graph')
],className = 'nine columns'),
html.Div([
html.Br(),
html.Label(['Choose Country / Genre / Company:'],style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(id = 'country_drop',
options = [{'label':country, 'value':country} for country in df['Country'].unique()],
value = 'USA',
multi = False,
disabled=False,
clearable=True,
searchable=True,
placeholder='Choose Country...',
className='form-dropdown',
style={'width':"90%"},
persistence='string',
persistence_type='memory'),
dcc.Dropdown(id= 'genre_drop',
options = [{'label': genre, 'value' : genre} for genre in df['Genre'].unique()],
value = 'Drama',
multi = False,
disabled=False,
clearable=True,
searchable=True,
placeholder='Choose Genre..',
className='form-dropdown',
style={'width':"90%"},
persistence='string',
persistence_type='memory'),
dcc.Dropdown(id = 'company_drop',
options = [{'label':company, 'value':company} for company in df['Company'].unique()],
value = 'Paramount Pictures',
multi = False,
disabled=False,
clearable=True,
searchable=True,
placeholder='Choose Company..',
className='form-dropdown',
style={'width':"90%"},
persistence='string',
persistence_type='memory'),
],className='three columns')
])
####################Callbacks#######################
#app.callback(
dash.dependencies.Output('our_graph', 'figure'),
[dash.dependencies.Input("company_drop", "value"),
dash.dependencies.Input("country_drop", "value"),
dash.dependencies.Input("genre_drop", "value")
]
)
def plots(country, genre,company):
new_df = df.loc[(df['Country'] == country) & (df['Genre'] == genre) & (df['Company'] == company)]
revenue_df = new_df.groupby(by = ['Year'])['Gross','Budget'].sum()
fig = px.line(revenue_df, x=revenue_df.index, y=revenue_df.columns, title = 'Which Country has the highest revenue by category?',
labels=dict(x="Year", y= 'Amount of $ in billions'))
return fig
#Run App
if __name__ == '__main__':
app.run_server(debug=False)`
If someone can help me out...i'm a begginer but although it might be simples i'm already looking for the solution into 2 days...
The reason why the data is not displayed is that the order of the drop-down and the order in which it is received by the graph function are different, so the acquired data does not exist, resulting in an error.
#app.callback(
dash.dependencies.Output('our_graph', 'figure'),
dash.dependencies.Input("company_drop", "value"),
dash.dependencies.Input("country_drop", "value"),
dash.dependencies.Input("genre_drop", "value"))
def plots(company, country, genre):
new_df = df[(df['Country'] == country) & (df['Genre'] == genre) & (df['Company'] == company)]
revenue_df = new_df.groupby(by = ['Year'])[['Gross','Budget']].sum()
revenue_df.reset_index(inplace=True)
fig = px.line(revenue_df,
x='Year',
y=['Gross', 'Budget'],
title='Which Country has the highest revenue by category?',
)
fig.update_xaxes(title_text='YEAR')
fig.update_yaxes(title_text='Amount of $ in billions')
return fig
Related
I am working on an NLP project analyzing the words spoken by characters in The Office. Part of this project involves making a network diagram of which characters talk to each other for a given episode.
This will be shown in a Dash app by allowing a user to select dropdowns for 4 parameters: season, episode, character1, and character2.
Here is a relevant snippet of my code so far:
#Import libraries
import pandas as pd
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
#Load data
sheet_url = 'https://docs.google.com/spreadsheets/d/18wS5AAwOh8QO95RwHLS95POmSNKA2jjzdt0phrxeAE0/edit#gid=747974534'
url = sheet_url.replace('/edit#gid=', '/export?format=csv&gid=')
df = pd.read_csv(url)
#Set parameters
choose_season = df['season'].unique()
choose_episode = df['episode'].unique()
choose_character = ['Andy','Angela', 'Darryl', 'Dwight', 'Jan', 'Jim','Kelly','Kevin','Meredith','Michael','Oscar','Pam','Phyllis','Roy','Ryan','Stanley','Toby']
#Define app layout
app = dash.Dash()
server = app.server
app.layout = html.Div([
dbc.Row([
dbc.Col(
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in choose_season],
value=choose_season[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown2',
options=[{'label': i, 'value': i} for i in choose_episode],
value=choose_episode[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown3',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown4',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[1]
), width=3
)
])
])
if __name__=='__main__':
app.run_server()
In order to have this work efficiently, I would like to have the following dependencies in the dropdown menus:
1.) The selection of the first dropdown menu updates the dropdown menu
ie: Season updates possible episodes
2.) The selection of the first two dropdown menus updates the 3rd and 4th dropdown menus
ie: Season, Episode updates possible characters (if a character was not in that episode, they will not appear)
3.) The selection of the third dropdown menu updates the fourth dropdown menu
ie: If a character is selected in the third dropdown menu, they can not be selected in the fourth (can't select the same character twice)
I understand one way to do this is to make a massive season to episode dictionary and then an even larger season to episode to character dictionary.
I've already made the code to process the season to episode dictionary:
#app.callback(
Output('dropdown2', 'options'), #--> filter episodes
Output('dropdown2', 'value'),
Input('dropdown1', 'value') #--> choose season
)
def set_episode_options(selected_season):
return [{'label': i, 'value': i} for i in season_episode_dict[selected_season]], season_episode_dict[selected_season][0]
I can definitely build these dictionaries, but this seems like a really inefficient use of time. Does anyone know of a way to build these dictionaries with just a few lines of code? Not sure how to approach building these in the easiest way possible. Also, if you have an idea for a better way to approach this problem, please let me know that too.
Any help would be appreciated! Thank you!
I think I see what you're asking about now. Something like this should get you a basic dictionary, which you could then modify for the options param for the dropdowns.
df = pd.read_csv(url)
season_episode_character_dictionary = {}
for season in df['season'].unique.tolist():
df_season = df[df['season'].eq(season)]
season_episode_character_dictionary[season] = {}
for episode in df_season['episode'].unique.tolist():
df_episode = df_season[df_season['episode'].eq(episode)]
characters = df_episode['characters'].unique.tolist()
season_episode_character_dictionary[season][episode] = characters
When I try to pass a Figure object to the dcc.Graph() in my layout, I get en error that says:
dash.exceptions.InvalidCallbackReturnValue: The callback ..graph.figure.. is a multi-output.
Expected the output type to be a list or tuple but got:
Figure({# the content of the figure})
my code is like:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
app.layout = html.Div([
dcc.Graph(
id='graph'
)
])
#app.callback(
[
Output('graph', 'figure'),
],
[
Input('my-input', 'value')
]
)
def gen_graph(value):
dff = # my filtered df
fig = px.line(dff, x='x_var', y='y_var')
return fig
Feels like I'm missing something in how the Figure should be passed to the dcc.Graph(). Any ideas?
You structured your Output as a list, that makes it a multi-output callback. Just change it like this:
#app.callback(
Output('graph', 'figure'),
[
Input('my-input', 'value')
]
)
def gen_graph(value):
...
Alternatively, you could wrap your output in brackets to make it a list (return [fig]). Either way should work fine.
I'm new to the Dash and Plotly ecosystem and began building a web-based dashboard a few days ago.
Here is a snippet of code:
import dash
import dash_html_components as html
import dash_core_components as dcc
# initialize the application
app = dash.Dash()
# define the layout of the app
app.layout = html.Div([
# add a date range selector
dcc.DatePickerRange(
id = 'my-date-picker-range',
min_date_allowed = dt(2010,1,4),
max_date_allowed = dt(2020, 12, 31),
initial_visible_month = dt(2020, 5, 23)
),
html.Div(id = 'output-container-date-picker-range'),
# add some markdown text
dcc.Markdown(f'''
This report covers the time period spanning {start_date} to {end_date}.
'''),
])
#app.callback(
dash.dependencies.Output('output-container-date-picker-range', 'children'),
[dash.dependencies.Input('my-date-picker-range', 'start_date'),
dash.dependencies.Input('my-date-picker-range', 'end_date')])
app.run_server(debug = True)
I'm attempting to display the start_date and end_date variables inside the markdown text (using an f string). Unfortunately, I'm getting the following error message:
NameError: name 'start_date' is not defined
Is it possible to include variable output in Markdown text? Thanks!
You are using a decorator (#app.callback) but you did not attach it to a function to be executed. You need to attach the decorator to the function that is responsible for updating the right div.
I think your best bet is to stick to the documentation.
This gives a similar result as what you want:
import dash
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime as dt
# initialize the application
app = dash.Dash()
# define the layout of the app
app.layout = html.Div([
# add a date range selector
dcc.DatePickerRange(
id = 'my-date-picker-range',
min_date_allowed = dt(2010,1,4),
max_date_allowed = dt(2020, 12, 31),
initial_visible_month = dt(2020, 5, 23)
),
html.Div(id = 'output-container-date-picker-range'),
])
#app.callback(
dash.dependencies.Output('output-container-date-picker-range', 'children'),
[dash.dependencies.Input('my-date-picker-range', 'start_date'),
dash.dependencies.Input('my-date-picker-range', 'end_date')])
def update_output_div(start_date, end_date):
return f"This report covers the time period spanning {start_date} to {end_date}"
app.run_server(debug = True)
I'm trying to use the dcc.DatePickerRange in dash to allow the user to enter in a start date and end date which would filter a dataframe and then update the graph. However, I keep receiving the following error
TypeError: type object None
Below is my code. Not sure where I'm going wrong. Any help would be appreciated thanks.
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.plotly as py
import plotly.graph_objs as go
import sqlite3
import pandas as pd
from functools import reduce
import datetime as dt
conn = sqlite3.connect('paychecks.db')
df_ct = pd.read_sql('SELECT * FROM CheckTotal',conn)
df_earn = pd.read_sql('SELECT * FROM Earnings', conn)
df_whold = pd.read_sql('SELECT * FROM Withholdings', conn)
data_frames = [df_ct, df_earn, df_whold]
df_paystub = reduce(lambda left,right: pd.merge(left,right,on=['Date'], how='outer'), data_frames)
df_paystub['Date'] = pd.to_datetime(df_paystub['Date'], format='%Y-%m-%d')
dcc.DatePickerRange(
id='date-picker-range',
start_date_placeholder_text="Start Date",
end_date_placeholder_text="End Date",
calendar_orientation='vertical',
)
#app.callback(
dash.dependencies.Output('pay', 'figure'),
[dash.dependencies.Input('date-picker-range', 'start_date'),
dash.dependencies.Input('date-picker-range', 'end_date')]
)
def figupdate(start_date, end_date):
df = df_paystub
df['Date'] = pd.to_datetime(df['Date'], format='%Y-%m-%d')
df = df[(df['Date'] > start_date) & (df['Date'] < end_date)]
figure={
'data': [
go.Bar(
x = df['Date'],
y = df['CheckTotal'],
name = 'Take Home Pay',
),
go.Bar(
x = df['Date'],
y = df['EarnTotal'],
name = 'Earnings',
)
],
'layout': go.Layout(
title = 'Take Home Pay vs. Earnings',
barmode = 'group',
yaxis = dict(title = 'Pay (U.S. Dollars)'),
xaxis = dict(title = 'Date Paid')
)
}
return figure
Turns out I needed to add a start_date and end_date attribute to dcc.DatePickerRange.
dcc.DatePickerRange(
id='date-picker-range',
start_date_placeholder_text="Start Date",
end_date_placeholder_text="End Date",
start_date=df_paystub['Date'].iloc[0],
end_date=df_paystub['Date'].iloc[-1],
)
i developed python dash based application for monitoring. as a part of the project i want to display live graph and change the live graph value based on user input. i am stuck in this part. the live graph getting update when i start typing in input box (eg:temp) the graph keep on updating for each letter like t,te,tem,temp. so i created a button to submit the input value. still the graph updating for each letter.
the code for the same:
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Input(id='input-value', value='example', type='text'),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
]
)
call back function is like below
#app.callback(Output('live-graph', 'figure'),
[Input('submit-button','n_clicks')],
state=[State(component_id='sentiment_term', component_property='value')],
events=[Event('graph-update', 'interval')])
def update_graph_scatter(n_clicks, input_value):
conn = sqlite3.connect('database.db')
c = conn.cursor()
df = pd.read_sql("SELECT * FROM table WHERE colume LIKE ? ORDER BY unix DESC LIMIT 1000", conn ,params=('%' + input_value+ '%',))
df.sort_values('unix', inplace=True)
df['date'] = pd.to_datetime(df['unix'],unit='ms')
df.set_index('date', inplace=True)
X = df.index
Y = df.column
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)])}
Note: If i removed the interval the button start working.but i want to be live update as well as button
You could use an intermediate component like a div to save the input from the text field and update that div only on button click.
So you would have
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input-value', value='example', type='text'),
html.Div(['example'], id='input-div', style={'display': 'none'}),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
])
Now you update the div only on button click:
#app.callback(Output('input-div', 'children'),
[Input('submit-button', 'n_clicks')],
state=[State(component_id='input-value', component_property='value')])
def update_div(n_clicks, input_value):
return input_value
And the Graph always uses the the div content to query your database (either when the interval triggers or the div changes):
#app.callback(Output('live-graph', 'figure'),
[Input('graph-update', 'interval'),
Input('input-div', 'children')])
def update_graph_scatter(n, input_value):
...
Are you sure the updates on each letter are because of the input? Sounds like the interval updates the graph with the not finished input you are typing.
P.S.: I guess you have a name discrepancy between you Input and State id.