Hi
The task is to update a browser window, localhost, with revised electricity prices via a table and chart.
I verify that the callback calls the function that creates the table and chart but these are not re rendered in the browser window. I, and a friend, must have tried at least 10 different versions including class based but clearly I am missing the point. The table and chart dont have any reactive parameters but just draw on the most recent data.
The called chart is returned as an MPL pane and the table is a styled data frame extract
Very grateful if someone could suggest what I might do to fix it. The original approach is:
After another few hours the styled data frame panenow updates correctly. However exactly the same syntax simply doesn’t work in Matplotlib chart even though I can see the make chart function is being called.
I really would be grateful if anyone could suggest why the chart doesn’t respond in the same way the data frame does. The revised code is:
counter = pn.rx(0)
#matplotlib.use('agg')
def get_data():
global counter
#print("fetching data "+str(counter.rx.value))
data = open_pickle_file(file_path)
return data.pivot(columns='REGIONID',values='RRP')
prices = pn.rx(get_data())
def update_prices():
global chart_view
counter.rx.value = counter + 1
prices.rx.value = get_data()
#print ("updated prices "+str(counter))
chart_view = pn.pane.Matplotlib(prices.rx.pipe(pcht),tight=True,format="svg", sizing_mode="scale_both")
prices_view = pn.pane.DataFrame(prices.rx.pipe(display_table))
pn.state.add_periodic_callback(update_prices, period=10000)
md2 = pn.indicators.Number(name =" this is the counter ", value = counter,default_color = 'white')
pn.Column(md2,prices_view,chart_view,max_width=450,max_height=700).servable()
Thanks to GPT4 and a lot of persistence i eventually worked out a very simple way to get it done. I post it here in case anyone as amateur as me ever wants to update a matplotlib chart with new data on a schedule. The only gripe I have is that matplotx(dracula) isn’t accepted as figure style although i use it everywhere else.
# Function to update the plot
def update_plot(event=None):
prices = get_data()
fig = pcht(prices)
mpl_pane.object = fig
table_pane.object = display_table(prices)
# Create an initial plot
prices = get_data()
fig = pcht(prices)
table = display_table(prices)
mpl_pane = pn.pane.Matplotlib(fig, sizing_mode='stretch_width')
table_pane = pn.pane.DataFrame(table)
# Set up periodic callback to update the plot every 5 minutes
pn.state.add_periodic_callback(update_plot, 270000) # 27000ms = 4.5 minutes
# Layout for the Panel
layout = pn.Column(mpl_pane,table_pane,max_width=450,max_height=600)
# Serve the Panel
layout.servable()
great product panel but I’ve chewed up a lot of time and despite best efforts the documentation remains difficult for an amateur like me.
Hi! Thanks for sharing the result. I’d like to understand this better. Have you had the chance to check out the tutorials, or were you just searching periodic callback? i.e. how did you approach the documentation? Any suggestions to improve the docs?
I read the documents as thoroughly as I could and conducted various experiments over the 3 days it took to get the few lines of code running properly.
I’ve been using a Panel application for a year now. The app at www.itkservices2.com displays various charts for Australian electricity fuels and prices in a series of tabs with some reactive widgets. Although I could do it better today I’m happy enough with it an use it regularly.
So this was the first time trying to use callbacks.
The difficulty is that the documentation presents various different call back strategies such as streamz or pn.rx or in the worst case(for me) a holoviews hv.map
The callback examples in the “how to” section all use .stream however the “periodically run callbacks” page uses “param.trigger”. Other examples use other methods.
The code that works for me uses
chart_stream = stream.map(prices)
and without gpt4 I would never have found that line of code
or the stream.emit method.
So I guess a page that deals with stream = Stream and how it links with call_backs would help an old guy like me
I am not complaining. The lyre bird in the bush is calling its tuneful song, the weather is good and my app is on the way to working. Getting it working was, so far, by far the hardest thing I’ve worked with in Panel
And for the sake of completeness or as an example the live streaming update (loads a touch slow) is at https://itkservices3.com embedded via an iframe and linked using a cloudflare tunnel to the server. The “nemdash” menu links to the main panel app via another iframe.
I am happy with result and with the tools available to me.
ahh… I was in error showing that line, it was copied from a file in haste. I should edit it out. Thanks for pointing that out and my apologies.
In the end the solution was very simple, but I maintain it wasn’t obvious from the docs. Either that or I, my mate who writes his own compiler, and Claude Opus are very silly.
In answer to the question about the how docs could be improved so that users can learn the callback code I’d have found it easier if there had been a mention somewhere in the “how to” or other commentary of the .object attribute. I’d have got to the required code by myself if I’d realised that rather than assinging the result to a pane directly it had to be assigned to a pane.object.
Again. I expect to use Panel in further applications, it’s a great tool. Next up electricity price forecasting and sensitivities about moving generators in or out of the bid stack.
the last code I posted worked successfully and is the model I will use next time I want to run periodic call backs.
I did not use .stream in the end. “All” that was needed was for the updated .objects to be rerendered on localhost.
For more context I have a separate process running that downloads the relevant data (in this case 5 minute electricity prices) from an online directory (a new file is added and beautiful soup identifies the last .zip file), parses the csv file, adds the prices to the “prices” data frame and saves it as .pkl.
That code runs fine with a traditional while true: sleep loop because there is no user interaction. Probably should be a cronjob.
The panel code is required to update webobjects and is a great resource. Back to my scheduled job.
And yes I used GPT 4 and claude opus occasionally asking one to critique the other In the end though its knowing the right question to ask. My wife once said you really want to have some idea of the answer before you ask a question but I would say speaking as someone that worked at a high level in investment banking research for many years that the skill is in knowing the right question to ask and also understanding why the answer is what it is.
Agree! So AI ping pong got it over the line? Nice.
I have been looking for a (web) client that makes that easy across 2+ AI’s.
Those 2 perspectives on AI sound pretty congruent btw
I am still wondering if .streams and pn.rx would work as well, and if there is a clear best of those 3. Would be nice to have all 3 variations of the same code as an example for others.
Same regarding assigning to a pane.object. Great that it works, but wondering if there is an even more optimal pattern that does not need object.