This commit is contained in:
2025-07-26 16:09:49 -04:00
parent e9573d0e5f
commit 272d23c6be

View File

@@ -376,6 +376,9 @@ class FlowListDockWidget(QWidget):
# Auto-resize numeric columns to fit content
for col in [2, 3, 4, 7]: # Packets, Bytes, Max σ, Outliers
self.flows_table.resizeColumnToContents(col)
# Update header with time range information if we have flows
self._update_signal_plot_header(flows_list)
def populate_flows_table_quick(self):
"""Populate the flows table quickly without plots for immediate display"""
@@ -448,6 +451,41 @@ class FlowListDockWidget(QWidget):
for col in [2, 3, 4, 7]: # Packets, Bytes, Max σ, Outliers
self.flows_table.resizeColumnToContents(col)
def _update_signal_plot_header(self, flows_list):
"""Update the Signal Plot column header with time range information"""
if not flows_list or not self.analyzer:
return
# Find earliest and latest timestamps across all flows
earliest_time = float('inf')
latest_time = float('-inf')
for flow in flows_list:
if flow.timestamps:
flow_start = min(flow.timestamps)
flow_end = max(flow.timestamps)
earliest_time = min(earliest_time, flow_start)
latest_time = max(latest_time, flow_end)
if earliest_time != float('inf') and latest_time != float('-inf'):
# Convert timestamps to time-of-day format (assuming they're epoch seconds)
import datetime
try:
start_time = datetime.datetime.fromtimestamp(earliest_time).strftime('%H:%M:%S')
end_time = datetime.datetime.fromtimestamp(latest_time).strftime('%H:%M:%S')
header_text = f"Signal Plot\n{start_time}{end_time}"
except (ValueError, OSError):
# If timestamp conversion fails, show duration instead
duration = latest_time - earliest_time
header_text = f"Signal Plot\n{duration:.1f}s span"
else:
header_text = "Signal Plot"
# Update the header
self.flows_table.setHorizontalHeaderLabels([
"Source IP", "Dest IP", "Pkts", "Bytes", "Max σ", "Avg ΔT", "Std ΔT", "Outliers", "Protocols", header_text
])
def on_flow_selected(self):
"""Handle flow selection"""
selected_rows = self.flows_table.selectionModel().selectedRows()
@@ -552,27 +590,46 @@ class FlowListDockWidget(QWidget):
# Modern color scheme - blue for primary data
ax.plot(timestamps, data, color='#0078d4', linewidth=1.2, alpha=0.9)
# Dark theme styling
ax.set_xlabel('Time (s)', fontsize=7, color='#ffffff')
ax.set_ylabel('Amplitude', fontsize=7, color='#ffffff')
ax.tick_params(labelsize=6, colors='#cccccc')
# Dark theme styling with larger, more legible text
ax.set_xlabel('Time (s)', fontsize=9, color='#ffffff')
# ax.set_ylabel('Amplitude', fontsize=9, color='#ffffff') # Removed for cleaner embedded view
ax.tick_params(labelsize=8, colors='#cccccc', left=False, labelleft=False, bottom=False, labelbottom=False) # Hide all tick labels
ax.grid(True, alpha=0.15, color='#404040')
# No legend needed for embedded plots - cleaner appearance
# Add Y-axis min/max indicators for better readability
y_min, y_max = ax.get_ylim()
ax.text(0.02, 0.95, f'Max: {y_max:.2f}', transform=ax.transAxes,
fontsize=7, color='#00ff88', weight='bold',
bbox=dict(boxstyle='round,pad=0.2', facecolor='#2d2d2d', alpha=0.8))
ax.text(0.02, 0.02, f'Min: {y_min:.2f}', transform=ax.transAxes,
fontsize=7, color='#ff6b6b', weight='bold',
bbox=dict(boxstyle='round,pad=0.2', facecolor='#2d2d2d', alpha=0.8))
# Style the spines
for spine in ax.spines.values():
spine.set_color('#404040')
spine.set_linewidth(0.5)
# Add compact title with dark theme
title_text = f'{channel_name} (+{len(signal_data_list)-1} more)' if len(signal_data_list) > 1 else channel_name
ax.set_title(title_text, fontsize=7, color='#ffffff', pad=8)
# Add compact title with time range info
time_start = timestamps[0] if len(timestamps) > 0 else 0
time_end = timestamps[-1] if len(timestamps) > 0 else 0
duration = time_end - time_start
title_text = f'{channel_name}'
if len(signal_data_list) > 1:
title_text += f' (+{len(signal_data_list)-1} more)'
title_text += f' | {duration:.2f}s span'
ax.set_title(title_text, fontsize=8, color='#ffffff', pad=8)
else:
self._create_error_plot(figure, canvas, "No channel data")
return
# Tight layout with minimal horizontal margins (fixed pixel-equivalent values)
figure.subplots_adjust(left=0.08, right=0.98, top=0.85, bottom=0.25)
# Maximum plot area with ultra-minimal margins on all sides
figure.subplots_adjust(left=0.01, right=0.99, top=0.92, bottom=0.15)
canvas.draw_idle() # Use draw_idle to avoid window creation
except Exception as e: