def create_plot(title, xlabel, ylabel, source, lines, yformatter=None): fig = plotting.figure( plot_width=PLOT_WIDTH, plot_height=PLOT_HEIGHT, tools=TOOLS ) fig.title.text = title fig.xaxis.axis_label = xlabel fig.yaxis.axis_label = ylabel fig.xaxis.formatter = models.NumeralTickFormatter(format='0,0') if yformatter is not None: fig.yaxis.formatter = yformatter is_legend = False for x in lines: if x.legend != '': is_legend = True fig.line(x='Time', y=x.col, color=x.color, legend_label=x.legend, source=source) else: fig.line(x='Time', y=x.col, color=x.color, source=source) if is_legend: fig.legend.click_policy="hide" return fig
def create_packets_plot(source, is_sender): side_name = 'Sender' if is_sender else 'Receiver' if is_sender: lines = [ linedesc('pktSent', 'Sent', 'green'), linedesc('pktSndLoss', 'Lost', 'orange'), linedesc('pktRetrans', 'Retransmitted', 'blue'), linedesc('pktSndDrop', 'Dropped', 'red'), linedesc('pktFlightSize', 'On Flight', 'black'), ] else: lines = [ linedesc('pktRecv', 'Received', 'green'), linedesc('pktRcvLoss', 'Lost', 'orange'), linedesc('pktRcvRetrans', 'Retransmitted', 'blue'), linedesc('pktRcvBelated', 'Belated', 'grey'), linedesc('pktRcvDrop', 'Dropped', 'red'), ] return create_plot( 'Packets (' + side_name + ' Side)', 'Time (ms)', 'Number of Packets', source, lines, models.NumeralTickFormatter(format='0,0') )
def figure_histogram(hist, edges, title: str, normalized=False, x_range=(0, 5000)): """ Create and return `bokeh` histogram figure. """ fig = plotting.figure( plot_height = 400, plot_width=800, tools=TOOLS, background_fill_color='#fafafa', x_range=x_range ) fig.quad( top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color='navy', line_color='white', alpha=0.5 ) fig.title.text = title fig.xaxis.axis_label = 'x, us' fig.y_range.start = 0 fig.grid.grid_line_color='white' if normalized: fig.yaxis.axis_label = 'f(x)' else: fig.yaxis.axis_label = 'f(x), packets' fig.yaxis.formatter = models.NumeralTickFormatter(format='0,0') return fig
def _prepare_plot(self): mean = np.array(self.mean) deviation = np.array(self.deviation) self._figure = bp.figure(title=self._title, plot_width=1200, plot_height=600) self._figure.title.text_font_size = '20pt' self._figure.xaxis.axis_label = "Base length" self._figure.xaxis.axis_label_text_font_size = '16pt' self._figure.xaxis.major_label_text_font_size = '12pt' self._figure.yaxis[0].formatter = bm.NumeralTickFormatter(format="0.00%") self._figure.yaxis[0].major_label_text_font_size = '12pt' self._figure.line(self.scales, mean, legend="Error mean", line_color="red", line_width=2) self._figure.circle(self.scales, mean, legend="Error mean", line_color="red", fill_color="red") self._figure.square(self.scales, deviation, legend="Deviation", fill_color=None, line_color="green", line_width=2) self._figure.line(self.scales, deviation, legend="Deviation", line_color="green") self._figure.ygrid.minor_grid_line_color = '#e5e5e5' self._figure.ygrid.minor_grid_line_dash = [6, 4] self._figure.ygrid.minor_grid_line_alpha = 0.7 self._figure.legend.location = "top_right" self._figure.legend.label_text_font_size = '16pt'
def new_plot(self, title, units, *, line_width=None, precision=2): """ Creates a blank line plot for with timestamps on the x-axis and a line for each data series on the y-axis. """ plot = plotting.figure(title=title, tools=[]) self.active_plot = plot self.plots.append(plot) self.colors = list(colors) self.units = units self.line_width = line_width or self.line_width plot.plot_width = self.width plot.plot_height = self.height plot.x_range = self.x_range datetime_tick_formats = { key: ["%a %b %d %H:%M:%S"] for key in ("seconds", "minsec", "minutes", "hourmin", "hours", "days") } plot.xaxis.formatter = models.DatetimeTickFormatter(**datetime_tick_formats) # https://bokeh.pydata.org/en/latest/docs/reference/models/formatters.html # plot.yaxis.formatter = models.NumeralTickFormatter(format="0a") plot.yaxis.formatter = models.NumeralTickFormatter(format="0,0.00 a") # With default precision level 2 (decimal places) # The units_formats = "@y{0,0.00}" # and the value would look like 1,234,567.89 units_formats = f"@y{{0,0.{'0' * precision}}}" hover = models.HoverTool( # mode = vline would be nice to use, # but then separate hovers block each when lines are too close. # Would like a single hover box with time once, and a value per line # perhaps this will help acheive that: # https://stackoverflow.com/questions/29435200/bokeh-plotting-enable-tooltips-for-only-some-glyphs mode="mouse", # other optins: vline line_policy="nearest", # other optins: prev, next, nearest, interp, none tooltips=[ ("Name", "$name"), ("Time", "@x{%a %m/%d %H:%M:%S}"), (self.units, units_formats), ], formatters={"x": "datetime", "Time": "datetime", "@x": "datetime"}, ) plot.add_tools(hover) plot.add_tools(models.BoxZoomTool()) plot.add_tools(models.HelpTool()) plot.add_tools(models.PanTool()) plot.add_tools(models.WheelZoomTool(dimensions="width")) plot.toolbar.active_scroll = plot.select_one(models.WheelZoomTool) plot.add_tools(models.WheelZoomTool(dimensions="height")) plot.add_tools(models.UndoTool()) plot.add_tools(models.RedoTool()) plot.add_tools(models.ResetTool()) plot.add_tools(models.SaveTool())
def plot_percents(data: list) -> plotting.Figure: """Return the bokeh of temperature data.""" plot = make_timeseries_plot() plot.yaxis.formatter = models.NumeralTickFormatter(format="0%") plot.y_range = models.Range1d(0, 1) plot = make_fact_lines(plot, data) plot.legend.location = "top_left" # because the legend requires glyphs return plot
def create_bandwidth_plot(source): lines = [linedesc('mbpsBandwidth', '', 'green')] return create_plot( 'Bandwith', 'Time (ms)', 'Bandwith (Mbps)', source, lines, models.NumeralTickFormatter(format='0,0') )
def create_window_size_plot(source): lines = [ linedesc('pktFlowWindow', 'Flow Window', 'green'), linedesc('pktCongestionWindow', 'Congestion Window', 'red'), ] return create_plot( 'Window Size', 'Time (ms)', 'Number of Packets', source, lines, models.NumeralTickFormatter(format='0,0') )
def create_avail_buffer_plot(source, is_sender): side_name = 'Sending' if is_sender else 'Receiving' if is_sender: if not 'byteAvailSndBuf' in source.column_names: return None lines = [linedesc('MBAvailSndBuf', '', 'green')] else: if not 'byteAvailRcvBuf' in source.column_names: return None lines = [linedesc('MBAvailRcvBuf', '', 'green')] return create_plot( 'Available ' + side_name + ' Buffer Size', 'Time (ms)', 'MB', source, lines, models.NumeralTickFormatter(format='0,0.00') )
def create_rate_plot(source, is_sender): side_name = 'Sending' if is_sender else 'Receiving' if is_sender: lines = [ linedesc('mbpsSendRate', 'Sendrate', 'green'), # Please don't delete the following line. # It is used in some cases. #linedesc('mbpsMaxBW', 'Bandwidth Limit', 'black'), ] else: lines = [linedesc('mbpsRecvRate', '', 'green')] return create_plot( side_name + ' Rate', 'Time (ms)', 'Rate (Mbps)', source, lines, models.NumeralTickFormatter(format='0,0.00') )
def create_bytes_plot(source, is_sender): side_name = 'Sender' if is_sender else 'Receiver' if is_sender: lines = [ linedesc('MBSent', 'Sent', 'green'), linedesc('MBSndDrop', 'Dropped', 'red') ] else: lines = [ linedesc('MBRecv', 'Received', 'green'), linedesc('MBRcvDrop', 'Dropped', 'red'), ] return create_plot( 'Megabytes (' + side_name + ' Side)', 'Time (ms)', 'MB', source, lines, models.NumeralTickFormatter(format='0,0.00') )
def make_color_bar(cmap, formatting): """ Generates color bar from make_color_mapper() :param (Bokeh object) cmap: colormapper from make_color_mapper() :param (dict) formatting: see DEFAULTFORMAT from params.py :return: None (adds to Bokeh object) """ color_bar = models.ColorBar(color_mapper=cmap, label_standoff=10, location='bottom_right', height=formatting['cbar_height'], background_fill_color=None, major_label_text_font_size=formatting['cbar_fontsize'], major_label_text_font=formatting['font'], major_tick_line_color=formatting['cbar_tick_color'], major_tick_line_alpha=formatting['cbar_tick_alpha'], title=formatting['cbar_title'], title_text_font_size=formatting['cbar_fontsize'], title_text_font=formatting['font'], title_text_align=formatting['cbar_title_align'], title_text_font_style=formatting['cbar_style'], title_standoff=int(formatting['width'] * \ formatting['cbar_title_standoff_ratio'])) if formatting['cbar_textfmt']: color_bar.formatter = models.NumeralTickFormatter( format=formatting['cbar_textfmt']) return color_bar
def __init__(self, readers, rule): super().__init__(readers, rule) self.figure.yaxis[0].formatter = bom.NumeralTickFormatter(format="0%")
def set_yaxis_cash(plot): plot.yaxis.axis_label = "Vuositulot" plot.yaxis[0].formatter = bm.NumeralTickFormatter(format="€0")
def panel_eda(data: pd.DataFrame): """ The main panel with exploratory data analysis consisting of: - packet timestamp vs packet inter-arrival time plot, - basic statistics table, - bar chart and table with sliced into intervals packet inter-arrival times, - histograms regular and normalized, 100us bins, - histograms regular and normalized, 10us bins, - ECDF. Attributes: data: `pd.DataFrame` with packet inter-arrival times data preliminary cleaned up and consisting of the two columns `ws.time` and `ws.iat.us`, where `ws.time` is the packet timestamp in seconds and `ws.iat.us` is the corresponding inter-arrival time from the previous data packet in microseconds. Returns: `models.widgets.Panel` bokeh panel. """ # Figure: Packet timestamp vs Inter-arrival packet time source_data = models.ColumnDataSource(data) fig_iat = plotting.figure( plot_height=400, plot_width=1000, x_range=(0, 10), tools=TOOLS ) fig_iat.title.text = 'Inter-arrival packet time' fig_iat.xaxis.axis_label = 'Time, s' fig_iat.yaxis.axis_label = 'IAT, us' fig_iat.yaxis.formatter = models.NumeralTickFormatter(format='0,0') fig_iat.line(x='ws.time', y='ws.iat.us', source=source_data) # Table: Statistics stats = {} stats['stats'] = [ '25th percentile (Q1), us', '50th percentile (Median, Q2), us', '75th percentile (Q3), us', '90th percentile, us', '95th percentile, us', '99th percentile, us', 'Interquartile range (IQR, Q3 - Q1), us', 'Mean, us', 'Standard deviation, us', 'Min, us', 'Max, us', 'Packets', ] stats['value'] = get_stats(data['ws.iat.us']) source_stats = models.ColumnDataSource(pd.DataFrame(stats)) columns = [ models.widgets.TableColumn(field='stats', title='Statistic'), models.widgets.TableColumn(field='value', title='Value'), ] table_stats = models.widgets.DataTable(columns=columns, source=source_stats) # Bar chart, table: Sliced into intervals inter-arrival packet times fig_slicing, table_slicing = perform_slicing(data['ws.iat.us']) # Histograms regular and normalized, 100us bins bins_100 = [n * 100 for n in range(0, 5001)] hist_100, edges_100 = np.histogram(data['ws.iat.us'], bins=bins_100) fig_hist_100 = figure_histogram(hist_100, edges_100, 'Histogram of inter-arrival packet time, 100us bins') hist_norm_100, edges_norm_100 = np.histogram(data['ws.iat.us'], bins=bins_100, density=True) fig_hist_norm_100 = figure_histogram(hist_norm_100, edges_norm_100, 'Normalized histogram of inter-arrival packet time, 100us bins', True) # Histograms regular and normalized, 100us bins bins_10 = [n * 10 for n in range(0, 50001)] hist_10, edges_10 = np.histogram(data['ws.iat.us'], bins=bins_10) fig_hist_10 = figure_histogram(hist_10, edges_10, 'Histogram of inter-arrival packet time, 10us bins') hist_norm_10, edges_norm_10 = np.histogram(data['ws.iat.us'], bins=bins_10, density=True) fig_hist_norm_10 = figure_histogram(hist_norm_10, edges_norm_10, 'Normalized histogram of inter-arrival packet time, 10us bins', True) # Synchronize x axeses of the histograms fig_hist_100.x_range = \ fig_hist_norm_100.x_range = \ fig_hist_10.x_range = \ fig_hist_norm_10.x_range # ECDF x, y = ecdf(data['ws.iat.us']) fig_ecdf = figure_ecdf(x, y) # Create grid grid = layouts.gridplot( [ [fig_iat, table_stats], [fig_slicing, table_slicing], [fig_hist_100, fig_hist_norm_100], [fig_hist_10, fig_hist_norm_10], [None, fig_ecdf], ] ) # Create panel panel = models.widgets.Panel(child=grid, title='Exploratory Data Analysis') return panel
def perform_slicing(s: pd.Series): """ Perform slicing of the packet IAT series `s` into following bins: '0 - 10', '10 - 100', '100 - 500', '500 - 1,000', '1,000 - 5,000', '5,000 - 10,000', '10,000 - 50,000', '50,000 - 100,000', '100,000 - 500,000', where each diapason is specified in microseconds (us). Attributes: s: ` pd.Series` of packet inter-arrival time in microseconds (us). Returns: `bokeh` bar chart figure and table with data. """ bins = [0, 10, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000] hist, edges = np.histogram(s, bins=bins) bins_str = [ '0 - 10', '10 - 100', '100 - 500', '500 - 1,000', '1,000 - 5,000', '5,000 - 10,000', '10,000 - 50,000', '50,000 - 100,000', '100,000 - 500,000' ] d = {} d['edges.us'] = bins_str d['packets'] = hist df = pd.DataFrame(d) n = df['packets'].sum() df['packets_cumsum'] = df['packets'].cumsum() df['percentage'] = df['packets'] * 100 / n df['percentage_cumsum'] = round(df['percentage'].cumsum(), 4) df['percentage'] = round(df['percentage'], 4) # Figure fig = plotting.figure( plot_height=300, plot_width=1000, x_range=bins_str, tools=TOOLS ) fig.title.text = 'Inter-arrival packet time diapason vs Packets' fig.xaxis.axis_label = 'IAT, us' fig.yaxis.axis_label = 'Packets' fig.yaxis.formatter = models.NumeralTickFormatter(format='0,0') # fig.xaxis.major_label_orientation = math.pi/4 fig.vbar(x=bins_str, top=hist, width=0.9) # Table source = models.ColumnDataSource(df) columns = [ models.widgets.TableColumn(field='edges.us', title='IAT, us'), models.widgets.TableColumn(field='packets', title='Packets', formatter=models.NumberFormatter(format='0,0')), models.widgets.TableColumn(field='packets_cumsum', title='Packets cumsum', formatter=models.NumberFormatter(format='0,0')), models.widgets.TableColumn(field='percentage', title='Packets, %'), models.widgets.TableColumn(field='percentage_cumsum', title='Packets cumsum, %'), ] table = models.widgets.DataTable(columns=columns, source=source) return fig, table