bookmark
This commit is contained in:
@@ -376,6 +376,9 @@ class FlowListDockWidget(QWidget):
|
|||||||
# Auto-resize numeric columns to fit content
|
# Auto-resize numeric columns to fit content
|
||||||
for col in [2, 3, 4, 7]: # Packets, Bytes, Max σ, Outliers
|
for col in [2, 3, 4, 7]: # Packets, Bytes, Max σ, Outliers
|
||||||
self.flows_table.resizeColumnToContents(col)
|
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):
|
def populate_flows_table_quick(self):
|
||||||
"""Populate the flows table quickly without plots for immediate display"""
|
"""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
|
for col in [2, 3, 4, 7]: # Packets, Bytes, Max σ, Outliers
|
||||||
self.flows_table.resizeColumnToContents(col)
|
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):
|
def on_flow_selected(self):
|
||||||
"""Handle flow selection"""
|
"""Handle flow selection"""
|
||||||
selected_rows = self.flows_table.selectionModel().selectedRows()
|
selected_rows = self.flows_table.selectionModel().selectedRows()
|
||||||
@@ -552,27 +590,46 @@ class FlowListDockWidget(QWidget):
|
|||||||
# Modern color scheme - blue for primary data
|
# Modern color scheme - blue for primary data
|
||||||
ax.plot(timestamps, data, color='#0078d4', linewidth=1.2, alpha=0.9)
|
ax.plot(timestamps, data, color='#0078d4', linewidth=1.2, alpha=0.9)
|
||||||
|
|
||||||
# Dark theme styling
|
# Dark theme styling with larger, more legible text
|
||||||
ax.set_xlabel('Time (s)', fontsize=7, color='#ffffff')
|
ax.set_xlabel('Time (s)', fontsize=9, color='#ffffff')
|
||||||
ax.set_ylabel('Amplitude', fontsize=7, color='#ffffff')
|
# ax.set_ylabel('Amplitude', fontsize=9, color='#ffffff') # Removed for cleaner embedded view
|
||||||
ax.tick_params(labelsize=6, colors='#cccccc')
|
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')
|
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
|
# Style the spines
|
||||||
for spine in ax.spines.values():
|
for spine in ax.spines.values():
|
||||||
spine.set_color('#404040')
|
spine.set_color('#404040')
|
||||||
spine.set_linewidth(0.5)
|
spine.set_linewidth(0.5)
|
||||||
|
|
||||||
# Add compact title with dark theme
|
# Add compact title with time range info
|
||||||
title_text = f'{channel_name} (+{len(signal_data_list)-1} more)' if len(signal_data_list) > 1 else channel_name
|
time_start = timestamps[0] if len(timestamps) > 0 else 0
|
||||||
ax.set_title(title_text, fontsize=7, color='#ffffff', pad=8)
|
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:
|
else:
|
||||||
self._create_error_plot(figure, canvas, "No channel data")
|
self._create_error_plot(figure, canvas, "No channel data")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Tight layout with minimal horizontal margins (fixed pixel-equivalent values)
|
# Maximum plot area with ultra-minimal margins on all sides
|
||||||
figure.subplots_adjust(left=0.08, right=0.98, top=0.85, bottom=0.25)
|
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
|
canvas.draw_idle() # Use draw_idle to avoid window creation
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user