@maxrottersman wrote:
I can see that what I want to do is in the sample satellite dashboard. But it’s so complicated I can’t see through it to what I want. In my project I get the “Multi output … that was already assigned” error because an output can only have one input, I surmise.
So can someone explain the basics if one has
- A dropdown list that selects a group. Mine are cryptocurrencies, so let’s say BTC
- That kicks off an live updating table and/or graph etc.
So far I have
# # Callback: TABLE POPULATE based on drop down selection # @app.callback([Output('table-container', 'data'), Output('table-container', 'columns')], [Input('group-dropdown', 'value')]) def gen_table(dropdown_value): return data_table_populate(dropdown_value)In my template, I have
dcc.Interval(id='invterval-component', interval=10*1000, # 10 seconds n_intervals=0) # 60 seconds, set counter to 0Which I believe gives me an input that will update every X period.
But how do I get that to call the same output that was generated with the dropdown. I’ll want to keep updating both a table and graph every X period with whatever was selected.
My guess is that my dropdown would call a function that listens to the timer callback and then updates the table. Sorry, I just can’t see how that exactly works in what I’ve researched. The tuts are for updating ony, not for working with a change in data query. Sorry I don’t get it! THANKS IN ADVANCE!
I’ll try to put what I learn here in a tutorial of my own for starters.
Here is my whole script at this point:
from pathlib import Path import dash import dash_html_components as html # handles html tag stuff import dash_core_components as dcc # handles controls, graphs, etc import dash_table as dash_table from dash.dependencies import Input, Output # Callback Input, Output only! import plotly.express as px import sqlite3 from sqlalchemy import create_engine import pandas as pd # Where is our database, wherever we're running this? # and let's abstract with SQLAlchemy scriptPath = Path(__file__).parent dbPath = scriptPath / 'db' dbPathFile = str(dbPath / 'db_cryptocompare.sqlite') db_uri = r'sqlite:///' + str(dbPathFile) # If problem, try hard path #conn = sqlite3.connect('/home/maxrottersman/python_chart_automation/db_cryptocompare.sqlite') conn = sqlite3.connect(dbPathFile) # We want latest 15 prices but sorted ascending sql = 'Select [symbol],[time],[close] From ' \ '(select * from Value_ByMinute_BTC ' \ 'ORDER BY [time] DESC limit 15) ORDER BY [symbol],[Time] ASC;' df= pd.read_sql(sql,conn) # From that, create unique Managers for Drop Down groups = sorted(df['symbol'].unique()) conn.close() external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets, suppress_callback_exceptions=True) # , server=server call flask server # THIS IS FOR GUNICORN (or WSGI production server) TO HOOK INTO! like unicorn webapp:app.server -b 0.0.0.0 #:8000 server = app.server # Part 1: DATA FUNCTIONS # Groups of data for our dropdown, which drives table and chart def data_group_options_build(): OptionList = [{'label': group, 'value': group} for group in groups] return OptionList # Fill DATATABLE from Dropdown List def data_table_populate(dropdown_value): is_group = df['symbol']==dropdown_value # Create dataframe of those rows only by passing in those booleans dff = df[is_group] # dff as in dataframe filtered # Data table won't work without column defs my_table_columns = [{"name": i, "id": i,} for i in (df.columns)] return dff.to_dict('records'), my_table_columns # Draw GRAPH from data picked in manager dropdown list def data_graph_draw(dropdown_value): is_group = df['symbol']==dropdown_value # Create dataframe of those rows only by passing in those booleans dff = df[is_group] # dff as in dataframe filtered # Using HELPER library plotly.express as px fig = px.scatter(dff, x=dff['time'], y=dff.close) return fig def data_get_latest(): conn = sqlite3.connect(dbPathFile) # We want latest 15 prices but sorted ascending sql = 'Select [symbol],[time],[close] From ' \ '(select * from Value_ByMinute_BTC ' \ 'ORDER BY [time] DESC limit 15) ORDER BY [symbol],[Time] ASC;' df_latestdata= pd.read_sql(sql,conn) my_table_columns = [{"name": i, "id": i,} for i in (df_latestdata.columns)] conn.close() return df_latestdata #, my_table_columns ##### END DATA FUNCTIONS ##### # # STYLES # # Give style same names as DASH uses, purpose here to keep app.layout ucluttered # style_cell_conditional=[ { 'if': {'column_id': c}, 'textAlign': 'left', 'width': '200px' } for c in ['close','time'] ] + [ { 'if': {'column_id': 'symbol'}, 'display': 'none' } ] + [ { 'if': {'column_id': 'close'}, 'textAlign': 'right', 'width': '200px' } ] + [ { 'if': {'column_id': 'time'}, 'width': '200px' } ] style_data_conditional=[ { 'if': {'row_index': 'odd'}, 'backgroundColor': 'rgb(248, 248, 248)' } ] style_header={ 'backgroundColor': 'rgb(230, 230, 230)', 'fontWeight': 'bold' } # # PART 2, Create our clean DASH LAYOUT object # def generate_layout(): return html.Div([ html.H1(children='Python automation charts using cryptocurrencies'), # dumm y callback to get things initialized dcc.Input(id='initialize_app_components_with_dummy_callback', value='', type='text', style={'display':'none'}), # html.Div to keep Dropdown and 'Data Table' text on same line html.Div([dcc.Dropdown(id='group-dropdown', value='BTC', style={'width': '100px', 'verticalAlign':'middle'}), html.H3(children=' Table Data', style={'verticalAlign':'middle','display': 'inline-block'}), html.A('Refresh', href='/') ]), html.Br(), dash_table.DataTable(id='table-container', style_table = {'width':'500px'}, style_cell_conditional = style_cell_conditional, style_data_conditional = style_data_conditional, style_header = style_header), html.H3(children='Cryptocurrenty Prices by Minute'), dcc.Graph(id='graph-container'), dcc.Interval(id='invterval-component', interval=10*1000, # 10 seconds n_intervals=0) # 60 seconds, set counter to 0 ]) suppress_callback_exceptions=True app.layout = generate_layout # # PART 2, Load Initial DROPDOWN LIST DATA in our DASH layout which # will happen after the app is run. # # 1. ON APP START, ALL CALLBACKS CALLED USING CURRENT VALUE OF INPUT CONTROLS!!! # 2. WHEN INPUT CHANGES, The FUNCTION underneath is called @app.callback( Output(component_id='group-dropdown', component_property='options'), [Input(component_id='initialize_app_components_with_dummy_callback', component_property='value')] ) def group_dropdown_BuildOptions(df_for_dropdown): return data_group_options_build() # # PART 3, set up our callbacks to hands dropdown selections, etc # # # Callback: TABLE POPULATE based on drop down selection # @app.callback([Output('table-container', 'data'), Output('table-container', 'columns')], [Input('group-dropdown', 'value')]) def gen_table(dropdown_value): return data_table_populate(dropdown_value) # # Callback: GRAPH DRAW based on drop down selection # @app.callback( dash.dependencies.Output('graph-container', 'figure'), [dash.dependencies.Input('group-dropdown', 'value')]) def gen_graph(dropdown_value): return data_graph_draw(dropdown_value) # Interval Callback, update every 60 seconds. @app.callback([Output('table-container', 'data')], [Input('interval-component', 'n_intervals')]) def callback_data_get_latest(): return data_get_latest() ### ### OKAY, LET 'ER RIP ### if __name__ == '__main__': # Can this ever work instead of dummy callback? #app.callback(Output('mgr-dropdown', 'options')) (mgr_options_build()) app.run_server() #http://127.0.0.1:8050
Posts: 1
Participants: 1







