# Note: Main must be imported even though it is not used. from h2o_wave import Q, ui, app, main, data, on import numpy as np import pandas as pd import random import time import asyncio NUMBER_SENSORS = 4 LIMIT_LEN_SHOWING = 20 REALTIME_UPDATE = 5 # seconds list_data = [] line_charts_data = [] # [(sensor_id, [data]), ...] for i in range(NUMBER_SENSORS): line_charts_data.append((i, [])) start_year = 1991 while True: for i in range(NUMBER_SENSORS): random_value = random.uniform(1, 50) # Generate a random value between 1 and 50 value = (str(start_year), random_value) line_charts_data[i][1].append(value) start_year += 1 if start_year == 2021: break async def update_value(q: Q): while True: time.sleep(REALTIME_UPDATE) # TODO: Update realtime values for current stats cards # value_counts = random.randint(0, 100) # percentages = random.random() percentages = np.random.random(NUMBER_SENSORS) value_counts = np.random.randint(0, 100, NUMBER_SENSORS) show_multiple_stats_cards(q, value_counts, percentages) await q.page.save() async def api_get_data(): global list_data, line_charts_data, start_year while True: for i in range(NUMBER_SENSORS): random_value = random.uniform(1, 50) # Generate a random value between 1 and 50 value = (str(start_year), random_value) line_charts_data[i][1].append(value) start_year += 1 await asyncio.sleep(REALTIME_UPDATE) async def update_charts(q: Q): global line_charts_data while True: time.sleep(REALTIME_UPDATE) for sensor_data in line_charts_data: sensor_id = str(sensor_data[0]) data = sensor_data[1] limites_showing_data = LIMIT_LEN_SHOWING if len(data) > LIMIT_LEN_SHOWING else len(data) show_line_graph(q, sensor_id, data[-limites_showing_data:]) percentages = np.random.random(NUMBER_SENSORS) value_counts = np.random.randint(0, 100, NUMBER_SENSORS) show_multiple_stats_cards(q, value_counts, percentages) await q.page.save() def on_startup(): print('App started!') def on_shutdown(): print('App stopped!') task_data = asyncio.create_task(api_get_data()) @app('/', on_startup=on_startup, on_shutdown=on_shutdown, mode='broadcast') async def sever(q: Q): apply_layout(q) show_homepage(q) # show_histograms(q, df, index=[1, 7, 8]) # await update_value(q) await update_charts(q) # await q.page.save() def show_homepage(q: Q): q.page['header'] = ui.header_card( box=ui.box('header', width='100%', height='86px'), icon='Video360Generic', icon_color='White', title='AgroTrack Application', subtitle='담양농업기술센터') q.page['footer'] = ui.footer_card( box='footer', caption='Copyright (C) [AISeed](https://sprout-fibre-be6.notion.site/AISEED-40e62bb70c024a2c974c0a7051aca86f?pvs=4) Designed by [Blackhole](https://github.com/andrewlee1807/)') def apply_layout(q: Q): q.page['meta'] = ui.meta_card(box='', theme='oceanic', title="SmartFarm's Sensor Dashboard", layouts=[ ui.layout( breakpoint='xl', width='1600px', zones=[ ui.zone('header'), ui.zone('body', direction=ui.ZoneDirection.ROW, zones=[ ui.zone('content', direction=ui.ZoneDirection.COLUMN, zones=[ ui.zone('section1'), ui.zone('top', size='300px', direction=ui.ZoneDirection.ROW), ui.zone('section2'), ui.zone('bottom', direction=ui.ZoneDirection.ROW), ui.zone('chart1', direction=ui.ZoneDirection.ROW), ]), ]), ui.zone('footer') ]), ]) ## Making stats cards def make_stats_card_data(q: Q, column): value_counts = column.value_counts() total = value_counts.sum() return value_counts[1], total # Randomly generate data for stats cards: percentage and value (randomly generated) def show_stats_card(q: Q, name, value_count, percentage): q.page['stat_' + name] = ui.tall_gauge_stat_card( box=ui.box('top', width='12.5%'), title='Number of houses with ' + name, value='={{intl one}}', aux_value='={{intl perc style="percent" minimum_fraction_digits=2 maximum_fraction_digits=2 }}', progress=percentage, data=dict(one=int(value_count), perc=float(percentage)), plot_color='$red' ) def show_multiple_stats_cards(q: Q, value_counts, percentages): for i, j in enumerate(zip(value_counts, percentages)): name = "feature_" + str(i) value_count, percentage = j show_stats_card(q, name, value_count, percentage) # Making histograms def make_histogram_data(values): count, division = np.histogram(values) return [(x, y) for x, y in zip(division.tolist(), count.tolist())] def show_histogram(q: Q, values, variable_name, index): q.page['feat' + str(index)] = ui.tall_series_stat_card( box=ui.box('bottom', width='25%'), title='Linear tall series' + variable_name, value='=${{intl qux minimum_fraction_digits=2 maximum_fraction_digits=2}}', aux_value='={{intl quux style="percent" minimum_fraction_digits=1 maximum_fraction_digits=1}}', data=dict(qux=800, quux=80 / 100), plot_type='area', plot_category='foo', plot_value='qux', plot_color='$yellow', plot_data=data('foo qux', 3, rows=[[90, 0.9], [50, 0.5], [80, 0.8]]), plot_zero_value=0, plot_curve='smooth', ) def show_line_graph(q: Q, name, data_rows): q.page['section2'] = ui.section_card(box='section2', title='Plot of the data', subtitle='') position = 'bottom' if int(name) < 2 else 'chart1' q.page[name] = ui.plot_card( box=ui.box(position, width='50%'), title='Sensor ' + name, animate=True, data=data('time value', LIMIT_LEN_SHOWING, rows=data_rows), events=['select_marks'], plot=ui.plot([ ui.mark(type='line', x_scale='time', x='=time', y='=value', y_min=0, interactive=True), ui.mark(type='point', x='=time', # x='={{intl year type="time" month="numeric" day="numeric" hour="numeric" minute="numeric" hourCycle="h24" }}', y='=value', size=4, fill_color='#FFFF28', x_title='Time', y_title='Value', interactive=True), ]), ) @on('select_marks') async def on_marks_selected(q: Q): print("Click")