jnareb's picture
Change it into demo of various plotting solutions available for Panel
0befa69
#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()