# Created: 2026-03-07 # Purpose: Horizontal bar chart for 7 forensic audio features # Dependencies: plotly, numpy """Horizontal bar chart visualization for 7 forensic audio features.""" import plotly.graph_objects as go def plot_feature_bars(feature_stats: dict) -> go.Figure: """7개 포렌식 피처를 horizontal bar chart로 시각화. Args: feature_stats: Dict with feature names as keys and normalized values (0-1) Returns: plotly Figure (horizontal bar chart) """ # 7개 포렌식 피처 (짧은 레이블) features = [ "Spectral Flux", "H/P Ratio", "Temporal Accel", "Temporal Delta", "Percussive", "Harmonic", "Residual Energy", ] # 기본값 (feature_stats가 없으면 중간값) if not feature_stats: values = [0.5] * 7 else: values = [ feature_stats.get("spectral_flux", 0.5), feature_stats.get("hp_ratio", 0.5), feature_stats.get("temporal_accel", 0.5), feature_stats.get("temporal_delta", 0.5), feature_stats.get("percussive_strength", 0.5), feature_stats.get("harmonic_strength", 0.5), feature_stats.get("residual_energy", 0.5), ] # AI 가능성 기준: 높을수록 AI 시그니처 # Residual Energy, H/P Ratio는 높을수록 AI # Temporal Delta/Accel는 낮을수록 AI (부드러운 변화) # Harmonic/Percussive는 특정 비율로 수렴 # Spectral Flux는 낮을수록 AI (일관적 변화) # AI 시그니처 강도에 따라 색상 결정 colors = [] for i, (feat, val) in enumerate(zip(features, values)): if "Residual" in feat or "H/P" in feat: # 높을수록 AI if val >= 0.7: colors.append('#ff4757') # AI (red) elif val >= 0.4: colors.append('#ffa502') # Uncertain (orange) else: colors.append('#2ed573') # Human (green) elif "Temporal" in feat or "Spectral" in feat: # 낮을수록 AI if val <= 0.3: colors.append('#ff4757') # AI (red) elif val <= 0.6: colors.append('#ffa502') # Uncertain (orange) else: colors.append('#2ed573') # Human (green) else: # Harmonic/Percussive는 중립 colors.append('#5f9ea0') # Neutral (cyan) fig = go.Figure(go.Bar( x=values, y=features, orientation='h', marker=dict( color=colors, line=dict(color='#fff', width=1) ), text=[f"{v:.2f}" for v in values], textposition='inside', textfont=dict(size=11, color='white', family='monospace'), hovertemplate="%{y}
Score: %{x:.3f}", )) fig.update_layout( xaxis=dict( title="Feature Strength", range=[0, 1], tickfont=dict(size=10, color='#aaa'), gridcolor='#333', ), yaxis=dict( tickfont=dict(size=11, color='white'), ), plot_bgcolor='#1a1a2e', paper_bgcolor='#1a1a2e', font=dict(color='white'), margin=dict(l=140, r=20, t=40, b=40), height=300, showlegend=False, title=dict( text="Forensic Feature Strength", font=dict(size=13), x=0.5, xanchor='center' ) ) return fig