im kinda new to Python and Dash.
As i'm interested in Data Analytics I started messing around with Dash.
The plan is to build a stock dashboard but i'm stuck with some things...
I want to have an dcc.Input box where you can put a Ticker and submit with html.button,
later on I want to display data from multiple stocks in different html.Details so my Question is
how to achieve that.
I'm not getting to far because I don't understand the callback.
When trying the provied code I get Error:Callback error updating table.children - AttributeError: 'NoneType' object has no attribute 'upper'
Whats the correct way to turn input into a datatable and put in a html.Details
import yfinance as yf
import pandas as pd
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input, State
app = dash.Dash()
app.layout = html.Div([
dcc.Input(id='input', value='', type='text', placeholder='Enter Stock ticker'),
html.Button('Submit', id='button'),
html.Div(id='table')
])
#app.callback(
[Output('table', 'children')],
[Input('button', 'n_clicks')],
[State('input', 'value')]
)
def update_table(input_value, n_clicks):
ticker = yf.Ticker(input_value.upper())
history = ticker.history(period='max')
return html.Div([
html.Details(
dash_table.DataTable(
id='tickerdata',
columns = [{'name': i, 'id': i} for i in history.columns],
data = history,
)
)
])
if __name__ == '__main__':
app.run_server(debug=True)
The cause of the error was that the order in which the callback functions were received and the arguments of the update function were not in the correct order. n_clicks is trying to capitalize the number and the error occurred. The next error is that the data frame needs to be changed to a dictionary in order to be displayed in the table. Also, the data in the stocks is indexed by date, so the date column needs to be unindexed in order to display it.
import yfinance as yf
import pandas as pd
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input, State
app = dash.Dash()
app.layout = html.Div([
dcc.Input(id='input', value='', type='text', placeholder='Enter Stock ticker'),
html.Button('Submit', id='submit_btn',n_clicks=0),
html.Div(id='table')
])
#app.callback(
Output('table', 'children'),
[Input('submit_btn', 'n_clicks')],
[State('input', 'value')]
)
def update_table(n_clicks, input_value):
ticker = yf.Ticker(input_value.upper())
history = ticker.history(period='max')
history.reset_index(inplace=True)
return html.Div([
html.Details(
dash_table.DataTable(
id='tickerdata',
columns = [{'name': i, 'id': i} for i in history.columns],
data = history.to_dict('records'),
fixed_rows={'headers':True}
)
)
])
if __name__ == '__main__':
app.run_server(debug=True)
Related
I am making a Python Dash Canvas and try to access the json data from geometries painted on the canvas. From here, I aim to return a data table from the information stored in json format.
I first predefined columns found in the json data: ['type', 'width', 'height', 'scaleX', 'strokeWidth', 'path']:
enter image description here
Then I would like to also add the column "pathOffset", found in the json, but when adding this column to the list of predefined columns, the table doesnt update accordingly.
This is my code:
from dash_canvas import DashCanvas
import dash
from dash.exceptions import PreventUpdate
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import dash_daq as daq
from dash_table import DataTable
import json
filename = 'https://www.publicdomainpictures.net/pictures/60000/nahled/flower-outline-coloring-page.jpg'
canvas_width = 100
columns = ['type', 'width', 'height', 'scaleX', 'strokeWidth', 'path']
app = JupyterDash(__name__)
app.layout = html.Div([
html.Div([
DashCanvas(
id='canvaas-color',
width=canvas_width,
filename=filename,
hide_buttons=['line', 'zoom', 'pan'],
)
], className="six columns"),
DataTable(id='canvaas-table',
style_cell={'textAlign': 'left'},
columns=[{"name": i, "id": i} for i in columns])
])
#app.callback(Output('canvaas-table', 'data'),
Input('canvaas-color', 'json_data'))
def update_data(string):
if string:
data = json.loads(string)
else:
raise PreventUpdate
return data['objects']
if __name__ == '__main__':
app.run_server(mode="inline", port=3000)
# Run app and display result inline in the notebook
CODE:
app.layout=html.Div([
html.Div('WORLD HAPPINESS REPORT',
style={
'textAlign':'center',
'color':'#F197C0',
'fontWeight':'bold',
'fontSize':'50px',
'fontFamily':'Sans-serif',
'border':({"width":"2px", "color":"black"})
}),
html.P('''The World Happiness Report is an annual report on the state of global happiness
and is currently participated by 155 countries. ''',
style={
'textAlign':'justify-text',
'color':'#B49FDC',
'fontWeight':'bold',
'fontSize':'15px',
'fontFamily':'Sans-serif'
}),
#for dropdown
html.Br(),
dcc.Dropdown(id='select_year',
options=[
{'label':'2015','value':2015},
{'label':'2016','value':2016},
{'label':'2017','value':2017},
{'label':'2018','value':2018},
{'label':'2019','value':2019},
{'label':'2020','value':2020},
],
multi=False,
value='2015',
style={'width': "40%"}
),
dcc.Graph(id='the_graph',figure={})
])
#app.callback(
Output(component_id='the_graph', component_property='figure'),
[Input(component_id='select_year', component_property='value')] #this is for the argument of the func.written below.
)
def update_graph(option_selected):
#print(option_slctd)
#print(type(option_slctd))
#container = "The year chosen by user was: {}".format(option_slctd)
#if option_selected==2015:
d1=data[data['Year']==option_selected]
fig=go.Bar(
x=df1['Country'],
y=df1['Happiness Score']
)
return fig
I have to make a bar graph using plotly dash. But i am not getting the required output.I am not able to understand as to why the outcome is coming like that.
The output that im getting is :
Can anyone please let me know what the issue is with the code ?
I think the reason you didn't get a graph is because you were missing go.Figure(). Since I don't have the same data you are using, I used the data used on the official website and modified the dropdown values to match the data. The environment I verified is JupyterLab, so there is some code about it, but please ignore it.
import dash
import dash_core_components as dcc
import dash_html_components as html
#from jupyter_dash import JupyterDash
from dash.dependencies import Input, Output, State
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
data = px.data.gapminder()
#app = JupyterDash(__name__)
app = dash.Dash(__name__)
app.layout = html.Div([html.Div('WORLD HAPPINESS REPORT',
style={'textAlign':'center',
'color':'#F197C0',
'fontWeight':'bold',
'fontSize':'50px',
'fontFamily':'Sans-serif',
'border':({"width":"2px", "color":"black"})
}),
html.P('''The World Happiness Report is an annual report on the state of global happiness
and is currently participated by 155 countries. ''',
style={'textAlign':'justify-text',
'color':'#B49FDC','fontWeight':'bold',
'fontSize':'15px',
'fontFamily':'Sans-serif'}),#for dropdown
html.Br(),
dcc.Dropdown(id='select_year',
options=[
{'label':'1982','value':1982},
{'label':'1987','value':1987},
{'label':'1992','value':1992},
{'label':'1997','value':1997},
{'label':'2002','value':2002},
{'label':'2007','value':2007},],
multi=False,
value='2015',
style={'width': "40%"}),
dcc.Graph(id='the_graph',figure={})
])
#app.callback(
Output(component_id='the_graph', component_property='figure'),
[Input(component_id='select_year', component_property='value')] #this is for the argument of the func.written below.
)
def update_graph(option_selected):
df1=data[data['year'] == option_selected]
fig=go.Figure(data=[go.Bar(x=df1['country'], y=df1['lifeExp'])])
return fig
if __name__ == "__main__":
app.run_server()
#app.run_server(mode='inline')
"I am trying to get the values of the single row based on the drop-down value selected.
I am confirming the output to ensure I can do a bar plot on the same late." need your expertise help fr the same.
Any otherr ways to call the same. Thanks for your help in advance.
code :
import dash
import pandas as pd
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 pandas as pd
df = pd.read_csv('E:\pylab\dshlab\my_dash_app\solar.csv')
app = dash.Dash()
dpdown = []
for i in df['state']:
str(dpdown.append({'label':i,'value':(i)}))
app.layout = html.Div([
html.H4('Select your State'),
dcc.Dropdown(id='dropdown', style={'height': '30px', 'width': '100px'}, options=dpdown,
value=df['state']),
#dcc.Graph(id='graph'),
html.Div(id='table-container')
])
#app.callback(
dash.dependencies.Output('table-container','children'),
[dash.dependencies.Input('dropdown', 'value')])
def display_table(dpdown):
return(df[df['state']==dpdown])
if __name__ == '__main__':
app.run_server(debug=True)
Error:
ash.exceptions.InvalidCallbackReturnValue:
The callback for <Outputtable-container.children>
returned a value having type DataFrame
which is not JSON serializable.
The value in question is either the only value returned,
or is in the top level of the returned list,
and has string representation
state Number of Solar Plants Installed Capacity (MW) Average MW Per Plant Generation (GWh)
1 Arizona 48 1078 22.5 2550
In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.
I used dash_table for creation of the table. You can read more about it here.
Code is as follows:
import dash
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
import dash_table as dt
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import pandas as pd
df = pd.read_csv('E:\pylab\dshlab\my_dash_app\solar.csv')
app = dash.Dash()
dpdown = []
for i in df['state']:
str(dpdown.append({'label':i,'value':(i)}))
app.layout = html.Div([
html.H4('Select your State'),
dcc.Dropdown(id='dropdown', style={'height': '30px', 'width': '100px'}, options=dpdown),
#dcc.Graph(id='graph'),
html.Div(
id='table-container',
className='tableDiv'
)
])
#app.callback(
dash.dependencies.Output('table-container','children'),
[dash.dependencies.Input('dropdown', 'value')])
def display_table(dpdown):
df_temp = df[df['state']==dpdown]
return html.Div([
dt.DataTable(
id='main-table',
columns=[{'name': i, 'id': i} for i in df_temp.columns],
data=df_temp.to_dict('rows')
)
])
if __name__ == '__main__':
app.run_server(debug=True)
This will temporarily subset the dataframe and filter for your state every time a callback occurs, and output only the row corresponding to the state.
I stumbled upon this post and used the modification mentioned in the comment of the final answer for my own program. But before I tried to test it with the following code:
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
app = dash.Dash()
daterange = pd.date_range(start='1994',end='2018',freq='W')
app.layout = html.Div(children=[
html.H1('Range Slider Testing'),
html.Div(
[
html.Label('From 1994 to 2018', id='time-range-label'),
dcc.RangeSlider(
id='year_slider',
min=daterange.min (),
max=daterange.max (),
value = [daterange.min(), daterange.max()],
step='W',
),
],
style={'margin-top': '20'}
),
html.Hr(),
dcc.Graph(id='my-graph')
])
#app.callback(
dash.dependencies.Output('my-graph', 'figure'),
[dash.dependencies.Input('year_slider', 'value')])
def _update_graph(year_range):
date_start = '{}'.format(year_range[0])
date_end = '{}'.format(year_range[1])
#app.callback(
dash.dependencies.Output('time-range-label', 'children'),
[dash.dependencies.Input('year_slider', 'value')])
def _update_time_range_label(year_range):
return 'From {} to {}'.format(year_range[0], year_range[1])
if __name__ == '__main__':
app.run_server()
As a result it doesn't raise any Python errors, but the HTML, created by Dash, has an Error loading dependencies text on it...
Seems like dash does not support datetime objects by default.
You can solve this issue by converting your datetime object into an unix timestamp.
My solution for your problem is:
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
import time
app = dash.Dash()
daterange = pd.date_range(start='1994',end='2018',freq='W')
def unixTimeMillis(dt):
''' Convert datetime to unix timestamp '''
return int(time.mktime(dt.timetuple()))
def unixToDatetime(unix):
''' Convert unix timestamp to datetime. '''
return pd.to_datetime(unix,unit='s')
def getMarks(start, end, Nth=100):
''' Returns the marks for labeling.
Every Nth value will be used.
'''
result = {}
for i, date in enumerate(daterange):
if(i%Nth == 1):
# Append value to dict
result[unixTimeMillis(date)] = str(date.strftime('%Y-%m-%d'))
return result
app.layout = html.Div(children=[
html.H1('Range Slider Testing'),
html.Div(
[
html.Label('From 1994 to 2018', id='time-range-label'),
dcc.RangeSlider(
id='year_slider',
min = unixTimeMillis(daterange.min()),
max = unixTimeMillis(daterange.max()),
value = [unixTimeMillis(daterange.min()),
unixTimeMillis(daterange.max())],
marks=getMarks(daterange.min(),
daterange.max()),
),
],
style={'margin-top': '20'}
),
html.Hr(),
dcc.Graph(id='my-graph')
])
#app.callback(
dash.dependencies.Output('time-range-label', 'children'),
[dash.dependencies.Input('year_slider', 'value')])
def _update_time_range_label(year_range):
return 'From {} to {}'.format(unixToDatetime(year_range[0]),
unixToDatetime(year_range[1]))
if __name__ == '__main__':
app.run_server()
I am in the process of learning Dash with the final goal being the development of an app that allows quick analysis of data sets in an excel file. I'd like a drop down menu that will allow for switching between the sheets in the excel file. I'm having trouble getting this to run properly. I can make it output to a graph but not a table. My code is as follows:
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import pandas as pd
app = dash.Dash()
df = pd.read_excel('output.xlsx', sheet_name=None)
app.layout = html.Div(
html.Div([dcc.Dropdown(id='drop_value',
options=[{'label': i, 'value': i} for i in df],
value='Sheet1')]),
html.Div([dt.DataTable(rows=[{}],
id='table')])
)
#app.callback(Output('table', 'rows'), [Input('drop_value', 'value')])
def update_info_table(drop_value):
if drop_value == 'Sheet1':
new_data = df['Sheet1'].to_dict()
return new_data
elif drop_value == 'Sheet2':
new_data = df['Sheet2'].to_dict()
return new_data
else:
new_data = df['Sheet3'].to_dict()
return new_data
if __name__ == '__main__':
app.run_server()
When I run this code I get the following error:
TypeError: init() takes from 1 to 2 positional arguments but 3 were given
I'm assuming this has something to do with the format of the dataset I'm trying to feed to the datatable. Right now I'm just using a dummy excel file with only two columns labeled 'x1' and 'y1'.
Adjusted code and seems to work now. Correct code is below for anyone who needs.
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import dash_table_experiments as dt
# Load in data set
sheet_to_df_map = pd.ExcelFile('output.xlsx')
dropdown_options = pd.read_excel('output.xlsx', sheet_name=None)
# Create the dash app
app = dash.Dash()
# Define the layout for the drop down menu
app.layout = html.Div([
html.H2("Select Sheet Number"),
html.Div([dcc.Dropdown(id="field_dropdown", options=[{
'label': i,
'value': i
} for i in dropdown_options],
value='Sheet3')],
style={'width': '25%',
'display': 'inline-block'}),
dt.DataTable(rows=[{}],
row_selectable=True,
filterable=True,
sortable=True,
selected_row_indices=[],
id='datatable')
])
#app.callback(
dash.dependencies.Output('datatable', 'rows'),
[dash.dependencies.Input('field_dropdown', 'value')])
def update_datatable(user_selection):
if user_selection == 'Sheet1':
return sheet_to_df_map.parse(0).to_dict('records')
elif user_selection == 'Sheet2':
return sheet_to_df_map.parse(1).to_dict('records')
else:
return sheet_to_df_map.parse(2).to_dict('records')
if __name__ == '__main__':
app.run_server()code here