Introduction
Most of the time I do java programming, but lately I started coding in python (Since i felt i need to update my skills and see what the whole fuss is about). After a quick tour I could code basic stuff with python, and so I decided to do something that will be more fun since I heard there are frameworks that can handle web user information for visualizations purposes quite easily.
So I started looking around and pretty soon I found Streamlit to be the most popular framework that enables a novice software programmer to developm a dashboard for data visualization. it looked quite nice, and within a few hours I could have a dashboard. I thought I got it right and tried to dig in and see whether it suites for coding a full blown SaaS SPA application.
I got really disappointed. It appeared that the development model of Streamlit allowed a rapid update of the display right after a python file update (that’s cool, though), but the one major (and I must say, horrible) flaw of this framework was that in case the code was comprised of several source files, the Streamlit framework had to automatically run all of the code in the files. To me it was bizzare, and against any kind coding logic. After a short while I understood that Streamlit coding paradigm is aimed for a quick and simple development of data dashboards, but not for SaaS application.
Having this set in my mind I went on with my research and found Panel, A framework that has the most generic name in the planet (which doesn’t allow to easily find them using search engines). But then again I found it to be amazing:
- It allows the development of a rapid (really rapid) web application.
- It offers large set visual compoents for web input and visual data representations.
- It’s available under BSD license and may be freely used for both commercial and non-commercial use.
- It connects with various tools and frameworks and tools under the Holoviz brand.
- It was originally developed by Anaconda Inc. which is an important company in the field of Data science.
And nobody is paying attention, just like Jared Vennett (Ryan Gosling) said in the movie “The Big Short”. Nobody is paying attention.
You can of course go to Panel’s homepage and invest plenty of time to learn what you can do with it at panel.holoviz.com, or….get a quick bite through an example I have here.
How I Did Stuff With Panel
I seeked for some data from the internet which I can visualize after some simple processing. For the sake of simplicity I decided to run pivot function over the data and display the values of the pivot as well bar graph for each slicing of the pivot table.
So I went to Kaggle, and since I am into the analysis of stuff in the cyber security world, I looked for relevant datasets. That’s were I saw the Cyber Security Indexes for 2020 which summarizes the info about cyber security attacks per each country in the world.
I downloaded the dataset and made sure the data looks clean and makes sense, which it did. The next step was, well, to code my web app using python and Panel. The code is deployed using HuggingFace.co, which a well known cloud environment which among other stuff allows the easy deployment and running of Panel web application. Since it’s a demo, I just called it with the dull name of Demo1. Click Demo1 to watch it in action.
How I Coded It
I am using VSCode for my software development. So after installing python and the environment (in my case it was venv), I installed two main packages: a) Panel (pip install panel) and b) For the debugging phase I installed debugpy (pip install debugpy). Since it’s the last one is not required for the normal running of a Panel web app I won’t cover this issue right now.
The first thing I did was to create two files: mainapp.py and CyberIndexDashboard.py. The first one’s purpose, as its name implies, was supposed to be the main running file. The second one’s purpose was to contain an object that will take care of reading the data, running a pivot on it, and display a table for a specific index, alongside a bar chart based on the same table.
The key points in the mainapp.py file are as follows:
• The main code runs in the main function (some of the variables are globals, but this implementation is not necessary)
• The pages dictionary is the list of pages that should be displayed to the user. Each key holds a complete page component and data of its own, according to the name of the column from the pivot table that should be the y-value for both the displayed table and the bar chart.
• The radio_button_group is the list of four button which are hooked to each of the pages according to the index name that each button exhibits to the users. The hooking action is done using the radio_button_group.param.watch method.
• The main_area and the sidebar variables represent, well, the main_area, and the sidebar parts of the application. In the case of this web app they basically contain a pn.Column object which is a container you may be familiar with in case you developed web apps with twitter bootstrap ui framework (for your web apps you can also use other containers such as pn.Row which is a container for a row, yes, again similarly to twitter boostrap grid model).
• The template variable gets the value of a ready made template named in this web app as FastListTemplate. You can also use BootstrapTemplate, FastGridTemplate, Material, React and more. No need to include all sort of javascript files and css files. Everything comes right right out the box.
• The template.servable() called makes this code behave as a web app (surprising, ha?), but here comes another goodie – In case you are not a web developer, but a data scientist, Panel can become a Jupyter notebook, by just omitting the template.servable() call.
The key points to notice in the CyberIndexDashboard:
• It reads the data file only once into the variable “df” by defining it as a static variable. This way the performance of the web application is stable. Pandas does the dirty work of reading the CSV file.
• It accepts several initialization parameters: the cyber attacks index column that’s being measured per continent, the values of the x-axis and the values header
• The pivot table is generated using pandas. Pretty cool – with one statement the whole computation is committed. It will later be shown within a Tabulator Panel’s component.
• The bar chart is then displayed by using Echarts Panel component which is totally free (it was created by Apache).
And the result looks like this:
MainApp.py:
import panel as pn
from panel.template import FastListTemplate
from CyberIndexDashboard import CyberIndexDashboard
main_area = pn.Column("")
ext="External"
def main():
global main_area
pn.extension('echarts','tabulator')
pn.config.sizing_mode="stretch_width"
# Instantiate pages and add them to the pages dictionarqy
pages = {
"CEIDashboard": CyberIndexDashboard("Region","CEI","CEI Avg."),
"GCIDashboard": CyberIndexDashboard("Region","GCI","GCI Avg."),
"NCSIDashboard": CyberIndexDashboard("Region","NCSI","NCSI Avg."),
"DDLDashboard": CyberIndexDashboard("Region","DDL","DDL Avg."),
}
sidebar = None
data_source_info = pn.pane.Markdown("""
***The data describes cyber attacks split by continent***
***Data is taken from [Kaggle](https://www.kaggle.com/datasets/katerynameleshenko/cyber-security-indexes)!***
""")
radio_button_group = pn.widgets.ToggleGroup(name='Index', options=['NCSI', 'CEI','GCI', 'DDL'], behavior="radio",button_type='primary',orientation='vertical')
def update(event):
global main_area
main_area.clear()
main_area.append(pages[radio_button_group.value+"Dashboard"].view())
radio_button_group.param.watch(update,'value',onlychanged=True)
radio_button_group.param.trigger('value')
sidebar = pn.Column(pn.Row(radio_button_group),pn.Row(data_source_info))
template = FastListTemplate(
title="Cyber Operations Instances",
sidebar=[sidebar],
main=[main_area],
)
pn.state.cache["template"] = template
pn.state.cache["modal"] = template.modal
# Serve the Panel app
template.servable()
main()
CyberIndexDashboard:
import panel as pn
import pandas as pd
import numpy as np
from bokeh.plotting import figure
# Dashboard Page
class CyberIndexDashboard:
np.random.seed(7)
pn.extension('tabulator')
#static variable: df
df=pd.read_csv("cyber-security-indexes.csv")
def __init__(self,index_col,values_col,values_header):
self.id = values_col
pivot_table=pd.pivot_table(self.df, index=index_col, values=values_col, aggfunc='mean')
bar_chart = self.echarts_bar_chart(np.array(pivot_table.index.values),
np.array(pivot_table[values_col].values),
values_header)
self.a_dataframe = self.dataframe_show(pivot_table)
row = [pn.Row(pn.Column(self.a_dataframe)), pn.Column(bar_chart)]
col = pn.Column(row[0],row[1])
self.content = col
def dataframe_show(self,pivot_table):
return pn.widgets.Tabulator(pivot_table)
def echarts_bar_chart(self,x,y,y_title):
echart_bar = {
'title': {
'text': y_title
},
'tooltip': {},
'legend': {
'data':['Index']
},
'xAxis': {
'data': x.tolist()
},
'yAxis': {},
'series': [{
'name': 'Index',
'type': 'bar',
'data': y.tolist()
}],
};
echart_pane = pn.pane.ECharts(echart_bar, height=480, width=640)
return echart_pane
def view(self):
return self.content
For those who want to see my code in action go to my own demo server at “mainapp”.
My code’s github repository is hehttps://github.com/savigdor73/panel-demo1re.
Conclusion
Panel seems to be a really cool framework. It saves loads of time for people like myself who just want to display web user interface without messing with the bits and bytes of javascript and html.
I demonstrated some of its most basic capabilities, but for those who are interested it has built-in solution for logins using Google and other systems so that SaaS applications can be developed rapidly.
Since there are tons of components included in Panel my intent is to explore it further and better understand to which use cases it is more suitable.