"""
"""
import os
import numpy as np
import datetime
try:
from nicegui import app, ui, events, Client
except ModuleNotFoundError as e:
print('Module `nicegui` not found.')
exit(1)
try:
import plotly.graph_objects as pgo
import plotly.io as pio
import plotly as ply
import plotly.subplots
import local_file_picker
except ModuleNotFoundError as e:
print('Module `plotly` not found.')
exit(1)
pio.templates["plotly_light"] = pgo.layout.Template(
layout = pio.templates["plotly_white"].layout)
#pio.templates["plotly_light"].layout['scene']['xaxis']['gridcolor'] = 'gray'
pio.templates["plotly_light"].layout['xaxis']['gridcolor'] = 'lightgray'
pio.templates["plotly_light"].layout['xaxis']['zerolinecolor'] = 'lightgray'
pio.templates["plotly_light"].layout['yaxis']['gridcolor'] = 'lightgray'
pio.templates["plotly_light"].layout['yaxis']['zerolinecolor'] = 'lightgray'
ELM = {
'name': 'tempplot',
'filename': './data/20260420213656.txt',
'label_file_fmt': 'file: {filename}',
#'label_data_len_fmt': 'data points (rendered): {num}',
'label_data_len_fmt': 'data points: {num} (rendered), {numa} (total)',
'plotly_light': 'plotly_light',
'plotly_dark': 'plotly_dark',
}
def main_cli():
import argparse
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawTextHelpFormatter,
prefix_chars='-',
add_help=False,
)
parser.add_argument(
'--host', type=str, default='', help='default 127.0.0.1')
parser.add_argument(
'--port', type=str, default='8085', help='default 8080')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Verbose output')
parser.add_argument(
'-D', '--debug', action='store_true', help=argparse.SUPPRESS)
parser.add_argument(
'-h', '--help', action='store_true', help='Show this help message and exit')
args = parser.parse_args()
if args.debug:
DEBUG = True
print(f'[DEBUG] args: {args}')
print(f'[DEBUG] __file__: {__file__}')
print(f'[DEBUG] cwd: {os.getcwd()}')
print(f'[DEBUG] host: {args.host}')
print(f'[DEBUG] port: {args.port}')
if args.help:
parser.print_help()
exit(0)
return args
def np2pgo(x, y, label=None):
res = {'x': x, 'y': y}
if label is not None:
res.update({'name': label})
return res
async def pick_file() -> None:
result = await local_file_picker.local_file_picker('./data', multiple=False)
# ui.notify(f'You chose {result}')
if result:
filename = result[-1]
ELM['filename'] = filename
# update_data() # see timer below
ELM['label_file'].set_text(ELM['label_file_fmt'].format(filename=os.path.basename(filename)))
async def get_data(filename=ELM['filename']):
data = np.genfromtxt(fname=filename, skip_header=1)
if len(data) > 0 and len(data[0]) > 6:
names = ['time', 'ts', 'ta', 'tb', 'tc', 'td', 'hp', 'hl']
else:
names = ['time', 'ts', 'ta', 'tb', 'hp', 'hl']
data = np.genfromtxt(
fname=filename, dtype=None, skip_header=1, converters={
0: lambda x: datetime.datetime.strptime(x, '%Y%m%d%H%M%S')},
names=names, encoding='utf-8'
)
return data
async def update_data():
filename=ELM['filename']
data_all = await get_data(filename)
data = data_all
# time_range = ELM['number_time_range'].value
time_range = app.storage.user['time_range']
if time_range is not None and time_range > 0:
# delta = datetime.datetime.now() - data['time']
delta = data['time'][-1] - data['time']
data = data[np.where(delta <= datetime.timedelta(hours=time_range))]
print(filename, data_all.shape, data.shape)
ELM['label_data_len'].set_text(ELM['label_data_len_fmt'].format(num=len(data), numa=len(data_all)))
ELM['fig'].data = []
ELM['plot'].visible = False
ELM['plot'].update()
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['ts'], 'Setp')))
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['ta'], 'Temp A')))
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['tb'], 'Temp B')))
if len(data) > 0 and len(data[0]) > 6:
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['tc'], 'Temp C')))
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['td'], 'Temp D')))
ELM['fig'].add_trace(pgo.Scatter(**np2pgo(data['time'], data['hp'], 'Heat')),
row=2, col=1)
ELM['plot'].visible = True
ELM['plot'].update()
@ui.page('/')
async def index():
await ui.context.client.connected()
# initialize objects
ELM['fig'] = ply.subplots.make_subplots(rows=2, cols=1)
# render header
ui.context.client.content.classes('h-[100vh]')
ui.add_head_html('''
''')
dark_mode = ui.dark_mode().bind_value(app.storage.user, 'dark_mode')
ui.colors(primary='#4888c4')
with ui.row(align_items="center").classes('w-full'):
ui.button('Choose file', on_click=pick_file, icon='folder')
ELM['number_time_range'] = ui.number(
label='time range', value=6, format='%.2f', min=0, step=0.5,
suffix='h',
# on_change=lambda e: update_data(), # see timer below
).props('clearable').bind_value(app.storage.user, 'time_range').classes('w-32')
ELM['switch_timer'] = ui.switch('auto-refresh').bind_value(app.storage.user, 'timer')
ui.space()
ui.switch(
'Dark mode', on_change=lambda: (
ELM['fig'].update_layout(
template=ELM['plotly_dark'] if dark_mode.value else ELM['plotly_light']),
'plot' in ELM and ELM['plot'].update())
).bind_value(app.storage.user, 'dark_mode').props('icon="dark_mode"')
with ui.row():
ELM['label_file'] = ui.label(
ELM['label_file_fmt'].format(filename=os.path.basename(ELM['filename'])))
ELM['label_data_len'] = ui.label(ELM['label_data_len_fmt'].format(num=0, numa=0))
pio.templates.default = 'plotly_dark'
# ELM['fig'] = pgo.Figure()
ELM['fig'].update_layout(
height=600,
#template='plotly_white'
template=ELM['plotly_dark'] if dark_mode.value else ELM['plotly_light'],
)
ELM['plot'] = ui.plotly(ELM['fig']).classes('w-full')
# update_data()
ui.timer(0, lambda: update_data(), once=True)
ELM['timer'] = ui.timer(2.0, lambda: update_data(), immediate=False)
ELM['switch_timer'].bind_value_to(ELM['timer'], 'active')
def main_gui(args):
ui.run(
host=args.host, port=int(args.port), title=ELM['name'],
dark=False,
native=False,
show=False, storage_secret='tempview')
def main(args):
return 0
if __name__ in {'__main__', '__mp_main__'}:
args = main_cli()
main_gui(args)