Exemple #1
0
    def _process(self, element, key=None):
        try:
            from matplotlib.contour import QuadContourSet
            from matplotlib.axes import Axes
            from matplotlib.figure import Figure
        except ImportError:
            raise ImportError("contours operation requires matplotlib.")
        extent = element.range(0) + element.range(1)[::-1]

        if type(element) is Raster:
            data = [np.flipud(element.data)]
        elif isinstance(element, Image):
            data = [np.flipud(element.dimension_values(2, flat=False))]
        elif isinstance(element, QuadMesh):
            data = (element.dimension_values(0, False),
                    element.dimension_values(1, False), element.data[2])

        if isinstance(self.p.levels, int):
            levels = self.p.levels + 2 if self.p.filled else self.p.levels + 3
            zmin, zmax = element.range(2)
            levels = np.linspace(zmin, zmax, levels)
        else:
            levels = self.p.levels

        xdim, ydim = element.dimensions('key', label=True)
        fig = Figure()
        ax = Axes(fig, [0, 0, 1, 1])
        contour_set = QuadContourSet(ax,
                                     *data,
                                     filled=self.p.filled,
                                     extent=extent,
                                     levels=levels)
        if self.p.filled:
            contour_type = Polygons
        else:
            contour_type = Contours
        vdims = element.vdims[:1]

        paths = []
        empty = np.full((1, 2), np.NaN)
        for level, cset in zip(contour_set.get_array(),
                               contour_set.collections):
            subpaths = []
            for path in cset.get_paths():
                if path.codes is None:
                    subpaths.append(path.vertices)
                else:
                    subpaths += np.split(path.vertices,
                                         np.where(path.codes == 1)[0][1:])
            subpath = np.concatenate(
                [p for sp in subpaths for p in (sp, empty)][:-1])
            paths.append({(xdim, ydim): subpath, element.vdims[0].name: level})
        contours = contour_type(paths,
                                label=element.label,
                                kdims=element.kdims,
                                vdims=vdims)
        if self.p.overlaid:
            contours = element * contours
        return contours
    def _process(self, element, key=None):
        try:
            from matplotlib.contour import QuadContourSet
            from matplotlib.axes import Axes
            from matplotlib.figure import Figure
            from matplotlib.dates import num2date, date2num
        except ImportError:
            raise ImportError("contours operation requires matplotlib.")
        extent = element.range(0) + element.range(1)[::-1]

        xs = element.dimension_values(0, True, flat=False)
        ys = element.dimension_values(1, True, flat=False)
        zs = element.dimension_values(2, flat=False)

        # Ensure that coordinate arrays specify bin centers
        if xs.shape[0] != zs.shape[0]:
            xs = xs[:-1] + np.diff(xs, axis=0)/2.
        if xs.shape[1] != zs.shape[1]:
            xs = xs[:, :-1] + (np.diff(xs, axis=1)/2.)
        if ys.shape[0] != zs.shape[0]:
            ys = ys[:-1] + np.diff(ys, axis=0)/2.
        if ys.shape[1] != zs.shape[1]:
            ys = ys[:, :-1] + (np.diff(ys, axis=1)/2.)
        data = (xs, ys, zs)

        # if any data is a datetime, transform to matplotlib's numerical format
        data_is_datetime = tuple(isdatetime(arr) for k, arr in enumerate(data))
        if any(data_is_datetime):
            data = tuple(
                date2num(d) if is_datetime else d
                for d, is_datetime in zip(data, data_is_datetime)
            )

        xdim, ydim = element.dimensions('key', label=True)
        if self.p.filled:
            contour_type = Polygons
        else:
            contour_type = Contours
        vdims = element.vdims[:1]

        kwargs = {}
        levels = self.p.levels
        zmin, zmax = element.range(2)
        if isinstance(self.p.levels, int):
            if zmin == zmax:
                contours = contour_type([], [xdim, ydim], vdims)
                return (element * contours) if self.p.overlaid else contours
            data += (levels,)
        else:
            kwargs = {'levels': levels}

        fig = Figure()
        ax = Axes(fig, [0, 0, 1, 1])
        contour_set = QuadContourSet(ax, *data, filled=self.p.filled,
                                     extent=extent, **kwargs)
        levels = np.array(contour_set.get_array())
        crange = levels.min(), levels.max()
        if self.p.filled:
            levels = levels[:-1] + np.diff(levels)/2.
            vdims = [vdims[0].clone(range=crange)]

        paths = []
        empty = np.array([[np.nan, np.nan]])
        for level, cset in zip(levels, contour_set.collections):
            exteriors = []
            interiors = []
            for geom in cset.get_paths():
                interior = []
                polys = geom.to_polygons(closed_only=False)
                for ncp, cp in enumerate(polys):
                    if any(data_is_datetime[0:2]):
                        # transform x/y coordinates back to datetimes
                        xs, ys = np.split(cp, 2, axis=1)
                        if data_is_datetime[0]:
                            xs = np.array(num2date(xs))
                        if data_is_datetime[1]:
                            ys = np.array(num2date(ys))
                        cp = np.concatenate((xs, ys), axis=1)
                    if ncp == 0:
                        exteriors.append(cp)
                        exteriors.append(empty)
                    else:
                        interior.append(cp)
                if len(polys):
                    interiors.append(interior)
            if not exteriors:
                continue
            geom = {
                element.vdims[0].name:
                num2date(level) if data_is_datetime[2] else level,
                (xdim, ydim): np.concatenate(exteriors[:-1])
            }
            if self.p.filled and interiors:
                geom['holes'] = interiors
            paths.append(geom)
        contours = contour_type(paths, label=element.label, kdims=element.kdims, vdims=vdims)
        if self.p.overlaid:
            contours = element * contours
        return contours
Exemple #3
0
    def _process(self, element, key=None):
        try:
            from matplotlib.contour import QuadContourSet
            from matplotlib.axes import Axes
            from matplotlib.figure import Figure
        except ImportError:
            raise ImportError("contours operation requires matplotlib.")
        extent = element.range(0) + element.range(1)[::-1]

        xs = element.dimension_values(0, True, flat=False)
        ys = element.dimension_values(1, True, flat=False)
        zs = element.dimension_values(2, flat=False)

        # Ensure that coordinate arrays specify bin centers
        if xs.shape[0] != zs.shape[0]:
            xs = xs[:-1] + np.diff(xs, axis=0)/2.
        if xs.shape[1] != zs.shape[1]:
            xs = xs[:, :-1] + (np.diff(xs, axis=1)/2.)
        if ys.shape[0] != zs.shape[0]:
            ys = ys[:-1] + np.diff(ys, axis=0)/2.
        if ys.shape[1] != zs.shape[1]:
            ys = ys[:, :-1] + (np.diff(ys, axis=1)/2.)
        data = (xs, ys, zs)

        xdim, ydim = element.dimensions('key', label=True)
        if self.p.filled:
            contour_type = Polygons
        else:
            contour_type = Contours
        vdims = element.vdims[:1]

        kwargs = {}
        levels = self.p.levels
        zmin, zmax = element.range(2)
        if isinstance(self.p.levels, int):
            if zmin == zmax:
                contours = contour_type([], [xdim, ydim], vdims)
                return (element * contours) if self.p.overlaid else contours
            data += (levels,)
        else:
            kwargs = {'levels': levels}

        fig = Figure()
        ax = Axes(fig, [0, 0, 1, 1])
        contour_set = QuadContourSet(ax, *data, filled=self.p.filled,
                                     extent=extent, **kwargs)
        levels = np.array(contour_set.get_array())
        crange = levels.min(), levels.max()
        if self.p.filled:
            levels = levels[:-1] + np.diff(levels)/2.
            vdims = [vdims[0].clone(range=crange)]

        paths = []
        empty = np.array([[np.nan, np.nan]])
        for level, cset in zip(levels, contour_set.collections):
            exteriors = []
            interiors = []
            for geom in cset.get_paths():
                interior = []
                polys = geom.to_polygons(closed_only=False)
                for ncp, cp in enumerate(polys):
                    if ncp == 0:
                        exteriors.append(cp)
                        exteriors.append(empty)
                    else:
                        interior.append(cp)
                if len(polys):
                    interiors.append(interior)
            if not exteriors:
                continue
            geom = {element.vdims[0].name: level, (xdim, ydim): np.concatenate(exteriors[:-1])}
            if self.p.filled and interiors:
                geom['holes'] = interiors
            paths.append(geom)
        contours = contour_type(paths, label=element.label, kdims=element.kdims, vdims=vdims)
        if self.p.overlaid:
            contours = element * contours
        return contours