예제 #1
0
    def grid(self, tiles=False, **kwargs):

        x = kwargs.get("x", self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get("y", self._obj.SCHISM_hgrid_node_y[:].values)
        tes = kwargs.get("tri3", self._obj.SCHISM_hgrid_face_nodes.values)

        width = kwargs.get("width", 800)
        height = kwargs.get("height", 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS("https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png")

        nodes = pd.DataFrame({"longitude": x, "latitude": y})

        points = gv.operation.project_points(gv.Points(nodes))

        if tes.shape[1] == 3:

            elems = pd.DataFrame(tes, columns=["a", "b", "c"])

            trimesh = gv.TriMesh((elems, points)).edgepaths

            if tiles:
                return tile * datashade(
                    trimesh, precompute=True, cmap=["black"])
            else:
                return datashade(trimesh, precompute=True,
                                 cmap=["green"]).opts(width=width,
                                                      height=height)

        else:  # there are quads

            elems = pd.DataFrame(tes, columns=["a", "b", "c", "d"])

            quads = elems.loc[~elems.d.isna()].copy()
            quads = quads.reset_index(drop=True)
            ap = nodes.loc[quads.a, ["longitude", "latitude"]]
            bp = nodes.loc[quads.b, ["longitude", "latitude"]]
            cp = nodes.loc[quads.c, ["longitude", "latitude"]]
            dp = nodes.loc[quads.d, ["longitude", "latitude"]]
            quads["ap"] = ap.values.tolist()
            quads["bp"] = bp.values.tolist()
            quads["cp"] = cp.values.tolist()
            quads["dp"] = dp.values.tolist()

            q = gv.Polygons([
                quads.loc[i, ["ap", "bp", "cp", "dp"]].tolist()
                for i in range(quads.shape[0])
            ]).options(fill_alpha=0, line_color="black")

            triangles = elems.loc[elems.d.isna()]

            trimesh = gv.TriMesh((triangles, points)).edgepaths

            g1 = datashade(trimesh, precompute=True, cmap=["black"])

            if tiles:
                return tile * g1 * q
            else:
                return g1 * q
예제 #2
0
def elevation_max(data_dir: pathlib.Path):
    # load data
    grid_path = data_dir / "grid.npz"
    elevation_max_path = data_dir / "elevation.max.npz"
    x, y, simplices = load_grid_from_disk(grid_path)
    z = load_elevation_from_disk(elevation_max_path)
    # create panel objects
    xyz_points = pd.DataFrame(dict(x=x, y=y, z=z))
    points = hv.Points(xyz_points, kdims=["x", "y"], vdims="z")
    trimesh = hv.TriMesh((simplices, points))
    opts.defaults(opts.WMTS(width=1200, height=900))
    datashaded_trimesh = (rasterize(trimesh,
                                    aggregator='mean').opts(colorbar=True,
                                                            cmap='Viridis',
                                                            clim=(z.min(),
                                                                  z.max()),
                                                            clabel='meters',
                                                            tools=["hover"]))
    tiles = gv.WMTS('https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')
    layout = tiles * datashaded_trimesh

    header = get_header(title="## Max elevation for the next 72 hours")
    disclaimer = get_disclaimer()

    return pn.Column(header, layout, disclaimer)
예제 #3
0
    def contourf(self, var='depth', it=None, **kwargs):

        x = kwargs.get('x', self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y', self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get('t', self._obj.time.values)
        except:
            pass
        tri3 = kwargs.get(
            'tri3',
            self._obj.SCHISM_hgrid_face_nodes.values[:, :3].astype(int))

        z = kwargs.get('z', self._obj[var].values[it, :].flatten())

        nodes = pd.DataFrame({
            'longitude': x,
            'latitude': y,
            '{}'.format(var): z
        })
        elems = pd.DataFrame(tri3, columns=['a', 'b', 'c'])

        opts.defaults(opts.WMTS(width=800, height=400))
        tiles = gv.WMTS(
            'https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')

        points = gv.operation.project_points(
            gv.Points(nodes, vdims=['{}'.format(var)]))

        trimesh = gv.TriMesh((elems, points))
        return tiles * rasterize(trimesh, aggregator='mean').opts(
            colorbar=True, cmap='Viridis', padding=.1, tools=['hover'])
예제 #4
0
    def show(self, **kwargs):
        width = kwargs.get("width", 800)
        height = kwargs.get("height", 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS("https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png")

        ps = [tile]

        # external
        ds = self._obj.loc["line0"]
        ds = ds.append(ds.iloc[0]).reset_index(drop=True)

        dland = ds.loc[ds.tag == "land"]
        dland_ = np.split(dland, np.flatnonzero(np.diff(dland.index) != 1) + 1)
        for seg in dland_:
            ps.append(
                seg.hvplot.paths(x="lon", y="lat", geo=True, color="brown"))

        dwater = ds.loc[ds.tag == "open"]
        dwater_ = np.split(dwater,
                           np.flatnonzero(np.diff(dwater.index) != 1) + 1)
        for seg in dwater_:
            ps.append(
                seg.hvplot.paths(x="lon", y="lat", geo=True, color="blue"))

        # islands
        for line in self._obj.index.levels[0][1:]:
            ds = self._obj.loc[line]
            ds = ds.append(ds.iloc[0]).reset_index(drop=True)
            ps.append(
                ds.hvplot.paths(x="lon", y="lat", geo=True, color="green"))

        return hv.Overlay(ps)
예제 #5
0
def elevation_max(dataset: xr.Dataset):
    #extract data
    x, y, simplices = extract_grid(dataset)
    w = dataset
    z = dataset.elev.max(dim='time').values
    # create panel objects
    xyz_points = pd.DataFrame(dict(longitude=x, latitude=y, elevation=z))
    points = hv.Points(xyz_points,
                       kdims=["longitude", "latitude"],
                       vdims="elevation")
    trimesh = hv.TriMesh((simplices, points))
    opts.defaults(opts.WMTS(width=1200, height=900))
    datashaded_trimesh = (rasterize(trimesh,
                                    aggregator='mean').opts(colorbar=True,
                                                            cmap='Viridis',
                                                            clim=(z.min(),
                                                                  z.max()),
                                                            clabel='meters',
                                                            tools=["hover"]))
    tiles = gv.WMTS('https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png')
    layout = tiles * datashaded_trimesh

    t0 = pd.to_datetime(w.time.values.min()).strftime(format='%Y-%m-%d:%H')
    t1 = pd.to_datetime(w.time.values.max()).strftime(format='%Y-%m-%d:%H')

    header = get_header(
        title="## Maximum forecasted elevation between {} and {}".format(
            t0, t1))
    disclaimer = get_disclaimer()

    return pn.Column(header, layout, disclaimer)
예제 #6
0
    def contourf(self, var="depth", it=None, tiles=False, **kwargs):

        x = kwargs.get("x", self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get("y", self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get("t", self._obj.time.values)
        except:
            pass
        tes = kwargs.get("tri3",
                         self._obj.SCHISM_hgrid_face_nodes.values[:, :4])

        # sort out quads
        try:
            mask = np.isnan(tes)[:, 3]
            tr3 = tes[mask][:, :3]
            tr3_ = quads_to_tris(tes[~mask])
            if tr3_:
                tri3 = np.append(tr3, tr3_, axis=0).astype(int)
            else:
                tri3 = tr3.astype(int)
        except:
            tri3 = tes.astype(int)

        if tri3.min() > 0:
            tri3 = tri3 - 1

        z = kwargs.get("z", self._obj[var].values[it, :].flatten())

        nodes = pd.DataFrame({
            "longitude": x,
            "latitude": y,
            "{}".format(var): z
        })
        elems = pd.DataFrame(tri3, columns=["a", "b", "c"])

        width = kwargs.get("width", 800)
        height = kwargs.get("height", 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS("https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png")

        points = gv.operation.project_points(
            gv.Points(nodes, vdims=["{}".format(var)]))

        trimesh = gv.TriMesh((elems, points))

        if tiles:
            return tile * rasterize(trimesh, aggregator="mean").opts(
                colorbar=True, cmap="Viridis", padding=0.1, tools=["hover"])
        else:
            return rasterize(trimesh, aggregator="mean").opts(
                colorbar=True,
                cmap="Viridis",
                padding=0.1,
                tools=["hover"],
                width=width,
                height=height,
            )
예제 #7
0
    def grid(self, tiles=False, **kwargs):

        x = kwargs.get('x',self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y',self._obj.SCHISM_hgrid_node_y[:].values)
        tes = kwargs.get('tri3',self._obj.SCHISM_hgrid_face_nodes.values)

        width = kwargs.get('width', 800)
        height = kwargs.get('height', 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS('https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png')

        nodes = pd.DataFrame({'longitude':x,'latitude':y})

        points = gv.operation.project_points(gv.Points(nodes))

        if tes.shape[1] == 3 :

            elems  = pd.DataFrame(tes, columns=['a', 'b', 'c'])

            trimesh=gv.TriMesh((elems, points)).edgepaths

            if tiles:
                return tile * datashade(trimesh, precompute=True, cmap=['black'])
            else:
                return datashade(trimesh, precompute=True, cmap=['green']).opts(width=width,height=height)


        else: # there are quads

            elems  = pd.DataFrame(tes, columns=['a', 'b', 'c', 'd'])

            quads = elems.loc[~elems.d.isna()].copy()
            quads = quads.reset_index(drop=True)
            ap = nodes.loc[quads.a,['longitude','latitude']]
            bp = nodes.loc[quads.b,['longitude','latitude']]
            cp = nodes.loc[quads.c,['longitude','latitude']]
            dp = nodes.loc[quads.d,['longitude','latitude']]
            quads['ap'] = ap.values.tolist()
            quads['bp'] = bp.values.tolist()
            quads['cp'] = cp.values.tolist()
            quads['dp'] = dp.values.tolist()

            q = gv.Polygons([quads.loc[i,['ap','bp','cp','dp']].tolist() for i in range(quads.shape[0])]).options(fill_alpha=0, line_color='black')

            triangles = elems.loc[elems.d.isna()]

            trimesh=gv.TriMesh((triangles, points)).edgepaths

            g1 = datashade(trimesh, precompute=True, cmap=['black'])

            if tiles : 
                return tile * g1 * q
            else:
                return g1 * q
예제 #8
0
    def frames(self,var='depth', tiles=False, **kwargs):

        x = kwargs.get('x',self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y',self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get('t',self._obj.time.values)
        except:
            pass
        tes = kwargs.get('tri3',self._obj.SCHISM_hgrid_face_nodes.values[:,:4])

        # sort out quads
        try:
            mask = np.isnan(tes)[:,3]
            tr3 = tes[mask][:,:3]
            tr3_ = quads_to_tris(tes[~mask])
            if tr3_ :
                tri3 = np.append(tr3,tr3_,axis=0).astype(int)
            else:
                tri3 = tr3.astype(int)
        except:
            tri3 = tes.astype(int)

        times=kwargs.get('times',self._obj.time.values)

        z = kwargs.get('z',self._obj[var].values[0,:].flatten())

        zmin = self._obj[var].values.min()
        zmax = self._obj[var].values.max()

        nodes = pd.DataFrame({'longitude':x,'latitude':y, '{}'.format(var):z})
        elems  = pd.DataFrame(tri3, columns=['a', 'b', 'c'])

        width = kwargs.get('width', 800)
        height = kwargs.get('height', 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS('https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png')

        points = gv.operation.project_points(gv.Points(nodes, vdims=['{}'.format(var)]))

        trimesh = gv.TriMesh((elems, points))

        def time_mesh(time):
            points.data[var] = self._obj[var].sel(time=time).values
            return gv.TriMesh((elems, points))#, crs=ccrs.GOOGLE_MERCATOR)

        meshes = hv.DynamicMap(time_mesh, kdims=['Time']).redim.values(Time=times)

        imesh = rasterize(meshes, aggregator='mean').opts(cmap='viridis', colorbar=True, padding=.1, tools=['hover'], clim=(zmin, zmax))

        if tiles:
            return hv.output(tile*imesh, holomap='scrubber', fps=1)
        else:
            return hv.output(imesh.opts(width=width,height=height), holomap='scrubber', fps=1)
예제 #9
0
def elevation(dataset: xr.Dataset):
    # extract data
    z = dataset
    x, y, simplices = extract_grid(dataset)
    # create panel objects
    xyz_points = pd.DataFrame(
        dict(longitude=x, latitude=y, elevation=z.elev.isel(time=0).values))
    points = hv.Points(xyz_points,
                       kdims=["longitude", "latitude"],
                       vdims="elevation")
    opts.defaults(opts.WMTS(width=1200, height=900))

    def time_mesh(time):
        points.data.elevation = z.elev.sel(time=time).values
        return hv.TriMesh((simplices, points))  #, crs=ccrs.GOOGLE_MERCATOR)

    meshes = hv.DynamicMap(time_mesh,
                           kdims='Time').redim.values(Time=z.time.values)

    datashaded_trimesh = (rasterize(meshes, aggregator='mean').opts(
        colorbar=True,
        cmap='Viridis',
        clim=(z.elev.values.min(), z.elev.values.max()),
        clabel='meters',
        tools=["hover"]))

    tiles = gv.WMTS('https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png')

    t_widget = pn.widgets.Select()

    @pn.depends(t_widget)
    def t_plot(time):
        return tiles * datashaded_trimesh

    tref_ = pd.to_datetime(z.time.values.min()) - pd.to_timedelta('1H')

    tref = tref_.strftime(format='%Y-%m-%d:%H')

    header = get_header(
        title="## Hourly sea level for 72 hours based on the {} forecast".
        format(tref))

    text = '''
      # USAGE
      Use the toolbox on the right to zoom in/out.
      '''
    footer = pn.Row(pn.pane.Markdown(text))
    disclaimer = get_disclaimer()

    return pn.Column(header, t_plot, footer, disclaimer)
예제 #10
0
    def frames(self, var='depth', **kwargs):

        x = kwargs.get('x', self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y', self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get('t', self._obj.time.values)
        except:
            pass
        tri3 = kwargs.get(
            'tri3',
            self._obj.SCHISM_hgrid_face_nodes.values[:, :3].astype(int))

        times = kwargs.get('times', self._obj.time.values)

        z = kwargs.get('z', self._obj[var].values[0, :].flatten())

        nodes = pd.DataFrame({
            'longitude': x,
            'latitude': y,
            '{}'.format(var): z
        })
        elems = pd.DataFrame(tri3, columns=['a', 'b', 'c'])

        opts.defaults(opts.WMTS(width=800, height=400))
        tiles = gv.WMTS(
            'https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')

        points = gv.operation.project_points(
            gv.Points(nodes, vdims=['{}'.format(var)]))

        trimesh = gv.TriMesh((elems, points))

        def time_mesh(time):
            points.data[var] = self._obj[var].sel(time=time).values
            return gv.TriMesh((elems, points))  #, crs=ccrs.GOOGLE_MERCATOR)

        meshes = hv.DynamicMap(time_mesh,
                               kdims=['Time']).redim.values(Time=times)

        imesh = rasterize(meshes, aggregator='mean').opts(cmap='viridis',
                                                          colorbar=True,
                                                          padding=.1,
                                                          tools=['hover'])

        return hv.output(tiles * imesh, holomap='scrubber', fps=1)
예제 #11
0
def elevation(data_dir: pathlib.Path):
    # load data
    grid_path = data_dir / "grid.npz"
    elevation_path = data_dir / "elevation.nc"
    x, y, simplices = load_grid_from_disk(grid_path)
    z = get_dataset(elevation_path)
    # create panel objects
    xyz_points = pd.DataFrame(dict(x=x, y=y, z=z.elev.isel(time=0).values))
    points = hv.Points(xyz_points, kdims=["x", "y"], vdims="z")
    opts.defaults(opts.WMTS(width=1200, height=900))

    def time_mesh(time):
        points.data.z = z.elev.sel(time=time).values
        return hv.TriMesh((simplices, points))  #, crs=ccrs.GOOGLE_MERCATOR)

    meshes = hv.DynamicMap(time_mesh,
                           kdims='Time').redim.values(Time=z.time.values)

    datashaded_trimesh = (rasterize(meshes, aggregator='mean').opts(
        colorbar=True,
        cmap='Viridis',
        clim=(z.elev.values.min(), z.elev.values.max()),
        clabel='meters',
        tools=["hover"]))

    tiles = gv.WMTS('https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')

    t_widget = pn.widgets.Select()

    @pn.depends(t_widget)
    def t_plot(time):
        return tiles * datashaded_trimesh

    header = get_header(title="## Time Steps")

    text = '''
      # USAGE
      Use the toolbox on the right to zoom in/out.
      '''
    footer = pn.Row(pn.pane.Markdown(text))
    disclaimer = get_disclaimer()

    return pn.Column(header, t_plot, footer, disclaimer)
예제 #12
0
    def grid(self, **kwargs):

        x = kwargs.get('x', self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y', self._obj.SCHISM_hgrid_node_y[:].values)
        tri3 = kwargs.get(
            'tri3',
            self._obj.SCHISM_hgrid_face_nodes.values[:, :3].astype(int))

        opts.defaults(opts.WMTS(width=800, height=400))
        tiles = gv.WMTS(
            'https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')

        nodes = pd.DataFrame({'longitude': x, 'latitude': y})
        elems = pd.DataFrame(tri3, columns=['a', 'b', 'c'])

        points = gv.operation.project_points(gv.Points(nodes))

        trimesh = gv.TriMesh((elems, points)).edgepaths

        return tiles * datashade(trimesh, precompute=True, cmap=['black'])
예제 #13
0
    def contourf(self, var='depth', it=None, tiles=False, **kwargs):

        x = kwargs.get('x',self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get('y',self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get('t',self._obj.time.values)
        except:
            pass
        tes = kwargs.get('tri3',self._obj.SCHISM_hgrid_face_nodes.values[:,:4])

        # sort out quads
        try:
            mask = np.isnan(tes)[:,3]
            tr3 = tes[mask][:,:3]
            tr3_ = quads_to_tris(tes[~mask])
            if tr3_ :
                tri3 = np.append(tr3,tr3_,axis=0).astype(int)
            else:
                tri3 = tr3.astype(int)
        except:
            tri3 = tes.astype(int)

        z = kwargs.get('z',self._obj[var].values[it,:].flatten())

        nodes = pd.DataFrame({'longitude':x,'latitude':y, '{}'.format(var):z})
        elems  = pd.DataFrame(tri3, columns=['a', 'b', 'c'])

        width = kwargs.get('width', 800)
        height = kwargs.get('height', 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS('https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png')

        points = gv.operation.project_points(gv.Points(nodes, vdims=['{}'.format(var)]))

        trimesh = gv.TriMesh((elems, points))
        
        if tiles:
            return tile * rasterize(trimesh, aggregator='mean').opts(colorbar=True, cmap='Viridis', padding=.1, tools=['hover'])
        else:
            return rasterize(trimesh, aggregator='mean').opts(colorbar=True, cmap='Viridis', padding=.1, tools=['hover'],width=width,height=height)
예제 #14
0
    def frames(self, var="depth", tiles=False, **kwargs):

        x = kwargs.get("x", self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get("y", self._obj.SCHISM_hgrid_node_y[:].values)
        try:
            t = kwargs.get("t", self._obj.time.values)
        except:
            pass
        tes = kwargs.get("tri3",
                         self._obj.SCHISM_hgrid_face_nodes.values[:, :4])

        # sort out quads
        try:
            mask = np.isnan(tes)[:, 3]
            tr3 = tes[mask][:, :3]
            tr3_ = quads_to_tris(tes[~mask])
            if tr3_:
                tri3 = np.append(tr3, tr3_, axis=0).astype(int)
            else:
                tri3 = tr3.astype(int)
        except:
            tri3 = tes.astype(int)

        times = kwargs.get("times", self._obj.time.values)

        z = kwargs.get("z", self._obj[var].values[0, :].flatten())

        zmin = self._obj[var].values.min()
        zmax = self._obj[var].values.max()

        nodes = pd.DataFrame({
            "longitude": x,
            "latitude": y,
            "{}".format(var): z
        })
        elems = pd.DataFrame(tri3, columns=["a", "b", "c"])

        width = kwargs.get("width", 800)
        height = kwargs.get("height", 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS("https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png")

        points = gv.operation.project_points(
            gv.Points(nodes, vdims=["{}".format(var)]))

        trimesh = gv.TriMesh((elems, points))

        def time_mesh(time):
            points.data[var] = self._obj[var].sel(time=time).values
            return gv.TriMesh((elems, points))  # , crs=ccrs.GOOGLE_MERCATOR)

        meshes = hv.DynamicMap(time_mesh,
                               kdims=["Time"]).redim.values(Time=times)

        imesh = rasterize(meshes, aggregator="mean").opts(cmap="viridis",
                                                          colorbar=True,
                                                          padding=0.1,
                                                          tools=["hover"],
                                                          clim=(zmin, zmax))

        if tiles:
            return hv.output(tile * imesh, holomap="scrubber", fps=1)
        else:
            return hv.output(imesh.opts(width=width, height=height),
                             holomap="scrubber",
                             fps=1)
예제 #15
0
    def mesh(self, tiles=False, **kwargs):

        x = kwargs.get("x", self._obj.SCHISM_hgrid_node_x[:].values)
        y = kwargs.get("y", self._obj.SCHISM_hgrid_node_y[:].values)
        tes = kwargs.get("tri3", self._obj.SCHISM_hgrid_face_nodes.values)

        width = kwargs.get("width", 800)
        height = kwargs.get("height", 600)
        opts.defaults(opts.WMTS(width=width, height=height))

        tile = gv.WMTS("https://b.tile.openstreetmap.org/{Z}/{X}/{Y}.png")

        nodes = pd.DataFrame({"longitude": x, "latitude": y})

        points = gv.operation.project_points(gv.Points(nodes),
                                             projection=ccrs.PlateCarree())

        if tes.shape[1] == 3:

            elems = pd.DataFrame(tes, columns=["a", "b", "c"])

            if elems.min().min() > 0:
                elems = elems - 1

            trimesh = gv.TriMesh((elems, points)).edgepaths

            if tiles:
                return tile * datashade(
                    trimesh, precompute=True, cmap=["black"])
            else:
                return datashade(trimesh, precompute=True,
                                 cmap=["green"]).opts(width=width,
                                                      height=height)

        else:  # there are quads

            elems = pd.DataFrame(tes, columns=["a", "b", "c", "d"])

            if elems.min().min() > 0:
                elems = elems - 1

            quads = elems.loc[~elems.d.isna()].copy()
            quads = quads.reset_index(drop=True)
            ap = nodes.loc[quads.a, ["longitude", "latitude"]]
            bp = nodes.loc[quads.b, ["longitude", "latitude"]]
            cp = nodes.loc[quads.c, ["longitude", "latitude"]]
            dp = nodes.loc[quads.d, ["longitude", "latitude"]]
            quads["ap"] = ap.values.tolist()
            quads["bp"] = bp.values.tolist()
            quads["cp"] = cp.values.tolist()
            quads["dp"] = dp.values.tolist()

            n = 2
            al = quads.ap + quads.bp + quads.cp + quads.dp + quads.ap
            coords = [[l[i:i + n] for i in range(0, len(l), n)] for l in al]

            quads["coordinates"] = coords

            qpolys = pygeos.polygons(quads.coordinates.to_list())

            df = gp.GeoDataFrame(geometry=qpolys)

            df_ = spatialpandas.GeoDataFrame(df)

            q = gv.Path(df_)

            qdf = dynspread(
                rasterize(q, precompute=True).options(cmap=["black"]))

            triangles = elems.loc[elems.d.isna()]

            trimesh = gv.TriMesh((triangles, points)).edgepaths

            wireframe = dynspread(
                rasterize(trimesh, precompute=True).opts(cmap=["black"]))

            if tiles:
                return tile * wireframe * qdf
            else:
                return wireframe.opts(cmap=["green"]) * qdf.opts(
                    cmap=["green"])