def main(): """Plot the timestack.""" # load the dataset ds = xr.open_dataset(args.input[0]) # extract variables secs = ellapsedseconds(pd.to_datetime( ds["time"].values).to_pydatetime()) x = ds["distance"].values z = ds["eta"].values # plot fig, ax = plt.subplots(figsize=(12, 5)) ax.set_axisbelow(False) m = ax.pcolormesh(secs, x, z.T, vmin=0, vmax=0.3) cb = plt.colorbar(m, aspect=15) cb.set_label("Surface elevation [m]") ax.grid(ls="--", lw=1, color="w") ax.set_ylabel("Distance [m]") ax.set_xlabel("Time [m]") sns.despine(ax=ax) fig.tight_layout() plt.savefig(args.input[0].replace(".nc", ".png")) plt.close()
def detect_breaking_events(time, crx_dist, rgb, crx_start=None, crx_end=None, px_mtrc="lightness", colours=None, resample_rule="100L", algorithm="peaks", peak_detection="local_maxima", posterize=False, ncolours=0, threshold=0.1, tswindow=11, denoise=True, pxwindow=3, mask_drysand=False, fix_constrast=False): """ Detect wave breaking events. Two main methods are implemented: 1 - Peak detection: detect wave breaking as lightness peaks in the timestack Two peak detection methods are implemented: 1-a Local maxima. Uses peaklocalextremas() function from pywavelearn to detect local maximas corresponding to wave breaking. 1-b Differential. Uses the first temporal derivative of the pixel intensity to detect sharp transitions in the timestack that should correspond to wave breaking. In both cases, the user can tell to the script to classifiy the identified pixel peaks based on known colours. For exemple, water is usually blue, sand is brownish and breaking waves are whiteish. Only peaks corresponding to wave breakin are append to the output structure. This is step done using classifiy_colour() from pywavelearn. 2 - Edge detection: detect wave breaking as sharp edges in the timestack Two-options are available: 2-a Edges only. Wave breaking events are obtained applying a sobel filter to the timestack. Edge locations (time,space) are obrained as: - argument of the maxima (argmax) of a cross-shore pixel intenstiy series obtained at every timestamp. - local maximas of a cross-shore pixel intenstiy series obtained at every timestamp. 2-b Edges and colours. Wave breaking events are obtained applying a Sobel filter to the timestack and the detected Edges are classified using the colour information as in 1-a. Edge locations (time,space) are obrained as: - argument of the maxima (argmax) of a cross-shore pixel intenstiy series obtained at every timestamp. - local maximas of a cross-shore pixel intenstiy series obtained at every timestamp. ---------- Args: time (Mandatory [np.array]): Array of datetimes. crx_dist (Mandatory [np.array]): Array of cross-shore locations. rgb (Mandatory [np.array]): timestack array. Shape is [time,crx_dist,3]. crx_start (Optional [float]): where in the cross-shore orientation to start the analysis. Default is crx_dist.min(). crx_start (Optional [float]): where in the cross-shore orientation to finish the analysis. Default is crx_dist.max(). px_mtrc (Optional [float]): Which pixel intenstiy metric to use. Default is "lightness". resample_rule (Optional [str]): To which frequency interpolate timeseries Default is "100L". algorithm (Optional [str]): Wave breaking detection algorithm. Default is "peaks". peak_detection (Optional [str]): Peak detection algorithm. Default is "local_maxima". threshold (Optional [float]): Threshold for peak detection algorithm. Default is 0.1 tswindow (Optional [int]): Window for peak detection algorithm. Default is 11. denoise (Optional [bool]): = Denoise timestack using denoise_bilateral Default is True. pxwindow (Optional [int]): Window for denoise_bilateral. Default is 3. posterize (Optional [bool]): If true will reduce the number of colours in the timestack. Default is False. ncolours (Optional [str]): Number of colours to posterize. Default is 16. colours (Optional [dict]): A dictionary for the colour learning step. Something like: train_colours = {'labels':[0,1,2], 'aliases': ["sand","water","foam"], 'rgb':[[195,185,155], [30,75,75], [255,255,255]] 'target':2} Default is None. mask_drysand (Experimental [bool]) = Mask dry sand using a colour-temperature (CCT) relationship. Default is False. ---------- Return: time (Mandatory [np.array]): time of occurance of wave breaking events. breakers (Mandatory [np.array]): cross-shore location of wave breaking events. """ if not crx_start: crx_start = crx_dist.min() crx_end = crx_dist.max() if posterize: print(" + >> posterizing") rgb = colour_quantization(rgb, ncolours=ncolours) # get colour data if algorithm == "colour" or algorithm == "edges_and_colour": target = colours["target"] labels = colours["labels"] dom_colours = colours["rgb"] # denoise a little bedore computing edges if denoise: rgb = denoise_bilateral(rgb, pxwindow, multichannel=True) # scale back to 0-255 rgb = (rgb - rgb.min()) / (rgb.max() - rgb.min()) * 255 # mask sand - Not fully tested if mask_drysand: print(" + >> masking dry sand [Experimental]") # calculate colour temperature cct = colour.xy_to_CCT_Hernandez1999( colour.XYZ_to_xy(colour.sRGB_to_XYZ(rgb / 255))) # scale back to 0-1 cct = (cct - cct.min()) / (cct.max() - cct.min()) * 255 # mask i, j = np.where(cct == 0) rgb[i, j, :] = 0 if fix_constrast: print(" + >> fixing contrast") rgb = exposure.equalize_hist(rgb) # rgb = (rgb-rgb.min())/(rgb.max()-rgb.min())*255 # detect edges if algorithm == "edges" or algorithm == "edges_and_colour": print(" + >> calculating edges") edges = sobel_h(rgb2grey(rgb)) # get pixel lines and RGB values at selected locations only if algorithm == "peaks" or algorithm == "colour": print(" + >> extracting cross-shore pixels") # rescale rgb = (rgb - rgb.min()) / (rgb.max() - rgb.min()) * 255 Y, crx_idx = get_analysis_locations(crx_dist, crx_start, crx_end) Time, PxInts, RGB = get_pixel_lines(time, rgb, crx_idx, resample_rule=resample_rule, pxmtc=px_mtrc) # get analysis frequency and a 1 sececond time window if not tswindow: fs = (time[1] - time[0]).total_seconds() win = np.int((1 / fs)) else: win = tswindow print(" + >> detecting breaking events") PeakTimes = [] print_check = False if algorithm == "peaks" or algorithm == "colour": if peak_detection == "argmax": peak_detection = "local_maxima" print(" - >> setting peak detection to local maxima") # loop over data rows for pxint, rgb in zip(PxInts, RGB): # calculate baseline bline = baseline(pxint, 2) # calculate pixel peaks if peak_detection == "local_maxima": _, max_idx = peaklocalextremas(pxint - bline, lookahead=win, delta=threshold * (pxint - bline).max()) elif peak_detection == "differential": # calculate first derivative pxintdt = np.diff(pxint - bline) # remove values below zero pxintdt[pxintdt <= 0] = 0 # scale from 0 to 1 pxintdt = pxintdt / pxintdt.max() # get indexes max_idx = indexes(pxintdt, thres=threshold, min_dist=win) else: raise ValueError # colour learning step if algorithm == "colour": if not print_check: print(" + >> colour learning") print_check = True # classifiy pixels breaker_idxs = [] for idx in max_idx: y_pred = classify_colour(rgb[idx], dom_colours, labels) if y_pred[0] == target: breaker_idxs.append(idx) # peaks only else: breaker_idxs = max_idx PeakTimes.append(Time[breaker_idxs]) # organize peaks and times Xpeaks = [] Ypeaks = [] for i, pxtimes in enumerate(PeakTimes): for v in pxtimes: Xpeaks.append(v) for v in np.ones(len(pxtimes)) * Y[i]: Ypeaks.append(v) # edges case if algorithm == "edges": Xpeaks = [] Ypeaks = [] # loop in time for i, t in enumerate(time): # cross-shore line crx_line = edges[i, :] # peaks with robust peak detection if peak_detection == "differential" or \ peak_detection == "local_maxima": crx_line = (crx_line - crx_line.min()) / (crx_line.max() - crx_line.min()) if not np.all(crx_line == 0): idx_peak = indexes(crx_line, thres=1 - threshold, min_dist=win) # apped peaks for peak in idx_peak: if crx_dist[peak] > crx_start and crx_dist[peak] < crx_end: Xpeaks.append(t) Ypeaks.append(crx_dist[peak]) # peaks with simple argmax - works better without colour learning else: peak = np.argmax(crx_line) if crx_dist[peak] > crx_start and crx_dist[peak] < crx_end: Xpeaks.append(t) Ypeaks.append(crx_dist[peak]) # edges + colour learning case if algorithm == "edges_and_colour": Ipeaks = [] Jpeaks = [] # loop in time for i, t in enumerate(time): # cross-shore line crx_line = edges[i, :] if peak_detection == "differential" or \ peak_detection == "local_maxima": crx_line = (crx_line - crx_line.min()) / (crx_line.max() - crx_line.min()) # peaks if not np.all(crx_line == 0): idx_peak = indexes(crx_line, thres=1 - threshold, min_dist=win) if not np.all(crx_line == 0): idx_peak = indexes(crx_line, thres=1 - threshold, min_dist=win) # apped peaks for peak in idx_peak: if crx_dist[peak] > crx_start and crx_dist[peak] < crx_end: Ipeaks.append(i) Jpeaks.append(peak) else: peak = np.argmax(crx_line) if crx_dist[peak] > crx_start and crx_dist[peak] < crx_end: Ipeaks.append(i) Jpeaks.append(peak) # colour learning step Xpeaks = [] Ypeaks = [] for i, j in zip(Ipeaks, Jpeaks): if not print_check: print(" + >> colour learning") print_check = True # classify colour y_pred = classify_colour(rgb[i, j, :], dom_colours, labels) if y_pred[0] == target: Xpeaks.append(time[i]) Ypeaks.append(crx_dist[j]) # sort values in time and outout y = np.array(Ypeaks)[np.argsort(date2num(Xpeaks))] x = np.array(Xpeaks)[np.argsort(Xpeaks)] return ellapsedseconds(x), y
def main(): """Call the main program.""" # read parameters from JSON with open(args.input[0], 'r') as f: H = json.load(f) # input file names wavepaths = H["data"]["breaking"] timestack = H["data"]["timestack"] # shoreline has_shoreline = False try: shoreline = H["data"]["shoreline"] has_shoreline = True except Exception: has_shoreline = False # load shoreline if has_shoreline: # read variables shore = pd.read_csv(shoreline) tshore = shore["time"].values xshore = shore["shoreline"].values else: raise IOError("Sorry, you must provide a shoreline.") # regression parameters order = H["parameters"]["OLS_order"] weights_time_threshold = H["parameters"]["max_time_threshold"] # read timestack ds = xr.open_dataset(timestack) stk_time, stk_dist, rgb = process_timestack(ds) # time in seconds stk_secs = ellapsedseconds(stk_time) if not monotonic(stk_secs.tolist()): stk_secs = np.linspace(0, stk_secs.max(), rgb.shape[0]) # fix distance offset stk_dist -= stk_dist.min() # projection time proj = H["parameters"]["projection"] # read waverays df = Dbf5(wavepaths, codec='utf-8').to_dataframe() if "newtime" in df.columns.values: df = df[["newtime", "newspace", "wave"]] df.columns = ["t", "x", "wave"] dfpts = df # else: # calculate optimal wave paths N = H["parameters"]["wavepath_npoints"] T, X, L = optimal_wavepaths(df, order=order, min_wave_period=1, N=N, project=False, t_weights=weights_time_threshold) # loop over each wave path and get possible intersections TF = [] # for plotting XF = [] # for plotting TP = [] # projections XP = [] # projections TI = [] # intersections XI = [] # intersections WID = [] k = 0 for t1, x1, in zip(T, X): # extend the first wave path "t" seconds, tf, xf = projet_fowards(t1, x1, order=order, time=proj, N=N) # add projection to the current wavepath ta = np.hstack([t1, tf]) xa = np.hstack([x1, xf]) # append to output TF.append(t1) XF.append(x1) TP.append(tf) XP.append(xf) # look for intersections for t2, x2 in zip(T, X): # if they are the same, do nothing if np.array_equal(x1, x2): pass else: ti, xi = intersection(ta, xa, t2, x2) if ti.any(): TI.append(ti[0]) XI.append(xi[0]) WID.append(k) k += 1 # process surf zone edge tsurf, xsurf = surfzone_edge(stk_secs, stk_dist, T, X) # interp shoreline and swash to the same time interval tmax = min(tsurf.max(), tshore.max()) tmin = max(tsurf.min(), tshore.min()) tfinal = np.arange(tmin, tmax, 0.1) f1 = interpolate.interp1d(tsurf, xsurf, kind="linear") f2 = interpolate.interp1d(tshore, xshore, kind="linear") xsurf = f1(tfinal) xshore = f2(tfinal) # intersect shoreline and surf zone edge # with each overruning eventā TShI = [] XShI = [] TSfI = [] XSfI = [] for ti, xi in zip(TI, XI): # find nearest shoreline and surf zone position in time idx1 = np.argmin(np.abs(tfinal - ti)) # append TShI.append(tfinal[idx1]) XShI.append(xshore[idx1]) TSfI.append(tfinal[idx1]) XSfI.append(xsurf[idx1]) # to dataframe df = pd.DataFrame(np.vstack([TI, XI, XSfI, XShI, [len(X)] * len(XI), WID]).T, columns=[ "time", "intersection", "surfzone_position", "shoreline_position", "n_waves", "wave_id" ]) df = df.drop_duplicates() # dump to csv print(" --- Detected {} overruning events".format(len(df))) print(df) df.to_csv(H["data"]["output"]) # plot projections results fig, ax = plot(stk_secs, stk_dist, rgb, TF, XF, TP, XP) # scatter mergings ax.scatter(df["time"], df["intersection"], 120, marker="s", edgecolor="lawngreen", facecolor="none", lw=3, zorder=50, label="Detected bore merging") for t, xsf, xsh in zip(TI, XSfI, XShI): ax.axvline(t, color="r", lw=2, ls="--", zorder=20) ax.scatter(t, xsf, s=100, marker="o", zorder=50, edgecolor="r", facecolor="none", lw=3) ax.scatter(t, xsh, s=100, marker="o", zorder=50, edgecolor="r", facecolor="none", lw=3) # ax.scatter(tpeaks, xpeaks, 120, marker="o", zorder=100, color="r") # plot shoreline and surf zone ax.plot(tfinal, xshore, lw=3, ls="-", color="dodgerblue", zorder=25) ax.plot(tfinal, xsurf, lw=3, ls="-", color="dodgerblue", zorder=25) ax.fill_between(tfinal, xshore, xsurf, facecolor="none", edgecolor="w", lw=2, hatch="//", alpha=0.5, label=r"$\mathcal{X}$", zorder=20) # finalize if H["parameters"]["savefig"]: plt.savefig(H["parameters"]["savefig"], dpi=120) if H["parameters"]["show_plot"]: plt.show() if args.force_show: plt.show() plt.close("all")
if __name__ == '__main__': # main() # files timestack = "Raw_Data/Timestacks/SevenMileBeach/20180614-001.nc" breaking = "Raw_Data/Breaking/SevenMileBeach/20180614-001.dbf" shoreline = "Raw_Data/Swash/SevenMileBeach/20180614-001.csv" merging = "Raw_Data/WaveOverruning/SevenMileBeach/20180614-001.csv" # process timestack t, sx, rgb = process_timestack(xr.open_dataset(timestack)) sx -= sx.min() # sx = np.abs(sx)[::-1] t = ellapsedseconds(t) # process wavepaths wp = Dbf5(breaking, codec='utf-8').to_dataframe() if "newtime" in wp.columns.values: wp = wp[["newtime", "newspace", "wave"]] wp.columns = ["t", "x", "wave"] T, X, L = optimal_wavepaths(wp, order=2, min_wave_period=1, N=250, project=False, t_weights=1) # process shoreline df = pd.read_csv(shoreline)
# load the dataset inp = args.input[0] ds = xr.open_dataset(inp) var = args.var[0] # tol = float(args.tol[0]) # output locations path = args.path[0] subprocess.call("mkdir -p {}".format(path), shell=True) # get raster eta = ds[var].values # get coordinates time = ellapsedseconds(pd.to_datetime(ds["time"].values).to_pydatetime()) dist = ds["distance"].values istr = inp.split("/")[-1] fname = os.path.join(path, istr.strip("nc").strip("/").strip(".") + ".jpeg") # dump stack to a jpeg fig = plt.figure(frameon=False) fig.set_size_inches(len(time) / 100, len(dist) / 100) ax = plt.Axes(fig, [0., 0., 1., 1.]) ax.set_axis_off() fig.add_axes(ax) ax.pcolormesh(time, dist, ds[var].values.T, cmap="inferno") # plt.show() fig.savefig(fname, dpi=100)
def main(): """Call the main script.""" # mAHD lookup table - You will need to build yours! mAHD = pd.read_csv("/mnt/doc/DataHub/SMB-2018/mAHD.csv") # read wave paths df = read_wavepaths(args.svg[0]) # read timestack ds = xr.open_dataset(args.netcdf[0]) eta = ds["eta"].values time = ellapsedseconds(pd.to_datetime(ds["time"].values).to_pydatetime()) dist = ds["distance"].values # Tree searsch for coordinates I, J = np.meshgrid(np.arange(0, eta.shape[0], 1), np.arange(0, eta.shape[1], 1)) # X, Y = np.meshgrid(time, dist) Tree = Tree = KDTree(np.vstack([I.flatten(), J.flatten()]).T) coords = df[["x", "y"]].values _, idx = Tree.query(coords, k=1) # unravel i = np.unravel_index(idx, I.shape)[0] j = np.unravel_index(idx, J.shape)[1] # get real-world coordinates df["time"] = time[j] df["dist"] = dist[::-1][i] # interpolate dt = 0.25 Itime = [] Idist = [] Ilblb = [] for l, ldf in df.groupby("label"): # new time tpred = np.arange(ldf["time"].min(), ldf["time"].max() + dt, dt) # OLS model model = Pipeline([('poly', PolynomialFeatures(degree=2)), ('ols', LinearRegression(fit_intercept=False))]) model.fit(ldf["time"].values.reshape(-1, 1), ldf["dist"].values) # predict ypred = model.predict(tpred.reshape(-1, 1)) # cut at maximun runup idx = np.argmin(ypred) for t, y in zip(tpred[:idx], ypred[:idx]): Itime.append(t) Idist.append(y) Ilblb.append(l) # get a runup height in mAHD ImAH = [] xmAHD = mAHD["distance"].values zmAHD = mAHD["height"].values for x in Idist: idx = np.argmin(np.abs(xmAHD - x)) ImAH.append(zmAHD[idx]) # final dataframe df = pd.DataFrame() df["time"] = Itime df["dist"] = Idist df["height"] = ImAH df["label"] = Ilblb df.to_csv(args.output[0]) # plot fig, ax = plt.subplots(figsize=(12, 6)) ax.pcolormesh(time, dist, eta.T) for _, gdf in df.groupby("label"): ax.plot(gdf["time"], gdf["dist"], ls="-", lw=2) sns.despine() ax.set_xlabel("Time [s") ax.set_ylabel("Distance [m]") ax.grid(color="w", ls="-", lw=2) fig.tight_layout() plt.savefig(args.output[0].replace(".csv", ".png")) plt.close()
mpl.rcParams['axes.linewidth'] = 2 # quite skimage warningss warnings.filterwarnings("ignore") if __name__ == '__main__': # main() lim = 0.02 # files f = "data/stacks/20180614_A_20180614_1900_1910.nc" # process timestack ds = xr.open_dataset(f) time = ellapsedseconds(ds["time"].values) distance = ds["distance"].values dx = distance.min() eta = ds["eta"].values # process wavepaths f = "data/tracking/SMB/20180614_A_20180614_1900_1910.dbf" wp = Dbf5(f, codec='utf-8').to_dataframe() if "newtime" in wp.columns.values: wp = wp[["newtime", "newspace", "wave"]] wp.columns = ["t", "x", "wave"] # unique colours colors = plt.cm.get_cmap("tab20", len(np.unique(wp["wave"].values))) # track
print(" - run {} of {}".format(i + 1, NRUNS - 1), end="\r") i += 1 # skip the first run # open a figure fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, figsize=(9, 12), sharex=True) # open and process timestack f = main_data + timestacks + loc + date + "-{}.nc".format( str(i).zfill(3)) t, x, rgb = process_timestack(xr.open_dataset(f)) gray = rgb2gray(rgb) dtime = t t = ellapsedseconds(t) x -= x.min() pxint = gray[:, int(len(x) / 2)] # plot timestack ax1.pcolormesh(t, x, gray.T, cmap="Greys_r") # open and process wavepaths f = main_data + breaking + loc + date + "-{}.dbf".format( str(i).zfill(3)) wp = Dbf5(f, codec='utf-8').to_dataframe() if "newtime" in wp.columns.values: wp = wp[["newtime", "newspace", "wave"]] wp.columns = ["t", "x", "wave"] T, X, _ = optimal_wavepaths(wp, order=2,
def main(): """ Run the main script """ # read parameters from JSON ## with open(args.input[0], 'r') as f: H = json.load(f) # input timestack ncin = H["data"]["ncin"] # output outputto = os.path.abspath(H["data"]["dataout"]) if not os.path.isdir(outputto): os.makedirs(outputto) basename = H["data"]["basename"] # get analysis parameters # which algorithm to use to detect breaking events brk_alg = H["parameters"]["breaking_algorithm"] if brk_alg not in ["colour", "peaks", "edges", "edges_and_colour"]: raise ValueError("Breaking detection algorithm should be \ either \'colour\', \'peaks\', \'edges\' or \ \'edges_and_colour\'.") # metric to use for pixel intensity px_mtrc = H["parameters"]["pixel_metric"] if px_mtrc not in ["lightness", "intensity"]: raise ValueError("Pixel metric should be either \'lightness\' \ or \'intensity\'.") # colour quantization qnt_cl = H["parameters"]["colour_quantization"] n_clrs = H["parameters"]["quantization_colours"] # peak detection method pxp_mtd = H["parameters"]["peak_detection_algorithm"] # threshold for peak detection px_trsh = H["parameters"]["pixel_threshold"] # pixel window for denoise_bilateral px_wndw = H["parameters"]["pixel_window"] # time window for peak detection ts_wndw = H["parameters"]["time_window"] # minimum number of samples to be used for the DBSCAN clustering step dbs_msp = H["parameters"]["min_samples"] # minimum distance be used for the DBSCAN clustering step dbs_eps = H["parameters"]["eps"] # distance metric for the DBSCAN clustering step dbs_mtc = H["parameters"]["dbscan_metric"] scipy_dists.append(['cityblock', 'cosine', 'euclidean', 'l1', 'l2', 'manhattan']) if dbs_mtc not in scipy_dists: raise ValueError("Distance \'{}\' is not valid. Please check \ scipy.spatial.distance for valid \ options.".format(dbs_mtc)) # resample rule for timeseries rs_rule = H["parameters"]["resample_rule"] # surf zone limits from input parameters file, if False, will call GUI. sz_lims = H["parameters"]["surf_zone_lims"] if not sz_lims[0]: sz_gui = True else: sz_gui = False # sand colour from input parameter file, if False, will call GUI s_color = H["parameters"]["sand_colour"] if not s_color[0]: sand_colour_gui = True else: sand_colour_gui = False sand = np.array(s_color) # water colour from input parameter file, if False, will call GUI w_color = H["parameters"]["water_colour"] if not w_color[0]: water_colour_gui = True else: water_colour_gui = False water = np.array(w_color) # foam colour from input parameter file, if False, will call GUI f_color = H["parameters"]["foam_colour"] if not f_color[0]: foam_colour_gui = True else: foam_colour_gui = False foam = np.array(f_color) # number of clicks for GUI n_clks = H["parameters"]["nclicks"] # pixel window for GUI px_wind = H["parameters"]["gui_window"] # try to fix bad pixel values gap_val = H["parameters"]["gap_value"] # plot? plot = H["parameters"]["plot"] # process timestack # read timestack ds = xr.open_dataset(ncin) # load timestack variables # x = ds["x"].values y = ds["y"].values # compute distance from shore stk_len = np.sqrt(((x.max() - x.min()) * (x.max() - x.min())) + ((y.max() - y.min()) * (y.max() - y.min()))) crx_dist = np.linspace(0, stk_len, len(x)) # get timestack times stk_time = pd.to_datetime(ds["time"].values).to_pydatetime() stk_secs = ellapsedseconds(stk_time) # get RGB values rgb = ds["rgb"].values # try to fix vertical grey strips, if any ifix, jfix = np.where(np.all(rgb == gap_val, axis=-1)) rgb[ifix, jfix, :] = rgb[ifix-2, jfix-2, :] # get analysis limits if sz_gui: crx_start, crx_end = get_analysis_domain(stk_secs, crx_dist, rgb) else: crx_start = sz_lims[0] crx_end = sz_lims[1] # run the analysis if brk_alg in ["colour", "edges_and_colour"]: # sand if sand_colour_gui: df_sand = get_training_data(rgb, regions=1, region_names=["sand"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, sand = get_dominant_colour(df_sand, n_colours=8) sand = sand[0] # water if water_colour_gui: df_water = get_training_data(rgb, regions=1, region_names=["water"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, water = get_dominant_colour(df_water, n_colours=8) water = water[0] # foam if foam_colour_gui: df_foam = get_training_data(rgb, regions=1, region_names=["foam"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, foam = get_dominant_colour(df_foam, n_colours=8) foam = foam[0] # build colour structures train_colours = {'labels': [0, 1, 2], 'aliases': ["sand", "water", "foam"], 'rgb': [sand, water, foam], 'target': 2} else: train_colours = None # detect breaking events times, breakers = detect_breaking_events(stk_time, crx_dist, rgb, crx_start=crx_start, crx_end=crx_end, tswindow=ts_wndw, pxwindow=px_wndw, px_mtrc=px_mtrc, resample_rule=rs_rule, algorithm=brk_alg, peak_detection=pxp_mtd, posterize=qnt_cl, ncolours=n_clrs, threshold=px_trsh, colours=train_colours, fix_constrast=True) # DBSCAN print(" + >> clustering wave paths") df_dbscan = dbscan(times, breakers, dbs_eps, dbs_msp, dbs_mtc) # Outputs print(" + >> writting output") if os.path.isfile(os.path.join(outputto, basename+".csv")): overwrite = input(" |- >> overwrite output?") if overwrite[0] == "y": write_outputs(outputto, basename, stk_secs, crx_dist, rgb, df_dbscan) else: print(" - >> warning: not writing outputs") else: write_outputs(outputto, basename, stk_secs, crx_dist, rgb, df_dbscan) if plot: print(" + >> plotting") fig = plt.figure(figsize=(16, 6)) ax1 = fig.add_axes([0.1, 0.1, 0.7, 0.8]) ax2 = fig.add_axes([0.85, 0.1, 0.1, 0.8]) # get unique colours for each wave colors = plt.cm.get_cmap("Set1", len(np.unique(df_dbscan["wave"].values))) # get traning colours if train_colours: for label, region, color in zip(train_colours["labels"], train_colours["aliases"], train_colours["rgb"]): ax2.scatter(1, label, 1000, marker="s", color=color/255, label=region, edgecolor="k", lw=2) # set axis ax2.set_yticks(train_colours["labels"]) ax2.set_yticklabels(train_colours["aliases"]) ax2.set_ylim(-0.25, len(train_colours["aliases"])-1+0.25) for tick in ax2.get_yticklabels(): tick.set_rotation(90) ax2.xaxis.set_major_locator(plt.NullLocator()) else: for label, region, color in zip([0, 1, 2], ['N/A', 'N/A', 'N/A'], [[1, 1, 1], [1, 1, 1], [1, 1, 1]]): ax2.scatter(1, label, 1000, marker="s", color=[1, 1, 1], label=region, edgecolor="k", lw=2) # set axis ax2.set_yticks([0, 1, 2]) ax2.set_yticklabels(['N/A', 'N/A', 'N/A']) ax2.set_ylim(-0.25, len([0, 1, 2])-1+0.25) for tick in ax2.get_yticklabels(): tick.set_rotation(90) ax2.xaxis.set_major_locator(plt.NullLocator()) ax2.set_title("Training colours") # plot timestack im = ax1.pcolormesh(stk_secs, crx_dist, rgb.mean(axis=2).T) # set timestack to to true color rgba = construct_rgba_vector(np.rollaxis(rgb, 1, 0), n_alpha=0) rgba[rgba > 1] = 1 im.set_array(None) im.set_edgecolor('none') im.set_facecolor(rgba) # plot analysis limits ax1.axhline(y=crx_start, lw=3, color="darkred", ls="--") ax1.axhline(y=crx_end, lw=3, color="darkred", ls="--") # plot all identified breaking events ax1.scatter(times, breakers, 20, color="k", alpha=0.5, marker="+", lw=1, zorder=10) # DBSCAN plot k = 0 for label, group in df_dbscan.groupby("wave"): if label > -1: # get x and y for regression xwave = group["time"].values ywave = group["breaker"].values # scatter points ax1.scatter(xwave, ywave, 40, label="wave " + str(label), c=colors(k), alpha=0.5, marker="o", edgecolor="k") bbox = dict(boxstyle="square", ec="k", fc="w", alpha=0.5) ax1.text(xwave.min(), ywave.max(), "wave " + str(k), rotation=45, fontsize=8, zorder=10, bbox=bbox) k += 1 # set axes limits ax1.set_xlim(xmin=stk_secs.min(), xmax=stk_secs.max()) ax1.set_ylim(ymin=crx_dist.min(), ymax=crx_dist.max()) # set axes labels ax1.set_ylabel(r"Cross-shore distance $[m]$", fontsize=16) ax1.set_xlabel(r"Time $[s]$", fontsize=16) # seaborn despine sns.despine(ax=ax2, bottom=True) sns.despine(ax=ax1) # fig.tight_layout() plt.show()