#import datetime import json #import math # data analysis import numpy as np import pandas as pd # dashboard import panel as pn # plotting import altair as alt import holoviews as hv import hvplot.pandas # noqa import seaborn as sns import matplotlib import matplotlib.pyplot as plt import plotly.express as px from bokeh.models import ColumnDataSource from bokeh.plotting import figure as b_figure from matplotlib.figure import Figure from plotnine import ggplot, aes, geom_line, theme_matplotlib, theme_set # configure panel and plots pn.extension('ipywidgets', 'plotly', 'vega', 'vizzu', design='material', sizing_mode='fixed') hv.extension('bokeh', 'matplotlib', 'plotly') matplotlib.use('agg') # configure app DATA_DIR = 'data' JSON_FILE = 'tensorflow.timeline.purpose-to-type.json' # get data, cached @pn.cache def get_timeline_data(): with open(f'{DATA_DIR}/{JSON_FILE}', mode='r') as json_fp: return json.load(json_fp) # TODO: include the rest of the app # widgets repos_widget = pn.widgets.Select( name="repository", value="tensorflow", options=["tensorflow"], disabled=True ) # ----------------------------------------------------------- def create_figure_matplotlib(figsize=(4,3)): # data t = np.arange(0.0, 2.0, 0.01) s = 1 + np.sin(2 * np.pi * t) # figure if figsize is None: fig = Figure() else: fig = Figure(figsize=figsize) ax = fig.subplots() # plot ax.plot(t, s) # decorations ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='Voltage') ax.grid() # https://matplotlib.org/ipympl/examples/full-example.html # NOTE: might require ipympl to be installed # Hide the Figure name at the top of the figure fig.canvas.header_visible = False # Disable the resizing feature fig.canvas.resizable = False return fig def create_figure_seaborn(figsize=(4,3)): # data t = np.arange(0.0, 2.0, 0.01) df = pd.DataFrame({ 'x': t, 'y': 1 + np.sin(2 * np.pi * t), }) # figure fig = Figure(figsize=figsize) ax = fig.subplots() # configure sns.set_theme() # 'default' theme # plot sns.lineplot(data=df, x='x', y='y', ax=ax) return fig def create_figure_pandas(figsize=(4,3)): # data t = np.arange(0.0, 2.0, 0.01) df = pd.DataFrame({ 'x': t, 'y': 1 + np.sin(2 * np.pi * t), }) # figure fig = Figure(figsize=figsize) ax = fig.subplots() # plot df.plot(x='x', y='y', legend=False, xlabel='time (s)', ylabel='voltage (mV)', title='Voltage', ax=ax) return fig def create_figure_plotnine(): # data t = np.arange(0.0, 2.0, 0.01) df = pd.DataFrame({ 'x': t, 'y': 1 + np.sin(2 * np.pi * t), }) # Set default theme for all the plots theme_set(theme_matplotlib()) # Basic Scatter Plot # - Gallery, points plot = ( ggplot(df, aes("x", "y")) + geom_line(color="blue") ) # draw the plot fig = plot.draw() plt.close(fig) # REMEMBER TO CLOSE THE FIGURE! return fig def create_figure_bokeh(): # data t = np.arange(0.0, 2.0, 0.01) s = 1 + np.sin(2 * np.pi * t) # wrapped data source = ColumnDataSource(data=dict(x=t, y=s)) # configuring the plot # https://docs.bokeh.org/en/latest/docs/user_guide/interaction/tools.html#inspectors tooltips = [ ("index", "$index"), ("(x,y)", "($x, $y)"), ] # set up plot plot = b_figure(height=400, width=400, title="my sine wave", tools="crosshair,pan,reset,save,wheel_zoom,hover", tooltips=tooltips, x_range=[-0.1, 2.1], y_range=[-0.1, 2.1]) plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) return plot def create_figure_hvplot_pandas(): # data t = np.arange(0.0, 2.0, 0.01) df = pd.DataFrame({ 'x': t, 'y': 1 + np.sin(2 * np.pi * t), }) # plot plot = df.hvplot(x='x', y='y', value_label='sin(2πt)+1', #responsive = True, # incompatible with fixed size height = 500, width = 620, # incompatible with responsive mode title='f(t) = sin(2πt)+1', legend='top') return plot def create_figure_hv(): # data t = np.arange(0.0, 2.0, 0.01) data = { "x": t, "y": 1 + np.sin(2 * np.pi * t), } # plot hv_box = hv.Scatter(data, kdims="x", vdims="y").opts() return hv_box def create_figure_plotly(): # data t = np.arange(0.0, 2.0, 0.01) data = { "x": t, "y": 1 + np.sin(2 * np.pi * t), } # create plot fig = px.line( data, x="x", y="y", # ??? 'fixed' sizing mode requires width and height to be set: PlotlyPlot(id='p1275', ...) width=500, height=420, # required for 'fixed' sizing mode ) # configure plot fig.update_traces(mode="lines", line=dict(width=1)) return fig def create_figure_altair(): # data t = np.arange(0.0, 2.0, 0.01) df = pd.DataFrame({ "x": t, "y": 1 + np.sin(2 * np.pi * t), }) # create plot # https://altair-viz.github.io/user_guide/marks/line.html chart = alt.Chart(df).mark_line( point=alt.OverlayMarkDef(opacity=0, size=1), ).encode( x='x', y='y', tooltip=['x', 'y'], # not used? ).properties( # ??? 'fixed' sizing mode requires width and height to be set: VegaPlot(id='p1282', ...) width =500, height=420, ).interactive() return chart # https://panel.holoviz.org/reference/panes/HoloViews.html#dynamic def hvplot_widgeted(height = 300): plot = create_figure_hvplot_pandas() plot_pane = pn.pane.HoloViews(plot, backend='bokeh', sizing_mode="fixed", height=height) backend_widget = pn.widgets.RadioButtonGroup.from_param( plot_pane.param.backend, button_type="primary", button_style="outline", ) return pn.Column(backend_widget, plot_pane) def wizzu_pane(): # data (may use DataFrame instead) t = np.arange(0.0, 2.0, 0.01) data = { "x": t, "y": 1 + np.sin(2 * np.pi * t), } df = pd.DataFrame(data) # plot configuration config = { 'geometry': 'line', 'x': 'x', 'y': 'y', 'title': 'sin(2πt)+1', } animate = { 'config': { 'channels': { 'x': { 'range': { 'min': 'auto', 'max': 'auto' } }, 'y': { 'range': { 'min': 'auto', 'max': 'auto', } } } } } # pane vizzu = pn.pane.Vizzu( df, config=config, animation=animate, duration=400, tooltip=True, sizing_mode='fixed', width=500, height=425, ) return vizzu # the application pn.template.MaterialTemplate( site="Panel", title="Demo of various plotting solutions", sidebar_width=300, sidebar=[ repos_widget, # disabled, and UNBOUND! ], main=[ pn.pane.Str("Plots would be shown here"), pn.FlexBox( pn.Card( pn.pane.Matplotlib(create_figure_matplotlib(), format="svg", tight=True, width=500, height=425), header="Matplotlib (svg)", ), pn.Card( pn.pane.Matplotlib(create_figure_matplotlib(figsize=None), interactive=True, tight=True, width=500, height=425), header="interactive Matplotlib (via ipympl) - BUGGY!!!", ), pn.Card( pn.pane.Matplotlib(create_figure_seaborn(), format="png", tight=True, width=500, height=425), header="seaborn (png)", ), pn.Card( pn.pane.Matplotlib(create_figure_pandas(), format="png", tight=True, width=500, height=425), header="pandas (png)", ), # TODO: https://panel.holoviz.org/reference/panes/Perspective.html pn.Card( pn.pane.Matplotlib(create_figure_plotnine(), format="svg", tight=True, width=500, height=425), header="plotnine / ggplot2 (png)", ), pn.Card( pn.Row( pn.pane.Bokeh(create_figure_bokeh(), theme="dark_minimal", height=600), pn.pane.Markdown(r""" - Pan/Drag Tools - 'box_select' - 'box_zoom' - 'lasso_select' - **'pan'**, 'xpan', 'ypan' - Click/Tap Tools - 'poly_select' - 'tap' - Scroll/Pinch Tools - **'wheel_zoom'**, 'xwheel_zoom', 'ywheel_zoom' - 'xwheel_pan', 'ywheel_pan' - Actions - 'examine' - 'undo' - 'redo' - **'reset'** - **'save'** - 'zoom_in', 'xzoom_in', 'yzoom_in' - 'zoom_out', 'xzoom_out', 'yzoom_out' - Inspectors - **'crosshair'** - **'hover'** (figure configurable with `tooltips=`) - Edit Tools - ... """), ), header="Bokeh (theme='dark_minimal')", ), # TODO?: https://panel.holoviz.org/reference/panes/ECharts.html pn.Card( create_figure_hvplot_pandas(), header="hvPlot (pandas.hvplot)", ), pn.Card( hvplot_widgeted(height=600), header="hvPlot - select backend", ), pn.Card( pn.pane.HoloViews(create_figure_hv(), sizing_mode='fixed', height=600), header="HoloViews (hv.Scatter)", ), pn.Card( pn.pane.Plotly(create_figure_plotly(), sizing_mode='fixed', width=500, height=425), header="Plotly.Express", ), pn.Card( pn.pane.Vega(create_figure_altair(), sizing_mode='fixed', width=500, height=425), # ALTERNATIVE: pn.panel(create_figure_altair()) header="Vega (using Altair)", ), pn.Card( wizzu_pane(), header="Vizzu JavaScript library - not configured!!!", ), ), ], ).servable()