def slider(aoi, pid, chipsize=512, extend=512, tms=['Google']): workdir = config.get_value(['paths', 'temp']) path = f'{workdir}/{aoi}/{pid}/' bg_path = f'{path}/backgrounds/' for t in tms: if not os.path.isfile(f'{bg_path}{t.lower()}.tif'): bg.by_pid(aoi, pid, chipsize, extend, t, True) with open(f'{path}info.json', "r") as f: json_data = json.load(f) def overlay_parcel(img, geom): patche = [ PolygonPatch(feature, edgecolor="yellow", facecolor="none", linewidth=2) for feature in geom['geom'] ] return patche with rasterio.open(f'{bg_path}{tms[0].lower()}.tif') as img: img_epsg = img.crs.to_epsg() geom = spatial_utils.transform_geometry(json_data, img_epsg) patches = overlay_parcel(img, geom) selection = SelectionSlider(options=tms, value=tms[0], disabled=False, continuous_update=False, orientation='horizontal', readout=True) output = Output() fig, ax = plt.subplots(figsize=(10, 10)) with output: with rasterio.open(f'{bg_path}{selection.value.lower()}.tif') as img: for patch in patches: ax.add_patch(copy(patch)) show(img, ax=ax) plt.show() def on_value_change(change): with output: output.clear_output() fig, ax = plt.subplots(figsize=(10, 10)) with rasterio.open( f'{bg_path}{selection.value.lower()}.tif') as im: for patch in patches: ax.add_patch(copy(patch)) show(im, ax=ax) plt.show() selection.observe(on_value_change, names='value') return VBox([selection, output])
def overlay_parcel(img, geom): with open(file_info, 'r') as f: info_data = json.loads(f.read()) img_epsg = img.crs.to_epsg() geo_json = spatial_utils.transform_geometry(info_data, img_epsg) patche = [ PolygonPatch(feature, edgecolor="yellow", facecolor="none", linewidth=2) for feature in [geo_json['geom'][0]] ] return patche[0]
def by_location(aoi, year, lon, lat, dates, band, chipsize, columns=5, quiet=True): from cbm.datas import api """Plot chip image with parcel polygon overlay. Examples: import cbm cbm.get.chip_images.by_pid(aoi, pid, start_date, end_date, band, chipsize) Arguments: aoi, the area of interest and year e.g.: es2020, cat2020 (str) pid, the parcel id (int). dates, the date of the image (str) or start_date and end_date (list) '2019-06-01' or ['2019-06-01', '2019-06-30'] band, 3 Sentinel-2 band names. One of [‘B02’, ‘B03’, ‘B04’, ‘B08’] (10 m bands) or [‘B05’, ‘B06’, ‘B07’, ‘B8A’, ‘B11’, ‘B12’] (20 m bands). 10m and 20m bands can be combined. The first band determines the resolution in the output composite. Defaults to B08_B04_B03. chipsize, size of the chip in pixels (int). columns, (int) """ if type(dates) is list: start_date, end_date = dates[0], dates[1] else: start_date, end_date = dates, dates json_data = json.loads(api.parcel_by_loc(aoi, lon, lat, True)) if type(json_data['ogc_fid']) is list: pid = json_data['ogc_fid'][0] else: pid = json_data['ogc_fid'] workdir = normpath(join(config.get_value(['paths', 'temp']), aoi, str(pid))) chip_imgs.by_pid(aoi, pid, start_date, end_date, band, chipsize, quiet) chips_dir = normpath(join(workdir, 'chip_images')) if type(dates) is list: chips = normpath(join(chips_dir, f"*{band}.tif")) else: chips = normpath( join(chips_dir, f"*{start_date.replace('-', '')}*{band}.tif")) chips_list = glob.glob(chips) if len(chips_list) > 0: if len(chips_list) < columns: columns = len(chips_list) with rasterio.open(chips_list[0]) as img: img_epsg = img.crs.to_epsg() geom = spatial_utils.transform_geometry(json_data, img_epsg) patches = overlay_parcel(img, geom) if not quiet: for chip in chips_list: print(chip) rows = int( len(chips_list) // columns + (len(chips_list) % columns > 0)) fig = plt.figure(figsize=(30, 10 * rows)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(rows, columns), # creates grid of axes axes_pad=0.4, # pad between axes in inch. ) for ax, t in zip(grid, chips_list): with rasterio.open(t) as img: for patch in patches: ax.add_patch(copy(patch)) show(img, ax=ax, cmap=data_options.cmaps(band)) ax.set_title(t.split('_')[-1].split('.')[0], fontsize=20) if len(chips_list) > columns: for ax in grid[-((columns * rows - len(chips_list))):]: ax.remove() plt.show() else: print("! No images to show.")
def by_location(aoi, year, lon, lat, chipsize=512, extend=512, tms=['google'], ptype=None, columns=4, debug=False): """Show the background image with parcels polygon overlay by selected parcel id. This function will get an image from the center of the polygon. Examples: from cbm.view import background background.by_location(aoi, year, lon, lat, 512, 512, 'Google', True, True) Arguments: aoi, the area of interest (str) year, the year of parcels table lon, lat, longitude and latitude in decimal degrees (float). chipsize, size of the chip in pixels (int). extend, size of the chip in meters (float). tms, tile map server Google or Bing (str). columns, the number of columns of the grid debug, print or not procedure information (Boolean). """ if type(tms) is str: tms = [tms] try: parcel = parcel_info.by_location(aoi, year, lon, lat, ptype, True, False, debug) if type(parcel['pid']) is list: pid = parcel['pid'][0] else: pid = parcel['pid'] workdir = normpath( join(config.get_value(['paths', 'temp']), aoi, str(year), str(pid))) parcel_id = True except Exception as err: workdir = normpath( join(config.get_value(['paths', 'temp']), aoi, str(year), f'_{lon}_{lat}'.replace('.', '_'))) parcel_id = False if debug: print("No parcel information found.", err) if len(tms) < columns: columns = len(tms) bg_path = normpath(join(workdir, 'backgrounds')) same_args = check_args(bg_path, chipsize, extend, debug) if debug: print('path: ', bg_path) print('same args: ', same_args) print('aoi-year-lon-lat-chipsize-extend-tms-ptype-columns-debug') print(aoi, year, lon, lat, chipsize, extend, tms, ptype, columns, debug) for t in tms: if not isfile(normpath(join(bg_path, f'{t.lower()}.tif'))) or not same_args: if parcel_id: get_bg.by_pid(aoi, year, pid, chipsize, extend, t, ptype, True, debug) else: get_bg.by_location(aoi, year, lon, lat, chipsize, extend, t, ptype, True, debug) if parcel_id: with open(normpath(join(workdir, 'info.json')), 'r') as f: parcel = json.load(f) with rasterio.open(normpath(join(bg_path, f'{tms[0].lower()}.tif'))) as img: img_epsg = img.crs.to_epsg() geom = spatial_utils.transform_geometry(parcel, img_epsg) patches = overlay_parcel(img, geom) rows = int(len(tms) // columns + (len(tms) % columns > 0)) fig = plt.figure(figsize=(30, 10 * rows)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(rows, columns), # creates grid of axes axes_pad=0.4, # pad between axes in inch. ) def overlay_title(img, date): date_text = ax.text( img.bounds.left + ((img.bounds.right - img.bounds.left) / 9), img.bounds.bottom + ((img.bounds.top - img.bounds.bottom) / 1.15), date, color='yellow', weight='bold', size=32 - columns * 2, bbox=dict(boxstyle="round", ec='yellow', fc='black', alpha=0.2)) return date_text for ax, t in zip(grid, tms): with rasterio.open(normpath(join(bg_path, f'{t.lower()}.tif'))) as img: if parcel_id: for patch in patches: ax.add_patch(copy(patch)) overlay_title(img, t) show(img, ax=ax) # ax.xaxis.set_major_locator(ticker.MultipleLocator(200)) if len(tms) > columns and columns * rows > len(tms): for ax in grid[-((columns * rows - len(tms))):]: ax.remove() plt.show()
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
def by_pid(aoi, year, pid, chipsize=512, extend=512, tms=['Google'], ptype=None, columns=4, debug=False): """Show the background image with parcels polygon overlay by selected parcel id. This function will get an image from the center of the polygon. Examples: from cbm.view import background background.by_location(aoi, year, lon, lat, 512, 512, 'Google', True, True) Arguments: aoi, the area of interest (str) year, the year of parcels table pid, the parcel id (str). chipsize, size of the chip in pixels (int). extend, size of the chip in meters (float). tms, tile map server Google or Bing (str). columns, the number of columns of the grid debug, print or not procedure information (Boolean). """ if type(tms) is str: tms = [tms] if len(tms) < columns: columns = len(tms) workdir = normpath( join(config.get_value(['paths', 'temp']), aoi, str(year), str(pid))) bg_path = normpath(join(workdir, 'backgrounds')) same_args = check_args(bg_path, chipsize, extend) if debug: print('path: ', bg_path) print('same args: ', same_args) print('aoi, year, pid, chipsize, extend, tms, columns, debug') print(aoi, year, pid, chipsize, extend, tms, columns, debug) for t in tms: if not isfile(normpath(join( bg_path, f'{t.lower()}.tif'))) or same_args is False: get_bg.by_pid(aoi, year, pid, chipsize, extend, t, ptype, True, debug) with open(normpath(join(workdir, 'info.json')), 'r') as f: parcel = json.load(f) with rasterio.open(normpath(join(bg_path, f'{tms[0].lower()}.tif'))) as img: img_epsg = img.crs.to_epsg() geom = spatial_utils.transform_geometry(parcel, img_epsg) patches = overlay_parcel(img, geom) rows = int(len(tms) // columns + (len(tms) % columns > 0)) fig = plt.figure(figsize=(30, 10 * rows)) grid = ImageGrid( fig, 111, # similar to subplot(111) nrows_ncols=(rows, columns), # creates grid of axes axes_pad=0.4) # pad between axes in inch. for ax, t in zip(grid, tms): with rasterio.open(normpath(join(bg_path, f'{t.lower()}.tif'))) as img: for patch in patches: ax.add_patch(copy(patch)) # ax.xaxis.set_major_locator(ticker.MultipleLocator(200)) show(img, ax=ax) ax.set_title(t, fontsize=20) if len(tms) > columns and columns * rows > len(tms): for ax in grid[-((columns * rows - len(tms))):]: ax.remove() plt.show()
def by_pid(aoi, year, pid, ptype=None, tms='osm', debug=False): """Show parcel information with an image with polygon overlay by selected parcel id. This function will get an image from the center of the polygon. Examples: from cbm.show import parcel_info parcel_info.by_id(aoi, year, pid) Arguments: aoi, the area of interest (str) year, the year of parcels table pid, the parcel id (str). ptype, parcel type debug, print or not procedure information (Boolean). """ workdir = normpath( join(config.get_value(['paths', 'temp']), aoi, str(year), str(pid))) bg_path = normpath(join(workdir, 'backgrounds')) if debug: print('path: ', bg_path) print('aoi, year, pid, debug') print(aoi, year, pid, debug) file_info = normpath(join(workdir, 'info.json')) if not isfile(file_info): parcel_info.by_pid(aoi, str(year), str(pid), ptype, True) with open(normpath(join(workdir, 'info.json')), 'r') as f: parcel = json.load(f) plt.rcParams['font.size'] = 14 plt.figure(figsize=(10, 3)) gs = gridspec.GridSpec(1, 2) ax1 = plt.subplot(gs[0, 0]) ax2 = plt.subplot(gs[0, 1]) try: if not isfile(normpath(join(bg_path, f'{tms}.tif'))): get_bg.by_pid(aoi, year, pid, 256, 1024, tms, ptype, True, debug) elif getsize(normpath(join(bg_path, f'osm.tif'))) < 1000: get_bg.by_pid(aoi, year, pid, 256, 1024, tms, ptype, True, debug) with rasterio.open(normpath(join(bg_path, f'{tms}.tif'))) as img: img_epsg = img.crs.to_epsg() geom = spatial_utils.transform_geometry(parcel, img_epsg) patches = overlay_parcel(geom) for patch in patches: ax2.add_patch(copy(patch)) show(img, ax=ax2) except Exception as err: print("Could not get image. ", err) text = [ f"AOI: {aoi}", f"Year: {year}", f"Parcel ID: {pid}", f"Crop type: {parcel['cropname'][0]}", f"Crop type code: {parcel['cropcode'][0]}", f"Area: {parcel['area'][0]} sqm", f"Centroid (Lat/Lon): {parcel['clat'][0]:.6f}, {parcel['clon'][0]:.6f}", f"Geometry SRID: {parcel['srid'][0]}" ] first_line = 0.9 for t in text: ax1.text(0, first_line, t) first_line -= 0.12 ax1.axis('off') ax2.axis('off') plt.show()