NiceGUI won't update Plotly trace Scattermap when I utilize a function, almost exactly like the documentation update sample here: https://nicegui.io/documentation/plotly#plot_updates Code runs fine without a function:
import plotly.graph_objects as go
import dataretrieval.nwis as nwis
from nicegui import ui
fig = go.Figure(go.Scattermap(
fill = "toself",
lon = [-90,-89,-89,-90],
lat = [45,45,44,44],
marker = { 'size': 10, 'color': "orange" },
name='BBox'))
fig.update_layout(margin=dict(l=0,r=0,t=0,b=0), width=400, showlegend=False,
map = {
'style': 'carto-darkmatter',
'center': {'lon': -90, 'lat': 44 },
'zoom':5})
plot = ui.plotly(fig)
# def update_plt():
siteBBOX, md = nwis.get_info(bBox=[-90,44,-89,45])
select_y = siteBBOX['dec_lat_va']
select_x = siteBBOX['dec_long_va']
names = siteBBOX['station_nm']
fig.add_trace(go.Scattermap(lon=select_x,
lat=select_y,
fill=None,
mode= 'markers',
marker=dict(
size=15,
color='blue'
), text=names, name='sites'))
plot.update()
# ui.button('Update', on_click=update_plt)
ui.run(title='Test')
But when I uncomment and indent to make a function, it does not update to add the new points.
import plotly.graph_objects as go
import dataretrieval.nwis as nwis
from nicegui import ui
fig = go.Figure(go.Scattermap(
fill = "toself",
lon = [-90,-89,-89,-90],
lat = [45,45,44,44],
marker = { 'size': 10, 'color': "orange" },
name='BBox'))
fig.update_layout(margin=dict(l=0,r=0,t=0,b=0), width=400, showlegend=False,
map = {
'style': 'carto-darkmatter',
'center': {'lon': -90, 'lat': 44 },
'zoom':5})
plot = ui.plotly(fig)
def update_plt():
siteBBOX, md = nwis.get_info(bBox=[-90,44,-89,45])
select_y = siteBBOX['dec_lat_va']
select_x = siteBBOX['dec_long_va']
names = siteBBOX['station_nm']
fig.add_trace(go.Scattermap(lon=select_x,
lat=select_y,
fill=None,
mode= 'markers',
marker=dict(
size=15,
color='blue'
), text=names, name='sites'))
plot.update()
ui.button('Update', on_click=update_plt)
ui.run(title='Test')
Edited. I'm not sure if I'm understanding what is different about my function and the NiceGUI example function. Thanks.
On my computer problem makes nwis.get_info()
which runs longer time.
First version works correctly because it gets data before it runs code in browser - and browser knows that there are new data to display.
But in second version it runs code when browser tries to keep connection with server, but long running nwis.get_info()
blocks all code on server and server can't response for browser's requests and finally browser shows me:
and after reconnecting it doesn't know that there are new data to display
(probably it may run all code from the beginning).
Partial solution is to change reconnection timeout:
ui.run(title='Test', reconnect_timeout=60)
and browser waits longer time before it reconnects.
And nwis.get_info()
has time to update data before before tries to reconnect.
But if code would need even longer time to get data then it would need to run it in background - as thread, subprocess, async function or something else.
At this moment I didn't find nice method to run it in background.
import plotly.graph_objects as go
import dataretrieval.nwis as nwis
from nicegui import ui
# --- functions ---
def update_plt():
print('clicked')
print('searching ...')
siteBBOX, md = nwis.get_info(bBox=[-90,44,-89,45])
print('updating ...')
#print(siteBBOX)
#print(md)
select_y = siteBBOX['dec_lat_va']
select_x = siteBBOX['dec_long_va']
names = siteBBOX['station_nm']
#print(select_y)
#print(select_x)
#print(names)
fig.data = [] # I remove previous map (because it keeps it in memory even if it doesn't show it in browser)
print(f"{fig.data = }") # if I don't remove previous data then it shows 2 (and more) Scattermaps on list
fig.add_trace(go.Scattermap(
lon=select_x,
lat=select_y,
fill=None,
mode='markers',
marker=dict(
size=15,
color='blue'
),
text=names,
name='sites'
))
plot.update()
# --- main ---
fig = go.Figure(go.Scattermap(
fill = "toself",
lon = [-90,-89,-89,-90],
lat = [45,45,44,44],
marker = { 'size': 10, 'color': "orange" },
name='BBox'))
fig.update_layout(margin=dict(l=0,r=0,t=0,b=0), width=400, showlegend=False,
map = {
'style': 'carto-darkmatter',
'center': {'lon': -90, 'lat': 44 },
'zoom':5})
plot = ui.plotly(fig)
ui.button('Update', on_click=update_plt)
ui.run(title='Test', reconnect_timeout=60)
EDIT:
I was searching method to run long-running code in plotly
but solution is in nicegui
.
It has
nicegui.run.cpu_bound()
to run CPU-bound tasksnicegui.run.io_bound()
to run I/O-bound tasksIt gets function's name and positional and/or named parameters.
I had problem to send named parameters directly to nwis.get_info
so I created new function with nwis.get_info
and I used it with cpu_bound()
.
It creates async function so it has to run with await
, and update_plt
has to use async
def get_data(**kwargs):
return nwis.get_info(**kwargs)
async def update_plt():
#siteBBOX, md = nwis.get_info(bBox=[-90,44,-89,45])
#siteBBOX, md = await run.cpu_bound(nwis.get_info, bBox=[-90,44,-89,45]) # it sends `bBox` to web service incorrectly formatted in url.
siteBBOX, md = await run.cpu_bound(get_data, bBox=[-90,44,-89,45])
# ... rest ...
And it seems it works withou extra reconnect_timeout
.
import plotly.graph_objects as go
import dataretrieval.nwis as nwis
from nicegui import ui, run
# --- functions ---
def get_data(**kwargs):
return nwis.get_info(**kwargs)
async def update_plt():
print('clicked')
print('searching ...')
#siteBBOX, md = nwis.get_info(bBox=[-90,44,-89,45])
#siteBBOX, md = await run.cpu_bound(nwis.get_info, bBox=[-90,44,-89,45]) # it sends `bBox` to web service incorrectly formatted in url.
siteBBOX, md = await run.cpu_bound(get_data, bBox=[-90,44,-89,45])
print('updating ...')
#print(siteBBOX)
#print(md)
select_y = siteBBOX['dec_lat_va']
select_x = siteBBOX['dec_long_va']
names = siteBBOX['station_nm']
#print(select_y)
#print(select_x)
#print(names)
fig.data = [] # I remove previous map (because it keeps it in memory even if it doesn't show it in browser)
print(f"{fig.data = }") # if I don't remove previous data then it shows 2 (and more) Scattermaps on list
fig.add_trace(go.Scattermap(
lon=select_x,
lat=select_y,
fill=None,
mode='markers',
marker=dict(
size=15,
color='blue'
),
text=names,
name='sites'
))
plot.update()
# --- main ---
fig = go.Figure(go.Scattermap(
fill = "toself",
lon = [-90,-89,-89,-90],
lat = [45,45,44,44],
marker = { 'size': 10, 'color': "orange" },
name='BBox'))
fig.update_layout(margin=dict(l=0,r=0,t=0,b=0), width=400, showlegend=False,
map = {
'style': 'carto-darkmatter',
'center': {'lon': -90, 'lat': 44 },
'zoom':5})
plot = ui.plotly(fig)
ui.button('Update', on_click=update_plt)
ui.run(title='Test')