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:
+8
-9
@@ -1,23 +1,21 @@
|
||||
# File: entropy.py
|
||||
# File: stats/entropy.py
|
||||
# Copyright (C) 2026 Erick Ahmed
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
"""CAN bus byte-level entropy analyzer and plotter."""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import plotly.graph_objects as go
|
||||
|
||||
from stats.utils.extractor import load_data
|
||||
from stats.utils.extractor import to_int
|
||||
from stats.utils.converter import format_can_id_vec as _format_can_id_vec, to_int
|
||||
from stats.utils.loader 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')
|
||||
|
||||
def _entropy_col(a: np.ndarray) -> float:
|
||||
a = a[~np.isnan(a)]
|
||||
@@ -36,6 +34,7 @@ def _entropy_col(a: np.ndarray) -> float:
|
||||
p = counts / counts.sum()
|
||||
return float(-np.sum(p * np.log2(p)))
|
||||
|
||||
|
||||
def calculate_byte_entropy(df: pd.DataFrame) -> pd.DataFrame:
|
||||
available_cols = [f"b{i}" for i in range(8) if f"b{i}" in df.columns]
|
||||
if not available_cols:
|
||||
@@ -64,7 +63,7 @@ def calculate_byte_entropy(df: pd.DataFrame) -> pd.DataFrame:
|
||||
else:
|
||||
groups = []
|
||||
|
||||
def _process_group(sub):
|
||||
def _process_group(sub: np.ndarray) -> np.ndarray:
|
||||
res = np.zeros(n_cols, dtype=np.float64)
|
||||
for ci in range(n_cols):
|
||||
res[ci] = _entropy_col(sub[:, ci])
|
||||
|
||||
Reference in New Issue
Block a user