104 lines
3.3 KiB
Python
104 lines
3.3 KiB
Python
import numpy as np
|
|
import plotly.graph_objects as go
|
|
from plotly.subplots import make_subplots
|
|
|
|
|
|
def stacked_plot(data):
|
|
"""Create a stacked plot with mean power on top and a 2D heatmap below.
|
|
|
|
Parameters
|
|
----------
|
|
data : array-like
|
|
Input data array. Will be squeezed to remove singleton dimensions.
|
|
Rows are interpreted as samples and columns as range/frequency bins.
|
|
|
|
Returns
|
|
-------
|
|
plotly.graph_objects.Figure
|
|
A two-row figure: the top panel shows the mean absolute power across
|
|
columns, and the bottom panel shows a heatmap of the absolute values.
|
|
"""
|
|
data = np.squeeze(data)
|
|
mean_dp = np.mean(np.abs(data), axis=1)
|
|
|
|
fig = make_subplots(rows=2, cols=1, row_heights=[0.3, 0.7], shared_xaxes=True,
|
|
vertical_spacing=0.01)
|
|
|
|
fig.add_trace(go.Scatter(y=mean_dp, name='Mean Power'), row=1, col=1)
|
|
fig.add_trace(go.Heatmap(z=np.abs(data).T, showscale=False, name='Heat Map'), row=2, col=1)
|
|
|
|
fig.update_layout(title='Mean DP Power and 2D Map', autosize=True)
|
|
fig.update_xaxes(visible=False, row=2, col=1)
|
|
fig.update_yaxes(visible=False, row=2, col=1)
|
|
|
|
return fig
|
|
|
|
|
|
def noise_mean(data):
|
|
"""Estimate the noise floor as the trimmed mean of absolute values.
|
|
|
|
Sorts the flattened absolute data and discards the bottom 10% and top 10%
|
|
before computing the mean, making the estimate robust to outliers and
|
|
strong targets.
|
|
|
|
Parameters
|
|
----------
|
|
data : array-like
|
|
Input data array of any shape.
|
|
|
|
Returns
|
|
-------
|
|
float
|
|
Mean of the central 80% of the sorted absolute values.
|
|
"""
|
|
sorted_data = np.sort(np.abs(data.flatten()))
|
|
cutoff_up_index = int(len(sorted_data) * 0.9)
|
|
cutoff_down_index = int(len(sorted_data) * 0.1)
|
|
trimmed_data = sorted_data[cutoff_down_index:cutoff_up_index]
|
|
|
|
return np.mean(trimmed_data)
|
|
|
|
|
|
def calculate_cdf(data):
|
|
"""Compute the empirical cumulative distribution function (CDF) of the data.
|
|
|
|
Parameters
|
|
----------
|
|
data : array-like
|
|
Input data array of any shape. Will be flattened before processing.
|
|
|
|
Returns
|
|
-------
|
|
tuple[numpy.ndarray, numpy.ndarray]
|
|
A ``(sorted_data, cdf)`` tuple where ``sorted_data`` contains the
|
|
sorted values and ``cdf`` contains the corresponding CDF probabilities
|
|
in the range (0, 1].
|
|
"""
|
|
sorted_data = np.sort(data.flatten())
|
|
cdf = np.arange(1, len(sorted_data) + 1) / len(sorted_data)
|
|
return (sorted_data, cdf)
|
|
|
|
|
|
def plot_cdfs(data_list, labels):
|
|
"""Plot the empirical CDFs of multiple datasets on a single figure.
|
|
|
|
Parameters
|
|
----------
|
|
data_list : list of array-like
|
|
List of data arrays to plot. Each array can have any shape and will
|
|
be flattened internally by :func:`calculate_cdf`.
|
|
labels : list of str
|
|
Legend labels corresponding to each entry in ``data_list``.
|
|
|
|
Returns
|
|
-------
|
|
plotly.graph_objects.Figure
|
|
A figure with one CDF line per dataset.
|
|
"""
|
|
fig = go.Figure()
|
|
for data, label in zip(data_list, labels):
|
|
sorted_data, cdf = calculate_cdf(data)
|
|
fig.add_trace(go.Scatter(x=sorted_data, y=cdf, mode='lines', name=label))
|
|
fig.update_layout(title='CDF of Data', xaxis_title='Value', yaxis_title='CDF', autosize=True)
|
|
return fig
|