Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipeline enhancements #222

Merged
merged 2 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions examples/user_guide/Pipelines.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
"* ``param.output(param.Number)``: Declaring an output with a specific ``Parameter`` or Python type also declares an output with the name of the method but declares that the output will be of a specific type.\n",
"* ``param.output(c=param.Number)``: Declaring an output using a keyword argument allows overriding the method name as the name of the output and declares the type.\n",
"\n",
"It is also possible to declare multiple parameters, either as keywords (Python >= 3.6 required) or tuples:\n",
"\n",
"* ``param.output(c=param.Number, d=param.String)`` or ``param.output(('c', param.Number), ('d', param.String))``\n",
"\n",
"In the example below the output is simply the result of multiplying the two inputs (``a`` and ``b``) which will produce output ``c``. Additionally we declare a ``view`` method which returns a ``LaTeX`` pane which will render the equation to ``LaTeX``. Finally a ``panel`` method declares returns a ``panel`` object rendering both the parameters and the view; this is the second convention that a ``Pipeline`` expects.\n",
"\n",
"Let's start by displaying this stage on its own:"
Expand All @@ -60,13 +64,15 @@
"\n",
" b = param.Number(default=5, bounds=(0, 10))\n",
" \n",
" @param.output(c=param.Number)\n",
" @param.output(c=param.Number, d=param.Number)\n",
" def output(self):\n",
" return self.a * self.b\n",
" return self.a * self.b, self.a ** self.b\n",
" \n",
" @param.depends('a', 'b')\n",
" def view(self):\n",
" return pn.pane.LaTeX('$%s * %s = %s$' % (self.a, self.b, self.output()))\n",
" c, d = self.output()\n",
" return pn.pane.LaTeX('${a} * {b} = {c}$\\n${a}^{{{b}}} = {d}$'.format(\n",
" a=self.a, b=self.b, c=c, d=d))\n",
"\n",
" def panel(self):\n",
" return pn.Row(self.param, self.view)\n",
Expand Down Expand Up @@ -117,7 +123,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"A ``Pipeline`` with only a single stage is not much of a ``Pipeline`` of course, so it's time to set up a second stage, which consumes the outputs of the first. Recall that ``Stage1`` declares one output named ``c``, this means that if the output from ``Stage1`` should flow to ``Stage2``, the latter should declare a ``Parameter`` named ``c`` which will consume the output of the first stage. Below we therefore define parameters ``c`` and ``exp`` and since ``c`` is the output of the first stage the ``c`` parameter will be declared with a negative precedence stopping ``panel`` from generating a widget for it. Otherwise this class is very similar to the first one, it declares both a ``view`` method which depends on the parameters of the class and a ``panel`` method which returns a view of the object."
"A ``Pipeline`` with only a single stage is not much of a ``Pipeline`` of course, so it's time to set up a second stage, which consumes the outputs of the first. Recall that ``Stage1`` declares one output named ``c``, this means that if the output from ``Stage1`` should flow to ``Stage2``, the latter should declare a ``Parameter`` named ``c`` which will consume the output of the first stage. It does not have to consume all parameters so we can ignore output ``d``.\n",
"\n",
"Below we therefore define parameters ``c`` and ``exp`` and since ``c`` is the output of the first stage the ``c`` parameter will be declared with a negative precedence stopping ``panel`` from generating a widget for it. Otherwise this class is very similar to the first one, it declares both a ``view`` method which depends on the parameters of the class and a ``panel`` method which returns a view of the object."
]
},
{
Expand All @@ -139,7 +147,7 @@
" def panel(self):\n",
" return pn.Row(self.param, self.view)\n",
" \n",
"stage2 = Stage2(c=stage1.output())\n",
"stage2 = Stage2(c=stage1.output()[0])\n",
"stage2.panel()"
]
},
Expand Down
25 changes: 23 additions & 2 deletions panel/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self, stages=[], **params):
self._progress_sel.add_subscriber(self._set_stage)
prev_button = Param(self.param, parameters=['previous'], show_name=False)
next_button = Param(self.param, parameters=['next'], show_name=False)
prev_button.layout[0][0].disabled = True
self._progress_bar = Row(self._make_progress, prev_button, next_button)
spinner = Pane(os.path.join(os.path.dirname(__file__), 'assets', 'spinner.gif'))
self._spinner_layout = Row(Spacer(width=300), Column(Spacer(height=200), spinner))
Expand Down Expand Up @@ -121,10 +122,27 @@ def _set_stage(self, index):
steps = idx-self._stage
if steps < 0:
for i in range(abs(steps)):
self._previous()
e = self._previous()
if e:
break
else:
for i in range(steps):
self._next()
e = self._next()
if e:
break

def _update_button(self):
# Disable previous button
if self._stage == 0:
self._progress_bar[1].layout[0][0].disabled = True
else:
self._progress_bar[1].layout[0][0].disabled = False

# Disable next button
if self._stage == len(self._stages)-1:
self._progress_bar[2].layout[0][0].disabled = True
else:
self._progress_bar[2].layout[0][0].disabled = False

@param.depends('next', watch=True)
def _next(self):
Expand All @@ -134,13 +152,15 @@ def _next(self):
try:
new_stage = self._init_stage()
self._layout[2][0] = new_stage
self._update_button()
except Exception as e:
self._stage -= 1
self._error.object = ('Next stage raised following error:\n\n\t%s: %s'
% (type(e).__name__, str(e)))
self._layout[2][0] = prev_state
if self.debug:
raise e
return e
else:
self._error.object = ''

Expand All @@ -150,6 +170,7 @@ def _previous(self):
try:
self._state = self._states[self._stage]
self._layout[2][0] = self._state.panel()
self._update_button()
except Exception as e:
self._stage += 1
self._error.object = ('Previous stage raised following error:\n\n\t%s: %s'
Expand Down