def test_fit_pole_noisy(self): np.random.seed(1) for strike in range(0, 370, 10): for dip in range(0, 100, 10): lon, lat = mplstereonet.pole(strike, dip) lon = lon + np.radians(np.random.normal(0, 1, 100)) lat = lat + np.radians(np.random.normal(0, 1, 100)) s_noisy, d_noisy = mplstereonet.geographic2pole(lon, lat) s, d = mplstereonet.fit_pole(s_noisy, d_noisy) ang_dist = self.cos_distance(strike, dip, s, d) assert ang_dist < 2 or (180 - ang_dist) < 2
def test_fit_pole(self): np.random.seed(1) for strike in range(0, 370, 10): for dip in range(0, 100, 10): s, d = mplstereonet.fit_pole([strike], [dip]) self.compare_strikedip(strike, dip, s, d)
def plotMultiPlanes(self, structures, **kwds): #get the dataset dataset = kwds.get("data", [self.dataDict]) #split into structure types structure_data = [self.filterByName(regx) for regx in structures] #get drawing kwds symbols = kwds.get("symbols", ['.'] * len(structure_data)) cols = kwds.get("colours", ['k'] * len(structure_data)) contours = kwds.get("contours", ["None"] * len(structure_data)) cmaps = kwds.get("cmap", ["Blues"] * len(structure_data)) size = kwds.get("marker_size", [6] * len(structure_data)) alphas = kwds.get("alphas", [0.75] * len(structure_data)) values = kwds.get("values", None) showCMaps = kwds.get("showCMaps", True) mean = kwds.get("mean", [False] * len(structure_data)) models = kwds.get("models", [None] * len(structure_data)) outlier_thresh = kwds.get("outlier_thresh", [None] * len(structure_data)) #length of all arrays should match assert len(structure_data) == len( symbols), "Error - symbols array is the incorrect length." assert len(structure_data) == len( cols), "Error - symbols cols is the incorrect length." assert len(structure_data) == len( contours), "Error - contours array is the incorrect length." assert len(structure_data) == len( cmaps), "Error - cmaps array is the incorrect length." assert len(structure_data) == len( size), "Error - size array is the incorrect length." assert len(structure_data) == len( alphas), "Error - alphas array is the incorrect length." assert len(structure_data) == len( mean), "Error - mean array is the incorrect length." assert len(structure_data) == len( models), "Error - models array is the incorrect length." assert len(structure_data) == len( outlier_thresh ), "Error - outlier_thresh array is the incorrect length." if values != None: assert len(structure_data) == len(values) #init plot fig = plt.figure() ax = fig.add_subplot(111, projection='stereonet') cax = [] #plot each structure type for i, data in enumerate(structure_data): #init orientations lists strikes = [] dips = [] x = [] y = [] #loop through data finding plane objects for o in data: planes = self.filterByKey('PLANE', data=o) for p in planes: strikes += [ float(p['DipDir']) - 90 ] #n.b. we use this to avoid ambiguity in strike direction (though Compass uses british RHR) dips += [float(p['Dip'])] x += [float(p['Cx'])] y += [float(p['Cy'])] strikes = np.array(strikes) dips = np.array(dips) x = np.array(x) y = np.array(y) #outlier detection? out_mask = np.array([True] * len(strikes)) #default is all outliers if models[i] != None and outlier_thresh[ i] != None: #do we have enough info to determine outliers? print("\tComputing outliers for threshold %d" % outlier_thresh[i]) strike_pred = models[i].predict(np.stack( [x, y]).T) #generate predicted values given the model diff = models[i].loss( strikes, strike_pred ) #calculate the difference between predicted and observed out_mask = diff > outlier_thresh[ i] #define outliers (boolean array) in_mask = np.logical_not(out_mask) #calculate inliers #plot poles #ax.pole(strikes[out_mask], dips[out_mask], symbols[i], markersize=size[i], color=cols[i], alpha=alphas[i]) #ax.pole(strikes[in_mask], dips[in_mask], '^', markersize=size[i], color=cols[i], alpha=alphas[i]) ax.pole(strikes, dips, symbols[i], markersize=size[i], color=cols[i], alpha=alphas[i]) #plot model? if models[i] != None and outlier_thresh[i] != None: #calculate centroid of inlier points cx = np.mean(x[in_mask]) cy = np.mean(y[in_mask]) #calculate expected strike given this point strike_pred = models[i].predict(np.stack([[cx], [cy]]).T)[0] #plot domain ax.plane( strike_pred - outlier_thresh[i] + 90, 90, '--', c='gray' ) #n.b. + 90 as we are mapping the domain of poles not the actual planes! ax.plane(strike_pred + outlier_thresh[i] + 90, 90, '--', c='gray') #plot radial line ax.plane(strike_pred, 90, '-', c='gray') #plot contours? if contours[i] == "Line": if (values == None): cax.append( ax.density_contour(strikes, dips, measurement='poles', cmap=cmaps[i], sigma=2)) else: cax.append( ax.density_contour(strikes, dips, levels=values[i], measurement='poles', cmap=cmaps[i], sigma=2)) if showCMaps: fig.colorbar(cax[-1]) if contours[i] == "Filled": if (values == None): cax.append( ax.density_contourf(strikes, dips, measurement='poles', cmap=cmaps[i], sigma=2)) else: cax.append( ax.density_contourf(strikes, dips, levels=values[i], measurement='poles', cmap=cmaps[i], sigma=2)) if showCMaps: fig.colorbar(cax[-1]) #plot n-observations xloc = 0.95 yloc = -0.04 + 0.032 * i ax.text(xloc, yloc, "n=%d" % len(strikes), color=cols[i], transform=ax.transAxes, ha='left', va='center') #calculate mean? if mean[i] == True: if len(strikes) > 0: strike, dip = mplstereonet.fit_pole(strikes, dips, measurement='poles') ax.plane(strike, dip, cols[i]) #plot outcrop orientation to give indication of uncertainty/outcrop bias if (kwds.get("show_outcrop", False)): #list to store normals in normals = [[], [], []] #[x-coords, y-coords, z-coords] #loop through trace datasets for o in dataset: traces = self.filterByKey('TRACE', data=o) for t in traces: #does this trace have normals? if t['POINTS']['@normals'] == "True": #extract normal coords normals[0] += list( map(float, t['POINTS']['nx'].split(","))) normals[1] += list( map(float, t['POINTS']['ny'].split(","))) normals[2] += list( map(float, t['POINTS']['nz'].split(","))) #plot normals as contours plunge, bearing = mplstereonet.vector2plunge_bearing( normals[0], normals[1], normals[2]) cax = ax.density_contour(plunge, bearing, measurement='lines', cmap="winter") fig.colorbar(cax) #draw grid ax.set_xticks([x / (2 * np.pi) for x in range(-180, 180, 45)]) ax.set_yticks([x / (2 * np.pi) for x in range(-180, 180, 45)]) ax.grid() return fig, ax, cax