jnareb commited on
Commit
0befa69
·
1 Parent(s): fc2d7ea

Change it into demo of various plotting solutions available for Panel

Browse files
Files changed (2) hide show
  1. app.py +379 -9
  2. requirements.txt +7 -0
app.py CHANGED
@@ -3,19 +3,31 @@ import json
3
  #import math
4
 
5
  # data analysis
6
- #import numpy as np
7
- #import pandas as pd
8
 
9
  # dashboard
10
  import panel as pn
11
 
12
  # plotting
13
- #import seaborn as sns
14
- #from matplotlib.figure import Figure
 
 
 
 
 
 
 
 
 
15
 
16
 
17
- # configure panel
18
- pn.extension('ipywidgets', design="material", sizing_mode='fixed')
 
 
 
19
 
20
  # configure app
21
  DATA_DIR = 'data'
@@ -36,14 +48,372 @@ repos_widget = pn.widgets.Select(
36
  disabled=True
37
  )
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  # the application
40
  pn.template.MaterialTemplate(
41
- site="diffannotator",
42
- title="Panel Demo",
 
43
  sidebar=[
44
  repos_widget, # disabled, and UNBOUND!
45
  ],
46
  main=[
47
- pn.pane.Str("Plots would be shown here")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  ],
49
  ).servable()
 
3
  #import math
4
 
5
  # data analysis
6
+ import numpy as np
7
+ import pandas as pd
8
 
9
  # dashboard
10
  import panel as pn
11
 
12
  # plotting
13
+ import altair as alt
14
+ import holoviews as hv
15
+ import hvplot.pandas # noqa
16
+ import seaborn as sns
17
+ import matplotlib
18
+ import matplotlib.pyplot as plt
19
+ import plotly.express as px
20
+ from bokeh.models import ColumnDataSource
21
+ from bokeh.plotting import figure as b_figure
22
+ from matplotlib.figure import Figure
23
+ from plotnine import ggplot, aes, geom_line, theme_matplotlib, theme_set
24
 
25
 
26
+ # configure panel and plots
27
+ pn.extension('ipywidgets', 'plotly', 'vega', 'vizzu',
28
+ design='material', sizing_mode='fixed')
29
+ hv.extension('bokeh', 'matplotlib', 'plotly')
30
+ matplotlib.use('agg')
31
 
32
  # configure app
33
  DATA_DIR = 'data'
 
48
  disabled=True
49
  )
50
 
51
+
52
+ # -----------------------------------------------------------
53
+ def create_figure_matplotlib(figsize=(4,3)):
54
+ # data
55
+ t = np.arange(0.0, 2.0, 0.01)
56
+ s = 1 + np.sin(2 * np.pi * t)
57
+
58
+ # figure
59
+ if figsize is None:
60
+ fig = Figure()
61
+ else:
62
+ fig = Figure(figsize=figsize)
63
+ ax = fig.subplots()
64
+
65
+ # plot
66
+ ax.plot(t, s)
67
+
68
+ # decorations
69
+ ax.set(xlabel='time (s)', ylabel='voltage (mV)',
70
+ title='Voltage')
71
+ ax.grid()
72
+ # https://matplotlib.org/ipympl/examples/full-example.html
73
+ # NOTE: might require ipympl to be installed
74
+ # Hide the Figure name at the top of the figure
75
+ fig.canvas.header_visible = False
76
+ # Disable the resizing feature
77
+ fig.canvas.resizable = False
78
+
79
+ return fig
80
+
81
+
82
+ def create_figure_seaborn(figsize=(4,3)):
83
+ # data
84
+ t = np.arange(0.0, 2.0, 0.01)
85
+ df = pd.DataFrame({
86
+ 'x': t,
87
+ 'y': 1 + np.sin(2 * np.pi * t),
88
+ })
89
+
90
+ # figure
91
+ fig = Figure(figsize=figsize)
92
+ ax = fig.subplots()
93
+
94
+ # configure
95
+ sns.set_theme() # 'default' theme
96
+
97
+ # plot
98
+ sns.lineplot(data=df, x='x', y='y',
99
+ ax=ax)
100
+
101
+ return fig
102
+
103
+
104
+ def create_figure_pandas(figsize=(4,3)):
105
+ # data
106
+ t = np.arange(0.0, 2.0, 0.01)
107
+ df = pd.DataFrame({
108
+ 'x': t,
109
+ 'y': 1 + np.sin(2 * np.pi * t),
110
+ })
111
+
112
+ # figure
113
+ fig = Figure(figsize=figsize)
114
+ ax = fig.subplots()
115
+
116
+ # plot
117
+ df.plot(x='x', y='y', legend=False,
118
+ xlabel='time (s)', ylabel='voltage (mV)', title='Voltage',
119
+ ax=ax)
120
+
121
+ return fig
122
+
123
+
124
+ def create_figure_plotnine():
125
+ # data
126
+ t = np.arange(0.0, 2.0, 0.01)
127
+ df = pd.DataFrame({
128
+ 'x': t,
129
+ 'y': 1 + np.sin(2 * np.pi * t),
130
+ })
131
+
132
+ # Set default theme for all the plots
133
+ theme_set(theme_matplotlib())
134
+
135
+ # Basic Scatter Plot
136
+ # - Gallery, points
137
+ plot = (
138
+ ggplot(df, aes("x", "y"))
139
+ + geom_line(color="blue")
140
+ )
141
+
142
+ # draw the plot
143
+ fig = plot.draw()
144
+ plt.close(fig) # REMEMBER TO CLOSE THE FIGURE!
145
+
146
+ return fig
147
+
148
+
149
+ def create_figure_bokeh():
150
+ # data
151
+ t = np.arange(0.0, 2.0, 0.01)
152
+ s = 1 + np.sin(2 * np.pi * t)
153
+
154
+ # wrapped data
155
+ source = ColumnDataSource(data=dict(x=t, y=s))
156
+
157
+ # configuring the plot
158
+ # https://docs.bokeh.org/en/latest/docs/user_guide/interaction/tools.html#inspectors
159
+ tooltips = [
160
+ ("index", "$index"),
161
+ ("(x,y)", "($x, $y)"),
162
+ ]
163
+
164
+ # set up plot
165
+ plot = b_figure(height=400, width=400, title="my sine wave",
166
+ tools="crosshair,pan,reset,save,wheel_zoom,hover",
167
+ tooltips=tooltips,
168
+ x_range=[-0.1, 2.1], y_range=[-0.1, 2.1])
169
+
170
+ plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)
171
+
172
+ return plot
173
+
174
+
175
+ def create_figure_hvplot_pandas():
176
+ # data
177
+ t = np.arange(0.0, 2.0, 0.01)
178
+ df = pd.DataFrame({
179
+ 'x': t,
180
+ 'y': 1 + np.sin(2 * np.pi * t),
181
+ })
182
+
183
+ # plot
184
+ plot = df.hvplot(x='x', y='y',
185
+ value_label='sin(2πt)+1',
186
+ #responsive = True, # incompatible with fixed size
187
+ height = 500, width = 620, # incompatible with responsive mode
188
+ title='f(t) = sin(2πt)+1',
189
+ legend='top')
190
+
191
+ return plot
192
+
193
+
194
+ def create_figure_hv():
195
+ # data
196
+ t = np.arange(0.0, 2.0, 0.01)
197
+ data = {
198
+ "x": t,
199
+ "y": 1 + np.sin(2 * np.pi * t),
200
+ }
201
+
202
+ # plot
203
+ hv_box = hv.Scatter(data, kdims="x", vdims="y").opts()
204
+
205
+ return hv_box
206
+
207
+
208
+ def create_figure_plotly():
209
+ # data
210
+ t = np.arange(0.0, 2.0, 0.01)
211
+ data = {
212
+ "x": t,
213
+ "y": 1 + np.sin(2 * np.pi * t),
214
+ }
215
+
216
+ # create plot
217
+ fig = px.line(
218
+ data, x="x", y="y",
219
+ # ??? 'fixed' sizing mode requires width and height to be set: PlotlyPlot(id='p1275', ...)
220
+ width=500, height=420, # required for 'fixed' sizing mode
221
+ )
222
+
223
+ # configure plot
224
+ fig.update_traces(mode="lines", line=dict(width=1))
225
+
226
+ return fig
227
+
228
+
229
+ def create_figure_altair():
230
+ # data
231
+ t = np.arange(0.0, 2.0, 0.01)
232
+ df = pd.DataFrame({
233
+ "x": t,
234
+ "y": 1 + np.sin(2 * np.pi * t),
235
+ })
236
+
237
+ # create plot
238
+ # https://altair-viz.github.io/user_guide/marks/line.html
239
+ chart = alt.Chart(df).mark_line(
240
+ point=alt.OverlayMarkDef(opacity=0, size=1),
241
+ ).encode(
242
+ x='x',
243
+ y='y',
244
+ tooltip=['x', 'y'], # not used?
245
+ ).properties(
246
+ # ??? 'fixed' sizing mode requires width and height to be set: VegaPlot(id='p1282', ...)
247
+ width =500,
248
+ height=420,
249
+ ).interactive()
250
+
251
+ return chart
252
+
253
+
254
+ # https://panel.holoviz.org/reference/panes/HoloViews.html#dynamic
255
+ def hvplot_widgeted(height = 300):
256
+ plot = create_figure_hvplot_pandas()
257
+
258
+ plot_pane = pn.pane.HoloViews(plot,
259
+ backend='bokeh',
260
+ sizing_mode="fixed", height=height)
261
+
262
+ backend_widget = pn.widgets.RadioButtonGroup.from_param(
263
+ plot_pane.param.backend,
264
+ button_type="primary", button_style="outline",
265
+ )
266
+
267
+ return pn.Column(backend_widget, plot_pane)
268
+
269
+
270
+ def wizzu_pane():
271
+ # data (may use DataFrame instead)
272
+ t = np.arange(0.0, 2.0, 0.01)
273
+ data = {
274
+ "x": t,
275
+ "y": 1 + np.sin(2 * np.pi * t),
276
+ }
277
+ df = pd.DataFrame(data)
278
+
279
+ # plot configuration
280
+ config = {
281
+ 'geometry': 'line',
282
+ 'x': 'x', 'y': 'y',
283
+ 'title': 'sin(2πt)+1',
284
+ }
285
+ animate = {
286
+ 'config': {
287
+ 'channels': {
288
+ 'x': {
289
+ 'range': {
290
+ 'min': 'auto',
291
+ 'max': 'auto'
292
+ }
293
+ },
294
+ 'y': {
295
+ 'range': {
296
+ 'min': 'auto',
297
+ 'max': 'auto',
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ # pane
305
+ vizzu = pn.pane.Vizzu(
306
+ df, config=config, animation=animate,
307
+ duration=400, tooltip=True,
308
+ sizing_mode='fixed', width=500, height=425,
309
+ )
310
+
311
+ return vizzu
312
+
313
+
314
  # the application
315
  pn.template.MaterialTemplate(
316
+ site="Panel",
317
+ title="Demo of various plotting solutions",
318
+ sidebar_width=300,
319
  sidebar=[
320
  repos_widget, # disabled, and UNBOUND!
321
  ],
322
  main=[
323
+ pn.pane.Str("Plots would be shown here"),
324
+ pn.FlexBox(
325
+ pn.Card(
326
+ pn.pane.Matplotlib(create_figure_matplotlib(),
327
+ format="svg", tight=True,
328
+ width=500, height=425),
329
+ header="Matplotlib (svg)",
330
+ ),
331
+ pn.Card(
332
+ pn.pane.Matplotlib(create_figure_matplotlib(figsize=None),
333
+ interactive=True, tight=True,
334
+ width=500, height=425),
335
+ header="interactive Matplotlib (via ipympl) - BUGGY!!!",
336
+ ),
337
+ pn.Card(
338
+ pn.pane.Matplotlib(create_figure_seaborn(),
339
+ format="png", tight=True,
340
+ width=500, height=425),
341
+ header="seaborn (png)",
342
+ ),
343
+ pn.Card(
344
+ pn.pane.Matplotlib(create_figure_pandas(),
345
+ format="png", tight=True,
346
+ width=500, height=425),
347
+ header="pandas (png)",
348
+ ),
349
+ # TODO: https://panel.holoviz.org/reference/panes/Perspective.html
350
+ pn.Card(
351
+ pn.pane.Matplotlib(create_figure_plotnine(),
352
+ format="svg", tight=True,
353
+ width=500, height=425),
354
+ header="plotnine / ggplot2 (png)",
355
+ ),
356
+ pn.Card(
357
+ pn.Row(
358
+ pn.pane.Bokeh(create_figure_bokeh(), theme="dark_minimal", height=600),
359
+ pn.pane.Markdown(r"""
360
+ - Pan/Drag Tools
361
+ - 'box_select'
362
+ - 'box_zoom'
363
+ - 'lasso_select'
364
+ - **'pan'**, 'xpan', 'ypan'
365
+ - Click/Tap Tools
366
+ - 'poly_select'
367
+ - 'tap'
368
+ - Scroll/Pinch Tools
369
+ - **'wheel_zoom'**, 'xwheel_zoom', 'ywheel_zoom'
370
+ - 'xwheel_pan', 'ywheel_pan'
371
+ - Actions
372
+ - 'examine'
373
+ - 'undo'
374
+ - 'redo'
375
+ - **'reset'**
376
+ - **'save'**
377
+ - 'zoom_in', 'xzoom_in', 'yzoom_in'
378
+ - 'zoom_out', 'xzoom_out', 'yzoom_out'
379
+ - Inspectors
380
+ - **'crosshair'**
381
+ - **'hover'** (figure configurable with `tooltips=`)
382
+ - Edit Tools
383
+ - ...
384
+ """),
385
+ ),
386
+ header="Bokeh (theme='dark_minimal')",
387
+ ),
388
+ # TODO?: https://panel.holoviz.org/reference/panes/ECharts.html
389
+ pn.Card(
390
+ create_figure_hvplot_pandas(),
391
+ header="hvPlot (pandas.hvplot)",
392
+ ),
393
+ pn.Card(
394
+ hvplot_widgeted(height=600),
395
+ header="hvPlot - select backend",
396
+ ),
397
+ pn.Card(
398
+ pn.pane.HoloViews(create_figure_hv(),
399
+ sizing_mode='fixed', height=600),
400
+ header="HoloViews (hv.Scatter)",
401
+ ),
402
+ pn.Card(
403
+ pn.pane.Plotly(create_figure_plotly(),
404
+ sizing_mode='fixed', width=500, height=425),
405
+ header="Plotly.Express",
406
+ ),
407
+ pn.Card(
408
+ pn.pane.Vega(create_figure_altair(),
409
+ sizing_mode='fixed', width=500, height=425),
410
+ # ALTERNATIVE: pn.panel(create_figure_altair())
411
+ header="Vega (using Altair)",
412
+ ),
413
+ pn.Card(
414
+ wizzu_pane(),
415
+ header="Vizzu JavaScript library - not configured!!!",
416
+ ),
417
+ ),
418
  ],
419
  ).servable()
requirements.txt CHANGED
@@ -6,6 +6,13 @@ ipywidgets_bokeh # for matplotlib, too
6
  #watchfiles # not needed when running `panel serve` without `--dev` option
7
  # Packages used by notebooks
8
  matplotlib
 
9
  seaborn
10
  numpy
11
  pandas
 
 
 
 
 
 
 
6
  #watchfiles # not needed when running `panel serve` without `--dev` option
7
  # Packages used by notebooks
8
  matplotlib
9
+ ipympl
10
  seaborn
11
  numpy
12
  pandas
13
+ bokeh
14
+ holoviews
15
+ hvplot
16
+ plotly
17
+ plotnine
18
+ altair