Example #1
0
                2 * np.pi * freq_subbands_hz, light_speed, K=K_est,
                tau_x=tau_x, tau_y=tau_y, M=M, N=N, tau_inter_x=tau_inter_x,
                tau_inter_y=tau_inter_y, max_ini=max_ini, num_rotation=1,
                G_iter=parameter_set['G_iter'],
                plane_norm_vec=plane_norm_vec, verbose=True,
                backend=backend, theano_build_G_func=theano_build_G_func,
                theano_build_amp_func=theano_build_amp_func
            )
    else:
        precomputed_result = np.load(parameter_set['precomputed_result_name'])
        xk_recon = precomputed_result['xk_recon']
        yk_recon = precomputed_result['yk_recon']
        alpha_k_recon = precomputed_result['alpha_k_recon']

    # compute partial reconstruction error
    dist_recon, idx_sort = planar_distance(x_ks, y_ks, xk_recon, yk_recon)

    # deal with the specific case when only 1 Dirac is reconstructed
    if not hasattr(xk_recon, '__iter__'):
        xk_recon = np.array([xk_recon])
        yk_recon = np.array([yk_recon])

    if len(idx_sort.shape) == 1:
        xk_recon_sorted = np.array([xk_recon])
        yk_recon_sorted = np.array([yk_recon])
        x_ks_sorted = np.array(x_ks[idx_sort[0]])
        y_ks_sorted = np.array(y_ks[idx_sort[0]])
    else:
        xk_recon_sorted = xk_recon[idx_sort[:, 1]]
        yk_recon_sorted = yk_recon[idx_sort[:, 1]]
        x_ks_sorted = x_ks[idx_sort[:, 0]]
Example #2
0
def planar_plot_diracs_plotly(x_plt,
                              y_plt,
                              img_lsq,
                              y_ref=None,
                              x_ref=None,
                              amplitude_ref=None,
                              y_recon=None,
                              x_recon=None,
                              amplitude_recon=None,
                              file_name='planar_recon_2d_dirac.html',
                              open_browser=False):
    plotly.offline.init_notebook_mode()
    surfacecolor = np.real(img_lsq)  # for plotting purposes

    if y_ref is not None and x_ref is not None and amplitude_ref is not None:
        ref_pt_available = True
    else:
        ref_pt_available = False

    if y_recon is not None and x_recon is not None and amplitude_recon is not None:
        recon_pt_available = True
    else:
        recon_pt_available = False

    trace1 = go.Surface(x=np.degrees(x_plt),
                        y=np.degrees(y_plt),
                        surfacecolor=surfacecolor,
                        opacity=1,
                        colorscale='Portland',
                        hoverinfo='none')

    trace1['contours']['x']['highlightwidth'] = 1
    trace1['contours']['y']['highlightwidth'] = 1
    # trace1['contours']['z']['highlightwidth'] = 1

    np.set_printoptions(precision=3, formatter={'float': '{: 0.2f}'.format})
    if ref_pt_available:
        if hasattr(y_ref, '__iter__'):  # <= not a scalar
            text_str2 = []
            for count, y0 in enumerate(y_ref):
                if amplitude_ref.shape[1] > 1:
                    text_str2.append((u'({0:.2f}\N{DEGREE SIGN}, ' +
                                      u'{1:.2f}\N{DEGREE SIGN}), </br>' +
                                      u'intensity: {2}').format(
                                          np.degrees(y0),
                                          np.degrees(x_ref[count]),
                                          amplitude_ref.squeeze()[count]))
                else:
                    text_str2.append((u'({0:.2f}\N{DEGREE SIGN}, ' +
                                      u'{1:.2f}\N{DEGREE SIGN}), </br>' +
                                      u'intensity: {2:.2f}').format(
                                          np.degrees(y0),
                                          np.degrees(x_ref[count]),
                                          amplitude_ref.squeeze()[count]))

            trace2 = go.Scatter(mode='markers',
                                name='ground truth',
                                x=np.degrees(x_ref),
                                y=np.degrees(y_ref),
                                text=text_str2,
                                hoverinfo='name+text',
                                marker=dict(size=6,
                                            symbol='circle',
                                            opacity=0.6,
                                            line=dict(color='rgb(0, 0, 0)',
                                                      width=1),
                                            color='rgb(255, 255, 255)'))
        else:
            if amplitude_ref.shape[1] > 1:
                text_str2 = [
                    (u'({0:.2f}\N{DEGREE SIGN}, ' +
                     u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                     u'intensity: {2}').format(np.degrees(y_ref),
                                               np.degrees(x_ref),
                                               amplitude_ref)
                ]
            else:
                text_str2 = [
                    (u'({0:.2f}\N{DEGREE SIGN}, ' +
                     u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                     u'intensity: {2:.2f}').format(np.degrees(y_ref),
                                                   np.degrees(x_ref),
                                                   amplitude_ref)
                ]
            trace2 = go.Scatter(mode='markers',
                                name='ground truth',
                                x=[np.degrees(x_ref)],
                                y=[np.degrees(y_ref)],
                                text=text_str2,
                                hoverinfo='name+text',
                                marker=dict(size=6,
                                            symbol='circle',
                                            opacity=0.6,
                                            line=dict(color='rgb(0, 0, 0)',
                                                      width=1),
                                            color='rgb(255, 255, 255)'))

    if recon_pt_available:
        if hasattr(y_recon, '__iter__'):
            text_str3 = []
            for count, y0 in enumerate(y_recon):
                if amplitude_recon.shape[1] > 1:
                    text_str3.append((u'({0:.2f}\N{DEGREE SIGN}, ' +
                                      u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                                      u'intensity: {2}').format(
                                          np.degrees(y0),
                                          np.degrees(x_recon[count]),
                                          amplitude_recon.squeeze()[count]))
                else:
                    text_str3.append((u'({0:.2f}\N{DEGREE SIGN}, ' +
                                      u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                                      u'intensity: {2:.2f}').format(
                                          np.degrees(y0),
                                          np.degrees(x_recon[count]),
                                          np.squeeze(amplitude_recon,
                                                     axis=1)[count]))

            trace3 = go.Scatter(mode='markers',
                                name='reconstruction',
                                x=np.degrees(x_recon),
                                y=np.degrees(y_recon),
                                text=text_str3,
                                hoverinfo='name+text',
                                marker=dict(size=6,
                                            symbol='diamond',
                                            opacity=0.6,
                                            line=dict(color='rgb(0, 0, 0)',
                                                      width=1),
                                            color='rgb(255, 105, 180)'))
        else:
            if amplitude_recon.shape[1] > 1:
                text_str3 = [
                    (u'({0:.2f}\N{DEGREE SIGN}, '
                     u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                     u'intensity: {2}').format(np.degrees(y_recon),
                                               np.degrees(x_recon),
                                               amplitude_recon)
                ]
            else:
                text_str3 = [
                    (u'({0:.2f}\N{DEGREE SIGN}, '
                     u'{1:.2f}\N{DEGREE SIGN}) </br>' +
                     u'intensity: {2:.2f}').format(np.degrees(y_recon),
                                                   np.degrees(x_recon),
                                                   amplitude_recon)
                ]

            trace3 = go.Scatter(mode='markers',
                                name='reconstruction',
                                x=[np.degrees(x_recon)],
                                y=[np.degrees(y_recon)],
                                text=text_str3,
                                hoverinfo='name+text',
                                marker=dict(size=6,
                                            symbol='diamond',
                                            opacity=0.6,
                                            line=dict(color='rgb(0, 0, 0)',
                                                      width=1),
                                            color='rgb(255, 105, 180)'))

    if ref_pt_available and recon_pt_available:
        data = go.Data([trace1, trace2, trace3])
    elif ref_pt_available and not recon_pt_available:
        data = go.Data([trace1, trace2])
    elif not ref_pt_available and recon_pt_available:
        data = go.Data([trace1, trace3])
    else:
        data = go.Data([trace1])

    if ref_pt_available and recon_pt_available:
        dist_recon = planar_distance(x_ref, y_ref, x_recon, y_recon)[0]
        layout = go.Layout(
            title=u'average error = {0:.2f}\N{DEGREE SIGN}'.format(
                np.degrees(dist_recon)),
            titlefont={
                'family': 'Open Sans, verdana, arial, sans-serif',
                'size': 14,
                'color': '#000000'
            },
            autosize=False,
            width=670,
            height=550,
            showlegend=True,
            margin=go.Margin(l=45, r=45, b=55, t=45))
    else:
        layout = go.Layout(title=u'',
                           titlefont={
                               'family':
                               'Open Sans, verdana, arial, sans-serif',
                               'size': 14,
                               'color': '#000000'
                           },
                           autosize=False,
                           width=670,
                           height=550,
                           showlegend=True,
                           margin=go.Margin(l=45, r=45, b=55, t=45))

    if ref_pt_available or recon_pt_available:
        layout['legend']['xanchor'] = 'center'
        layout['legend']['yanchor'] = 'top'
        layout['legend']['x'] = 0.5

    layout['scene']['camera']['eye'] = {'x': 0, 'y': 0}

    fig = go.Figure(data=data, layout=layout)
    plot(fig, filename=file_name, auto_open=open_browser)
Example #3
0
def planar_plot_diracs(x_plt_grid,
                       y_plt_grid,
                       x_ref=None,
                       y_ref=None,
                       amplitude_ref=None,
                       x_recon=None,
                       y_recon=None,
                       amplitude_recon=None,
                       max_amp_ref=None,
                       max_amp=None,
                       cmap='magma_r',
                       background_img=None,
                       marker_scale=1,
                       marker_alpha=0.6,
                       save_fig=False,
                       file_name='sph_recon_2d_dirac',
                       xticklabels=None,
                       yticklabels=None,
                       reverse_xaxis=True,
                       label_ref_sol='ground truth',
                       label_recon='reconstruction',
                       legend_loc=0,
                       file_format='pdf',
                       dpi=300,
                       close_fig=True,
                       has_title=True,
                       title_str=None):
    """
    plot the reconstructed point sources with basemap module
    :param y_ref: ground truth colatitudes of the Dirac
    :param x_ref: ground truth azimuths of the Dirac
    :param amplitude_ref: ground truth amplitudes of the Dirac
    :param y_recon: reconstructed colatitudes of the Dirac
    :param x_recon: reconstructed azimuths of the Dirac
    :param amplitude_recon: reconstructed amplitudes of the Dirac
    :param lon_0: center of the projection (longitude) <- azimuth
    :param lat_0: center of the projection (latitude) <- pi/2 - co-latitude
    :param save_fig: whether to save figure or not
    :param file_name: figure file name (basename)
    :param file_format: format of the saved figure file
    :return:
    """
    if y_ref is not None and x_ref is not None and amplitude_ref is not None:
        ref_pt_available = True
    else:
        ref_pt_available = False

    if y_recon is not None and x_recon is not None and amplitude_recon is not None:
        recon_pt_available = True
    else:
        recon_pt_available = False

    # plot
    x_plt_grid_degree = np.degrees(x_plt_grid)
    y_plt_grid_degree = np.degrees(y_plt_grid)
    if background_img is not None:
        # cmap = sns.cubehelix_palette(dark=0.95, light=0.1, reverse=True,
        #                              start=1, rot=-0.6, as_cmap=True)
        # cmap = sns.cubehelix_palette(dark=0.95, light=0.1, reverse=True,
        #                              start=0.3, rot=-0.6, as_cmap=True)
        # cmap = 'cubehelix_r'  # 'Spectral_r'  # 'BuPu'
        # move the plotting area slight up
        ax = plt.figure(figsize=(5, 4), dpi=dpi).add_subplot(111)
        pos_original = ax.get_position()
        pos_new = [
            pos_original.x0, pos_original.y0 + 0.01, pos_original.width,
            pos_original.height
        ]
        ax.set_position(pos_new)
        plt.pcolormesh(x_plt_grid_degree,
                       y_plt_grid_degree,
                       background_img,
                       shading='gouraud',
                       cmap=cmap)

    if ref_pt_available:
        if max_amp_ref is not None:
            amplitude_ref_rescaled = amplitude_ref / max_amp_ref
        else:
            amplitude_ref_rescaled = amplitude_ref / np.max(amplitude_ref)

        plt.scatter(np.degrees(x_ref),
                    np.degrees(y_ref),
                    s=amplitude_ref_rescaled * 350 * marker_scale,
                    marker='^',
                    edgecolors='k',
                    linewidths=0.5,
                    alpha=marker_alpha,
                    c='w',
                    label=label_ref_sol)

    if recon_pt_available:
        if max_amp is not None:
            amplitude_rescaled = amplitude_recon / max_amp
        else:
            amplitude_rescaled = amplitude_recon / np.max(amplitude_recon)

        plt.scatter(np.degrees(x_recon),
                    np.degrees(y_recon),
                    s=amplitude_rescaled * 600 * marker_scale,
                    marker='*',
                    edgecolors='k',
                    linewidths=0.5,
                    alpha=marker_alpha,
                    c=np.tile([0.996, 0.410, 0.703], (x_recon.size, 1)),
                    label=label_recon)

    if has_title and ref_pt_available and recon_pt_available and title_str is None:
        dist_recon = planar_distance(x_ref, y_ref, x_recon, y_recon)[0]

        # in degree, minute, and second representation
        dist_recon_dms = SkyCoord(
            ra=0, dec=dist_recon,
            unit=units.radian).to_string('dms').split(' ')[1]
        dist_recon_dms = list(filter(None, re.split('[dms]+', dist_recon_dms)))
        dist_recon_dms = ('{0}' + u'\u00B0' + '{1}' + u'\u2032' + '{2:.2f}' +
                          u'\u2033').format(dist_recon_dms[0],
                                            dist_recon_dms[1],
                                            float(dist_recon_dms[2]))

        plt.title(u'average error = {0}'.format(dist_recon_dms), fontsize=11)
    elif has_title and title_str is not None:
        plt.title(title_str, fontsize=11)
    else:
        plt.title(u'', fontsize=11)

    if ref_pt_available or recon_pt_available:
        plt.legend(scatterpoints=1,
                   loc=legend_loc,
                   fontsize=9,
                   ncol=1,
                   markerscale=0.7,
                   handletextpad=0.1,
                   columnspacing=0.1,
                   labelspacing=0.1,
                   framealpha=0.5,
                   frameon=True)

    plt.axis('image')
    plt.xlim((np.min(x_plt_grid_degree), np.max(x_plt_grid_degree)))
    plt.ylim((np.min(y_plt_grid_degree), np.max(y_plt_grid_degree)))

    if xticklabels is not None:
        # set the number of ticks to match the length of the labels
        ''' from matplotlib documentation: "the number of ticks <= nbins +1" '''
        plt.gca().locator_params(axis='x', nbins=len(xticklabels) - 1)
        plt.gca().set_xticklabels(xticklabels, fontsize=9)

    if yticklabels is not None:
        # set the number of ticks to match the length of the labels
        ''' from matplotlib documentation: "the number of ticks <= nbins +1" '''
        plt.gca().locator_params(axis='y', nbins=len(yticklabels) - 1)
        plt.gca().set_yticklabels(yticklabels, fontsize=9)

    plt.xlabel('RA (J2000)')
    plt.ylabel('DEC (J2000)')

    if reverse_xaxis:
        plt.gca().invert_xaxis()

    if save_fig:
        plt.savefig(filename=(file_name + '.' + file_format),
                    format=file_format,
                    dpi=dpi,
                    transparent=True)

    if close_fig:
        plt.close()
Example #4
0
def planar_plot_diracs_J2000(x_plt_grid,
                             y_plt_grid,
                             RA_focus_rad=0,
                             DEC_focus_rad=0,
                             x_ref=None,
                             y_ref=None,
                             amplitude_ref=None,
                             marker_ref='^',
                             x_recon=None,
                             y_recon=None,
                             amplitude_recon=None,
                             marker_recon='*',
                             max_amp_ref=None,
                             max_amp=None,
                             cmap='magma_r',
                             background_img=None,
                             marker_scale=1,
                             marker_alpha=0.6,
                             legend_marker_scale=0.7,
                             save_fig=False,
                             file_name='sph_recon_2d_dirac',
                             reverse_xaxis=True,
                             label_ref_sol='ground truth',
                             label_recon='reconstruction',
                             legend_loc=0,
                             file_format='pdf',
                             dpi=300,
                             close_fig=True,
                             has_title=True,
                             title_str=None):
    """
    plot the reconstructed point sources in the J2000 coordinates
    :param y_ref: ground truth colatitudes of the Dirac
    :param x_ref: ground truth azimuths of the Dirac
    :param amplitude_ref: ground truth amplitudes of the Dirac
    :param y_recon: reconstructed colatitudes of the Dirac
    :param x_recon: reconstructed azimuths of the Dirac
    :param amplitude_recon: reconstructed amplitudes of the Dirac
    :param lon_0: center of the projection (longitude) <- azimuth
    :param lat_0: center of the projection (latitude) <- pi/2 - co-latitude
    :param save_fig: whether to save figure or not
    :param file_name: figure file name (basename)
    :param file_format: format of the saved figure file
    :return:
    """
    if y_ref is not None and x_ref is not None and amplitude_ref is not None:
        ref_pt_available = True
    else:
        ref_pt_available = False

    if y_recon is not None and x_recon is not None and amplitude_recon is not None:
        recon_pt_available = True
    else:
        recon_pt_available = False

    # convert UVW coordinates to J2000 in [arcmin]
    x_plt_grid_J2000 = x_plt_grid * 180 / np.pi * 60
    y_plt_grid_J2000 = y_plt_grid * 180 / np.pi * 60
    if ref_pt_available:
        x_ref_J2000, y_ref_J2000, z_ref_J2000 = UVW2J2000(
            RA_focus_rad, DEC_focus_rad, x_ref, y_ref, convert_dms=False)[:3]
        RA_ref_J2000 = np.arctan2(y_ref_J2000, x_ref_J2000)
        DEC_ref_J2000 = np.arcsin(z_ref_J2000)

    if recon_pt_available:
        x_recon_J2000, y_recon_J2000, z_recon_J2000 = UVW2J2000(
            RA_focus_rad, DEC_focus_rad, x_recon, y_recon,
            convert_dms=False)[:3]
        RA_recon_J2000 = np.arctan2(y_recon_J2000, x_recon_J2000)
        DEC_recon_J2000 = np.arcsin(z_recon_J2000)

    # plot
    if background_img is not None:
        ax = plt.figure(figsize=(5.5, 4), dpi=dpi).add_subplot(111)
        pos_original = ax.get_position()
        pos_new = [
            pos_original.x0 + 0.06, pos_original.y0 + 0.01, pos_original.width,
            pos_original.height
        ]
        ax.set_position(pos_new)
        plt.pcolormesh(x_plt_grid_J2000,
                       y_plt_grid_J2000,
                       background_img,
                       shading='gouraud',
                       cmap=cmap)

    if ref_pt_available:
        if max_amp_ref is not None:
            amplitude_ref_rescaled = amplitude_ref / max_amp_ref
        else:
            amplitude_ref_rescaled = amplitude_ref / np.max(amplitude_ref)

        plt.scatter(
            RA_ref_J2000 * 180 / np.pi * 60,
            DEC_ref_J2000 * 180 / np.pi * 60,
            s=amplitude_ref_rescaled * 200 * marker_scale,  # 350 for '^'
            marker=marker_ref,
            edgecolors='k',
            linewidths=0.5,
            alpha=marker_alpha,
            c='w',
            label=label_ref_sol)

    if recon_pt_available:
        if max_amp is not None:
            amplitude_rescaled = amplitude_recon / max_amp
        else:
            amplitude_rescaled = amplitude_recon / np.max(amplitude_recon)

        plt.scatter(RA_recon_J2000 * 180 / np.pi * 60,
                    DEC_recon_J2000 * 180 / np.pi * 60,
                    s=amplitude_rescaled * 600 * marker_scale,
                    marker=marker_recon,
                    edgecolors='k',
                    linewidths=0.5,
                    alpha=marker_alpha,
                    c=np.tile([0.996, 0.410, 0.703], (x_recon.size, 1)),
                    label=label_recon)

    if has_title and ref_pt_available and recon_pt_available and title_str is None:
        dist_recon = planar_distance(x_ref, y_ref, x_recon, y_recon)[0]

        # in degree, minute, and second representation
        dist_recon_dms = SkyCoord(
            ra=0, dec=dist_recon,
            unit=units.radian).to_string('dms').split(' ')[1]
        dist_recon_dms = list(filter(None, re.split('[dms]+', dist_recon_dms)))
        dist_recon_dms = ('{0}' + u'\u00B0' + '{1}' + u'\u2032' + '{2:.2f}' +
                          u'\u2033').format(dist_recon_dms[0],
                                            dist_recon_dms[1],
                                            float(dist_recon_dms[2]))

        plt.title(u'average error = {0}'.format(dist_recon_dms), fontsize=11)
    elif has_title and title_str is not None:
        plt.title(title_str, fontsize=11)
    else:
        plt.title(u'', fontsize=11)

    if ref_pt_available or recon_pt_available:
        plt.legend(scatterpoints=1,
                   loc=legend_loc,
                   fontsize=9,
                   ncol=1,
                   markerscale=legend_marker_scale,
                   handletextpad=0.1,
                   columnspacing=0.1,
                   labelspacing=0.1,
                   framealpha=0.5,
                   frameon=True)

    plt.axis('image')
    plt.xlim((np.min(x_plt_grid_J2000), np.max(x_plt_grid_J2000)))
    plt.ylim((np.min(y_plt_grid_J2000), np.max(y_plt_grid_J2000)))
    plt.xlabel('RA (J2000)')
    plt.ylabel('DEC (J2000)')

    if reverse_xaxis:
        plt.gca().invert_xaxis()

    # extract lablels to convert to hmsdms format
    x_tick_loc, _ = plt.xticks()
    y_tick_loc, _ = plt.yticks()

    x_tick_loc = x_tick_loc[1:-1]
    y_tick_loc = y_tick_loc[1:-1]

    # evaluate a uniform grid of the same size
    x_tick_loc = np.linspace(start=x_tick_loc[0],
                             stop=x_tick_loc[-1],
                             num=x_tick_loc.size,
                             endpoint=True)
    y_tick_loc = np.linspace(start=y_tick_loc[0],
                             stop=y_tick_loc[-1],
                             num=y_tick_loc.size,
                             endpoint=True)

    xlabels_hms_all = []
    for label_idx, xlabels_original_loop in enumerate(x_tick_loc):
        xlabels_original_loop = float(xlabels_original_loop)

        xlabels_hms = SkyCoord(
            ra=xlabels_original_loop, dec=0,
            unit=units.arcmin).to_string('hmsdms').split(' ')[0]
        xlabels_hms = list(filter(None, re.split('[hms]+', xlabels_hms)))
        if label_idx == 0:
            xlabels_hms = (u'{0:.0f}h{1:.0f}m{2:.0f}s').format(
                float(xlabels_hms[0]), float(xlabels_hms[1]),
                float(xlabels_hms[2]))
        else:
            xlabels_hms = (u'{0:.0f}m{1:.0f}s').format(float(xlabels_hms[1]),
                                                       float(xlabels_hms[2]))

        xlabels_hms_all.append(xlabels_hms)

    ylabels_dms_all = []
    for label_idx, ylabels_original_loop in enumerate(y_tick_loc):
        ylabels_original_loop = float(ylabels_original_loop)
        ylabels_dms = SkyCoord(
            ra=0, dec=ylabels_original_loop,
            unit=units.arcmin).to_string('hmsdms').split(' ')[1]
        ylabels_dms = list(filter(None, re.split('[dms]+', ylabels_dms)))
        ylabels_dms = (u'{0:.0f}\u00B0{1:.0f}\u2032').format(
            float(ylabels_dms[0]),
            float(ylabels_dms[1]) + float(ylabels_dms[2]) / 60.)
        ylabels_dms_all.append(ylabels_dms)

    plt.axis('image')
    plt.xlim((np.min(x_plt_grid_J2000), np.max(x_plt_grid_J2000)))
    plt.ylim((np.min(y_plt_grid_J2000), np.max(y_plt_grid_J2000)))
    plt.xticks(x_tick_loc)
    plt.yticks(y_tick_loc)
    plt.gca().set_xticklabels(xlabels_hms_all, fontsize=9)
    plt.gca().set_yticklabels(ylabels_dms_all, fontsize=9)

    if reverse_xaxis:
        plt.gca().invert_xaxis()

    if save_fig:
        plt.savefig(filename=(file_name + '.' + file_format),
                    format=file_format,
                    dpi=dpi,
                    transparent=True)

    if close_fig:
        plt.close()
Example #5
0
                                                    peak_locs[1, :]]

                        # deal with the specific case when only 1 Dirac is reconstructed
                        if not hasattr(clean_xk_recon, '__iter__'):
                            clean_xk_recon = np.array([clean_xk_recon])
                            clean_yk_recon = np.array([clean_yk_recon])
                        # choose only K_est of them in case of over-estimation
                        if clean_xk_recon.size > K_est:
                            amp_sort_idx = np.argsort(clean_amp_recon)[::-1]
                            clean_xk_recon = clean_xk_recon[
                                amp_sort_idx[:K_est]]
                            clean_yk_recon = clean_yk_recon[
                                amp_sort_idx[:K_est]]

                        # compute partial reconstruction error
                        dist_recon_loop, idx_sort = planar_distance(
                            x_ks, y_ks, clean_xk_recon, clean_yk_recon)
                        avg_recon_dist[sep_ind, snr_ind] += dist_recon_loop

                        if len(idx_sort.shape) == 1:
                            clean_xk_recon_sorted = np.array([clean_xk_recon])
                            clean_yk_recon_sorted = np.array([clean_yk_recon])
                            x_ks_sorted = np.array([x_ks[idx_sort[0]]])
                            y_ks_sorted = np.array([y_ks[idx_sort[0]]])
                        else:
                            clean_xk_recon_sorted = clean_xk_recon[idx_sort[:,
                                                                            1]]
                            clean_yk_recon_sorted = clean_yk_recon[idx_sort[:,
                                                                            1]]
                            x_ks_sorted = x_ks[idx_sort[:, 0]]
                            y_ks_sorted = y_ks[idx_sort[:, 0]]
                        theano_build_amp_func=theano_build_amp_func
                    )
            else:
                xk_recon, yk_recon, alpha_k_recon = planar_select_reliable_recon(
                    visi_noisy, r_antenna_x, r_antenna_y, xk_recon, yk_recon,
                    2 * np.pi * freq_subbands_hz, light_speed,
                    partial_beamforming_func, num_station, num_subband, num_sti,
                    removal_blk_len_lst[stages - 1],
                    theano_func=theano_build_amp_func,
                    backend=backend
                )

                if catalog_available:
                    # compute partial reconstruction error
                    dist_recon_stage, idx_sort = \
                        planar_distance(skycatalog_U, skycatalog_V, xk_recon, yk_recon)
                    # in degree, minute, and second representation
                    dist_recon_stage_dms = SkyCoord(
                        ra=0, dec=dist_recon_stage, unit=units.radian
                    ).to_string('dms').split(' ')[1]
                    print('Partial recon error: {0}'.format(dist_recon_stage_dms))

                file_name = (fig_dir + 'planar_K_{0}_numSta_{1}_locations_stage{2}'
                             ).format(repr(K_est), repr(num_station), stages)
                for bg_img in bg_img_lst:
                    planar_plot_diracs_J2000(
                        x_plt, y_plt,
                        RA_focus_rad=sky_ra, DEC_focus_rad=sky_dec,
                        x_ref=skycatalog_U[idx_sort[:, 0]] if catalog_available else None,
                        y_ref=skycatalog_V[idx_sort[:, 0]] if catalog_available else None,
                        amplitude_ref=skycatalog_intensities[idx_sort[:, 0]] if catalog_available else None,