Пример #1
0
    def plot(self, nsamples=200):
        hv = ensure_holoviews()
        if self.space.n_dims > 1:
            raise ValueError("Can only plot 1D functions")
        bounds = self.space.bounds[0]
        if not self.Xi:
            p = hv.Scatter([]) * hv.Curve([]) * hv.Area([])
        else:
            scatter = hv.Scatter(([p[0] for p in self.Xi], self.yi))
            if self.models:
                model = self.models[-1]
                xs = np.linspace(*bounds, nsamples)
                xsp = self.space.transform(xs.reshape(-1, 1).tolist())
                y_pred, sigma = model.predict(xsp, return_std=True)
                # Plot model prediction for function
                curve = hv.Curve((xs, y_pred)).opts(style=dict(line_dash="dashed"))
                # Plot 95% confidence interval as colored area around points
                area = hv.Area(
                    (xs, y_pred - 1.96 * sigma, y_pred + 1.96 * sigma),
                    vdims=["y", "y2"],
                ).opts(style=dict(alpha=0.5, line_alpha=0))

            else:
                area = hv.Area([])
                curve = hv.Curve([])
            p = scatter * curve * area

        # Plot with 5% empty margins such that the boundary points are visible
        margin = 0.05 * (bounds[1] - bounds[0])
        plot_bounds = (bounds[0] - margin, bounds[1] + margin)

        return p.redim(x=dict(range=plot_bounds))
Пример #2
0
    def plot(self, n=None, tri_alpha=0):
        """Plot the function we want to learn, only works in 2D.

        Parameters
        ----------
        n : int
            the number of boxes in the interpolation grid along each axis
        tri_alpha : float (0 to 1)
            Opacity of triangulation lines
        """
        hv = ensure_holoviews()
        if self.vdim > 1:
            raise NotImplementedError(
                "holoviews currently does not support", "3D surface plots in bokeh."
            )
        if self.ndim != 2:
            raise NotImplementedError(
                "Only 2D plots are implemented: You can "
                "plot a 2D slice with 'plot_slice'."
            )
        x, y = self._bbox
        lbrt = x[0], y[0], x[1], y[1]

        if len(self.data) >= 4:
            if n is None:
                # Calculate how many grid points are needed.
                # factor from A=√3/4 * a² (equilateral triangle)
                scale_factor = np.product(np.diag(self._transform))
                a_sq = np.sqrt(np.min(self.tri.volumes()) * scale_factor)
                n = max(10, int(0.658 / a_sq))

            xs = ys = np.linspace(0, 1, n)
            xs = xs * (x[1] - x[0]) + x[0]
            ys = ys * (y[1] - y[0]) + y[0]
            z = self._ip()(xs[:, None], ys[None, :]).squeeze()

            im = hv.Image(np.rot90(z), bounds=lbrt)

            if tri_alpha:
                points = np.array(
                    [self.tri.get_vertices(s) for s in self.tri.simplices]
                )
                points = np.pad(
                    points[:, [0, 1, 2, 0], :],
                    pad_width=((0, 0), (0, 1), (0, 0)),
                    mode="constant",
                    constant_values=np.nan,
                ).reshape(-1, 2)
                tris = hv.EdgePaths([points])
            else:
                tris = hv.EdgePaths([])
        else:
            im = hv.Image([], bounds=lbrt)
            tris = hv.EdgePaths([])

        im_opts = dict(cmap="viridis")
        tri_opts = dict(line_width=0.5, alpha=tri_alpha)
        no_hover = dict(plot=dict(inspection_policy=None, tools=[]))

        return im.opts(style=im_opts) * tris.opts(style=tri_opts, **no_hover)
Пример #3
0
    def plot(self, *, scatter_or_line="scatter"):
        """Returns a plot of the evaluated data.

        Parameters
        ----------
        scatter_or_line : str, default: "scatter"
            Plot as a scatter plot ("scatter") or a line plot ("line").

        Returns
        -------
        plot : `holoviews.Overlay`
            Plot of the evaluated data.
        """
        if scatter_or_line not in ("scatter", "line"):
            raise ValueError("scatter_or_line must be 'scatter' or 'line'")
        hv = ensure_holoviews()

        xs, ys = zip(*sorted(self.data.items())) if self.data else ([], [])
        if scatter_or_line == "scatter":
            if self.vdim == 1:
                plots = [hv.Scatter((xs, ys))]
            else:
                plots = [hv.Scatter((xs, _ys)) for _ys in np.transpose(ys)]
        else:
            plots = [hv.Path((xs, ys))]

        # Put all plots in an Overlay because a DynamicMap can't handle changing
        # datatypes, e.g. when `vdim` isn't yet known and the live_plot is running.
        p = hv.Overlay(plots)
        # Plot with 5% empty margins such that the boundary points are visible
        margin = 0.05 * (self.bounds[1] - self.bounds[0])
        plot_bounds = (self.bounds[0] - margin, self.bounds[1] + margin)

        return p.redim(x=dict(range=plot_bounds))
Пример #4
0
    def plot(self):
        """Returns a plot of the evaluated data with error bars (not implemented
           for vector functions, i.e., it requires vdim=1).

        Returns
        -------
        plot : `holoviews.element.Scatter * holoviews.element.ErrorBars *
                holoviews.element.Path`
            Plot of the evaluated data.
        """
        hv = ensure_holoviews()
        if not self.data:
            p = hv.Scatter([]) * hv.ErrorBars([]) * hv.Path([])
        elif not self.vdim > 1:
            xs, ys = zip(*sorted(self.data.items()))
            scatter = hv.Scatter(self.data)
            error = hv.ErrorBars([(x, self.data[x], self.error[x]) for x in self.data])
            line = hv.Path((xs, ys))
            p = scatter * error * line
        else:
            raise Exception("plot() not implemented for vector functions.")

        # Plot with 5% empty margins such that the boundary points are visible
        margin = 0.05 * (self.bounds[1] - self.bounds[0])
        plot_bounds = (self.bounds[0] - margin, self.bounds[1] + margin)

        return p.redim(x=dict(range=plot_bounds))
Пример #5
0
 def plot(self):
     hv = ensure_holoviews()
     ivals = sorted(self.ivals, key=attrgetter("a"))
     if not self.data:
         return hv.Path([])
     xs, ys = zip(*[(x, y) for ival in ivals for x, y in sorted(ival.data.items())])
     return hv.Path((xs, ys))
Пример #6
0
    def plot(self):
        """Returns a histogram of the evaluated data.

        Returns
        -------
        holoviews.element.Histogram
            A histogram of the evaluated data."""
        hv = ensure_holoviews()
        vals = [v for v in self.data.values() if v is not None]
        if not vals:
            return hv.Histogram([[], []])
        num_bins = int(max(5, sqrt(self.npoints)))
        vals = hv.Points(vals)
        return hv.operation.histogram(vals, num_bins=num_bins, dimension=1)
Пример #7
0
    def plot_isoline(self, level=0.0, n=None, tri_alpha=0):
        """Plot the isoline at a specific level, only works in 2D.

        Parameters
        ----------
        level : float, default: 0
            The value of the function at which you would like to see
            the isoline.
        n : int
            The number of boxes in the interpolation grid along each axis.
            This is passed to `plot`.
        tri_alpha : float
            The opacity of the overlaying triangulation. This is passed
            to `plot`.

        Returns
        -------
        `holoviews.core.Overlay`
            The plot of the isoline(s). This overlays a `plot` with a
            `holoviews.element.Path`.
        """
        hv = ensure_holoviews()
        if n == -1:
            plot = hv.Path([])
        else:
            plot = self.plot(n=n, tri_alpha=tri_alpha)

        if isinstance(level, Iterable):
            for l in level:
                plot = plot * self.plot_isoline(level=l, n=-1)
            return plot

        vertices, lines = self._get_iso(level, which="line")
        paths = [[vertices[i], vertices[j]] for i, j in lines]
        contour = hv.Path(paths)

        contour_opts = dict(color="black")
        contour = contour.opts(style=contour_opts)
        return plot * contour
Пример #8
0
    def plot(self):
        """Returns a plot of the evaluated data.

        Returns
        -------
        plot : `holoviews.element.Scatter` (if vdim=1)\
               else `holoviews.element.Path`
            Plot of the evaluated data.
        """
        hv = ensure_holoviews()

        xs, ys = zip(*sorted(self.data.items())) if self.data else ([], [])
        if self.vdim == 1:
            p = hv.Path([]) * hv.Scatter((xs, ys))
        else:
            p = hv.Path((xs, ys)) * hv.Scatter([])

        # Plot with 5% empty margins such that the boundary points are visible
        margin = 0.05 * (self.bounds[1] - self.bounds[0])
        plot_bounds = (self.bounds[0] - margin, self.bounds[1] + margin)

        return p.redim(x=dict(range=plot_bounds))
Пример #9
0
    def plot(self, cdims=None, plotter=None, dynamic=True):
        """Returns a DynamicMap with sliders.

        Parameters
        ----------
        cdims : sequence of dicts, or (keys, iterable of values), optional
            Constant dimensions; the parameters that label the learners.
            Example inputs that all give identical results:

            - sequence of dicts:

                >>> cdims = [{'A': True, 'B': 0},
                ...          {'A': True, 'B': 1},
                ...          {'A': False, 'B': 0},
                ...          {'A': False, 'B': 1}]`

            - tuple with (keys, iterable of values):

                >>> cdims = (['A', 'B'], itertools.product([True, False], [0, 1]))
                >>> cdims = (['A', 'B'], [(True, 0), (True, 1),
                ...                       (False, 0), (False, 1)])

        plotter : callable, optional
            A function that takes the learner as a argument and returns a
            holoviews object. By default ``learner.plot()`` will be called.
        dynamic : bool, default True
            Return a `holoviews.core.DynamicMap` if True, else a
            `holoviews.core.HoloMap`. The `~holoviews.core.DynamicMap` is
            rendered as the sliders change and can therefore not be exported
            to html. The `~holoviews.core.HoloMap` does not have this problem.

        Returns
        -------
        dm : `holoviews.core.DynamicMap` (default) or `holoviews.core.HoloMap`
             A `DynamicMap` ``(dynamic=True)`` or `HoloMap`
             ``(dynamic=False)`` with sliders that are defined by `cdims`.
        """
        hv = ensure_holoviews()
        cdims = cdims or self._cdims_default

        if cdims is None:
            cdims = [{'i': i} for i in range(len(self.learners))]
        elif not isinstance(cdims[0], dict):
            # Normalize the format
            keys, values_list = cdims
            cdims = [dict(zip(keys, values)) for values in values_list]

        mapping = {
            tuple(_cdims.values()): l
            for l, _cdims in zip(self.learners, cdims)
        }

        d = defaultdict(list)
        for _cdims in cdims:
            for k, v in _cdims.items():
                d[k].append(v)

        def plot_function(*args):
            with suppress(KeyError):
                learner = mapping[tuple(args)]
                return learner.plot() if plotter is None else plotter(learner)

        dm = hv.DynamicMap(plot_function, kdims=list(d.keys()))
        dm = dm.redim.values(**d)

        if dynamic:
            return dm
        else:
            # XXX: change when https://github.com/ioam/holoviews/issues/3085
            # is fixed.
            vals = {d.name: d.values for d in dm.dimensions() if d.values}
            return hv.HoloMap(dm.select(**vals))
Пример #10
0
    def plot(self, n=None, tri_alpha=0):
        r"""Plot the Learner2D's current state.

        This plot function interpolates the data on a regular grid.
        The gridspacing is evaluated by checking the size of the smallest
        triangle.

        Parameters
        ----------
        n : int
            Number of points in x and y. If None (default) this number is
            evaluated by looking at the size of the smallest triangle.
        tri_alpha : float
            The opacity ``(0 <= tri_alpha <= 1)`` of the triangles overlayed
            on top of the image. By default the triangulation is not visible.

        Returns
        -------
        plot : `holoviews.core.Overlay` or `holoviews.core.HoloMap`
            A `holoviews.core.Overlay` of
            ``holoviews.Image * holoviews.EdgePaths``. If the
            `learner.function` returns a vector output, a
            `holoviews.core.HoloMap` of the
            `holoviews.core.Overlay`\s wil be returned.

        Notes
        -----
        The plot object that is returned if ``learner.function`` returns a
        vector *cannot* be used with the live_plotting functionality.
        """
        hv = ensure_holoviews()
        x, y = self.bounds
        lbrt = x[0], y[0], x[1], y[1]

        if len(self.data) >= 4:
            ip = self.interpolator(scaled=True)
            x, y, z = self.interpolated_on_grid(n)

            if self.vdim > 1:
                ims = {
                    i: hv.Image(np.rot90(z[:, :, i]), bounds=lbrt)
                    for i in range(z.shape[-1])
                }
                im = hv.HoloMap(ims)
            else:
                im = hv.Image(np.rot90(z), bounds=lbrt)

            if tri_alpha:
                points = self._unscale(ip.tri.points[ip.tri.vertices])
                points = np.pad(
                    points[:, [0, 1, 2, 0], :],
                    pad_width=((0, 0), (0, 1), (0, 0)),
                    mode="constant",
                    constant_values=np.nan,
                ).reshape(-1, 2)
                tris = hv.EdgePaths([points])
            else:
                tris = hv.EdgePaths([])
        else:
            im = hv.Image([], bounds=lbrt)
            tris = hv.EdgePaths([])

        im_opts = dict(cmap="viridis")
        tri_opts = dict(line_width=0.5, alpha=tri_alpha)
        no_hover = dict(plot=dict(inspection_policy=None, tools=[]))

        return im.opts(style=im_opts) * tris.opts(style=tri_opts, **no_hover)
Пример #11
0
    def plot(self, n=None, tri_alpha=0):
        r"""Plot the Learner2D's current state.

        This plot function interpolates the data on a regular grid.
        The gridspacing is evaluated by checking the size of the smallest
        triangle.

        Parameters
        ----------
        n : int
            Number of points in x and y. If None (default) this number is
            evaluated by looking at the size of the smallest triangle.
        tri_alpha : float
            The opacity ``(0 <= tri_alpha <= 1)`` of the triangles overlayed
            on top of the image. By default the triangulation is not visible.

        Returns
        -------
        plot : `holoviews.core.Overlay` or `holoviews.core.HoloMap`
            A `holoviews.core.Overlay` of
            ``holoviews.Image * holoviews.EdgePaths``. If the
            `learner.function` returns a vector output, a
            `holoviews.core.HoloMap` of the
            `holoviews.core.Overlay`\s wil be returned.

        Notes
        -----
        The plot object that is returned if ``learner.function`` returns a
        vector *cannot* be used with the live_plotting functionality.
        """
        hv = ensure_holoviews()
        x, y = self.bounds
        lbrt = x[0], y[0], x[1], y[1]

        if len(self.data) >= 4:
            ip = self.ip()

            if n is None:
                # Calculate how many grid points are needed.
                # factor from A=√3/4 * a² (equilateral triangle)
                n = int(0.658 / sqrt(areas(ip).min()))
                n = max(n, 10)

            # The bounds of the linspace should be (-0.5, 0.5) but because of
            # numerical precision problems it could (for example) be
            # (-0.5000000000000001, 0.49999999999999983), then any point at exact
            # boundary would be outside of the domain. See #181.
            eps = 1e-13
            x = y = np.linspace(-0.5 + eps, 0.5 - eps, n)
            z = ip(x[:, None], y[None, :] * self.aspect_ratio).squeeze()

            if self.vdim > 1:
                ims = {
                    i: hv.Image(np.rot90(z[:, :, i]), bounds=lbrt)
                    for i in range(z.shape[-1])
                }
                im = hv.HoloMap(ims)
            else:
                im = hv.Image(np.rot90(z), bounds=lbrt)

            if tri_alpha:
                points = self._unscale(ip.tri.points[ip.tri.vertices])
                points = np.pad(points[:, [0, 1, 2, 0], :],
                                pad_width=((0, 0), (0, 1), (0, 0)),
                                mode='constant',
                                constant_values=np.nan).reshape(-1, 2)
                tris = hv.EdgePaths([points])
            else:
                tris = hv.EdgePaths([])
        else:
            im = hv.Image([], bounds=lbrt)
            tris = hv.EdgePaths([])

        im_opts = dict(cmap='viridis')
        tri_opts = dict(line_width=0.5, alpha=tri_alpha)
        no_hover = dict(plot=dict(inspection_policy=None, tools=[]))

        return im.opts(style=im_opts) * tris.opts(style=tri_opts, **no_hover)
Пример #12
0
    def plot_slice(self, cut_mapping, n=None):
        """Plot a 1D or 2D interpolated slice of a N-dimensional function.

        Parameters
        ----------
        cut_mapping : dict (int → float)
            for each fixed dimension the value, the other dimensions
            are interpolated. e.g. ``cut_mapping = {0: 1}``, so from
            dimension 0 ('x') to value 1.
        n : int
            the number of boxes in the interpolation grid along each axis
        """
        hv = ensure_holoviews()
        plot_dim = self.ndim - len(cut_mapping)
        if plot_dim == 1:
            if not self.data:
                return hv.Scatter([]) * hv.Path([])
            elif self.vdim > 1:
                raise NotImplementedError(
                    "multidimensional output not yet supported by `plot_slice`"
                )
            n = n or 201
            values = [
                cut_mapping.get(i, np.linspace(*self._bbox[i], n))
                for i in range(self.ndim)
            ]
            ind = next(i for i in range(self.ndim) if i not in cut_mapping)
            x = values[ind]
            y = self._ip()(*values)
            p = hv.Path((x, y))

            # Plot with 5% margins such that the boundary points are visible
            margin = 0.05 / self._transform[ind, ind]
            plot_bounds = (x.min() - margin, x.max() + margin)
            return p.redim(x=dict(range=plot_bounds))

        elif plot_dim == 2:
            if self.vdim > 1:
                raise NotImplementedError(
                    "holoviews currently does not support 3D surface plots in bokeh."
                )
            if n is None:
                # Calculate how many grid points are needed.
                # factor from A=√3/4 * a² (equilateral triangle)
                scale_factor = np.product(np.diag(self._transform))
                a_sq = np.sqrt(np.min(self.tri.volumes()) * scale_factor)
                n = max(10, int(0.658 / a_sq))

            xs = ys = np.linspace(0, 1, n)
            xys = [xs[:, None], ys[None, :]]
            values = [
                cut_mapping[i]
                if i in cut_mapping
                else xys.pop(0) * (b[1] - b[0]) + b[0]
                for i, b in enumerate(self._bbox)
            ]

            lbrt = [b for i, b in enumerate(self._bbox) if i not in cut_mapping]
            lbrt = np.reshape(lbrt, (2, 2)).T.flatten().tolist()

            if len(self.data) >= 4:
                z = self._ip()(*values).squeeze()
                im = hv.Image(np.rot90(z), bounds=lbrt)
            else:
                im = hv.Image([], bounds=lbrt)

            return im.opts(style=dict(cmap="viridis"))
        else:
            raise ValueError("Only 1 or 2-dimensional plots can be generated.")