예제 #1
0
파일: interact.py 프로젝트: tjcorona/panel
    def __init__(self, object, params={}, **kwargs):
        if signature is None:
            raise ImportError(
                'interact requires either recent Python version '
                '(>=3.3 or IPython to inspect function signatures.')

        super(interactive, self).__init__(object, **params)

        new_kwargs = self.find_abbreviations(kwargs)
        # Before we proceed, let's make sure that the user has passed a set of args+kwargs
        # that will lead to a valid call of the function. This protects against unspecified
        # and doubly-specified arguments.
        try:
            check_argspec(object)
        except TypeError:
            # if we can't inspect, we can't validate
            pass
        else:
            getcallargs(object, **{n: v for n, v, _ in new_kwargs})

        widgets = self.widgets_from_abbreviations(new_kwargs)
        if self.manual_update:
            widgets.append(('manual', Button(name=self.manual_name)))
        self._widgets = OrderedDict(widgets)
        self._pane = panel(self.object(**self.kwargs), name=self.name)
        self._inner_layout = Row(self._pane)
        widgets = [
            widget for _, widget in widgets if isinstance(widget, Widget)
        ]
        if 'name' in params:
            widgets.insert(0, HTML('<h2>%s</h2>' % self.name))
        self.widget_box = Column(*widgets)
        self.layout.objects = [self.widget_box, self._inner_layout]
        self._link_widgets()
예제 #2
0
    def __init__(self, object, params={}, **kwargs):
        super(interactive, self).__init__(object, **params)

        new_kwargs = self.find_abbreviations(kwargs)
        # Before we proceed, let's make sure that the user has passed a set of args+kwargs
        # that will lead to a valid call of the function. This protects against unspecified
        # and doubly-specified arguments.
        try:
            check_argspec(object)
        except TypeError:
            # if we can't inspect, we can't validate
            pass
        else:
            getcallargs(object, **{n: v for n, v, _ in new_kwargs})

        widgets = self.widgets_from_abbreviations(new_kwargs)
        if self.manual_update:
            widgets.append(('manual', Button(name=self.manual_name)))
        self._widgets = OrderedDict(widgets)
        self._pane = Pane(self.object(**self.kwargs),
                          name=self.name,
                          _temporary=True)
        self._inner_layout = Row(self._pane)
        self.widget_box = WidgetBox(*(widget for _, widget in widgets
                                      if isinstance(widget, Widget)))
        self.layout.objects = [self.widget_box, self._inner_layout]
        self._link_widgets()
예제 #3
0
    def __init__(self, __interact_f, __options={}, **kwargs):
        VBox.__init__(self, _dom_classes=['widget-interact'])
        self.result = None
        self.args = []
        self.kwargs = {}

        self.f = f = __interact_f
        self.clear_output = kwargs.pop('clear_output', True)
        self.manual = __options.get("manual", False)
        self.manual_name = __options.get("manual_name", "Run Interact")
        self.auto_display = __options.get("auto_display", False)

        new_kwargs = self.find_abbreviations(kwargs)
        # Before we proceed, let's make sure that the user has passed a set of args+kwargs
        # that will lead to a valid call of the function. This protects against unspecified
        # and doubly-specified arguments.
        try:
            check_argspec(f)
        except TypeError:
            # if we can't inspect, we can't validate
            pass
        else:
            getcallargs(f, **{n:v for n,v,_ in new_kwargs})
        # Now build the widgets from the abbreviations.
        self.kwargs_widgets = self.widgets_from_abbreviations(new_kwargs)

        # This has to be done as an assignment, not using self.children.append,
        # so that traitlets notices the update. We skip any objects (such as fixed) that
        # are not DOMWidgets.
        c = [w for w in self.kwargs_widgets if isinstance(w, DOMWidget)]

        # If we are only to run the function on demand, add a button to request this.
        if self.manual:
            self.manual_button = Button(description=self.manual_name)
            c.append(self.manual_button)

        self.out = Output()
        c.append(self.out)
        self.children = c

        # Wire up the widgets
        # If we are doing manual running, the callback is only triggered by the button
        # Otherwise, it is triggered for every trait change received
        # On-demand running also suppresses running the function with the initial parameters
        if self.manual:
            self.manual_button.on_click(self.update)

            # Also register input handlers on text areas, so the user can hit return to
            # invoke execution.
            for w in self.kwargs_widgets:
                if isinstance(w, Text):
                    w.on_submit(self.update)
        else:
            for widget in self.kwargs_widgets:
                widget.observe(self.update, names='value')

            self.on_displayed(self.update)
예제 #4
0
    def __init__(self, __interact_f, __options={}, **kwargs):
        VBox.__init__(self, _dom_classes=['widget-interact'])
        self.result = None
        self.args = []
        self.kwargs = {}

        self.f = f = __interact_f
        self.clear_output = kwargs.pop('clear_output', True)
        self.manual = __options.get("manual", False)
        self.manual_name = __options.get("manual_name", "Run Interact")
        self.auto_display = __options.get("auto_display", False)

        new_kwargs = self.find_abbreviations(kwargs)
        # Before we proceed, let's make sure that the user has passed a set of args+kwargs
        # that will lead to a valid call of the function. This protects against unspecified
        # and doubly-specified arguments.
        try:
            check_argspec(f)
        except TypeError:
            # if we can't inspect, we can't validate
            pass
        else:
            getcallargs(f, **{n: v for n, v, _ in new_kwargs})
        # Now build the widgets from the abbreviations.
        self.kwargs_widgets = self.widgets_from_abbreviations(new_kwargs)

        # This has to be done as an assignment, not using self.children.append,
        # so that traitlets notices the update. We skip any objects (such as fixed) that
        # are not DOMWidgets.
        c = [w for w in self.kwargs_widgets if isinstance(w, DOMWidget)]

        # If we are only to run the function on demand, add a button to request this.
        if self.manual:
            self.manual_button = Button(description=self.manual_name)
            c.append(self.manual_button)

        self.out = Output()
        c.append(self.out)
        self.children = c

        # Wire up the widgets
        # If we are doing manual running, the callback is only triggered by the button
        # Otherwise, it is triggered for every trait change received
        # On-demand running also suppresses running the function with the initial parameters
        if self.manual:
            self.manual_button.on_click(self.update)

            # Also register input handlers on text areas, so the user can hit return to
            # invoke execution.
            for w in self.kwargs_widgets:
                if isinstance(w, Text):
                    w.on_submit(self.update)
        else:
            for widget in self.kwargs_widgets:
                widget.observe(self.update, names='value')

            self.on_displayed(self.update)
예제 #5
0
    def __call__(self, __interact_f=None, **kwargs):
        """
        Make the given function interactive by adding and displaying
        the corresponding :class:`interactive` widget.
        Expects the first argument to be a function. Parameters to this
        function are widget abbreviations passed in as keyword arguments
        (``**kwargs``). Can be used as a decorator (see examples).
        Returns
        -------
        f : __interact_f with interactive widget attached to it.
        Parameters
        ----------
        __interact_f : function
            The function to which the interactive widgets are tied. The `**kwargs`
            should match the function signature. Passed to :func:`interactive()`
        **kwargs : various, optional
            An interactive widget is created for each keyword argument that is a
            valid widget abbreviation. Passed to :func:`interactive()`
        Examples
        --------
        Render an interactive text field that shows the greeting with the passed in
        text::
            # 1. Using interact as a function
            def greeting(text="World"):
                print("Hello {}".format(text))
            interact(greeting, text="IPython Widgets")
            # 2. Using interact as a decorator
            @interact
            def greeting(text="World"):
                print("Hello {}".format(text))
            # 3. Using interact as a decorator with named parameters
            @interact(text="IPython Widgets")
            def greeting(text="World"):
                print("Hello {}".format(text))
        Render an interactive slider widget and prints square of number::
            # 1. Using interact as a function
            def square(num=1):
                print("{} squared is {}".format(num, num*num))
            interact(square, num=5)
            # 2. Using interact as a decorator
            @interact
            def square(num=2):
                print("{} squared is {}".format(num, num*num))
            # 3. Using interact as a decorator with named parameters
            @interact(num=5)
            def square(num=2):
                print("{} squared is {}".format(num, num*num))
        """
        # If kwargs are given, replace self by a new
        # _InteractFactory with the updated kwargs
        if kwargs:
            params = list(interactive.param)
            kw = dict(self.kwargs)
            kw.update({k: v for k, v in kwargs.items() if k not in params})
            opts = dict(self.opts,
                        **{k: v
                           for k, v in kwargs.items() if k in params})
            self = type(self)(self.cls, opts, kw)

        f = __interact_f
        if f is None:
            # This branch handles the case 3
            # @interact(a=30, b=40)
            # def f(*args, **kwargs):
            #     ...
            #
            # Simply return the new factory
            return self
        elif 'throttled' in check_argspec(f).args:
            raise ValueError(
                'A function cannot have "throttled" as an argument')

        # positional arg support in: https://gist.github.com/8851331
        # Handle the cases 1 and 2
        # 1. interact(f, **kwargs)
        # 2. @interact
        #    def f(*args, **kwargs):
        #        ...
        w = self.widget(f)
        try:
            f.widget = w
        except AttributeError:
            # some things (instancemethods) can't have attributes attached,
            # so wrap in a lambda
            f = lambda *args, **kwargs: __interact_f(*args, **kwargs)
            f.widget = w
        return w.layout
예제 #6
0
def interactive(__interact_f, **kwargs):
    """
    Builds a group of interactive widgets tied to a function and places the
    group into a Box container.

    Returns
    -------
    container : a Box instance containing multiple widgets

    Parameters
    ----------
    __interact_f : function
        The function to which the interactive widgets are tied. The `**kwargs`
        should match the function signature.
    **kwargs : various, optional
        An interactive widget is created for each keyword argument that is a
        valid widget abbreviation.
    """
    f = __interact_f
    co = kwargs.pop('clear_output', True)
    manual = kwargs.pop('__manual', False)
    kwargs_widgets = []
    container = Box(_dom_classes=['widget-interact'])
    container.result = None
    container.args = []
    container.kwargs = dict()
    kwargs = kwargs.copy()

    new_kwargs = _find_abbreviations(f, kwargs)
    # Before we proceed, let's make sure that the user has passed a set of args+kwargs
    # that will lead to a valid call of the function. This protects against unspecified
    # and doubly-specified arguments.
    try:
        check_argspec(f)
    except TypeError:
        # if we can't inspect, we can't validate
        pass
    else:
        getcallargs(f, **{n: v for n, v, _ in new_kwargs})
    # Now build the widgets from the abbreviations.
    kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))

    # This has to be done as an assignment, not using container.children.append,
    # so that traitlets notices the update. We skip any objects (such as fixed) that
    # are not DOMWidgets.
    c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]

    # If we are only to run the function on demand, add a button to request this.
    if manual:
        manual_button = Button(description="Run %s" % f.__name__)
        c.append(manual_button)
    out = Output()
    c.append(out)
    container.children = c

    # Build the callback
    def call_f(*args):

        container.kwargs = {}
        for widget in kwargs_widgets:
            value = widget.value
            container.kwargs[widget._kwarg] = value
        if manual:
            manual_button.disabled = True
        try:
            with out:
                if co:
                    clear_output(wait=True)
                container.result = f(**container.kwargs)
                if container.result is not None:
                    display(container.result)
        except Exception as e:
            ip = get_ipython()
            if ip is None:
                container.log.warn("Exception in interact callback: %s",
                                   e,
                                   exc_info=True)
            else:
                ip.showtraceback()
        finally:
            if manual:
                manual_button.disabled = False

    # Wire up the widgets
    # If we are doing manual running, the callback is only triggered by the button
    # Otherwise, it is triggered for every trait change received
    # On-demand running also suppresses running the function with the initial parameters
    if manual:
        manual_button.on_click(call_f)

        # Also register input handlers on text areas, so the user can hit return to
        # invoke execution.
        for w in kwargs_widgets:
            if isinstance(w, Text):
                w.on_submit(call_f)
    else:
        for widget in kwargs_widgets:
            widget.observe(call_f, names='value')

        container.on_displayed(
            lambda _: call_f(dict(name=None, old=None, new=None)))

    return container
def interactive(__interact_f, **kwargs):
    """
    Builds a group of interactive widgets tied to a function and places the
    group into a Box container.

    Returns
    -------
    container : a Box instance containing multiple widgets

    Parameters
    ----------
    __interact_f : function
        The function to which the interactive widgets are tied. The `**kwargs`
        should match the function signature.
    **kwargs : various, optional
        An interactive widget is created for each keyword argument that is a
        valid widget abbreviation.
    """
    f = __interact_f
    co = kwargs.pop('clear_output', True)
    manual = kwargs.pop('__manual', False)
    kwargs_widgets = []
    container = Box(_dom_classes=['widget-interact'])
    container.result = None
    container.args = []
    container.kwargs = dict()
    kwargs = kwargs.copy()

    new_kwargs = _find_abbreviations(f, kwargs)
    # Before we proceed, let's make sure that the user has passed a set of args+kwargs
    # that will lead to a valid call of the function. This protects against unspecified
    # and doubly-specified arguments.
    try:
        check_argspec(f)
    except TypeError:
        # if we can't inspect, we can't validate
        pass
    else:
        getcallargs(f, **{n:v for n,v,_ in new_kwargs})
    # Now build the widgets from the abbreviations.
    kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))

    # This has to be done as an assignment, not using container.children.append,
    # so that traitlets notices the update. We skip any objects (such as fixed) that
    # are not DOMWidgets.
    c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]

    # If we are only to run the function on demand, add a button to request this.
    if manual:
        manual_button = Button(description="Run %s" % f.__name__)
        c.append(manual_button)
    container.children = c

    # Build the callback
    def call_f(*args):
        container.kwargs = {}
        for widget in kwargs_widgets:
            value = widget.value
            container.kwargs[widget._kwarg] = value
        if co:
            clear_output(wait=True)
        if manual:
            manual_button.disabled = True
        try:
            container.result = f(**container.kwargs)
            if container.result is not None:
                display(container.result)
        except Exception as e:
            ip = get_ipython()
            if ip is None:
                container.log.warn("Exception in interact callback: %s", e, exc_info=True)
            else:
                ip.showtraceback()
        finally:
            if manual:
                manual_button.disabled = False

    # Wire up the widgets
    # If we are doing manual running, the callback is only triggered by the button
    # Otherwise, it is triggered for every trait change received
    # On-demand running also suppresses running the function with the initial parameters
    if manual:
        manual_button.on_click(call_f)

        # Also register input handlers on text areas, so the user can hit return to
        # invoke execution.
        for w in kwargs_widgets:
            if isinstance(w, Text):
                w.on_submit(call_f)
    else:
        for widget in kwargs_widgets:
            widget.observe(call_f, names='value')

        container.on_displayed(lambda _: call_f(dict(name=None, old=None, new=None)))

    return container