Skip to content

Commit

Permalink
Improved Introduction
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Jan 11, 2019
1 parent ccef599 commit 22e3bbe
Showing 1 changed file with 74 additions and 37 deletions.
111 changes: 74 additions & 37 deletions examples/user_guide/Introduction.ipynb
Expand Up @@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Panel lets you add interactive controls for just about anything you can display in Python. Panel can help you build simple interactive apps, complex multi-page dashboards, or anything in between. As a simple example, let's say you have created a function to plot a sine wave using the Pandas `.plot()` command (based on Matplotlib):"
"Panel lets you add interactive controls for just about anything you can display in Python. Panel can help you build simple interactive apps, complex multi-page dashboards, or anything in between. As a simple example, let's say you have created a function to plot a sine wave using Matplotlib and the Pandas `.plot()` command:"
]
},
{
Expand All @@ -16,16 +16,16 @@
"import panel as pn, numpy as np, pandas as pd, matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"\n",
"def mplplot(df):\n",
"def mplplot(df, **kwargs):\n",
" fig = df.plot().get_figure()\n",
" plt.close(fig)\n",
" return fig\n",
"\n",
"def sine(frequency=1.0, amplitude=1.0, n=200, view=mplplot):\n",
"def sine(frequency=1.0, amplitude=1.0, n=200, view_fn=mplplot):\n",
" xs = np.arange(n)/n*20.0\n",
" ys = amplitude*np.sin(frequency*xs)\n",
" df = pd.DataFrame(dict(y=ys), index=xs)\n",
" return view(df)\n",
" return view_fn(df, frequency=frequency, amplitude=amplitude, n=n)\n",
"\n",
"sine(1.5, 2.5)"
]
Expand All @@ -36,7 +36,7 @@
"source": [
"## Interactive Panels\n",
"\n",
"If we wanted to try out lots of combinations of these values to understand how the frequency and amplitude parameters affect this plot, we could edit and re-evaluate the above cell lots of times. But it's a lot quicker to use sliders to adjust the values interactively. You can quickly make a Panel app to explore a function's parameters using `pn.interact`:"
"If we wanted to try out lots of combinations of these values to understand how frequency and amplitude affect this plot, we could reevaluate the above cell lots of times. But it's a lot quicker to use sliders to adjust the values interactively. You can quickly make a Panel app to explore a function's parameters using `pn.interact`:"
]
},
{
Expand Down Expand Up @@ -69,7 +69,7 @@
"outputs": [],
"source": [
"i = pn.interact(sine, n=(5,100))\n",
"print(i)"
"i.pprint()"
]
},
{
Expand Down Expand Up @@ -126,7 +126,7 @@
"source": [
"## Composing new Panels\n",
"\n",
"You can use this compositional approach to build arbitrary combinations of widgets, plots, text, and other elements needed for an app or dashboard. E.g. we can build something just like `interact` returns, starting from scratch and linking the widgets manually:"
"You can use this compositional approach to build arbitrary combinations of widgets, plots, text, and other elements needed for an app or dashboard. E.g. we can build something just like `interact` returns, starting from scratch and linking the widget to an ``update`` function which replaces the output:"
]
},
{
Expand All @@ -138,11 +138,16 @@
"import panel.widgets as pnw\n",
"frequency = pnw.FloatSlider(name='frequency', value=1, start=1, end=5)\n",
"amplitude = pnw.FloatSlider(name='amplitude', value=1, start=0.1, end=10)\n",
"\n",
"widgets = pn.Column(frequency, amplitude)\n",
"# ...\n",
"# build an object for the sine plot\n",
"# ...\n",
"sine_panel = pn.Row(widgets)\n",
"sine_panel = pn.Row(widgets, sine(frequency.value, amplitude.value))\n",
"\n",
"def update(event):\n",
" sine_panel[1] = sine(frequency.value, amplitude.value)\n",
" \n",
"frequency.param.watch(update, 'value')\n",
"amplitude.param.watch(update, 'value')\n",
"\n",
"sine_panel"
]
},
Expand Down Expand Up @@ -177,7 +182,7 @@
"metadata": {},
"outputs": [],
"source": [
"sine_panel.servable() # Need to check -- the %matplotlib magic may prevent serving"
"sine_panel.servable()"
]
},
{
Expand All @@ -186,9 +191,9 @@
"source": [
"## Declarative Panels\n",
"\n",
"The above compositional approach is very flexible, but it ties your domain-specific code (the parts about sine waves) with your widget display code. That's fine for small, quick projects or projects dominated by visualization code, but what about large-scale, long-lived projects, where the code is used in many different contexts over time, such as in large batch runs, interactive command-line execution, notebooks, and deployed dashboards? For larger projects like that, it's important to be able to separate the parts of the code that are about the underlying domain (i.e. application or research area) from those that are tied to specific display technologies (such as Jupyter notebooks or web servers) that change over time.<br> \n",
"The above compositional approach is very flexible, but it ties your domain-specific code (the parts about sine waves) with your widget display code. That's fine for small, quick projects or projects dominated by visualization code, but what about large-scale, long-lived projects, where the code is used in many different contexts over time, such as in large batch runs, one-off command-line usage, notebooks, and deployed dashboards? For larger projects like that, it's important to be able to separate the parts of the code that are about the underlying domain (i.e. application or research area) from those that are tied to specific display technologies (such as Jupyter notebooks or web servers). \n",
"\n",
"For such usages, Panel supports objects declared with the separate [Param](http://param.pyviz.org) library, which provides a GUI-independent way of capturing and declaring the parameters of your objects (and dependencies between your code and those parameters), in a way that's independent of any particular application or dashboard technology. For instance, the above code can be captured in an object that declares the ranges and values of all parameters, as well as how to generate the plot as a PNG, independently of the Panel library or any other way of interacting with the object:"
"For such usages, Panel supports objects declared with the separate [Param](http://param.pyviz.org) library, which provides a GUI-independent way of capturing and declaring the parameters of your objects (and dependencies between your code and those parameters), in a way that's independent of any particular application or dashboard technology. For instance, the above code can be captured in an object that declares the ranges and values of all parameters, as well as how to generate the plot, independently of the Panel library or any other way of interacting with the object:"
]
},
{
Expand All @@ -198,27 +203,19 @@
"outputs": [],
"source": [
"import param\n",
"\n",
"class Sine(param.Parameterized):\n",
" pass\n",
"# ..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Sine definition can now be stored in a version-controlled Python module that is shared across many applications and users. When it comes time to visualize it, it's now simple to pop up an interactive visualization as part of a notebook whenever that's appropriate:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
" \n",
" amplitude = param.Number(default=1, bounds=(0, 5))\n",
" frequency = param.Number(default=2, bounds=(0, 10))\n",
" n = param.Integer(default=200, bounds=(1, 200))\n",
"\n",
" def view(self):\n",
" return sine(self.frequency, self.amplitude, self.n)\n",
" \n",
"sine_obj = Sine()\n",
"\n",
"pn.Row(sine_obj.param)# ..."
"pn.Row(sine_obj.param, sine_obj.view)"
]
},
{
Expand All @@ -227,7 +224,7 @@
"source": [
"## Linking plots and actions between panes\n",
"\n",
"The above approaches each work with nearly any displayable object, including images, equations, tables, and plots. In each case, Panel provides interactive functionality using widgets, and updates the displayed objects accordingly, while making very few assumptions about what actually is being displayed. Panel also supports richer, more dynamic interactivity where the displayed object is itself interactive, such as the JavaScript-based plots from Bokeh and Plotly.\n",
"The above approaches each work with a very wide variety of displayable objects, including images, equations, tables, and plots. In each case, Panel provides interactive functionality using widgets, and updates the displayed objects accordingly, while making very few assumptions about what actually is being displayed. Panel also supports richer, more dynamic interactivity where the displayed object is itself interactive, such as the JavaScript-based plots from Bokeh and Plotly.\n",
"\n",
"For instance, if we use the [Bokeh](http://bokeh.pydata.org) wrapper [hvPlot](http://hvplot.pyviz.org) instead of the Matplotlib wrapper provided with Pandas, we will get interactive plots that allow zooming, panning and hovering:"
]
Expand All @@ -238,14 +235,19 @@
"metadata": {},
"outputs": [],
"source": [
"# replace mplplot(df) above with .hvplot()"
"import hvplot.pandas\n",
"\n",
"def hvplot(df, **kwargs):\n",
" return df.hvplot()\n",
"\n",
"pn.interact(sine, view_fn=hvplot)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These interactive actions and others (e.g. clicking) can be linked to make it easy to explore data more deeply and uncover connections. For instance, with hvPlot we can..."
"These interactive actions can be combined with more complex interactions with a plot (e.g. tap, hover) to make it easy to explore data more deeply and uncover connections. For instance, by dropping down to HoloViews we can extend the hvPlot example by adding dynamic features indicating the position on the unit circle when hovering over the sine curve:"
]
},
{
Expand All @@ -254,7 +256,42 @@
"metadata": {},
"outputs": [],
"source": [
"# add a plot or table to the sine example, and have the plot or table update for clicking or hovering on the first plot"
"import holoviews as hv\n",
"\n",
"tap = hv.streams.PointerX(x=0)\n",
"\n",
"def hvplot(df, frequency, **kwargs):\n",
" plot = df.hvplot(width=500, padding=(0, 0.1))\n",
" tap.source = plot\n",
"\n",
" def unit_circle(x):\n",
" cosx = np.cos(x*frequency)\n",
" sinx = np.sin(x*frequency)\n",
" circle = hv.Path([\n",
" hv.Ellipse(0, 0, 2),\n",
" [(-1, 0), (1, 0)],\n",
" [(0, -1), (0, 1)]]).opts(color='black')\n",
" triangle = hv.Path([\n",
" [(0, 0), (cosx, sinx)],\n",
" [(0, 0), (cosx, 0)],\n",
" [(cosx, 0), (cosx, sinx)]]).opts(\n",
" color='red', line_width=2)\n",
" labels = hv.Labels([\n",
" (cosx/2, 0, '%.2f' % cosx),\n",
" (cosx, sinx/2., '%.2f' % sinx)]).opts(\n",
" padding=0.1, xaxis=None, yaxis=None,\n",
" text_baseline='bottom')\n",
" return (circle * triangle * labels)\n",
"\n",
" vline = hv.DynamicMap(hv.VLine, streams=[tap])\n",
" circle = hv.DynamicMap(unit_circle, streams=[tap])\n",
" return (plot * vline.opts(color='black') + circle).opts(shared_axes=False)\n",
"\n",
"unit_curve = pn.interact(sine, view_fn=hvplot, n=(1, 200), frequency=(0, 10.))\n",
"\n",
"pn.Row(\n",
" pn.Column('# The Unit Circle', unit_curve[0], latex),\n",
" unit_curve[1])"
]
},
{
Expand All @@ -265,7 +302,7 @@
"\n",
"The other sections in this user guide expand on each of the topics above, explaining in detail how to do various tasks and use various types of functionality from Panel:\n",
"\n",
"- [Interact](Interact.ipynb): More detailed and advanced usage of `interact()`, including controlling ranges and available options\n",
"- [Interact](Interact.ipynb): More detailed and advanced usage of `interact()`, including controlling ranges\n",
"- [Panes](Panes.ipynb): Types of panes supported (Matplotlib, SVG, HTML, etc.) and how to use them in panels\n",
"- [Widgets](Widgets.ipynb): Types of widgets supported and how to link them to actions\n",
"- [Layouts](Layouts.ipynb): Composing panes and widgets into panels\n",
Expand Down

0 comments on commit 22e3bbe

Please sign in to comment.