Refactor CANveyor dashboard architecture
- Replace `stats.utils.extractor` with dedicated `loader` and `converter` modules to improve code organization. - Implement explicit pipeline stages for ingestion, decoding, and precomputation with caching. - Standardize data loading and J1939 parsing logic across sub-modules. - Enhance dashboard responsiveness by pre-calculating figures and downsampling ID-grouped data. - Enforce strict typing and add docstrings to public components.
This commit is contained in:
+9
-7
@@ -1,19 +1,19 @@
|
||||
# File: frequency.py
|
||||
# File: stats/frequency.py
|
||||
# Copyright (C) 2026 Erick Ahmed
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
"""CAN bus message frequency analyzer and plotter."""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import plotly.graph_objects as go
|
||||
from stats.utils.extractor import load_data
|
||||
|
||||
def _format_can_id_vec(s: pd.Series) -> pd.Series:
|
||||
s = s.astype('string').str.strip()
|
||||
s = s.str.replace(r'^0x', '', case=False, regex=True)
|
||||
s = s.str.upper()
|
||||
return s.fillna('UNKNOWN').replace('', 'UNKNOWN')
|
||||
from stats.utils.converter import format_can_id_vec as _format_can_id_vec
|
||||
from stats.utils.loader import load_data
|
||||
|
||||
|
||||
def calculate_frequency(df: pd.DataFrame) -> pd.DataFrame:
|
||||
can_id_col = 'ID' if 'ID' in df.columns else 'Identifier'
|
||||
@@ -28,6 +28,7 @@ def calculate_frequency(df: pd.DataFrame) -> pd.DataFrame:
|
||||
freq_df['Percentage'] = np.round(freq_df['Count'] / total * 100, 2) if total else 0.0
|
||||
return freq_df.sort_values('Count', ascending=True).reset_index(drop=True)
|
||||
|
||||
|
||||
def plot_frequency(stats_df: pd.DataFrame, title: str) -> go.Figure:
|
||||
n = len(stats_df)
|
||||
fig = go.Figure(go.Bar(
|
||||
@@ -106,6 +107,7 @@ def plot_frequency(stats_df: pd.DataFrame, title: str) -> go.Figure:
|
||||
)
|
||||
return fig
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Analyze CAN bus message frequency")
|
||||
parser.add_argument("input", type=Path, help="Path to the input CAN log file")
|
||||
|
||||
Reference in New Issue
Block a user