#!/usr/bin/env python # coding: utf-8 # # OUTPUT TRACKING ALGORITHM # # # --- # Author: **Helvecio B. Leal Neto** & **Alan J. P. Calheiros**\ # **National Institute for Space Research - Brazil - (2021)** # # # # ## About # # This notebook is designed for viewing the tracking results of the storm/precipitation tracking algorithm beta version. The results presented here refer to the tracking of clusters via radar data provided by the GoAmazon project, for the following periods: # # **Start**: 2014-09-07 00:00:00 # # **End**: 2014-09-09 00:00:00 # # The tracking threshold is: # # * **20** dBZ # * inner 1 - ***35*** dBZ # * inner 2 - ***40*** dBZ # # Minimum size threshold per cluster: # # * **30** pixels # * inner 1 - ***15*** pixels # * inner 2 - ***10*** pixels # ## Dependencies libraries # In[2]: get_ipython().run_line_magic('load_ext', 'autoreload') get_ipython().run_line_magic('autoreload', '2') import sys sys.path.append("../") import stanalyzer as sta # In[2]: import pandas as pd import geopandas as gpd import numpy as np from shapely import wkt import matplotlib.pyplot as plt # standard graphics library from matplotlib.colors import LinearSegmentedColormap import gzip import netCDF4 import cartopy.io.img_tiles as cimgt import cartopy.crs as ccrs # cartographic coordinate reference system import io from urllib.request import urlopen, Request from PIL import Image from math import floor from matplotlib import patheffects # In[103]: VAR = 'DBZc' LEVEL = 5 CPT = sta.loadCPT('../stanalyzer/cpt/humidity.cpt') CMAP = LinearSegmentedColormap('cpt', CPT) VMIN = 0 VMAX = 65 # In[4]: pd.read_csv # In[5]: pd.read_pickle # In[3]: track_frame = sta.read_file('../output/tracking_compressed.pkl') # In[7]: track_frame.nc_file # In[8]: ## This function returns the duration of events lifes = sta.life_cicle(track_frame,sort=True) lifes # In[9]: ### Filter by time TIME_MIN = 0 TIME_MAX = 15 UNIT = 'h' # In[10]: ## Apply filter by time df_filter1 = sta.time_filter(track_frame,TIME_MIN,TIME_MAX,UNIT) # In[11]: sta.life_cicle(df_filter1,sort=True) # In[12]: fam_test = df_filter1.query('uid == 118') # In[13]: fam_test.head() # In[104]: def get_cmap(n, name='hsv'): '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct RGB color; the keyword argument name must be a standard mpl colormap name.''' return plt.cm.get_cmap(name, n) def open_ncdf(nc_file): ## OPEN RADAR DATA COMPRESS with gzip.open(nc_file) as gz: with netCDF4.Dataset('dummy', mode='r', memory=gz.read()) as nc: data = nc.variables[VAR][0][LEVEL][:].filled() extent = [nc.variables['lon0'][:].min(),nc.variables['lon0'][:].max(),nc.variables['lat0'][:].min(),nc.variables['lat0'][:].max()] return data,extent ## Image def image_spoof(self, tile): # this function pretends not to be a Python script url = self._image_url(tile) # get the url of the street map API req = Request(url) # start request req.add_header('User-agent','Anaconda 3') # add user agent to request fh = urlopen(req) im_data = io.BytesIO(fh.read()) # get image fh.close() # close url img = Image.open(im_data) # open image with PIL img = img.convert(self.desired_tile_form) # set image format return img, self.tileextent(tile), 'lower' # reformat for cartopy ## Scale bar def scale_bar(ax, proj, length, location=(0.5, 0.05), linewidth=3, units='km', m_per_unit=1000): # find lat/lon center to find best UTM zone x0, x1, y0, y1 = ax.get_extent(proj.as_geodetic()) # Projection in metres utm = ccrs.UTM(utm_from_lon((x0+x1)/2)) # Get the extent of the plotted area in coordinates in metres x0, x1, y0, y1 = ax.get_extent(utm) # Turn the specified scalebar location into coordinates in metres sbcx, sbcy = x0 + (x1 - x0) * location[0], y0 + (y1 - y0) * location[1] # Generate the x coordinate for the ends of the scalebar bar_xs = [sbcx - length * m_per_unit/2, sbcx + length * m_per_unit/2] # buffer for scalebar buffer = [patheffects.withStroke(linewidth=5, foreground="w")] # Plot the scalebar with buffer ax.plot(bar_xs, [sbcy, sbcy], transform=utm, color='k', linewidth=linewidth, path_effects=buffer) # buffer for text buffer = [patheffects.withStroke(linewidth=3, foreground="w")] # Plot the scalebar label t0 = ax.text(sbcx, sbcy, str(length) + ' ' + units, transform=utm, horizontalalignment='center', verticalalignment='bottom', path_effects=buffer, fontsize=14, zorder=4) left = x0+(x1-x0)*(0.9) # Plot the N arrow t1 = ax.text(left, sbcy, u'\u25B2\nN', transform=utm, horizontalalignment='center', verticalalignment='bottom', path_effects=buffer, fontsize=14, zorder=4) # Plot the scalebar without buffer, in case covered by text buffer ax.plot(bar_xs, [sbcy, sbcy], transform=utm, color='k', linewidth=linewidth, zorder=6) def utm_from_lon(lon): return floor( ( lon + 180 ) / 6) + 1 # In[105]: def plot(dframe,t = 0): ## GET TIMESTAMP LIST time_list = [np.unique(sorted(dframe.time))[t]] locked_by_time = dframe.query('time <= @time_list') geo_cols = [] list_cols = locked_by_time.columns.to_list() tresholds = [] for c in list_cols: if 'geom_' in c or 'line' in c or 'traj' in c or 'vect' in c: geo_cols.append(c) if 'geom_' in c and 'geom_i' not in c: tresholds.append(int(c[-2:])) geo_cols = sorted(geo_cols) no_geo_cols = [item for item in list_cols if item not in geo_cols] ### CREATE GEODATAFRAME geo_frame = gpd.GeoDataFrame(locked_by_time[no_geo_cols]) ### OPEN MATRIX nc_file = locked_by_time.loc[locked_by_time['time'] == time_list[-1]]['nc_file'].unique()[0] data,extent = open_ncdf(nc_file) ## FILTER data[data <= 0 ] = np.nan ## FIGURE cimgt.Stamen.get_image = image_spoof # reformat web request for street map spoofing osm_img = cimgt.Stamen('terrain-background'); # spoofed, downloaded street map plt.figure(figsize=(10,10),dpi=100) ax = plt.axes(projection = osm_img.crs) ax.set_extent(extent) ### BACKGROUND zoom = 1 scale = np.ceil(-np.sqrt(2)*np.log(np.divide(zoom,350.0))) # empirical solve for scale based on zoom scale = (scale<20) and scale or 19 # scale cannot be larger than 19 ax.add_image(osm_img, int(scale)) # add OSM with zoom specification color_range = ['red','C1','C2','C3','C4','C5'] ## Geometries for g in range(len(geo_cols)): ## Plot Boundary if 'geom_' in geo_cols[g] and 'geom_i' not in geo_cols[g]: last_time = time_list[-1] last_series = locked_by_time.query('time == @last_time')[geo_cols[g]].apply(wkt.loads) geo_frame['geometry'] = last_series geo_frame.exterior.plot(ax=ax,color=color_range[g],linewidth=1,label=geo_cols[g],transform = ccrs.PlateCarree()) ## Plot Trajectory if 'traj' in geo_cols[g]: lock_uids = locked_by_time.query('time == @last_time').uid.values.tolist() traject = locked_by_time.query('uid == @lock_uids')[geo_cols[g]].apply(wkt.loads) geo_frame['geometry'] = traject geo_frame.plot(ax=ax,color='black',label=geo_cols[g],transform = ccrs.PlateCarree()) # # Plot vectores # if 'vect' in geo_cols[g]: # lock_uids = locked_by_time.query('time == @last_time').uid.values.tolist() # traject = locked_by_time.query('uid == @lock_uids')[geo_cols[g]].apply(wkt.loads) # geo_frame['geometry'] = traject # geo_frame.plot(ax=ax,color='gray',label=geo_cols[g],transform = ccrs.PlateCarree()) ### Plot INFO buffer = [patheffects.withStroke(linewidth=3, foreground="w")] transform = ccrs.PlateCarree()._as_mpl_transform(ax) for i,row in locked_by_time.query('time == @last_time').iterrows(): print(row.p0,row.p1,row.uid) ax.annotate(s=' UID \n'+str(row.uid), xy=(float(row.lon),float(row.lat)), xycoords=transform, weight='bold', size=10, path_effects=buffer) #### PLOT DATA cs = ax.contourf(data, cmap = CMAP, vmin = VMIN, vmax = VMAX, extent = extent,alpha=0.9, transform = ccrs.PlateCarree()) ### LINES LABELS gl = ax.gridlines( draw_labels=True, linewidth=1, color='gray', alpha=0.5, linestyle='--') # label all axes gl.top_labels = False # turn off top label gl.right_labels = False # turn off right label ## PLOT SCALE BAR scale_bar(ax, ccrs.Mercator(), 50) ## COLOR BAR sm = plt.cm.ScalarMappable(cmap=CMAP,norm=plt.Normalize(VMIN,VMAX)) sm._A = [] cbar = plt.colorbar(sm,ax=ax,extend='both',pad=0.05,shrink=0.6,orientation='horizontal') cbar.set_label('Refletividade (dBZ)') ## LEGEND ax.legend() # In[106]: df_filter1.columns # In[107]: df_filter1.query('time == 5') # In[108]: plot(df_filter1,5) # In[109]: import plotly.express as px import plotly.graph_objects as go # In[110]: geo_cols = [] for c in df_filter1.columns: if 'geom_' in c or 'line' in c or 'traj' in c or 'vect' in c: geo_cols.append(c) # In[111]: no_geo_cols = [item for item in df_filter1.columns if item not in geo_cols] # In[112]: geo_df = gpd.GeoDataFrame(df_filter1) geo_df['geometry'] = df_filter1['geom_20'].apply(wkt.loads) # In[113]: geo_df.query('time <= 5') # In[114]: gd_t = geo_df.query('time == 5') # In[115]: gd_t = gd_t.reset_index() # In[ ]: # In[116]: def ncdf(nc_file): ## OPEN RADAR DATA COMPRESS with gzip.open(nc_file) as gz: with netCDF4.Dataset('dummy', mode='r', memory=gz.read()) as nc: data = nc.variables[VAR][0][LEVEL][:].filled() lon = nc.variables['lon0'][:].filled() lat = nc.variables['lat0'][:].filled() return data,lon,lat data_,lon_,lat_ = ncdf(gd_t.nc_file.iloc[0]) # In[117]: data_[data_ == -9999] = np.nan # In[118]: img_pts,lons,lats = [],[],[] for i in range(len(data_)): for j in range(len(data_)): if data_[i][j] != np.nan: img_pts.append(data_[i][j]) lons.append(lon_[i][j]) lats.append(lat_[i][j]) img_df = pd.DataFrame(list(zip(lons,lats,img_pts)), columns =['lon','lat','metric']) # In[119]: import datashader.transfer_functions as tf from colorcet import rainbow import datashader as ds import json cvs = ds.Canvas(plot_width=data_.shape[0], plot_height=data_.shape[1]) agg = cvs.points(img_df, x='lon', y='lat') coords_lat, coords_lon = agg.coords['lat'].values, agg.coords['lon'].values # Corners of the image, which need to be passed to mapbox coordinates = [[coords_lon[0], coords_lat[0]], [coords_lon[-1], coords_lat[0]], [coords_lon[-1], coords_lat[-1]], [coords_lon[0], coords_lat[-1]]] # In[306]: np.nanmin(agg.values) # In[301]: # data_[data_ <= 20 ] = np.nan agg.values = data_ img = tf.shade(agg, cmap=complet_rbb['HEX'].tolist(),alpha=255)[::-1].to_pil() # In[151]: from colormap import rgb2hex # In[293]: np.nanmin(data_) # In[ ]: map(int, results) # In[280]: tab = pd.read_table('../stanalyzer/cpt/NEXRAD.cpt',sep=';',names=['RGB','DBZ']) tab['HEX'] = tab['RGB'].apply(lambda x: rgb2hex(int(x.split(",")[0]),int(x.split(",")[1]),int(x.split(",")[2]))) # In[281]: tab2 = pd.DataFrame(columns=['RGB','DBZ','HEX']) tab2['DBZ'] = np.arange(-186,-30) tab2['HEX'] = ['#000000'] * len(tab2['DBZ']) tab2['RGB'] = ['0, 0, 0'] * len(tab2['DBZ']) # In[283]: complet_rbb = pd.concat([tab2,tab]) # In[308]: complet_rbb # In[307]: CMAP # In[303]: complet_rbb['HEX'].tolist() # In[302]: rainbow # In[88]: geo1 = json.loads(gpd.GeoSeries(gd_t['geom_20'].apply(wkt.loads)).to_json()) geo2 = json.loads(gpd.GeoSeries(gd_t['geom_35'].apply(wkt.loads)).to_json()) geo3 = json.loads(gpd.GeoSeries(gd_t['geom_40'].apply(wkt.loads)).to_json()) traj = json.loads(gpd.GeoSeries(gd_t['trajectory'].apply(wkt.loads)).to_json()) # In[300]: img # In[102]: img # In[69]: img # In[1]: layers1 = [ {'source': geo1, 'type': "line", 'color': "black", 'line':dict(width=1.5) }, {'source': geo2, 'type': "line", 'color': "royalblue", 'name':'ds', 'line':dict(width=0.8) }, {'source': geo3, 'type': "line", 'color': "red", 'name':'ds', 'line':dict(width=0.8) }, {'source': traj, 'type': "line", 'color': "red", 'name':'ds', 'line':dict(width=1.8) }, {"sourcetype": "image", 'below': "traces", "source": img, "coordinates": coordinates, } ] # In[90]: colorbar=dict(thickness=20, ticklen=3, tickcolor='orange', tickfont=dict(size=14, color='orange')) showscale=True, colorscale=[[0, 'green'],[1, 'red']], cmin=0, cmax=10 # In[317]: mapbox_access_token = 'pk.eyJ1Ijoic3BsaW50ZXJzdG0iLCJhIjoiY2tydWxjMzdlMTRxYTJwcGZlYmc0aWJyYSJ9.3-nO2w18a1fbjmAXrH7kEA' hover_info = dict(bgcolor="white", font_size=14, font_family="Rockwell") hover_temp = "%{customdata[0]}

" + \ "longitude: %{lon}
" + \ "latitude: %{lat}
" + \ "UID: %{customdata[1]}" ### FIGURE data = go.Scattermapbox(customdata=gd_t[['timestamp','uid','time']], lat=list(gd_t["lat"]), lon=list(gd_t["lon"]), textfont=dict(size=16, color='black'), hoverlabel=hover_info, mode='markers', marker=dict(size=10, color='black', showscale=True,colorscale=[[0, 'green'],[1, 'red']],cmin=0,cmax=50, colorbar=dict(thickness=20, ticklen=3, tickcolor='orange', tickfont=dict(size=14, color='orange'))), hovertemplate = hover_temp, ) layout = dict(margin=dict(l=0, t=0, r=0, b=0, pad=0), mapbox=dict(layers=layers1, accesstoken=mapbox_access_token, center=dict(lat=-3.14, lon=-60), style='light', zoom=6), ) fig = go.Figure(data=data, layout=layout) fig.update_mapboxes() fig.show() # In[ ]: fig = go.Figure() fig = px.scatter_mapbox(gd_t, lat="lat", lon="lon", hover_name="uid", hover_data=["time", "uid","max_ref_20"], color_discrete_sequence=["fuchsia"],width=900, height=700) fig.update_layout(mapbox=dict(layers=layers, style="stamen-terrain", center = {'lon': -60, 'lat': -3.14}, zoom = 6)) # buttons for updatemenu buttons = [dict(method='restyle', label='linear', visible=True, args=[{'label': 'linear', 'visible':[True, False],}]), dict(method='restyle', label='sqrt', visible=True, args=[{'label': 'linear', 'visible':[False, True],}])] # specify updatemenu um = [{'buttons':buttons, 'direction': 'down'}] fig.update_layout(updatemenus=um) fig.show() # In[ ]: fig.update_layout( updatemenus=[ dict( buttons=list([ dict(label="High", method="update", args=[{"visible": [False]}, {"shapes": layers1[3]}]) ]), type = "buttons", direction="right", pad={"r": 0, "t": 0}, showactive=True, x=0.38, xanchor="left", y=1, yanchor="top" ) ]) # In[ ]: width=800, height=400 # In[ ]: fig = px.density_mapbox(img_df,lat="lat", lon="lon",z='metric',radius=5) fig.update_layout(mapbox=dict(layers=layers, style="stamen-terrain", center = {'lon': -60, 'lat': -3.14}, zoom = 6 ), ) fig.update_layout(mapbox=dict(layers=layers, style="stamen-terrain", center = {'lon': -60, 'lat': -3.14}, zoom = 6 ), ) # In[ ]: # In[ ]: # In[ ]: x_states = [] y_states = [] for i,row in gd_t.iterrows(): x = row.geometry.exterior.xy[0].tolist() y = row.geometry.exterior.xy[0].tolist() for segment in range(len(x)): x_states = x_states + x y_states = y_states + y # In[ ]: state_trace = [dict( type = 'scatter', legendgroup = "States", line = dict(color='white', width=1), x = x_states, y = y_states, hoverinfo='none', showlegend=False, mode='lines')] # In[52]: dir(go.Choroplethmapbox) # In[39]: fig = go.Figure(go.Choroplethmapbox(geojson=gd_t.geometry, locations=gd_t.index, z=gd_t.uid, colorscale='Viridis', zauto=True, marker_opacity=0.5, marker_line_width=0.5) ) # fig.update_layout(mapbox_style='white-bg', # #mapbox_accesstoken=mapbox_token, # mapbox_zoom=12, # mapbox_center={'lat': 45.41117, 'lon': -75.69812}) # fig.update_layout(margin={'r':0, 't':0, 'l':0, 'b':0}) # pio.renderers.default = 'browser' fig.show() # In[41]: df # In[43]: import plotly.express as px df = px.data.gapminder() fig = px.choropleth(df, locations="iso_alpha", color="lifeExp", # lifeExp is a column of gapminder hover_name="country", # column to add to hover information color_continuous_scale=px.colors.sequential.Plasma, animation_frame='year') # fig2 = px.scatter_geo(df, locations="iso_alpha", # size="lifeExp", # lifeExp is a column of gapminder # hover_name="country", # column to add to hover information # color_continuous_scale=px.colors.sequential.Plasma, # animation_frame='year') fig.add_trace(fig2.data[0]) # for i, frame in enumerate(fig.frames): # fig.frames[i].data += (fig2.frames[i].data[0],) fig.show() # In[ ]: get_ipython().system('conda install -c plotly plotly_express -y') # In[ ]: # In[ ]: open_ncdf(df_filter1['nc_file'].iloc[0]) # In[ ]: # In[ ]: # In[ ]: from shapely import wkt import numpy as np # In[ ]: fam_test = df_filter1.query('uid == 118') fam_test['geom_35'].fillna(value='GEOMETRYCOLLECTION EMPTY', inplace=True) geo_frame = gpd.GeoDataFrame() geo_frame['geometry'] = fam_test['geom_35'].apply(wkt.loads) # In[ ]: geo_frame.tail(2).plot() # In[ ]: fam_test['geom_35'].apply(wkt.loads) # In[ ]: tt = gpd.GeoDataFrame() tt['geometry'] = fam_test['geom_intersect'].apply(wkt.loads) # In[ ]: tt.plot() # In[ ]: import geopandas as gpd # In[ ]: ### PATH PATH_FILE = '../tracks/S201409070000_E201409100000_VDBZc_T20_L5.pkl' # In[ ]: ### Read tracking file df = sta.read_file(PATH_FILE) df.head() # In[ ]: sta.life_cicle() # In[ ]: life_cicle(df) # In[ ]: # Dataframe library import pandas as pd # Numerical Python library import numpy as np # netCDF4 library import netCDF4 # Import gzip to open netCDF import gzip # Visualization library import matplotlib.pyplot as plt # ## Variables # # **Fam_NÂș**-> Refers to the number of the Tracked Family. #
# # **timestamp** ->A digital record of the time of occurrence of a particular event. #
# **time** -> Refers to the tracking time in the algorithm. #
# **uid** -> Unique IDentifier, it is used to generate the families. #
# **id_t** -> Referring cluster identifier at the time of tracking occurrence. From the DBSCAN clustering algorithm. #
# **lat** -> Refers latitude centroid, taken from the reference matrix of the original nc files. #
# **lon** -> Refers longitude centroid, taken from the reference matrix of the original nc files. #
# **p0** -> The first coordinate point of centroid in matrix (clusters or nc_file): (p0,p1)=(x,y)=(lon,lat). #
# **p1** -> The second coordinate point of centroid in matrix (clusters or nc_file): (p0,p1)=(x,y)=(lon,lat). #
# **size_%THRESHOLD** -> Total number of Pixels in the main cluster. Each point depends on the sensor's spatial resolution (pixel size): RADAR 2x2km. #
# **mean_ref_%THRESHOLD** -> Averaged reflectivity of the cluster. Value in dBZ. #
# **max_ref_%THRESHOLD** -> Max reflectivity of the cluster. Value in dBZ. #
# **angle_%THRESHOLD_orig** -> Original displacement angle of the cluster at the current time. #
# **angle_%THRESHOLD_cor** -> Corrected displacement angle of the cluster at the current time. #
# **vel_%THRESHOLD_orig** -> Original displacement velocity of the cluster at the current time in kilometers per hour (km/h). #
# **vel_%THRESHOLD_cor** -> Corrected displacement velocity of the cluster at the current time in kilometers per hour (km/h). #
# **mean_total_ref_%THRESHOLD** -> Average reflectivity of the inner clusters by threshold (Value in dBZ). #
# **total_size_%THRESHOLD** -> Total size of inner clusters by threshold (number of pixels). #
# **n_cluster_%THRESHOLD** -> Total number of inner clusters by Threshold. #
# **avg_angle_%THRESHOLD** -> Averaged angle for the inner cluster by threshold (Value in degree). #
# **avg_vel_%THRESHOLD** -> Averaged velocity for inner clusters by threshold (Value in km/h). #
# **status** -> Status of occurrence, type: NEW-> New cluster; CONT-> Continous cluster; SPLT -> Splitted cluster; MERG -> Merged Cluster. #
# **delta_t** -> Time interval for cluster life cycle. #
# **nc_file** -> Path of netCDF file. #
# **cluster_file** -> Path of cluster file (From DBSCAN). #
# **dsize_%THRESHOLD** -> Difference between the sizes of two consecutive clusters (in Pixel). #
# **dmean_ref_%THRESHOLD** -> Difference between the mean reflectivities of two consecutive clusters for main threshold (in dBZ). #
# **dmean_total_ref_%THRESHOLD** -> Difference between the mean reflectivities of all clusters between two consecutive times for an inner threshold (in dBZ). #
# **dtotal_size_%THRESHOLD** -> Difference between the total size (in pixel) of all clusters between two consecutive times for an inner threshold (values in pixel). # ## Read tracking file # # Tracking DataFrame. # In[ ]: fam_tracking = pd.read_pickle("./S201409070000_E201409100000_VDBZc_T20_L5.pkl") fam_tracking # ### Example how to select a FAM by uid # In[ ]: uid = 97 selected_fam = fam_tracking.query('uid == @uid') selected_fam # ## Example how to select a cluster in the family # In[ ]: line = 0 #first line selected_line = selected_fam.iloc[[line]] selected_line # ## Example how to open the cluster file and the original data to extract reflectivity values # In[ ]: ## OPEN CLUSTERS def open_cluster(path): try: cluster = np.load(path['cluster_file'].values[0])['arr_0'] cluster[cluster == 0] = np.NAN return cluster except: print('File not found!') # In[ ]: selected_line # In[ ]: cluster_matrix_all = open_cluster(selected_line) print('Original dimensions of cluster->',cluster_matrix_all.shape) THRESHOLD_LEVEL = 0 #to select the main threshold (ex: 0-20dBZ,1-35dBZ,2-40dBZ) cluster_matrix = cluster_matrix_all[:,:,THRESHOLD_LEVEL] print('Selected dimensions of cluster->',cluster_matrix.shape) # In[ ]: ### OPEN NETCDF def open_file(file_path): VAR_NAME = 'DBZc' LEVEL = 5 #2.5km height THRESHOLDS = [20,35,40] #dBZ with gzip.open(file_path['nc_file'].values[0]) as gz: with netCDF4.Dataset('dummy', mode='r', memory=gz.read()) as nc: data = nc.variables[VAR_NAME][0][LEVEL][:].filled() data[data == -9999.] = np.NAN data[data < THRESHOLDS[0]] = np.nan return data # In[ ]: nc_matrix = open_file(selected_line) print('NetCDF Max/Min values (thresholded):\n',np.nanmax(nc_matrix),np.nanmin(nc_matrix)) # In[ ]: fig, (ax,ax1) = plt.subplots(1,2, figsize=(15,6)) ax.imshow(nc_matrix) ax1.imshow(cluster_matrix); ax.set_title('Original file') ax1.set_title('Cluster file'); # ## Extracting reflectivities from the selected cluster # # To extract the reflectivity values of an individual cluster, you will need to choose the tracking 'id_t', this should be done as follows: # # Visualization of individual line. # In[ ]: selected_line # In[ ]: ### This line shows that id_t is equal to 20. selected_id_t = selected_line.id_t.values[0] ### Get XY coordinates from cluster matrix x,y = np.where(cluster_matrix == selected_id_t) ### Get reflectivities values from nc_file cluster dbz_list = nc_matrix[x,y] # In[ ]: print('List with reflectivity values of an individual cluster.\n',dbz_list) # ### Cluster location view # In[ ]: fig, (ax,ax1) = plt.subplots(1,2, figsize=(15,6)) ax.imshow(nc_matrix) ax1.imshow(cluster_matrix); ax.set_title('Original file') ax1.set_title('Cluster file'); ax.scatter(selected_line.p0,selected_line.p1,marker='x',color='r',s=100) ax1.scatter(selected_line.p0,selected_line.p1,marker='x',color='r',s=100) # In[ ]: