Last active
May 11, 2021 19:46
-
-
Save mtanco/807b8e83f117f8a022817c52de9bdded to your computer and use it in GitHub Desktop.
Use the AsyncIOScheduler to run a scheduled job for updating a dashboard while maintaining the ability to use all features of an interactive app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
from h2o_wave import main, app, Q, ui, handle_on, on, data | |
SCHEDULER = AsyncIOScheduler() | |
@app('/') | |
async def serve(q: Q): | |
print(q.args) | |
""" | |
Handles requests from end users | |
Runs any time a user interacts with the app at all | |
""" | |
if not q.client.initialized: | |
initialize_app_for_new_client(q) | |
else: | |
await handle_on(q) | |
await q.page.save() | |
@on() | |
async def close_rows(q: Q): | |
for closed_row in q.args.data_table: | |
for row in q.client.data: | |
print(int(closed_row)) | |
print(row[0]) | |
if int(closed_row) == row[0]: | |
row[2] = 'Michelle' | |
update_table(q) | |
def initialize_app_for_new_client(q: Q): | |
""" | |
Sets up the UI and background tasks for the end user | |
Runs when a new browser tab comes to the app | |
""" | |
if not q.app.initialized: | |
initialize_app(q) | |
q.client.data_location = 20 | |
q.client.data = [[i, i, ''] for i in range(0, q.client.data_location)] | |
q.client.dropdown_value = str(1008) | |
render_main_ui(q) | |
render_home_view(q) | |
start_scheduled_job(job_id=f'user_{q.app.user_count}', q=q) | |
q.client.initialized = True | |
def initialize_app(q: Q): | |
q.app.user_count = 1 | |
q.app.initialized = True | |
def start_scheduled_job(job_id: str, q: Q): | |
SCHEDULER.add_job( | |
func=render_new_data, | |
args=[q], | |
trigger='interval', | |
seconds=3, | |
id=job_id, | |
) | |
SCHEDULER.start() | |
def render_main_ui(q: Q): | |
q.page['meta'] = ui.meta_card( | |
box='', | |
layouts=[ | |
ui.layout( | |
breakpoint='xs', | |
width='1200px', | |
zones=[ | |
ui.zone('header'), | |
ui.zone('command'), | |
ui.zone('body', direction=ui.ZoneDirection.COLUMN, zones=[ | |
ui.zone('sidebar'), | |
ui.zone('content', direction=ui.ZoneDirection.ROW) | |
]), | |
ui.zone('footer'), | |
] | |
) | |
] | |
) | |
q.page['header'] = ui.header_card( | |
box='header', | |
title='Scheduled Plots', | |
subtitle='Interactive apps with scheduled data pulls', | |
) | |
q.page['footer'] = ui.footer_card( | |
box='footer', | |
caption='Made with 💛 using [H2O Wave](https://github.com/h2oai/wave)!' | |
) | |
def render_home_view(q: Q): | |
q.page['interactive_commands'] = ui.section_card( | |
box='command', | |
title='Testing Area', | |
subtitle='Confirming the app is still interactive while real-time updates are happening', | |
items=[ | |
ui.dropdown( | |
name='dropdown_value', | |
choices=[ui.choice(str(i), str(i)) for i in range(1000, 1010)], | |
value=str(1008), | |
trigger=False | |
) | |
] | |
) | |
q.page['plot'] = ui.plot_card( | |
box='content', | |
title='Live Fake Monitoring', | |
data=data('price performance closer', size=-20), # negative means we want to cycle through with new data | |
plot=ui.plot([ | |
ui.mark(type='interval', x='=price', y='=performance', x_title='Event Count', y_title='Fake Value') | |
]) | |
) | |
q.page['plot'].data = q.client.data | |
q.page['table'] = ui.form_card( | |
box='content', | |
items=[ | |
ui.table( | |
name='data_table', | |
columns=[ | |
ui.table_column('price', 'Event Count', sortable=True, filterable=True), | |
ui.table_column('performance', 'Fake Value'), | |
ui.table_column('closer', 'Closer') | |
], | |
rows=[ui.table_row( | |
str(i), | |
[str(v) for v in q.client.data[i]] | |
) for i in range(len(q.client.data))], | |
multiple=True | |
), | |
ui.button('close_rows', 'Close Rows') | |
] | |
) | |
async def render_new_data(q: Q): | |
new_data = [q.client.data_location, random.randrange(1, 10), ''] | |
q.client.data.append(new_data) | |
q.client.data_location += 1 | |
q.page['plot'].data = [new_data] | |
update_table(q) | |
await q.page.save() | |
def update_table(q: Q): | |
q.page['table'].items[0].table.rows = [ | |
ui.table_row( | |
str(i), | |
[str(v) for v in q.client.data[i]] | |
) for i in range(len(q.client.data)) | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Perfect example for the scenario I sent via email last week or so. Stumbled across this looking for wave examples! Seems to crash on refresh, but may use this logic to accomplish on the hour data pulls. Thanks Michelle!