Source code for raspberry_wifi_scanner.plotting

import numpy as np
import pandas as pd
import plotly.graph_objects as go


[docs] def gaussian_curve( center: int, quality: float, spread: int = 2, step: float = 0.1 ) -> tuple[np.ndarray, np.ndarray]: """ Return a tuple of ndarray (x,y) for plotting approximate curves :param center: channel at which network is centered :type center: int :param quality: signal quality of the network (typically between 0 and 1) :type quality: float :param spread: number of channels for the curve to reach on either side of center (typically around 2 for 20 MHz width) :type spread: int :param step: increments on the x-axis to calculate, typically a smaller number will produce a smoother curve :type step: float :return: two arrays of x, y values for plotting :rtype: tuple[np.ndarray, np.ndarray] """ x: np.ndarray = np.arange(center - spread, center + spread + step, step) sigma: float = 0.8 y: np.ndarray = quality * np.exp(-((x - center) ** 2) / (2 * sigma**2)) return x, y
[docs] def plot_curves(df: pd.DataFrame, title: str, spread: int = 2) -> go.Figure: """ Return a Plotly Figure of plotted curves based on signal_quality column and defined channel spread :param df: Dataframe containing signal quality and channel columns along with essid for its name :type df: pd.DataFrame :param title: Title of plot :type title: str :param spread: number of channels on left/right side of center to cover :type spread: int :return: Figure with a curve for every supplied row/network :rtype: go.Figure """ curves: list[go.Scatter] = [] for _, network in df.iterrows(): x: np.ndarray y: np.ndarray x, y = gaussian_curve( center=network["channel"], quality=network["quality_decimal"], spread=spread ) curve: go.Scatter = go.Scatter(x=x, y=y, mode="lines", name=network["essid"]) curves.append(curve) layout: go.Layout = go.Layout( title=title, xaxis=dict(title="Wi-Fi Channel", dtick=1), yaxis=dict(title="Signal Quality", range=[0, 1.1]), ) fig: go.Figure = go.Figure(data=curves, layout=layout) return fig
[docs] def plot_over_time( df: pd.DataFrame, y_column: str, category: str, title: str ) -> go.Figure: """ Return a figure of a given column plotted over time based on a given category :param df: Aggregated/sorted DataFrame recommend to sort_values(by=['time', category]) in advance :type df: pd.DataFrame :param y_column: Given column to plot on the Y-Axis :type y_column: str :param category: column name to separate the data into groups for individual traces, examples: "channel", "mac", "essid", etc :type category: str :param title: Title for the plot :type title: str :return: A figure with a trace for each unique value in the category column :rtype: go.Figure """ fig: go.Figure = go.Figure() for cat in df[category].unique(): cat_df: pd.DataFrame = df[df[category] == cat].reset_index() fig.add_trace( go.Scatter( x=cat_df["time"], y=cat_df[y_column], mode="lines", name=f"{cat}" ) ) fig.update_layout(title=title) return fig