(im_ms, cloud_mask, im_labels, im_ref_buffer, image_epsg, georef,
                       settings, date, satname, buffer_size_pixels)
return skip_image, shoreline, t_mndwi
Advanced version of show detection where the user can adjust the detected 
    shorelines with a slide bar.

    KV WRL 2020

    Arguments:
    -----------
    im_ms: np.array
        RGB + downsampled NIR and SWIR
    cloud_mask: np.array
        2D cloud mask with True where cloud pixels are
    im_labels: np.array
        3D image containing a boolean image for each class in the order (sand, swash, water)
    im_ref_buffer: np.array
        Binary image containing a buffer around the reference shoreline
    image_epsg: int
        spatial reference system of the image from which the contours were extracted
    georef: np.array
        vector of 6 elements [Xtr, Xscale, Xshear, Ytr, Yshear, Yscale]
    date: string
        date at which the image was taken
    satname: string
        indicates the satname (L5,L7,L8 or S2)
    buffer_size_pixels: int
        buffer_size converted to number of pixels
    settings: dict with the following keys
        'inputs': dict
            input parameters (sitename, filepath, polygon, dates, sat_list)
        'output_epsg': int
            output spatial reference system as EPSG code
        'save_figure': bool
            if True, saves a -jpg file for each mapped shoreline

    Returns:
    -----------
    skip_image: boolean
        True if the user wants to skip the image, False otherwise
    shoreline: np.array
        array of points with the X and Y coordinates of the shoreline 
    t_mndwi: float
        value of the MNDWI threshold used to map the shoreline
Advanced version of show detection where the user can adjust the detected 
    shorelines with a slide bar.
Advanced version of show detection where the user can adjust the detected shorelines with a slide bar .
def adjust_detection(im_ms, cloud_mask, im_labels, im_ref_buffer, image_epsg, georef,
                       settings, date, satname, buffer_size_pixels):
    """
    Advanced version of show detection where the user can adjust the detected 
    shorelines with a slide bar.

    KV WRL 2020

    Arguments:
    -----------
    im_ms: np.array
        RGB + downsampled NIR and SWIR
    cloud_mask: np.array
        2D cloud mask with True where cloud pixels are
    im_labels: np.array
        3D image containing a boolean image for each class in the order (sand, swash, water)
    im_ref_buffer: np.array
        Binary image containing a buffer around the reference shoreline
    image_epsg: int
        spatial reference system of the image from which the contours were extracted
    georef: np.array
        vector of 6 elements [Xtr, Xscale, Xshear, Ytr, Yshear, Yscale]
    date: string
        date at which the image was taken
    satname: string
        indicates the satname (L5,L7,L8 or S2)
    buffer_size_pixels: int
        buffer_size converted to number of pixels
    settings: dict with the following keys
        'inputs': dict
            input parameters (sitename, filepath, polygon, dates, sat_list)
        'output_epsg': int
            output spatial reference system as EPSG code
        'save_figure': bool
            if True, saves a -jpg file for each mapped shoreline

    Returns:
    -----------
    skip_image: boolean
        True if the user wants to skip the image, False otherwise
    shoreline: np.array
        array of points with the X and Y coordinates of the shoreline 
    t_mndwi: float
        value of the MNDWI threshold used to map the shoreline

    """

    sitename = settings['inputs']['sitename']
    filepath_data = settings['inputs']['filepath']
    # subfolder where the .jpg file is stored if the user accepts the shoreline detection
    filepath = os.path.join(filepath_data, sitename, 'jpg_files', 'detection')
    # format date
    date_str = datetime.strptime(date,'%Y-%m-%d-%H-%M-%S').strftime('%Y-%m-%d  %H:%M:%S')
    im_RGB = SDS_preprocess.rescale_image_intensity(im_ms[:,:,[2,1,0]], cloud_mask, 99.9)

    # compute classified image
    im_class = np.copy(im_RGB)
    cmap = cm.get_cmap('tab20c')
    colorpalette = cmap(np.arange(0,13,1))
    colours = np.zeros((3,4))
    colours[0,:] = colorpalette[5]
    colours[1,:] = np.array([204/255,1,1,1])
    colours[2,:] = np.array([0,91/255,1,1])
    for k in range(0,im_labels.shape[2]):
        im_class[im_labels[:,:,k],0] = colours[k,0]
        im_class[im_labels[:,:,k],1] = colours[k,1]
        im_class[im_labels[:,:,k],2] = colours[k,2]

    # compute MNDWI grayscale image
    im_mndwi = SDS_tools.nd_index(im_ms[:,:,4], im_ms[:,:,1], cloud_mask)
    # buffer MNDWI using reference shoreline
    im_mndwi_buffer = np.copy(im_mndwi)
    im_mndwi_buffer[~im_ref_buffer] = np.nan

    # get MNDWI pixel intensity in each class (for histogram plot)
    int_sand = im_mndwi[im_labels[:,:,0]]
    int_ww = im_mndwi[im_labels[:,:,1]]
    int_water = im_mndwi[im_labels[:,:,2]]
    labels_other = np.logical_and(np.logical_and(~im_labels[:,:,0],~im_labels[:,:,1]),~im_labels[:,:,2])
    int_other = im_mndwi[labels_other]
    
    # create figure
    if plt.get_fignums():
            # if it exists, open the figure 
            fig = plt.gcf()
            ax1 = fig.axes[0]
            ax2 = fig.axes[1]
            ax3 = fig.axes[2]
            ax4 = fig.axes[3]      
    else:
        # else create a new figure
        fig = plt.figure()
        fig.set_size_inches([18, 9])
        mng = plt.get_current_fig_manager()
        mng.window.showMaximized()
        gs = gridspec.GridSpec(2, 3, height_ratios=[4,1])
        gs.update(bottom=0.05, top=0.95, left=0.03, right=0.97)
        ax1 = fig.add_subplot(gs[0,0])
        ax2 = fig.add_subplot(gs[0,1], sharex=ax1, sharey=ax1)
        ax3 = fig.add_subplot(gs[0,2], sharex=ax1, sharey=ax1)
        ax4 = fig.add_subplot(gs[1,:])
    ##########################################################################
    # to do: rotate image if too wide
    ##########################################################################

    # change the color of nans to either black (0.0) or white (1.0) or somewhere in between
    nan_color = 1.0
    im_RGB = np.where(np.isnan(im_RGB), nan_color, im_RGB)
    im_class = np.where(np.isnan(im_class), 1.0, im_class)

    # plot image 1 (RGB)
    ax1.imshow(im_RGB)
    ax1.axis('off')
    ax1.set_title('%s - %s'%(sitename, satname), fontsize=12)

    # plot image 2 (classification)
    ax2.imshow(im_class)
    ax2.axis('off')
    orange_patch = mpatches.Patch(color=colours[0,:], label='sand')
    white_patch = mpatches.Patch(color=colours[1,:], label='whitewater')
    blue_patch = mpatches.Patch(color=colours[2,:], label='water')
    black_line = mlines.Line2D([],[],color='k',linestyle='-', label='shoreline')
    ax2.legend(handles=[orange_patch,white_patch,blue_patch, black_line],
               bbox_to_anchor=(1.1, 0.5), fontsize=10)
    ax2.set_title(date_str, fontsize=12)

    # plot image 3 (MNDWI)
    ax3.imshow(im_mndwi, cmap='bwr')
    ax3.axis('off')
    ax3.set_title('MNDWI', fontsize=12)
    
    # plot histogram of MNDWI values
    binwidth = 0.01
    ax4.set_facecolor('0.75')
    ax4.yaxis.grid(color='w', linestyle='--', linewidth=0.5)
    ax4.set(ylabel='PDF',yticklabels=[], xlim=[-1,1])
    if len(int_sand) > 0 and sum(~np.isnan(int_sand)) > 0:
        bins = np.arange(np.nanmin(int_sand), np.nanmax(int_sand) + binwidth, binwidth)
        ax4.hist(int_sand, bins=bins, density=True, color=colours[0,:], label='sand')
    if len(int_ww) > 0 and sum(~np.isnan(int_ww)) > 0:
        bins = np.arange(np.nanmin(int_ww), np.nanmax(int_ww) + binwidth, binwidth)
        ax4.hist(int_ww, bins=bins, density=True, color=colours[1,:], label='whitewater', alpha=0.75) 
    if len(int_water) > 0 and sum(~np.isnan(int_water)) > 0:
        bins = np.arange(np.nanmin(int_water), np.nanmax(int_water) + binwidth, binwidth)
        ax4.hist(int_water, bins=bins, density=True, color=colours[2,:], label='water', alpha=0.75) 
    if len(int_other) > 0 and sum(~np.isnan(int_other)) > 0:
        bins = np.arange(np.nanmin(int_other), np.nanmax(int_other) + binwidth, binwidth)
        ax4.hist(int_other, bins=bins, density=True, color='C4', label='other', alpha=0.5) 
    
    # automatically map the shoreline based on the classifier if enough sand pixels
    try:
        if sum(sum(im_labels[:,:,0])) > 10:
            # use classification to refine threshold and extract the sand/water interface
            contours_mndwi, t_mndwi = find_wl_contours2(im_ms, im_labels, cloud_mask,
                                                        buffer_size_pixels, im_ref_buffer)
        else:       
            # find water contours on MNDWI grayscale image
            contours_mndwi, t_mndwi = find_wl_contours1(im_mndwi, cloud_mask, im_ref_buffer)    
    except:
        print('Could not map shoreline so image was skipped')
        # clear axes and return skip_image=True, so that image is skipped above
        for ax in fig.axes:
            ax.clear()
        return True,[],[]

    # process the water contours into a shoreline
    shoreline = process_shoreline(contours_mndwi, cloud_mask, georef, image_epsg, settings)
    # convert shoreline to pixels
    if len(shoreline) > 0:
        sl_pix = SDS_tools.convert_world2pix(SDS_tools.convert_epsg(shoreline,
                                                                    settings['output_epsg'],
                                                                    image_epsg)[:,[0,1]], georef)
    else: sl_pix = np.array([[np.nan, np.nan],[np.nan, np.nan]])
    # plot the shoreline on the images
    sl_plot1 = ax1.plot(sl_pix[:,0], sl_pix[:,1], 'k.', markersize=3)
    sl_plot2 = ax2.plot(sl_pix[:,0], sl_pix[:,1], 'k.', markersize=3)
    sl_plot3 = ax3.plot(sl_pix[:,0], sl_pix[:,1], 'k.', markersize=3)
    t_line = ax4.axvline(x=t_mndwi,ls='--', c='k', lw=1.5, label='threshold')
    ax4.legend(loc=1)
    plt.draw() # to update the plot
    # adjust the threshold manually by letting the user change the threshold
    ax4.set_title('Click on the plot below to change the location of the threhsold and adjust the shoreline detection. When finished, press <Enter>')
    while True:  
        # let the user click on the threshold plot
        pt = ginput(n=1, show_clicks=True, timeout=-1)
        # if a point was clicked
        if len(pt) > 0: 
            # if user clicked somewhere wrong and value is not between -1 and 1
            if np.abs(pt[0][0]) >= 1: continue
            # update the threshold value
            t_mndwi = pt[0][0]
            # update the plot
            t_line.set_xdata([t_mndwi,t_mndwi])
            # map contours with new threshold
            contours = measure.find_contours(im_mndwi_buffer, t_mndwi)
            # remove contours that contain NaNs (due to cloud pixels in the contour)
            contours = process_contours(contours) 
            # process the water contours into a shoreline
            shoreline = process_shoreline(contours, cloud_mask, georef, image_epsg, settings)
            # convert shoreline to pixels
            if len(shoreline) > 0:
                sl_pix = SDS_tools.convert_world2pix(SDS_tools.convert_epsg(shoreline,
                                                                            settings['output_epsg'],
                                                                            image_epsg)[:,[0,1]], georef)
            else: sl_pix = np.array([[np.nan, np.nan],[np.nan, np.nan]])
            # update the plotted shorelines
            sl_plot1[0].set_data([sl_pix[:,0], sl_pix[:,1]])
            sl_plot2[0].set_data([sl_pix[:,0], sl_pix[:,1]])
            sl_plot3[0].set_data([sl_pix[:,0], sl_pix[:,1]])
            fig.canvas.draw_idle()
        else:
            ax4.set_title('MNDWI pixel intensities and threshold')
            break
    
    # let user manually accept/reject the image
    skip_image = False
    # set a key event to accept/reject the detections (see https://stackoverflow.com/a/15033071)
    # this variable needs to be immuatable so we can access it after the keypress event
    key_event = {}
    def press(event):
        # store what key was pressed in the dictionary
        key_event['pressed'] = event.key
    # let the user press a key, right arrow to keep the image, left arrow to skip it
    # to break the loop the user can press 'escape'
    while True:
        btn_keep = plt.text(1.1, 0.9, 'keep ⇨', size=12, ha="right", va="top",
                            transform=ax1.transAxes,
                            bbox=dict(boxstyle="square", ec='k',fc='w'))
        btn_skip = plt.text(-0.1, 0.9, '⇦ skip', size=12, ha="left", va="top",
                            transform=ax1.transAxes,
                            bbox=dict(boxstyle="square", ec='k',fc='w'))
        btn_esc = plt.text(0.5, 0, '<esc> to quit', size=12, ha="center", va="top",
                            transform=ax1.transAxes,
                            bbox=dict(boxstyle="square", ec='k',fc='w'))
        plt.draw()
        fig.canvas.mpl_connect('key_press_event', press)
        plt.waitforbuttonpress()
        # after button is pressed, remove the buttons
        btn_skip.remove()
        btn_keep.remove()
        btn_esc.remove()

        # keep/skip image according to the pressed key, 'escape' to break the loop
        if key_event.get('pressed') == 'right':
            skip_image = False
            break
        elif key_event.get('pressed') == 'left':
            skip_image = True
            break
        elif key_event.get('pressed') == 'escape':
            plt.close()
            raise StopIteration('User cancelled checking shoreline detection')
        else:
            plt.waitforbuttonpress()

    # if save_figure is True, save a .jpg under /jpg_files/detection
    if settings['save_figure'] and not skip_image:
        fig.savefig(os.path.join(filepath, date + '_' + satname + '.jpg'), dpi=150)

    # don't close the figure window, but remove all axes and settings, ready for next plot
    for ax in fig.axes:
        ax.clear()

    return skip_image, shoreline, t_mndwi
def adjust_detection ( im_ms , cloud_mask , im_labels , im_ref_buffer , image_epsg , georef , settings , date , satname , buffer_size_pixels ) : sitename = settings [ 'inputs' ] [ 'sitename' ] filepath_data = settings [ 'inputs' ] [ 'filepath' ] # subfolder where the .jpg file is stored if the user accepts the shoreline detection filepath = os . path . join ( filepath_data , sitename , 'jpg_files' , 'detection' ) # format date date_str = datetime . strptime ( date , '%Y-%m-%d-%H-%M-%S' ) . strftime ( '%Y-%m-%d  %H:%M:%S' ) im_RGB = SDS_preprocess . rescale_image_intensity ( im_ms [ : , : , [ 2 , 1 , 0 ] ] , cloud_mask , 99.9 ) # compute classified image im_class = np . copy ( im_RGB ) cmap = cm . get_cmap ( 'tab20c' ) colorpalette = cmap ( np . arange ( 0 , 13 , 1 ) ) colours = np . zeros ( ( 3 , 4 ) ) colours [ 0 , : ] = colorpalette [ 5 ] colours [ 1 , : ] = np . array ( [ 204 / 255 , 1 , 1 , 1 ] ) colours [ 2 , : ] = np . array ( [ 0 , 91 / 255 , 1 , 1 ] ) for k in range ( 0 , im_labels . shape [ 2 ] ) : im_class [ im_labels [ : , : , k ] , 0 ] = colours [ k , 0 ] im_class [ im_labels [ : , : , k ] , 1 ] = colours [ k , 1 ] im_class [ im_labels [ : , : , k ] , 2 ] = colours [ k , 2 ] # compute MNDWI grayscale image im_mndwi = SDS_tools . nd_index ( im_ms [ : , : , 4 ] , im_ms [ : , : , 1 ] , cloud_mask ) # buffer MNDWI using reference shoreline im_mndwi_buffer = np . copy ( im_mndwi ) im_mndwi_buffer [ ~ im_ref_buffer ] = np . nan # get MNDWI pixel intensity in each class (for histogram plot) int_sand = im_mndwi [ im_labels [ : , : , 0 ] ] int_ww = im_mndwi [ im_labels [ : , : , 1 ] ] int_water = im_mndwi [ im_labels [ : , : , 2 ] ] labels_other = np . logical_and ( np . logical_and ( ~ im_labels [ : , : , 0 ] , ~ im_labels [ : , : , 1 ] ) , ~ im_labels [ : , : , 2 ] ) int_other = im_mndwi [ labels_other ] # create figure if plt . get_fignums ( ) : # if it exists, open the figure  fig = plt . gcf ( ) ax1 = fig . axes [ 0 ] ax2 = fig . axes [ 1 ] ax3 = fig . axes [ 2 ] ax4 = fig . axes [ 3 ] else : # else create a new figure fig = plt . figure ( ) fig . set_size_inches ( [ 18 , 9 ] ) mng = plt . get_current_fig_manager ( ) mng . window . showMaximized ( ) gs = gridspec . GridSpec ( 2 , 3 , height_ratios = [ 4 , 1 ] ) gs . update ( bottom = 0.05 , top = 0.95 , left = 0.03 , right = 0.97 ) ax1 = fig . add_subplot ( gs [ 0 , 0 ] ) ax2 = fig . add_subplot ( gs [ 0 , 1 ] , sharex = ax1 , sharey = ax1 ) ax3 = fig . add_subplot ( gs [ 0 , 2 ] , sharex = ax1 , sharey = ax1 ) ax4 = fig . add_subplot ( gs [ 1 , : ] ) ########################################################################## # to do: rotate image if too wide ########################################################################## # change the color of nans to either black (0.0) or white (1.0) or somewhere in between nan_color = 1.0 im_RGB = np . where ( np . isnan ( im_RGB ) , nan_color , im_RGB ) im_class = np . where ( np . isnan ( im_class ) , 1.0 , im_class ) # plot image 1 (RGB) ax1 . imshow ( im_RGB ) ax1 . axis ( 'off' ) ax1 . set_title ( '%s - %s' % ( sitename , satname ) , fontsize = 12 ) # plot image 2 (classification) ax2 . imshow ( im_class ) ax2 . axis ( 'off' ) orange_patch = mpatches . Patch ( color = colours [ 0 , : ] , label = 'sand' ) white_patch = mpatches . Patch ( color = colours [ 1 , : ] , label = 'whitewater' ) blue_patch = mpatches . Patch ( color = colours [ 2 , : ] , label = 'water' ) black_line = mlines . Line2D ( [ ] , [ ] , color = 'k' , linestyle = '-' , label = 'shoreline' ) ax2 . legend ( handles = [ orange_patch , white_patch , blue_patch , black_line ] , bbox_to_anchor = ( 1.1 , 0.5 ) , fontsize = 10 ) ax2 . set_title ( date_str , fontsize = 12 ) # plot image 3 (MNDWI) ax3 . imshow ( im_mndwi , cmap = 'bwr' ) ax3 . axis ( 'off' ) ax3 . set_title ( 'MNDWI' , fontsize = 12 ) # plot histogram of MNDWI values binwidth = 0.01 ax4 . set_facecolor ( '0.75' ) ax4 . yaxis . grid ( color = 'w' , linestyle = '--' , linewidth = 0.5 ) ax4 . set ( ylabel = 'PDF' , yticklabels = [ ] , xlim = [ - 1 , 1 ] ) if len ( int_sand ) > 0 and sum ( ~ np . isnan ( int_sand ) ) > 0 : bins = np . arange ( np . nanmin ( int_sand ) , np . nanmax ( int_sand ) + binwidth , binwidth ) ax4 . hist ( int_sand , bins = bins , density = True , color = colours [ 0 , : ] , label = 'sand' ) if len ( int_ww ) > 0 and sum ( ~ np . isnan ( int_ww ) ) > 0 : bins = np . arange ( np . nanmin ( int_ww ) , np . nanmax ( int_ww ) + binwidth , binwidth ) ax4 . hist ( int_ww , bins = bins , density = True , color = colours [ 1 , : ] , label = 'whitewater' , alpha = 0.75 ) if len ( int_water ) > 0 and sum ( ~ np . isnan ( int_water ) ) > 0 : bins = np . arange ( np . nanmin ( int_water ) , np . nanmax ( int_water ) + binwidth , binwidth ) ax4 . hist ( int_water , bins = bins , density = True , color = colours [ 2 , : ] , label = 'water' , alpha = 0.75 ) if len ( int_other ) > 0 and sum ( ~ np . isnan ( int_other ) ) > 0 : bins = np . arange ( np . nanmin ( int_other ) , np . nanmax ( int_other ) + binwidth , binwidth ) ax4 . hist ( int_other , bins = bins , density = True , color = 'C4' , label = 'other' , alpha = 0.5 ) # automatically map the shoreline based on the classifier if enough sand pixels try : if sum ( sum ( im_labels [ : , : , 0 ] ) ) > 10 : # use classification to refine threshold and extract the sand/water interface contours_mndwi , t_mndwi = find_wl_contours2 ( im_ms , im_labels , cloud_mask , buffer_size_pixels , im_ref_buffer ) else : # find water contours on MNDWI grayscale image contours_mndwi , t_mndwi = find_wl_contours1 ( im_mndwi , cloud_mask , im_ref_buffer ) except : print ( 'Could not map shoreline so image was skipped' ) # clear axes and return skip_image=True, so that image is skipped above for ax in fig . axes : ax . clear ( ) return True , [ ] , [ ] # process the water contours into a shoreline shoreline = process_shoreline ( contours_mndwi , cloud_mask , georef , image_epsg , settings ) # convert shoreline to pixels if len ( shoreline ) > 0 : sl_pix = SDS_tools . convert_world2pix ( SDS_tools . convert_epsg ( shoreline , settings [ 'output_epsg' ] , image_epsg ) [ : , [ 0 , 1 ] ] , georef ) else : sl_pix = np . array ( [ [ np . nan , np . nan ] , [ np . nan , np . nan ] ] ) # plot the shoreline on the images sl_plot1 = ax1 . plot ( sl_pix [ : , 0 ] , sl_pix [ : , 1 ] , 'k.' , markersize = 3 ) sl_plot2 = ax2 . plot ( sl_pix [ : , 0 ] , sl_pix [ : , 1 ] , 'k.' , markersize = 3 ) sl_plot3 = ax3 . plot ( sl_pix [ : , 0 ] , sl_pix [ : , 1 ] , 'k.' , markersize = 3 ) t_line = ax4 . axvline ( x = t_mndwi , ls = '--' , c = 'k' , lw = 1.5 , label = 'threshold' ) ax4 . legend ( loc = 1 ) plt . draw ( ) # to update the plot # adjust the threshold manually by letting the user change the threshold ax4 . set_title ( 'Click on the plot below to change the location of the threhsold and adjust the shoreline detection. When finished, press <Enter>' ) while True : # let the user click on the threshold plot pt = ginput ( n = 1 , show_clicks = True , timeout = - 1 ) # if a point was clicked if len ( pt ) > 0 : # if user clicked somewhere wrong and value is not between -1 and 1 if np . abs ( pt [ 0 ] [ 0 ] ) >= 1 : continue # update the threshold value t_mndwi = pt [ 0 ] [ 0 ] # update the plot t_line . set_xdata ( [ t_mndwi , t_mndwi ] ) # map contours with new threshold contours = measure . find_contours ( im_mndwi_buffer , t_mndwi ) # remove contours that contain NaNs (due to cloud pixels in the contour) contours = process_contours ( contours ) # process the water contours into a shoreline shoreline = process_shoreline ( contours , cloud_mask , georef , image_epsg , settings ) # convert shoreline to pixels if len ( shoreline ) > 0 : sl_pix = SDS_tools . convert_world2pix ( SDS_tools . convert_epsg ( shoreline , settings [ 'output_epsg' ] , image_epsg ) [ : , [ 0 , 1 ] ] , georef ) else : sl_pix = np . array ( [ [ np . nan , np . nan ] , [ np . nan , np . nan ] ] ) # update the plotted shorelines sl_plot1 [ 0 ] . set_data ( [ sl_pix [ : , 0 ] , sl_pix [ : , 1 ] ] ) sl_plot2 [ 0 ] . set_data ( [ sl_pix [ : , 0 ] , sl_pix [ : , 1 ] ] ) sl_plot3 [ 0 ] . set_data ( [ sl_pix [ : , 0 ] , sl_pix [ : , 1 ] ] ) fig . canvas . draw_idle ( ) else : ax4 . set_title ( 'MNDWI pixel intensities and threshold' ) break # let user manually accept/reject the image skip_image = False # set a key event to accept/reject the detections (see https://stackoverflow.com/a/15033071) # this variable needs to be immuatable so we can access it after the keypress event key_event = { } def press ( event ) : # store what key was pressed in the dictionary key_event [ 'pressed' ] = event . key # let the user press a key, right arrow to keep the image, left arrow to skip it # to break the loop the user can press 'escape' while True : btn_keep = plt . text ( 1.1 , 0.9 , 'keep ⇨',  s ze=1 2 ,  h =" r ight",  v =" t op", transform = ax1 . transAxes , bbox = dict ( boxstyle = "square" , ec = 'k' , fc = 'w' ) ) btn_skip = plt . text ( - 0.1 , 0.9 , '⇦ skip',  s ze=1 2 ,  h =" l eft",  v =" t op", transform = ax1 . transAxes , bbox = dict ( boxstyle = "square" , ec = 'k' , fc = 'w' ) ) btn_esc = plt . text ( 0.5 , 0 , '<esc> to quit' , size = 12 , ha = "center" , va = "top" , transform = ax1 . transAxes , bbox = dict ( boxstyle = "square" , ec = 'k' , fc = 'w' ) ) plt . draw ( ) fig . canvas . mpl_connect ( 'key_press_event' , press ) plt . waitforbuttonpress ( ) # after button is pressed, remove the buttons btn_skip . remove ( ) btn_keep . remove ( ) btn_esc . remove ( ) # keep/skip image according to the pressed key, 'escape' to break the loop if key_event . get ( 'pressed' ) == 'right' : skip_image = False break elif key_event . get ( 'pressed' ) == 'left' : skip_image = True break elif key_event . get ( 'pressed' ) == 'escape' : plt . close ( ) raise StopIteration ( 'User cancelled checking shoreline detection' ) else : plt . waitforbuttonpress ( ) # if save_figure is True, save a .jpg under /jpg_files/detection if settings [ 'save_figure' ] and not skip_image : fig . savefig ( os . path . join ( filepath , date + '_' + satname + '.jpg' ) , dpi = 150 ) # don't close the figure window, but remove all axes and settings, ready for next plot for ax in fig . axes : ax . clear ( ) return skip_image , shoreline , t_mndwi