def make_plot3d(x, y, z, title=None, orthogonal_fig=True): cmean = np.mean([x, y, z], axis=1) cmed = np.median([x, y, z], axis=1) ce90 = geolib.CE90(x, y) le90 = geolib.LE90(z) coefs = [ce90, ce90, le90] maxdim = np.ceil(np.max([np.max(np.abs([x, y, z])), ce90, le90])) if orthogonal_fig: from matplotlib.patches import Ellipse fig_ortho = plt.figure(figsize=(10, 4)) #fig_ortho = plt.figure() title = 'Co-registration Translation Vector Components\nn=%i, mean: (%0.2f, %0.2f, %0.2f)\nCE90: %0.2f, LE90: %0.2f' % ( x.shape[0], cmean[0], cmean[1], cmean[2], ce90, le90) plt.suptitle(title) m = '.' ax = fig_ortho.add_subplot(131) ax.plot(x, y, color='b', linestyle='None', marker=m, label='ICP correction vector') ax.plot(cmean[0], cmean[1], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(x, y) #ax.scatter(cmean[0], cmean[1], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('X offset (m)') ax.set_ylabel('Y offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * ce90, linewidth=0, alpha=0.1) ax.add_artist(e) plt.legend(prop={'size': 8}, numpoints=1, loc='upper left') ax = fig_ortho.add_subplot(132) ax.plot(x, z, color='b', linestyle='None', marker=m, label='ICP correction vector') ax.plot(cmean[0], cmean[2], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(x, z) #ax.scatter(cmean[0], cmean[2], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('X offset (m)') ax.set_ylabel('Z offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * le90, linewidth=0, alpha=0.1) ax.add_artist(e) ax = fig_ortho.add_subplot(133) ax.plot(y, z, color='b', linestyle='None', marker=m, label='ICP correction vector') ax.plot(cmean[1], cmean[2], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(y, z) #ax.scatter(cmean[1], cmean[2], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('Y offset (m)') ax.set_ylabel('Z offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * le90, linewidth=0, alpha=0.1) ax.add_artist(e) plt.tight_layout() #Note: postscript doesn't properly handle tansparency #fig_fn = 'icp_translation_vec_proj_meters_orthogonal.pdf' fig_fn = 'icp_translation_vec_local_meters_orthogonal.pdf' plt.savefig(fig_fn, dpi=600, bbox_inches='tight')
def make_plot3d(x, y, z, title=None, orthogonal_fig=True): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.set_aspect('equal') ax.set_xlabel('X offset (m)') ax.set_ylabel('Y offset (m)') ax.set_zlabel('Z offset (m)') if title is not None: plt.suptitle(title) ax.plot(x, y, z, 'o') cmean = np.mean([x,y,z], axis=1) cmed = np.median([x,y,z], axis=1) ax.scatter(cmean[0], cmean[1], cmean[2], color='r', marker='s') ce90 = geolib.CE90(x,y) le90 = geolib.LE90(z) coefs = [ce90, ce90, le90] ax.set_title("CE90: %0.2f, LE90: %0.2f, n=%i" % (ce90, le90, x.shape[0])) maxdim = np.ceil(np.max([np.max(np.abs([x, y, z])), ce90, le90])) ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.set_zlim(-maxdim, maxdim) rx, ry, rz = coefs u = np.linspace(0, 2 * np.pi, 100) v = np.linspace(0, np.pi, 100) ex = rx * np.outer(np.cos(u), np.sin(v)) ey = ry * np.outer(np.sin(u), np.sin(v)) ez = rz * np.outer(np.ones_like(u), np.cos(v)) ax.plot_surface(ex, ey, ez, rstride=2, cstride=2, linewidth=0, color='b', alpha=0.1) #max_radius = max(rx, ry, rz) #for axis in 'xyz': # getattr(ax, 'set_{}lim'.format(axis))((-max_radius, max_radius)) if orthogonal_fig: from matplotlib.patches import Ellipse fig_ortho = plt.figure(figsize=(10,4)) #fig_ortho = plt.figure() title='ICP Alignment Translation Vectors\nn=%i, mean: (%0.2f, %0.2f, %0.2f)\nCE90: %0.2f, LE90: %0.2f' % (x.shape[0], cmean[0], cmean[1], cmean[2], ce90, le90) plt.suptitle(title) ax = fig_ortho.add_subplot(131) ax.plot(x, y, color='b', linestyle='None', marker='o', label='ICP correction vector') ax.plot(cmean[0], cmean[1], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(x, y) #ax.scatter(cmean[0], cmean[1], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('X offset (m)') ax.set_ylabel('Y offset (m)') e = Ellipse((0,0), 2*ce90, 2*ce90, linewidth=0, alpha=0.1) ax.add_artist(e) plt.legend(prop={'size':8}, numpoints=1, loc='upper left') ax = fig_ortho.add_subplot(132) ax.plot(x, z, color='b', linestyle='None', marker='o', label='ICP correction vector') ax.plot(cmean[0], cmean[2], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(x, z) #ax.scatter(cmean[0], cmean[2], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('X offset (m)') ax.set_ylabel('Z offset (m)') e = Ellipse((0,0), 2*ce90, 2*le90, linewidth=0, alpha=0.1) ax.add_artist(e) ax = fig_ortho.add_subplot(133) ax.plot(y, z, color='b', linestyle='None', marker='o', label='ICP correction vector') ax.plot(cmean[1], cmean[2], color='r', linestyle='None', marker='s', label='Mean') #ax.scatter(y, z) #ax.scatter(cmean[1], cmean[2], color='r', marker='s') ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') ax.set_xlabel('Y offset (m)') ax.set_ylabel('Z offset (m)') e = Ellipse((0,0), 2*ce90, 2*le90, linewidth=0, alpha=0.1) ax.add_artist(e) plt.tight_layout() #Note: postscript doesn't properly handle tansparency #fig_fn = 'icp_translation_vec_proj_meters_orthogonal.pdf' fig_fn = 'icp_translation_vec_local_meters_orthogonal.pdf' plt.savefig(fig_fn, dpi=600, bbox_inches='tight') #Set back to original figure plt.figure(fig.number)
def main(): #filenames = !ls *align/*reference-DEM.tif #run ~/src/demtools/error_analysis.py $filenames.s if len(sys.argv) < 1: sys.exit('No input files provided') fn_list = sys.argv[1:] n_samp = len(fn_list) error_dict_list = [] for fn in fn_list: ed = parse_pc_align_log(fn) if 'Translation vector (North-East-Down, meters)' in ed.keys(): error_dict_list.append(ed) import matplotlib.dates as mdates #This is used for interactive display of x-value in plot window date_str = '%Y-%m-%d %H:%M' date_fmt = mdates.DateFormatter(date_str) #ax.fmt_xdata = mdates.DateFormatter(date_fmt) months = mdates.MonthLocator() months_int = mdates.MonthLocator(interval=6) # every n months years = mdates.YearLocator() # every year yearsFmt = mdates.DateFormatter('%Y') #ax.xaxis.set_major_formatter(yearsFmt) #ax.xaxis.set_major_locator(months_int3) print print "n:", len(error_dict_list) """ #ECEF translations #key = 'Translation vector (ECEF meters)' key = 'Translation vector (Cartesian, meters)' #key = 'Translation vector (meters)' val = np.array([e[key] for e in error_dict_list]) #make_plot3d(val[:,0], val[:,1], val[:,2], title=key) ce90 = geolib.CE90(val[:,0], val[:,1]) le90 = geolib.LE90(val[:,2]) print print key print "CE90:", ce90 print "LE90:", le90 print #Proj translation key = 'Translation vector (Proj meters)' val = np.array([e[key] for e in error_dict_list]) ce90 = geolib.CE90(val[:,0], val[:,1]) le90 = geolib.LE90(val[:,2]) print print key print "CE90:", ce90 print "LE90:", le90 print print 'Centroid (mean) of offsets (Proj meters): ', np.mean(val, axis=0) print 'Centroid (median) of offsets (Proj meters): ', np.median(val, axis=0) """ #NOTE: changed default to N-E-D on 9/18/15 #Can have significant differences for local proj vs. polar stereographic proj #Should regenerate all previous figures #Local translation on ellipsoid #This appears to be local stereographic projection on ellipsoid key = 'Translation vector (North-East-Down, meters)' val = np.array([e[key] for e in error_dict_list]) #Reformat (n, e, +d) for (x, y, +z) coord sys val[:,[0,1]] = val[:,[1,0]] val[:,2] *= -1 ce90 = geolib.CE90(val[:,0], val[:,1]) le90 = geolib.LE90(val[:,2]) print print key print "CE90:", ce90 print "LE90:", le90 print print 'Centroid (mean) of offsets (local ned meters): ', np.mean(val, axis=0) print 'Centroid (median) of offsets (local ned meters): ', np.median(val, axis=0) #Remove vertical bias remove_vertbias = False if remove_vertbias: print "Removing vertical bias: %0.2f" % np.mean(val, axis=0)[2] val[:,2] -= np.mean(val, axis=0)[2] remove_outliers = False #Flag outliers x_mag = val[:,0] y_mag = val[:,1] h_mag = np.sqrt(val[:,0]**2 + val[:,1]**2) v_mag = val[:,2] mag = np.sqrt(val[:,0]**2 + val[:,1]**2 + val[:,2]**2) abs_thresh = 10.0 p = 98.0 p_thresh = np.percentile(h_mag, p) #print "Outliers with horiz error >= %0.2f (%0.1f%%)" % (p_thresh, p) print "Outliers:" #idx = (h_mag >= p_thresh).nonzero()[0] idx = (h_mag >= ce90).nonzero()[0] idx = np.unique(np.hstack([idx, ((np.abs(v_mag) >= le90).nonzero()[0])])) #Print all #idx = np.arange(h_mag.size) #idx_sort = np.argsort(mag[idx]) #idx = idx[idx_sort] print 'name, m, h, v, x, y, z' for i in idx: print error_dict_list[i]['File'], mag[i], h_mag[i], v_mag[i], val[i,0:3] #Delete from list if remove_outliers: print "Removing from calculation" del error_dict_list[i] if remove_vertbias or remove_outliers: print print "Updated values" print key print "CE90:", geolib.CE90(val[:,0], val[:,1]) print "LE90:", geolib.LE90(val[:,2]) print print 'Centroid (mean) of offsets (local ned meters): ', np.mean(val, axis=0) print 'Centroid (median) of offsets (local ned meters): ', np.median(val, axis=0) #Extract dates date_vec = np.array([e['Date'] for e in error_dict_list]) x = date_vec make_plot3d(val[:,0], val[:,1], val[:,2], title=key) #Note: there is a bug in pdf that displayes surface lines #fig_fn = 'icp_translation_vec_proj_meters.png' fig_fn = 'icp_translation_vec_local_meters.png' #plt.savefig(fig_fn, dpi=600, bbox_inches='tight') fig, ax = plt.subplots(1) key = 'Translation vector (lat,lon,z)' plt.title('ICP translation vector (lat,lon,z): Z component') val = np.array([e[key] for e in error_dict_list]) y = val[:,2] make_plot(x,y,c='b',label=key, abs=False) fig.autofmt_xdate() ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('Z offset (m)') fig, ax = plt.subplots(1) key = 'Translation vector magnitude (meters)' plt.title('ICP Translation vector magnitude (meters)') y = np.array([e[key] for e in error_dict_list]) make_plot(x,y,c='b',label=key, abs=True) fig.autofmt_xdate() ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('Offset (m)') fig, ax = plt.subplots(1) key = 'Number of errors' plt.title('Number of error samples') nerr = np.array([e[key] for e in error_dict_list]) make_plot(x,nerr,c='b',label=key) fig.autofmt_xdate() ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('N samples') """ fig, ax = plt.subplots(1) plt.title('ICP Standard Deviation') key = 'Input Std Error' in_std = np.array([e[key] for e in error_dict_list]) make_plot(x,in_std,c='r',label=key) key = 'Output Std Error' out_std = np.array([e[key] for e in error_dict_list]) make_plot(x,out_std,c='b',label=key) fig.autofmt_xdate() ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt plt.legend(scatterpoints=1) """ fig, ax = plt.subplots(1) plt.title('ICP Mean Error') key = 'Input Mean Error' in_mean = np.array([e[key] for e in error_dict_list]) #make_plot(x,in_mean,c='r',label=key,yerr=in_std) make_plot(x,in_mean,c='r',label=key, abs=True) key = 'Output Mean Error' out_mean = np.array([e[key] for e in error_dict_list]) #make_plot(x,out_mean,c='b',label=key,yerr=out_std) make_plot(x,out_mean,c='b',label=key, abs=True) fig.autofmt_xdate() ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('Mean error (m)') plt.legend(scatterpoints=1, loc='upper left', prop={'size':8}) fig, ax = plt.subplots(1) plt.title('ICP Median Error') key = 'Input 16th Percentile Error' in_16p = np.array([e[key] for e in error_dict_list]) key = 'Input 84th Percentile Error' in_84p = np.array([e[key] for e in error_dict_list]) key = 'Input Median Error' in_med = np.array([e[key] for e in error_dict_list]) make_plot(x,in_med,c='r',label=key,yerr=[in_med - in_16p, in_84p - in_med], abs=True) key = 'Output 16th Percentile Error' out_16p = np.array([e[key] for e in error_dict_list]) key = 'Output 84th Percentile Error' out_84p = np.array([e[key] for e in error_dict_list]) key = 'Output Median Error' out_med = np.array([e[key] for e in error_dict_list]) make_plot(x,out_med,c='b',label=key,yerr=[out_med - out_16p, out_84p - out_med], abs=True) fig.autofmt_xdate() ax.fmt_xdata = mdates.DateFormatter(date_fmt) ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('Median error (m)') plt.legend(scatterpoints=1, loc='upper left', prop={'size':8}) fig_fn = 'icp_median_error.pdf' plt.savefig(fig_fn, dpi=600, bbox_inches='tight') fig, ax = plt.subplots(1) plt.title('Sampled Median Error') key = 'Input Sampled 16th Percentile Error' in_16p = np.ma.fix_invalid([e[key] for e in error_dict_list]) if in_16p.count() > 0: key = 'Input Sampled 84th Percentile Error' in_84p = np.ma.fix_invalid([e[key] for e in error_dict_list]) key = 'Input Sampled Median Error' in_med = np.ma.fix_invalid([e[key] for e in error_dict_list]) in_spread = in_84p - in_16p make_plot(x,in_med,c='r',label=key,yerr=[in_med - in_16p, in_84p - in_med], abs=True) key = 'Output Sampled 16th Percentile Error' out_16p = np.ma.fix_invalid([e[key] for e in error_dict_list]) key = 'Output Sampled 84th Percentile Error' out_84p = np.ma.fix_invalid([e[key] for e in error_dict_list]) key = 'Output Sampled Median Error' out_med = np.ma.fix_invalid([e[key] for e in error_dict_list]) out_spread = out_84p - out_16p p = 90.0 out_med_thresh = np.percentile(out_med, p) out_spread_thresh = np.percentile(out_spread, p) #print "Outliers with horiz error >= %0.2f (%0.1f%%)" % (p_thresh, p) print print "Sampled Error Outliers:" #idx = (h_mag >= p_thresh).nonzero()[0] idx = (out_med >= out_med_thresh).nonzero()[0] idx = np.unique(np.hstack([idx, ((out_spread >= out_spread_thresh).nonzero()[0])])) #Print all idx = np.arange(out_med.size) idx_sort = np.argsort(out_med[idx]) idx = idx[idx_sort] print 'name, samp_mederrr, samp_errspread, nerr' for i in idx: print error_dict_list[i]['File'], out_med[i], out_spread[i], nerr[i] #Delete from list if remove_outliers: print "Removing from calculation" del error_dict_list[i] print print 'Input sampled median error (spread/2): %0.2f (%0.2f)' % (np.median(in_med), np.median(in_spread)/2.) print 'Output sampled median error (spread/2): %0.2f (%0.2f)' % (np.median(out_med), np.median(out_spread)/2.) print make_plot(x,out_med,c='b',label=key,yerr=[out_med - out_16p, out_84p - out_med], abs=True) fig.autofmt_xdate() ax.set_ylabel('Median error (m)') ax.fmt_xdata = mdates.DateFormatter(date_fmt) ax.xaxis.set_minor_locator(months) #ax.xaxis.set_major_locator(months_int) #ax.xaxis.set_major_formatter(date_fmt) ax.fmt_xdata = date_fmt ax.set_ylabel('Median error (m)') plt.legend(scatterpoints=1, loc='upper left', prop={'size':8}) ax.set_ylim(-15,15) fig_fn = 'sampled_median_error.pdf' #fig_fn = 'sampled_median_error_2014-2016.pdf' #from datetime import datetime #ax.set_xlim(datetime(2014,1,1),datetime(2016,7,1)) plt.savefig(fig_fn, dpi=600, bbox_inches='tight')
def make_plot3d(x, y, z, title=None, orthogonal_fig=True): cmean = np.mean([x, y, z], axis=1) cstd = np.std([x, y, z], axis=1) cmed = np.median([x, y, z], axis=1) cnmad = malib.mad([x, y, z], axis=1) x_corr = x - cmean[0] y_corr = y - cmean[1] z_corr = z - cmean[2] ce90 = geolib.CE90(x, y) ce90_corr = geolib.CE90(x_corr, y_corr) le90 = geolib.LE90(z) le90_corr = geolib.LE90(z_corr) coefs = [ce90, ce90, le90] #maxdim = np.ceil(np.max([np.max(np.abs([x, y, z])), ce90, le90])) maxdim = np.ceil(np.max([np.percentile(np.abs([x, y, z]), 99), ce90, le90])) if orthogonal_fig: from matplotlib.patches import Ellipse #fig_ortho, axa = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(10,5)) fig_ortho, axa = plt.subplots(1, 3, figsize=(10, 5)) title = 'Co-registration Translation Vector Components, n=%i\n' % x.shape[ 0] title += 'mean: (%0.2f, %0.2f, %0.2f), std: (%0.2f, %0.2f, %0.2f)\n' % ( tuple(cmean) + tuple(cstd)) title += 'med: (%0.2f, %0.2f, %0.2f), nmad: (%0.2f, %0.2f, %0.2f)\n' % ( tuple(cmed) + tuple(cnmad)) title += 'CE90: %0.2f (Bias-corrected: %0.2f), LE90: %0.2f (Bias-corrected: %0.2f)' % ( ce90, ce90_corr, le90, le90_corr) plt.suptitle(title) dot_prop = { 'color': 'k', 'linestyle': 'None', 'marker': '.', 'ms': 3, 'label': 'ICP correction vector', 'alpha': 0.5 } mean_prop = { 'color': 'r', 'linestyle': 'None', 'marker': 'o', 'label': 'Mean' } for ax in axa: ax.set_xlim(-maxdim, maxdim) ax.set_ylim(-maxdim, maxdim) ax.minorticks_on() ax.set_aspect('equal') axa[0].plot(x, y, **dot_prop) axa[0].plot(cmean[0], cmean[1], **mean_prop) axa[0].set_xlabel('X offset (m)') axa[0].set_ylabel('Y offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * ce90, linewidth=0, alpha=0.1) axa[0].add_artist(e) axa[0].legend(prop={'size': 8}, numpoints=1, loc='upper left') axa[1].plot(x, z, **dot_prop) axa[1].plot(cmean[0], cmean[2], **mean_prop) axa[1].set_xlabel('X offset (m)') axa[1].set_ylabel('Z offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * le90, linewidth=0, alpha=0.1) axa[1].add_artist(e) axa[2].plot(y, z, **dot_prop) axa[2].plot(cmean[1], cmean[2], **mean_prop) axa[2].set_xlabel('X offset (m)') axa[2].set_ylabel('Z offset (m)') e = Ellipse((0, 0), 2 * ce90, 2 * le90, linewidth=0, alpha=0.1) axa[2].add_artist(e) plt.tight_layout() #Note: postscript doesn't properly handle tansparency fig_fn = '%s_translation_vec_local_meters_orthogonal.pdf' % out_fn_prefix plt.savefig(fig_fn, dpi=600, bbox_inches='tight')