Creating an interactive dashboard in Jupyter

The functional approach we used in the previous section is convenient for exploration within the notebook. For a complex dashboard, however, it is better to use a somewhat declarative approach for more complex dashboards. In order to do that, we need to inherit from the Panel's param.Parameterized object and declare the parameters as it's attributed. For each view, we will create a separate method, using the @param.depends('param1', 'param2') decorator to bind the view refresh with the corresponding parameter updates. Let's give it a try:

  1. First, we'll define the DateRange parameter, using a simple tuple of date-time values:
bounds = (dt.datetime(2019,1,1),dt.datetime(2019,5,30))
dr = param.DateRange(bounds=bounds, default=bounds)
  1. Another parameter we want to use is boroughs. As we want to be able to select multiple boroughs at the same time, we'll have to explicitly pass them:
boros_list = ['Manhattan', 'Bronx', 'Brooklyn', 'Queens', 'Staten Island']
boros = param.ListSelector(default=boros_list, objects=boros_list)
  1. Once the parameters are defined, we can create our view object, based on the dummy param.Parametrized class, as follows:
class Timeline(param.Parameterized):
dr = dr
boros = boros
  1. Next, we need to draw visualizations. As everything here runs in Python, all we need is to access the input parameters, filter data by them, and make a chart, returning the plot. The decorator will tell the Panel which parameters we want the chart to be updated on. We'll start with the timeline:
    # method for Timeline
@param.depends('dr', 'boros')
def view_tl(self):
start, end = pd.to_datetime(self.dr[0]),
pd.to_datetime(self.dr[1])

tl_data = boro_total.loc[(boro_total.index >= start) &
(boro_total.index <= end),
[el.lower() for el in self.boros]]


plot = plt.figure(figsize=(10,5))
ax = plot.add_subplot(111)
tl_data.plot(ax=ax, linewidth=1)

ax.legend(loc=4)
plt.tight_layout()
plt.close(plot)
return plot

Similarly, we will create a chart for the top five complaint types. It also consists of a decorator, filtering, and visualization parts. Consider the following code:

    @param.depends('dr', 'boros')
def view_top(self, N=5):
start, end = pd.to_datetime(self.dr[0]),
pd.to_datetime(self.dr[1])

boro_mask = DATA.boro.isin([el.lower()
for el in self.boros])
time_mask = (DATA.date >= start)
& (DATA.date <= end)

top = DATA[boro_mask & time_mask]

S = top.groupby(['complaint_type', 'boro'])
['complaint_type'].count().unstack()
topN = S.iloc[S.sum(1).argsort()].tail(N)

plot = plt.figure()
ax = plot.add_subplot(111)

topN.plot(kind='barh',stacked=True, ax=ax)
plt.tight_layout()
plt.close(plot)

return plot

This concludes the logic behind the dashboard. Now, we need to define its layout. For that, we will create a simple grid, using Panel's Row and Column objects. For more advanced layouts, panel also has a Grid object, but we will not use it here:

panel = pn.Column( '<h1>NYC 311 dashboard</h1>',
T.view_tl,
pn.Row(T.param, T.view_top,), sizing_mode='stretch_width')

Now, all we need is to start serving panel:

panel.servable()

As a result, we'll get the following dashboard:

Dashboards can be represented as separate windows, using two object methods of aneither panel.show() or panel.servable(). Both will result in a new browser tab, serving the dashboard. The difference between them is that, with the second method, we can also run the dashboard with no Jupyter Notebook attached, using a bash command:

 panel serve --show 2_panel.ipynb  

Using panel serve, we can deploy our dashboard as an independent web application. All we need is to deploy the environment (all of the packages we need and Python itself) on a dedicated machine and make it run this command. In this case, we could swap the SQLite connection with one to the external database, so that the data will be shared between the dashboard and any other applications. The power of dynamic dashboards lies in their large capacity and flexibility. Here, we ignored the intermediary step of computing top complaint types per day and were able to run our analytics on the raw data. If needed, we could always drill-down and check the properties of a specific record, as well.

As everything is running on the server, in Python, we can use any package and are very flexible in designing the dashboard. As we mentioned, Panel supports any visualization that can be rendered in the notebook, so you can even reuse some visualizations you already have, including those we built in Altair.

One limitation to this approach is that we can only control the appearance of the visualizations to the extent that all of the libraries we use allow us to do so; for example, while we can use Altair, there is no way, at least currently, to pull back its parameters and use it to interact with other packages.

Overall, dynamic dashboards allow a wide range of possibilities for exploring and communicating your data. Compared to the static ones, they are easy to write, support any Python package, and can do the heavy lifting of data consumption and aggregation, pulling from raw data. This, of course, requires a dedicated server and may require maintenance and governance, especially if available to the public.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset