import numpy as np import matplotlib.pyplot as plt from selectpoints import selectpoints N = 50 x = np.random.rand(N) y = np.random.rand(N) colors = ["r" if c > .75 else "b" for c in np.random.rand(N)] pts = [] for ix in range(N): if colors[ix] == "r": pts.append([x[ix], y[ix]]) fig = plt.figure() ax = fig.add_subplot(1, 1, 1) c, r = selectpoints(ax, pts, radius=.05, ec='r', fill=False) print "center:", c print "radius:", r plt.scatter(x, y, s=30, c=colors, alpha=0.5) plt.savefig("example.png")
def analyze_capture(capture, rule, parameters, increment, loop, ks_threshold, visualize_option): table_data = [[ 'Time (since epoch)', parameters.split(',')[0], parameters.split(',')[1] ]] change_lst = [] color_dict = OrderedDict() link_lst = [] reset_lst = [] ref = () warn = 0 for packet in capture: param = ['null', 'null'] for i in range(0, 2): #search data associated with PARAM_0 and PARAM_1 for j in packet.layers: if parameters.split(',')[i] in j._all_fields: param[i] = j._all_fields[parameters.split(',')[i]] if param[0] != 'null' and param[ 1] != 'null': #if PARAM_0 AND PARAM_1 are not NULL if not ref: #first packet to handle ref = (param[0], param[1], packet.frame_info.time_epoch) if rule == 'SYNC_CNT_CHG': try: int(param[1]) except: print '[ERROR] Parameter "' + parameters.split( ',')[1] + '" is not a counter.' sys.exit(1) attribute_color(param[0], color_dict) #reset_lst.append((param[0],param[1],packet.frame_info.time_epoch)) else: if param[0] != ref[0] or param[1] != ref[ 1]: #if PARAM_0 OR PARAM_1 change if param[0] != ref[0] and param[1] != ref[ 1]: #if PARAM_0 AND PARAM_1 change for i in range( 0, 2 ): #PARAM_0/PARAM_1 has taken the same value as before when change lst = [ item for item in change_lst if item[i] == param[i] ] if lst: table_data.extend( ([lst[-1][2], lst[-1][0], lst[-1][1]], [ packet.frame_info.time_epoch, param[0], param[1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split( ',' )[i] + '" has already taken this value @ ' + packet.frame_info.time_epoch + '.' warn += 1 if rule == 'SYNC_CNT_CHG' and ref[ 1] != 'null': #definition of the SYNC_CNT_CHG rule link_lst.append( [[float(ref[2]), int(ref[1])], [ float(packet.frame_info.time_epoch), int(param[1]) ]]) reset_lst.append((param[0], param[1], packet.frame_info.time_epoch)) attribute_color(param[0], color_dict) if cmp(int(param[1]), int(ref[1])) > 0 and abs( int(param[1]) - int(ref[1]) ) <= increment: #PARAM_1 is incremented table_data.extend(([ref[2], ref[0], ref[1]], [ packet.frame_info.time_epoch, param[0], param[1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split( ',' )[1] + '" is incremented @ ' + packet.frame_info.time_epoch + '.' warn += 1 elif cmp(int(param[1]), int(ref[1])) < 0 and abs( int(param[1]) + loop - int(ref[1]) ) <= increment: #PARAM_1 has looped table_data.extend(([ref[2], ref[0], ref[1]], [ packet.frame_info.time_epoch, param[0], param[1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split( ',' )[1] + '" has looped @ ' + packet.frame_info.time_epoch + '.' warn += 1 elif rule == 'SYNC_ID_CHG' and param[0] == ref[ 0] and param[1] != ref[ 1]: #PARAM_0 is not synchronously changed with PARAM_1 table_data.extend(([ref[2], ref[0], ref[1]], [ packet.frame_info.time_epoch, param[0], param[1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split( ',' )[0] + '" is not synchronously changed with parameter "' + parameters.split( ',' )[1] + '" @ ' + packet.frame_info.time_epoch + '.' warn += 1 elif param[0] != ref[0] and param[1] == ref[ 1]: #PARAM_1 is not synchronously changed with PARAM_0 table_data.extend(([ref[2], ref[0], ref[1]], [ packet.frame_info.time_epoch, param[0], param[1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split( ',' )[1] + '" is not synchronously changed with parameter "' + parameters.split( ',' )[0] + '" @ ' + packet.frame_info.time_epoch + '.' warn += 1 change_lst.append((ref[0], ref[1], ref[2])) ref = (param[0], param[1], packet.frame_info.time_epoch) if ref: #if capture contains at least one packet if (change_lst and change_lst[-1] != ref) or not change_lst: change_lst.append((ref[0], ref[1], ref[2])) if len( list(set([(item[0], item[1]) for item in change_lst])) ) == 1: #PARAM_0 and PARAM_1 are static (i.e. do not change) over time table_data.extend( ([change_lst[-1][2], change_lst[-1][0], change_lst[-1][1]], ['', '', ''])) print '[WARN] Parameters "' + parameters.split( ',')[0] + '" and "' + parameters.split( ',')[1] + '" are static (i.e. do not change) over time.' warn += 1 else: for i in range( 0, 2 ): #PARAM_0/PARAM_1 is static (i.e. does not change) over time if len(list(set([item[i] for item in change_lst]))) == 1: table_data.extend(([ change_lst[-1][2], change_lst[-1][0], change_lst[-1][1] ], ['', '', ''])) print '[WARN] Parameter "' + parameters.split(',')[ i] + '" is static (i.e. does not change) over time.' warn += 1 if rule == 'SYNC_CNT_CHG': if reset_lst: if reset_lst[-1] != ref: reset_lst.append((ref[0], ref[1], ref[2])) attribute_color(ref[0], color_dict) if kstest( [int(item[1]) for item in reset_lst], 'uniform' )[1] < ks_threshold: #submit values of the reset of the counter to the Kolmogorov-Smirnov statistical test #print '[DEBUG] Results of the Kolmogorov-Smirnov test: (statistic='+str(kstest([int(item[1]) for item in reset_lst],'uniform')[0])+', pvalue='+str(kstest([int(item[1]) for item in reset_lst],'uniform')[1])+')' print '[WARN] Parameter "' + parameters.split( ',' )[1] + '" is non-uniformly distributed (i.e. the reset of the counter is not random).' warn += 1 if visualize_option: #if option enabled, visualize results in a SingleTable (and in a scatter plot for the SYNC_CNT_CHG rule) if len(table_data) > 1: table_data.pop() print '\n' + SingleTable(table_data).table if rule == 'SYNC_CNT_CHG': ax = plt.figure().add_subplot(1, 1, 1) for link in link_lst: selectpoints(ax, link, radius=0.6, ec='r', lw=2, ls='-', a=1, fill=False) plt.title( parameters.split(',')[1] + ' wrt. time (since epoch)') plt.xlabel('Time (since epoch)') plt.ylabel(parameters.split(',')[1]) plt.scatter([float(item[2]) for item in change_lst], [int(item[1]) for item in change_lst], color=[color_dict[item[0]] for item in change_lst], marker='o', edgecolors='black') legend = [ Line2D([0], [0], color='white', marker='o', label='Data', markerfacecolor='white', markeredgecolor='black', markeredgewidth=1.1, markersize=6) ] if link_lst: legend.append( Patch(facecolor='white', edgecolor='red', linewidth=1.6, label='Link')) plt.legend(handles=legend, loc='best') plt.show() if warn != 0: print bold( red('\n' + 'The analysis raised ' + str(warn) + ' warning(s). Please correct them.')) else: print bold( green('The analysis raised no warning. Very privacy \o/')) else: print '[ERROR] No packets to analyze.' sys.exit(1)
def plot_kmap(data, data_raw=True, as_partitions=None, data_label = "", filename = "", plot_annotation = True, annotation_params=None, title = None, title_loc = "center", titlelabelsize=26, axlabelsize=22, textsize=16, annotationsize=13, tail_threshold=None, plot_legend = True, plot_scatter=True, scatter_ms = None, scatter_c='k', scatter_a=.5, scatter_m=r'.', plot_heatmap=True, colormap=plt.cm.Greys, plot_contour=False, plot_contour_lbls=False, max_val_exp = 5): # Plot basic setup matplotlib.rcParams.update({'font.size': textsize}) fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1) if title != None: plt.title(title, loc=title_loc, fontdict={'fontsize': titlelabelsize}) ax.set_xlabel("Anonymity Set Size ($k$)") ax.set_ylabel("Num. Anonymity Sets at Size of $k$") plt.tick_params(axis='both', which='major', labelsize=axlabelsize) # Process data if data_raw: # Assumed that anonymity sets partition the dataset data_length = len(data) xy = Counter(Counter(data).values()) x = [x_ for x_ in sorted(xy.keys())] y = [xy[ass] for ass in sorted(xy.keys())] if as_partitions == None or as_partitions == True: z = [ass*xy[ass] for ass in sorted(xy.keys())] w = [float(ass*xy[ass])/data_length for ass in sorted(xy.keys())] else: z = [xy[ass] for ass in sorted(xy.keys())] w = [float(xy[ass])/data_length for ass in sorted(xy.keys())] else: # Not assumed that anonymity sets partition the dataset (e.g., they could be overlapping) data_length = data[0] xy = data[1] x = [x_ for x_ in sorted(xy.keys())] y = [xy[ass] for ass in sorted(xy.keys())] if as_partitions == None or as_partitions == False: z = [xy[ass] for ass in sorted(xy.keys())] w = [float(xy[ass])/data_length for ass in sorted(xy.keys())] else: z = [ass*xy[ass] for ass in sorted(xy.keys())] w = [float(ass*xy[ass])/data_length for ass in sorted(xy.keys())] if plot_heatmap or plot_contour: # Emphasize heavy spots for the contour (but visualize only one for each) x_ = [] y_ = [] z_ = [] for ix in range(len(z)): for i in range((z[ix])): if i == 0: if scatter_ms == None: z_.append(float(10000*z[ix])/data_length) else: z_.append(scatter_ms) else: z_.append(0.0) x_.append(math.log(x[ix], 10)) y_.append(math.log(y[ix], 10)) # Heatmap calculation X, Y = np.mgrid[-0.5:5:100j, -0.5:5:100j] positions = np.vstack([X.ravel(), Y.ravel()]) values = np.vstack([x_, y_]) kernel = gaussian_kde(values) Z = np.reshape(kernel(positions).T, X.shape) Z = np.sqrt(np.sqrt(Z)) # Strengthen low-weighted regions # Plot heatmap if plot_heatmap: plt.contourf(X, Y, Z, 10, cmap=colormap, alpha=.5) # Plot contour if plot_contour: cs = plt.contour(X, Y, Z, 10, cmap=colormap, alpha=.5) if plot_contour_lbls: plt.clabel(cs, inline=1, fontsize=int(textsize/2)) if plot_scatter: # Scatter points plt.scatter([math.log(_, 10) for _ in x], [math.log(_, 10) for _ in y], s=[10**4*_ for _ in w], alpha=scatter_a, c=scatter_c, marker=scatter_m, label = data_label) # alpha=.5, if plot_legend: # Legend lgnd = plt.legend(loc="upper right", fontsize=textsize) # , numpoints=1 lgnd.legendHandles[0]._sizes = [30] # Select groups of datapoints if isinstance(plot_annotation, list): grps = [[] for _ in range(len(plot_annotation))] weights = [0.0 for _ in range(len(plot_annotation))] for ix in range(len(x)): for gix in range(len(plot_annotation)): grp = plot_annotation[gix] if x[ix] >= min(grp) and x[ix] <= max(grp): grps[gix].append([x[ix], y[ix]]) weights[gix] += w[ix] for gix, grp in enumerate(grps): if len(grp) == 0: continue annotation_radius=.1 if isinstance(annotation_params, dict) and 'radius' in annotation_params: if isinstance(annotation_params['radius'], list): annotation_radius = annotation_params['radius'][gix] else: annotation_radius = annotation_params['radius'] annotation_distance=1.0 if isinstance(annotation_params, dict) and 'distance' in annotation_params: if isinstance(annotation_params['radius'], list): annotation_distance = annotation_params['distance'][gix] else: annotation_distance = annotation_params['distance'] annotation_linestyle=dict(color='r', width=2, style='-') if isinstance(annotation_params, dict) and 'linestyle' in annotation_params: annotation_linestyle = annotation_params['linestyle'] pts = [[math.log(pt[0], 10), math.log(pt[1], 10)] for pt in grp] c, r = selectpoints(ax, pts, radius=annotation_radius, ec=annotation_linestyle['color'], lw=annotation_linestyle['width'], ls=annotation_linestyle['style'], fill=False) annotation_shift_vector = [r*annotation_distance, 0.0] if isinstance(annotation_params, dict) and 'location' in annotation_params: if isinstance(annotation_params['location'], list): if annotation_params['location'][gix] == 'left': annotation_shift_vector = [-r*annotation_distance, 0.0] elif annotation_params['location'][gix] == 'top': annotation_shift_vector = [0.0, r*annotation_distance] elif annotation_params['location'][gix] == 'bottom': annotation_shift_vector = [0.0, -r*annotation_distance] else: if annotation_params['location'] == 'left': annotation_shift_vector = [-r*annotation_distance, 0.0] elif annotation_params['location'] == 'top': annotation_shift_vector = [0.0, r*annotation_distance] elif annotation_params['location'] == 'bottom': annotation_shift_vector = [0.0, -r*annotation_distance] plt.text(c[0]+annotation_shift_vector[0], c[1]+annotation_shift_vector[1], "%.2f %%" % (weights[gix] * 100)) # Add annotations for minimum and maximum anonymity sets elif isinstance(plot_annotation, bool) and plot_annotation: add_annotations(ax, x, y, z, annotationsize, tail_threshold) # Setup XY axes maxval = max_val_exp plt.ylim(-0.5, maxval) plt.xlim(-0.5, maxval) ticks = range(maxval+1) lbls = ["${10}^{%d}$" % v for v in range(maxval)] ax.set_xticks(ticks) ax.set_xticklabels(lbls) ax.set_yticks(ticks) ax.set_yticklabels(lbls) # Save file plt.tight_layout() if '.' in filename: plt.savefig(filename) else: plt.savefig(filename+'.pdf') plt.savefig(filename+'.png')
def plot_kmap(data, data_raw=True, as_partitions=None, data_label="", filename="", plot_annotation=True, annotation_params=None, title=None, title_loc="center", titlelabelsize=26, axlabelsize=22, textsize=16, annotationsize=13, tail_threshold=None, plot_legend=False, plot_scatter=True, scatter_ms=None, scatter_c='k', scatter_a=.5, scatter_m=r'.', plot_heatmap=True, colormap=plt.cm.Greys, plot_contour=False, plot_contour_lbls=False, max_val_exp=5): # Plot basic setup matplotlib.rcParams.update({'font.size': textsize}) fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1) if title != None: plt.title(title, loc=title_loc, fontdict={'fontsize': titlelabelsize}) ax.set_xlabel("Anonymity Set Size ($k$)") ax.set_ylabel("Num. Anonymity Sets at Size of $k$") plt.tick_params(axis='both', which='major', labelsize=axlabelsize) # Process data if data_raw: # Assumed that anonymity sets partition the dataset data_length = len(data) xy = Counter(Counter(data).values()) x = [x_ for x_ in sorted(xy.keys())] y = [xy[ass] for ass in sorted(xy.keys())] if as_partitions == None or as_partitions == True: z = [ass * xy[ass] for ass in sorted(xy.keys())] w = [ float(ass * xy[ass]) / data_length for ass in sorted(xy.keys()) ] else: z = [xy[ass] for ass in sorted(xy.keys())] w = [float(xy[ass]) / data_length for ass in sorted(xy.keys())] else: # Not assumed that anonymity sets partition the dataset (e.g., they could be overlapping) data_length = data[0] xy = data[1] x = [x_ for x_ in sorted(xy.keys())] y = [xy[ass] for ass in sorted(xy.keys())] if as_partitions == None or as_partitions == False: z = [xy[ass] for ass in sorted(xy.keys())] w = [float(xy[ass]) / data_length for ass in sorted(xy.keys())] else: z = [ass * xy[ass] for ass in sorted(xy.keys())] w = [ float(ass * xy[ass]) / data_length for ass in sorted(xy.keys()) ] if plot_heatmap or plot_contour: # Emphasize heavy spots for the contour (but visualize only one for each) x_ = [] y_ = [] z_ = [] for ix in range(len(z)): for i in range((z[ix])): if i == 0: if scatter_ms == None: z_.append(float(10000 * z[ix]) / data_length) else: z_.append(scatter_ms) else: z_.append(0.0) x_.append(math.log(x[ix], 10)) y_.append(math.log(y[ix], 10)) # Heatmap calculation X, Y = np.mgrid[-0.5:5:100j, -0.5:5:100j] positions = np.vstack([X.ravel(), Y.ravel()]) values = np.vstack([x_, y_]) kernel = gaussian_kde(values) Z = np.reshape(kernel(positions).T, X.shape) Z = np.sqrt(np.sqrt(Z)) # Strengthen low-weighted regions # Plot heatmap if plot_heatmap: plt.contourf(X, Y, Z, 10, cmap=colormap, alpha=.5) # Plot contour if plot_contour: cs = plt.contour(X, Y, Z, 10, cmap=colormap, alpha=.5) if plot_contour_lbls: plt.clabel(cs, inline=1, fontsize=int(textsize / 2)) if plot_scatter: # Scatter points plt.scatter([math.log(_, 10) for _ in x], [math.log(_, 10) for _ in y], s=[10**4 * _ for _ in w], alpha=scatter_a, c=scatter_c, marker=scatter_m, label=data_label) # alpha=.5, if plot_legend: # Legend lgnd = plt.legend(loc="upper right", fontsize=textsize) # , numpoints=1 lgnd.legendHandles[0]._sizes = [30] # Select groups of datapoints if isinstance(plot_annotation, list): grps = [[] for _ in range(len(plot_annotation))] weights = [0.0 for _ in range(len(plot_annotation))] for ix in range(len(x)): for gix in range(len(plot_annotation)): grp = plot_annotation[gix] if x[ix] >= min(grp) and x[ix] <= max(grp): grps[gix].append([x[ix], y[ix]]) weights[gix] += w[ix] for gix, grp in enumerate(grps): if len(grp) == 0: continue annotation_radius = .1 if isinstance(annotation_params, dict) and 'radius' in annotation_params: if isinstance(annotation_params['radius'], list): annotation_radius = annotation_params['radius'][gix] else: annotation_radius = annotation_params['radius'] annotation_distance = 1.0 if isinstance(annotation_params, dict) and 'distance' in annotation_params: if isinstance(annotation_params['radius'], list): annotation_distance = annotation_params['distance'][gix] else: annotation_distance = annotation_params['distance'] annotation_linestyle = dict(color='r', width=2, style='-') if isinstance(annotation_params, dict) and 'linestyle' in annotation_params: annotation_linestyle = annotation_params['linestyle'] pts = [[math.log(pt[0], 10), math.log(pt[1], 10)] for pt in grp] c, r = selectpoints(ax, pts, radius=annotation_radius, ec=annotation_linestyle['color'], lw=annotation_linestyle['width'], ls=annotation_linestyle['style'], fill=False) annotation_shift_vector = [r * annotation_distance, 0.0] if isinstance(annotation_params, dict) and 'location' in annotation_params: if isinstance(annotation_params['location'], list): if annotation_params['location'][gix] == 'left': annotation_shift_vector = [ -r * annotation_distance, 0.0 ] elif annotation_params['location'][gix] == 'top': annotation_shift_vector = [ 0.0, r * annotation_distance ] elif annotation_params['location'][gix] == 'bottom': annotation_shift_vector = [ 0.0, -r * annotation_distance ] else: if annotation_params['location'] == 'left': annotation_shift_vector = [ -r * annotation_distance, 0.0 ] elif annotation_params['location'] == 'top': annotation_shift_vector = [ 0.0, r * annotation_distance ] elif annotation_params['location'] == 'bottom': annotation_shift_vector = [ 0.0, -r * annotation_distance ] plt.text(c[0] + annotation_shift_vector[0], c[1] + annotation_shift_vector[1], "%.2f %%" % (weights[gix] * 100)) # Add annotations for minimum and maximum anonymity sets elif isinstance(plot_annotation, bool) and plot_annotation: add_annotations(ax, x, y, z, annotationsize, tail_threshold) # Setup XY axes maxval = max_val_exp plt.ylim(-0.5, maxval) plt.xlim(-0.5, maxval) ticks = range(maxval + 1) lbls = ["${10}^{%d}$" % v for v in range(maxval)] ax.set_xticks(ticks) ax.set_xticklabels(lbls) ax.set_yticks(ticks) ax.set_yticklabels(lbls) # Save file plt.tight_layout() if '.' in filename: plt.savefig(filename) else: plt.savefig(filename + '.pdf') plt.savefig(filename + '.png')