Tabbed dashboard with altair, folium, and custom template

Hi all!

I have recently developed a dashboard to explore the merit order of power plants in Europe.

Source code : https://github.com/kavvkon/power-merit-Eur
Live version (heroku free tier) : https://power-merit.herokuapp.com/
Demo: streamable.com/i73vxk (couldn’t put links and embedding here due to new user restrictions)

This is basically a plot that shows the marginal cost of operation of the installed power plant capacity in ascending order. The main requirement was that any parameter change were immediately obvious to the user. The Figure was pretty complex to make: Variable width, variable colour bar charts with overlayed elements. Those deep parametrization options were available in matplotlib soon but I realized that the rendering of the image was taking a bit more time. More over it didn’t allow any interactivity and hover events. So I ended up with altair. I also added an interactive map with folium and a DataTable as it was pretty easy to include without much overhead.

The code initially followed the approach described panel.holoviz. org/user_guide/Param.html). Everything is organized in a class. Parameters are defined in the main body of the class. The methods return the individual panes relating the defined parameters with individual elements using @param.depends decorators. One bug I initially had was that the tabs were always refreshing and resetting to the first one in every parameter change. In the constructor I explicitly defined the structure of the dashboard using different pane elements pn.Tabs, pn.Columns, pn.Rows. I discovered that this was more efficient as it doesn’t redraw stuff everytime something is changing. I tried to avoid unneeded calculations and dependencies and the result is pretty snappy even when there are over 5000 datapoints plotted. I am sure that this can be improved though so feel free to suggest any improvements.

I found some examples of embedding one or more panel objects to to a template by using pn.Template, so then I could add different bootstrap elements that have nothing to do with the panel itself.

2 Likes

Another challenge that I had was that I wanted to programmatically generate many parameters and sliders based on my data model without explicitly needing to define them. Maybe this is not the best way to do it but I added those parameters in a dictionary. Fixing them in self.param didn’t work for me so I just transfered the to locals() as variable names

par_price_dict_default = {}
for ind, par in df_params.iterrows():
   par_price_dict[ind] = param.Number(par["Cost (EUR/Mwh)"], bounds =(0, 100))
 
locals().update(par_price_dict)
price_params = list(par_price_dict.keys())

Then to call them:

widget_prices = pn.Column(pn.Param( self.param, parameters=self.price_params))

Unpack list so that I do not express everything in dependencies:

@param.depends("countries", "carbon_price", "toggle_operation", *price_params)
def plot_merit_order_altair(self):
        ...
1 Like

Hi @kavvkon

I’ve tried it out your work is really awesome for many reasons. Thanks for sharing

It’s a really nice educational tool. I support traders at Ørsted trading power. And some of my colleagues also supporting the traders do not understands the basics of how the merit order curve determines the power price. So I will be using the tool for education.

It’s a really nice use of a Custom Panel Template. The Panel Template can super power your app into something that looks and feels awesome. But not a lot of Panel users know or use this super power. Checkout the merit-order-template here.

Finally the template works really well in the notebook as well. Being able to develop applications for both notebook and web is a super power I am very interested in. That makes it easy to create a lot of data science tools for EDA that works both in the notebook and as a web app. For example something like Tensorboard, something like Pandas Profiling Report or something like the Merit Order App.

2 Likes