Пример #1
0
def get_polygon(mask, lat, lon):
    x0 = lon
    x1 = x0 + mask.shape[1] / 1200
    y0 = lat
    y1 = y0 - mask.shape[0] / 1200
    mask2 = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint16)
    mask2[1:-1, 1:-1] = mask
    affine = Affine(1 / 1200, 0, lon - 1 / 1200, 0, -1 / 1200, lat + 1 / 1200)
    shapes = list(rasterio.features.shapes(mask2, transform=affine))
    polygons = []
    polygon = polygons
    i = 0
    for shape in shapes:
        if len(shape[0]['coordinates'][0]) > 5:
            if i == 1:
                # more than one polygon
                polygons = [polygons]
            if i >= 1:
                polygons.append([])
                polygon = polygons[-1]
            for coord in shape[0]['coordinates'][0]:
                x, y = coord
                polygon.append((y, x))
            i += 1
    polygon = Polygon(locations=polygons, color='green', fill_color='green')
    return polygon
Пример #2
0
    def __init__(self, center=(41.8204600, 1.8676800), zoom=9):
        self.map = Map(center=center,
                       zoom=zoom,
                       basemap=basemaps.OpenStreetMap.HOT)

        polygon = Polygon(locations=[[]], color="green", fill_color="green")

        def handle_click(**kwargs):
            if kwargs.get('type') == 'click':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                coords = kwargs.get('coordinates')
                if (len(polygon.locations) == 0):
                    pol.locations[0].extend([coords, coords])
                else:
                    pol.locations[0].insert(1, coords)

                self.map.remove_layer(pol)
                other = Polygon(locations=pol.locations,
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)

            if kwargs.get('type') == 'contextmenu':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                self.map.remove_layer(pol)
                other = Polygon(locations=[[]],
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)

        self.map.on_interaction(handle_click)
        self.map.add_layer(polygon)
        display(self.map)
Пример #3
0
def airspace_leaflet(airspace: Airspace, **kwargs) -> Polygon:
    shape = airspace.flatten()

    kwargs = {**dict(weight=3), **kwargs}

    return Polygon(locations=list(
        (lat, lon) for (lon, lat) in shape.exterior.coords),
                   **kwargs)
def ipyleaflet_contourmap(
        center,
        datapoints=None,
        contourmap=None,
        isolines=[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
        lineopacity=1.0,
        colormap=linear.viridis,
        fillopacity=0.7,
        legend_title='Legend',
        m=None,
        zoom=11,
        width='600px',
        height='400px'):

    if m is None:
        m = Map(center=center, zoom=zoom)

    m.layout.width = width
    m.layout.height = height

    cs = contourmap
    colors = [
        colormap(i / (len(cs.levels) - 1)) for i in range(len(cs.levels) - 1)
    ]
    allsegs = cs.allsegs
    allkinds = cs.allkinds

    for clev in range(len(cs.allsegs)):
        kinds = None if allkinds is None else allkinds[clev]
        segs = split_contours(allsegs[clev], kinds)
        polygons = Polygon(
            locations=[p.tolist() for p in segs],
            # locations=segs[14].tolist(),
            color=colors[clev],
            weight=2,
            opacity=lineopacity,
            fill_color=colors[clev],
            fill_opacity=fillopacity)
        m.add_layer(polygons)

    if datapoints is not None:
        m = ipyleaflet_scatterplot_per_class(datapoints[0],
                                             datapoints[1],
                                             proportion=1.0,
                                             m=m)

    legend_colors = {}
    for i in reversed(range(len(isolines) - 1)):
        legend_colors["{:0.1f}-{:0.1f}".format(
            isolines[i], isolines[i + 1])] = colormap(i / (len(isolines) - 1))

    legend = LegendControl(legend_colors,
                           name=legend_title,
                           position="topright")
    m.add_control(legend)
    return m
Пример #5
0
    def _update_domain_render(self):
        if self.polygon is not None:
            self.m.remove_layer(self.polygon)

        if len(self.domain_coords) > 1:
            self.polygon = Polygon(
                locations=self.domain_coords, color="green", fill_color="green"
            )
            self.m.add_layer(self.polygon)
        else:
            self.polygon = None
Пример #6
0
def airspace_leaflet(airspace: Airspace, **kwargs) -> Polygon:
    shape = airspace.flatten()

    kwargs = {**dict(weight=3), **kwargs}
    coords: List[Any] = []
    if shape.geom_type == "Polygon":
        coords = list((lat, lon) for (lon, lat) in shape.exterior.coords)
    else:
        coords = list(
            list((lat, lon) for (lon, lat) in piece.exterior.coords)
            for piece in shape)

    return Polygon(locations=coords, **kwargs)
Пример #7
0
def bdc_plot_datasets(datasets,
                      zoom=4,
                      layout=Layout(width='600px', height='600px')):
    """Plot Dataset tiles
    """

    bbox = get_bounds(datasets, datasets[0].crs)
    bbox_pol = shapely.wkt.loads(bbox.wkt)

    project = partial(pyproj.transform, pyproj.Proj(datasets[0].crs.crs_str),
                      pyproj.Proj(init='epsg:4674'))
    bbox_pol_wgs84 = transform(project, bbox_pol)
    bbox = bbox_pol_wgs84.bounds

    center = ((bbox[1] + bbox[3]) / 2, (bbox[0] + bbox[2]) / 2)

    m = Map(basemap=basemaps.Esri.WorldImagery,
            center=center,
            zoom=zoom,
            layout=layout)
    grid = WMSLayer(
        url='http://brazildatacube.dpi.inpe.br/bdc/geoserver/grids/ows',
        layers='BDC_GRID',
        styles='tiles',
        format='image/png',
        transparent=True,
        tile_size=512)
    m.add_layer(grid)

    if len(datasets):
        project = partial(pyproj.transform,
                          pyproj.Proj(datasets[0].crs.crs_str),
                          pyproj.Proj(init='epsg:4674'))

        plotted = []
        for ds in datasets:
            idt = "{},{};{},{}".format(ds.metadata.lon[0], ds.metadata.lat[0],
                                       ds.metadata.lon[1], ds.metadata.lat[1])
            if idt not in plotted:
                plotted.append(idt)
                # apply projection
                ds_pol = transform(project, shapely.wkt.loads(ds.extent.wkt))
                x, y = ds_pol.exterior.xy
                points = [(y1, x1) for x1, y1 in zip(x, y)]
                polygon = Polygon(locations=points,
                                  color="#0033CC",
                                  fill_color="#388b8b",
                                  weight=2,
                                  fill_opacity=.6)
                m.add_layer(polygon)
    return m
Пример #8
0
        def handle_click(**kwargs):
            if kwargs.get('type') == 'click':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                coords = kwargs.get('coordinates')
                if (len(polygon.locations) == 0):
                    pol.locations[0].extend([coords, coords])
                else:
                    pol.locations[0].insert(1, coords)

                self.map.remove_layer(pol)
                other = Polygon(locations=pol.locations,
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)

            if kwargs.get('type') == 'contextmenu':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                self.map.remove_layer(pol)
                other = Polygon(locations=[[]],
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)
Пример #9
0
 def init_map(self):
     self.mainmap = ilfl.Map(basemap=ilfl.basemaps.Gaode.Satellite,
                             center=[self.lat, self.lon],
                             zoom=self.zoom)
     self.marker = ilfl.Marker(location=[self.lat, self.lon],
                               draggable=True)
     self.mainmap.add_layer(self.marker)
     self.pr_selection = self.idxs.data.index[0]
     self.record = self.spatial_index.data.loc[self.pr_selection]
     self.map_polygon = Polygon(locations=[
         (self.record.lat_UL, self.record.lon_UL),
         (self.record.lat_UR, self.record.lon_UR),
         (self.record.lat_LR, self.record.lon_LR),
         (self.record.lat_LL, self.record.lon_LL)
     ],
                                color="blue")
     self.mainmap.add_layer(self.map_polygon)
Пример #10
0
def airspace_leaflet(airspace: "Airspace", **kwargs) -> Polygon:
    """Returns a Leaflet layer to be directly added to a Map.

    .. warning::
        This is only available if the Leaflet `plugin <plugins.html>`_ is
        activated. (true by default)

    The elements passed as kwargs as passed as is to the Polygon constructor.
    """
    shape = airspace.flatten()

    kwargs = {**dict(weight=3), **kwargs}
    coords: List[Any] = []
    if shape.geom_type == "Polygon":
        coords = list((lat, lon) for (lon, lat) in shape.exterior.coords)
    else:
        coords = list(
            list((lat, lon) for (lon, lat) in piece.exterior.coords)
            for piece in shape)

    return Polygon(locations=coords, **kwargs)
Пример #11
0
def update_Map(keys,polysel,df):
    """Update ipyleaflet Map with query results
    
    Parameters:
        keys (list): list of product names
        polysel (dict): dictionary containing the AOI coordinates
        df (pandas dataframe): dataframe containing query results
    
    Returns: Map containing the drawn AOI and single product footprints (ipyleaflet Map)
    """
    polygon = Polygon(
    locations=make_locations(polysel),
    color="dodgerblue",
    fill_color="dodgerblue"
    )
    ind = [list(key)[1] for key in keys][0]
    objects = see_footprint(df,ind) # single footprint related to the (selected) product
    m = Map(basemap=basemaps.Esri.WorldTopoMap,
            center=centre(polysel), zoom=3,dragging=True,scroll_wheel_zoom=True) # initial map
    m.add_layer(polygon); # reference polygon (user input)
    for obj in objects:
        m.add_layer(obj);
    return m
Пример #12
0
def overlaymap(aoiY,
               imagesurls,
               zoom=13,
               layout=ipywidgets.Layout(width='100%', height='500px')):

    import json
    import numpy as np

    from ipyleaflet import (
        Map,
        Rectangle,
        Polygon,
        TileLayer,
        ImageOverlay,
        DrawControl,
    )

    ## handle the case of imageurls not a list
    if type(imagesurls) != list:
        imagesurls = [imagesurls]

    number_of_images = len(imagesurls)

    ## handle both kinds of calls with aoi, or aoi['coordinates']
    if 'coordinates' in aoiY:
        aoiY = aoiY['coordinates'][0]

    # create the Map object
    # google tileserver
    # https://stackoverflow.com/questions/9394190/leaflet-map-api-with-google-satellite-layer
    mosaicsTilesURL = 'https://mt1.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}'  # Hybrid: s,h; Satellite: s; Streets: m; Terrain: p;
    m = Map(
        center=aoiY[0][::-1],
        zoom=zoom,
        scroll_wheel_zoom=True,
        layout=layout,
    )

    # using custom basemap
    m.clear_layers()
    m.add_layer(TileLayer(url=mosaicsTilesURL, opacity=1.00))

    #vlayer = VideoOverlay(videoUrl, videoBounds )
    #m.add_layer(vlayer)

    ### this shows an animated gif
    #m.add_layer(layer)

    # display map (this show)
    #display(m)

    ############## ADD INTERACTIVE LAYER
    from ipywidgets import interact, interactive, fixed, interact_manual
    import ipywidgets as widgets

    # meke sure that the images have unique names
    imagesurls = [
        '%s?%05d' % (i, np.random.randint(10000)) for i in imagesurls
    ]

    # draw bounding polygon
    y = [a[::-1] for a in aoiY]
    p = Polygon(locations=y, weight=2, fill_opacity=0.25)
    m.add_layer(p)

    # create image
    layer = ImageOverlay(url='%s' % (imagesurls[0]),
                         bounds=[
                             list(np.max(aoiY, axis=0)[::-1]),
                             list(np.min(aoiY, axis=0)[::-1])
                         ])

    m.add_layer(layer)

    # callback fro flipping images
    def showim(i):
        if (i < len(imagesurls)):
            #      -----       FLICKERS ----
            #             layer.url='%s'%(imagesurls[i])
            #             layer.visible = False
            #             layer.visible = True

            #    ALTERNATIVE:  add a new layer
            layer = ImageOverlay(url='%s' % (imagesurls[i]),
                                 bounds=[
                                     list(np.max(aoiY, axis=0)[::-1]),
                                     list(np.min(aoiY, axis=0)[::-1])
                                 ])
            m.add_layer(layer)
            # remove old ones
            if len(m.layers) > 30:  # image buffer
                for l in (m.layers[1:-1]):
                    m.remove_layer(l)

    # build the UI
    #interact(showim,i=len(imagesurls)-1)
    #interact(showim, i=widgets.IntSlider(min=0,max=len(imagesurls),step=1,value=0));
    play = widgets.Play(
        interval=200,  #ms
        value=0,
        min=0,
        max=len(imagesurls) - 1,
        step=1,
        description="Press play",
        disabled=False,
    )
    slider = widgets.IntSlider(min=0,
                               max=len(imagesurls) - 1,
                               description='Frame:')
    label = widgets.Label(value="")

    def on_value_change(change):
        label.value = imagesurls[change['new']]
        showim(change['new'])

    slider.observe(on_value_change, 'value')
    b1 = widgets.Button(description='fw', layout=widgets.Layout(width='auto'))
    b2 = widgets.Button(description='bw', layout=widgets.Layout(width='auto'))
    b3 = widgets.Button(description='hide',
                        layout=widgets.Layout(width='auto'))
    b4 = widgets.Button(description='hidePoly',
                        layout=widgets.Layout(width='auto'))

    def clickfw(b):
        slider.value = slider.value + 1

    def clickbw(b):
        slider.value = slider.value - 1

    def clickhide(b):
        if layer.visible:
            layer.visible = False
        else:
            layer.visible = True

    def clickhidePoly(b):
        if p.visible:
            p.visible = False
        else:
            p.visible = True

    b1.on_click(clickfw)
    b2.on_click(clickbw)
    b3.on_click(clickhide)
    b4.on_click(clickhidePoly)

    # add a custom function to create and add a Polygon layer
    def add_geojson(*args, **kwargs):
        # ugly workaround to call without data=aoi
        if 'data' not in kwargs:
            kwargs['data'] = args[0]
            args2 = [i for i in args[1:-1]]
        else:
            args2 = args

        r = GeoJSON(*args2, **kwargs)
        return m.add_layer(r)

    m.add_GeoJSON = add_geojson

    widgets.jslink((play, 'value'), (slider, 'value'))
    if number_of_images > 1:
        return widgets.VBox(
            [widgets.HBox([play, b2, b1, b3, b4, slider, label]), m])
    else:
        return widgets.VBox([widgets.HBox([b3, b4, label]), m])
Пример #13
0
def see_footprint(dataframe,i):
    """Draw the single product footprint
    
    Parameters:
        dataframe (pandas dataframe): query results (from function: search)
        i (int): index of a single product
        
    Returns: polygons per each product (list), with different color attribute    
    """
    colors = ["orange","forestgreen","blue","violet"]
    if "S1" in dataframe.iloc[i,1]:
        color = colors[0]
    elif "S2" in dataframe.iloc[i,1]:
        color = colors[1]
    elif "S3" in dataframe.iloc[i,1]:
        color = colors[2]
    elif "S5" in dataframe.iloc[i,1]:
        color = colors[3]
    else:
        color = "gray"
    objects = list() # list containing polygons 
    if "MULT" in dataframe.iloc[i,4]:
        tmp = dataframe.iloc[i,4][14:-1].split("))")[0:-1]
        if len(tmp) == 1: # multipolygon that is a polygon actually
            string = tmp[0][2:].split(",")[:-1]
            b = list()
            for s in string:
                temp = s.split(" ")
                tlist = [float(temp[-1]),float(temp[-2])] # fixed
                b.append(tuple(tlist))
            
            obj = Polygon(
                    locations=b,
                    color=color,
                    fill_color=color
                )
            objects.append(obj) # len 1
        else: # this is a true multipolygon 
            for k in range(len(tmp)): # instances help in finding how to split string
                if k > 0: 
                    string = tmp[k][3:].split(",")[:-1]
                    b = list()
                    for s in string:
                        temp = s.split(" ")
                        tlist = [float(temp[-1]),float(temp[-2])] # fixed
                        b.append(tuple(tlist))
                    obj = Polygon(
                            locations=b,
                            color=color,
                            fill_color=color
                        )
                    objects.append(obj)
                else:
                    string = tmp[k][2:].split(",")[:-1]
                    b = list()
                    for s in string:
                        temp = s.split(" ")
                        tlist = [float(temp[-1]),float(temp[-2])] # fixed
                        b.append(tuple(tlist))
                    obj = Polygon(
                            locations=b,
                            color=color,
                            fill_color=color
                        )
                    objects.append(obj)
    else: # this is a simple POLYGON
        string = dataframe.iloc[i,4][10:-2].split(",")[:-1]
        b = list()
        for s in string:
            temp = s.split(" ")
            tlist = [float(temp[-1]),float(temp[-2])] # fix 
            b.append(tuple(tlist))
        obj = Polygon(
                locations=b,
                color=color,
                fill_color=color
            )
        objects.append(obj)
    return objects
Пример #14
0
    def update_selected_cells(self, *args, **kwargs):
        """ """
        # clear all draw and selection layers
        self.draw_control.clear()

        # --------------------------------------------------------------------
        # update active cells and make a big merged polgyon for selection

        # make shapely geom from geojson
        drawn_json = kwargs["geo_json"]
        shapely_geom = shape(drawn_json["geometry"])
        cells = self.grid_dict

        # iterate over cells and collect intersecting cells
        on = []
        for id, cell in cells.items():
            if shapely_geom.intersects(cell.shape):
                on.append(cell.shape)

        # this is blatant abuse of try/except; fix it
        try:
            # get the union of all of the cells that are toggled on
            union = cascaded_union(on)
            centroid = union.centroid

            # make layer that represents selected cells and add to selected_layer
            self.selected_layer.clear_layers()
            x, y = union.exterior.coords.xy
            self.selected_layer.add_layer(Polygon(locations=list(zip(y, x))))
            self.map.center = (centroid.y, centroid.x)

            # --------------------------------------------------------------
            # find all CMR collections that intersect with merged cells geom

            selected = []
            for index, collection in above_results_df.iterrows():
                box = collection.boxes
                shapely_box = CMR_box_to_Shapely_box(box[0])

                # intersect: use shapely_geom if strictly using drawn poly
                intersect_bool = shapely_box.intersects(union)
                if intersect_bool:
                    selected.append(index)

            self.coll = above_results_df.iloc[selected]

            self.tab = qgrid.show_grid(
                self.coll[["dataset_id", "time_start", "time_end", "boxes"]],
                grid_options={
                    'forceFitColumns': False,
                    'minColumnWidth': "0",
                    'maxColumnWidth': "400"
                },
                show_toolbar=False)

            self.output.clear_output()
            with self.output:
                display(self.tab)
                #display(self.coll[[
                #    "dataset_id", "time_start", "time_end", "boxes"]])

        except:
            pass
def create_layer(geo_table,
                 name,
                 label_col=None,
                 secondary_label_col=None,
                 layer_type=None,
                 inverse=False,
                 **kwargs):
    if 'color' in kwargs:
        color = kwargs['color']
    else:
        color = 'orange'
    output = LayerGroup(name=name)
    geo_table = clean_table(geo_table)
    if 'filter_on' in kwargs.keys():
        filter_col = kwargs['filter_on']
        if inverse:
            geo_table = geo_table[geo_table[filter_col].isna()]
        else:
            geo_table = geo_table[~geo_table[filter_col].isna()]
    if layer_type is None:
        raise (ValueError('must provide a type of layer to make with table!'))
    for _, row in geo_table.iterrows():
        if layer_type == 'polygon':
            y = list(row.geometry.exterior.coords.xy[1])
            x = list(row.geometry.exterior.coords.xy[0])
            locations = [(y, x) for y, x in zip(y, x)]
            temp_layer = Polygon(
                locations=locations,
                color=color,
                fill_color=color,
                opacity=0.8,
            )
        elif layer_type == 'marker':
            temp_layer = CircleMarker(
                location=(row.geometry.y, row.geometry.x),
                color=color,
                radius=5,
                fill_color=color,
            )
        if label_col is not None:
            if secondary_label_col is not None:
                extra_labels = row[secondary_label_col]
                if extra_labels is None:
                    extra_labels = ''
                else:
                    extra_labels = extra_labels.split(',')
                    size = len(extra_labels)
                    if size > 6:
                        size = 6
                        extra_labels = extra_labels[:size]
                        extra_labels.append('truncated')
                    extra_labels = '\n'.join(extra_labels[:size])
            else:
                extra_labels = ''
            message = HTML()
            message.value = extra_labels
            message.description = row[label_col]
            temp_layer.popup = message
            temp_layer.popup_max_width = 800
        output.add_layer(temp_layer)
    geo_table.to_file(name + '.shp')
    return output
Пример #16
0
    def TheisContours(self,
                      T,
                      qs,
                      bnds=None,
                      grad=[0, 0],
                      levels=(0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0)):

        lats = []
        lons = []
        for w in self.wells:
            lat, lon = w.location
            lats.append(lat)
            lons.append(lon)
        xs, ys = transform(outProj, inProj, lats, lons)
        if bnds is None:
            xs2, ys2 = xs, ys
        else:
            for bnd in bnds:
                lat, lon = bnd
                lats.append(lat)
                lons.append(lon)
                xs2, ys2 = transform(outProj, inProj, lats, lons)
        n = 100
        x0, x1 = np.min(xs2), np.max(xs2)
        xr = x1 - x0
        y0, y1 = np.min(ys2), np.max(ys2)
        yr = y1 - y0
        xx, yy = np.meshgrid(np.linspace(x0 - 0.05 * xr, x1 + 0.05 * xr, n),
                             np.linspace(y0 - 0.05 * yr, y1 + 0.05 * yr, n))
        hh = 0. * xx + grad[0] * (np.cos(grad[1]) *
                                  (xx - xs[0]) + np.sin(grad[1]) *
                                  (yy - ys[0]))  #/1.e3
        try:
            t = self.widgets['t'].value
        except KeyError:
            t = 100.
        for w, x, y, q in zip(self.wells, xs, ys, qs):
            hh += Theis(np.sqrt((xx.flatten() - x)**2 + (yy.flatten() - y)**2),
                        t * 24 * 3600, T, 1.e-4, q).reshape(xx.shape)
        lat, lon = transform(inProj, outProj, xx.flatten(), yy.flatten())
        cs = plt.contourf(lat.reshape(xx.shape),
                          lon.reshape(yy.shape),
                          hh,
                          levels=levels,
                          extend='both')
        ts = plt.clabel(
            cs,
            levels=[l for l, a in zip(cs.levels, cs.allsegs) if len(a) > 0])
        plt.close()

        allsegs = cs.allsegs
        allkinds = cs.allkinds
        cmap = cm.Blues
        colors = [
            '#%02x%02x%02x' % tuple(int(j * 255) for j in cmap(i)[:3])
            for i in np.linspace(0, 1, len(allsegs))
        ]
        alphas = np.linspace(0.2, 0.7, len(allsegs))
        ps = []
        for clev in range(len(cs.allsegs)):
            kinds = None if allkinds is None else allkinds[clev]
            segs = split_contours(allsegs[clev], kinds)
            polygons = Polygon(locations=[p.tolist() for p in segs],
                               color='yellow',
                               weight=1,
                               opacity=1.,
                               fill_color=colors[clev],
                               fill_opacity=alphas[clev])
            ps.append(polygons)
        return ps, ts
Пример #17
0
    def show_m():

        multipoly = []
        multycent = []
        geom = spatial_utils.transform_geometry(info_data)
        poly = geom['geom'][0]['coordinates'][0]
        #     poly = spatial_utils.swap_xy(geom['coordinates'][0])[0]
        multipoly.append(poly)
        centroid = spatial_utils.centroid(poly)
        multycent.append(centroid)

        centroid = spatial_utils.centroid(multycent)
        m = Map(center=centroid,
                zoom=16,
                basemap=basemaps.OpenStreetMap.Mapnik)

        polygon = Polygon(locations=multipoly,
                          name='Parcel polygon',
                          color="yellow",
                          fill_color=None)

        m.add_layer(polygon)
        basemap2 = basemap_to_tiles(basemaps.Esri.WorldImagery)

        poly_text = HTML()
        poly_text.value = f"""Parcel ID: {pid}<br>
                                    Crop name: {crop_name}<br>
                                    Area: {area:.2f} sqm<br>
                                    Coordinates: {centroid}
                                    """
        poly_text.placeholder = "HTML"
        poly_text.description = ""

        # Popup with a given location on the map:
        poly_popup = Popup(child=poly_text,
                           close_button=False,
                           auto_close=False,
                           close_on_escape_key=False)
        m.add_layer(poly_popup)

        polygon.popup = poly_popup  # Popup associated to a layer

        # Layers control
        show_poly = Checkbox(value=True,
                             description='Polygon',
                             indent=False,
                             layout=Layout(width='140px'))
        show_sat = Checkbox(value=False,
                            description='High res basemap',
                            indent=False,
                            layout=Layout(width='140px'))

        def polygon_changed(b):
            try:
                if show_poly.value is True:
                    m.add_layer(polygon)
                else:
                    m.remove_layer(polygon)
            except Exception:
                pass

        show_poly.observe(polygon_changed)

        def show_sat_changed(b):
            try:
                if show_sat.value is True:
                    m.add_layer(basemap2)
                else:
                    m.remove_layer(basemap2)
            except Exception:
                pass

        show_sat.observe(show_sat_changed)

        try:
            df = raster_utils.create_df(ci_path, pid, ci_band.value)

            geotiff = normpath(
                join(ci_path, f"{df['imgs'][0]}.{ci_band.value[0]}.tif"))
            bounds = raster_utils.bounds(geotiff)

            images = {}
            for i, row in df.iterrows():
                str_date = str(row['date'].date()).replace('-', '')
                img_tc = normpath(
                    join(ci_path,
                         f"{('').join(ci_band.value)}_{str_date}.png"))

                # Create false color image if it does not exist
                # Merge bands (images path, export image path, bands list)
                if not isfile(img_tc):
                    imgs_path = normpath(join(ci_path, row['imgs']))
                    raster_utils.merge_bands(imgs_path, img_tc, ci_band.value)

                if bool(config.get_value(['set', 'jupyterlab'])) is True:
                    jlab_path = os.getcwd().replace(os.path.expanduser("~"),
                                                    '')
                    image_path = normpath(join(f'files{jlab_path}', img_tc))
                else:
                    image_path = img_tc

                # print('image_path: ', image_path)
                images[i] = ImageOverlay(url=image_path,
                                         name=str_date,
                                         bounds=(bounds))

            # Time slider
            slider = IntSlider(value=1,
                               min=1,
                               max=len(images),
                               step=1,
                               description=str(df['date'][0].date()),
                               continuous_update=False,
                               orientation='horizontal',
                               readout=True,
                               readout_format='d')
            show_chip = Checkbox(value=True,
                                 description='Chip image',
                                 indent=False,
                                 layout=Layout(width='140px'))

            def on_ci_band_change(change):
                pass

            ci_band.observe(on_ci_band_change, 'value')

            def show_chip_changed(b):
                try:
                    if show_chip.value is True:
                        m.add_layer(images[slider.value - 1])
                    else:
                        m.remove_layer(images[slider.value - 1])
                except Exception:
                    pass

            show_chip.observe(show_chip_changed)

            # Slider control
            play = Play(
                value=1,
                min=1,
                max=len(images),
                step=1,
                interval=1000,
                description="Press play",
            )

            def slider_changed(b):
                if show_chip.value is True:
                    try:
                        m.substitute_layer(images[b['old'] - 1],
                                           images[b['new'] - 1])
                    except Exception:
                        pass
                    slider.description = str(df['date'][slider.value -
                                                        1].date())

            slider.observe(slider_changed)
            jslink((play, 'value'), (slider, 'value'))
            time_box = HBox([slider, play])
            time_control = WidgetControl(widget=time_box,
                                         position='bottomleft')
            m.add_control(time_control)
            m.add_layer(images[0])

            map_options = VBox([show_poly, show_chip, show_sat])
        except Exception as err:
            map_options = VBox([show_poly, show_sat])
            print(err)

        layers_control = WidgetControl(widget=map_options,
                                       position='topright',
                                       max_width=150)
        m.add_control(layers_control)
        return m