| """
|
| Chart Styles Configuration - Standardized Plotly Styling
|
|
|
| This module defines standard colors, fonts, and styles for all charts
|
| to ensure visual consistency across the platform.
|
| """
|
|
|
|
|
|
|
|
|
|
|
| COLORS = {
|
|
|
| "data_primary": "#003366",
|
| "data_secondary": "#0066cc",
|
|
|
|
|
| "prediction_line": "#28a745",
|
| "prediction_ci": "rgba(40, 167, 69, 0.2)",
|
|
|
|
|
| "specification_limit": "#dc3545",
|
| "warning_limit": "#ffc107",
|
|
|
|
|
| "compliant": "#28a745",
|
| "marginal": "#ffc107",
|
| "non_compliant": "#dc3545",
|
|
|
|
|
| "grid": "#e0e0e0",
|
| "background": "#ffffff",
|
| "paper": "#fafafa",
|
|
|
|
|
| "batch_palette": [
|
| "#1f77b4",
|
| "#ff7f0e",
|
| "#2ca02c",
|
| "#d62728",
|
| "#9467bd",
|
| "#8c564b",
|
| "#e377c2",
|
| "#7f7f7f",
|
| ]
|
| }
|
|
|
|
|
|
|
|
|
|
|
| FONTS = {
|
| "family": "'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif",
|
| "family_cn": "'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', sans-serif",
|
| "size_title": 16,
|
| "size_axis": 12,
|
| "size_tick": 10,
|
| "size_annotation": 11,
|
| }
|
|
|
|
|
|
|
|
|
|
|
| def get_prediction_chart_layout() -> dict:
|
| """Get standard layout for prediction charts."""
|
| return {
|
| "template": "plotly_white",
|
| "font": {
|
| "family": FONTS["family"],
|
| "size": FONTS["size_axis"]
|
| },
|
| "title": {
|
| "font": {"size": FONTS["size_title"], "color": COLORS["data_primary"]}
|
| },
|
| "xaxis": {
|
| "title": {"text": "时间 (月)", "font": {"size": FONTS["size_axis"]}},
|
| "gridcolor": COLORS["grid"],
|
| "zeroline": False
|
| },
|
| "yaxis": {
|
| "title": {"text": "含量 (%)", "font": {"size": FONTS["size_axis"]}},
|
| "gridcolor": COLORS["grid"],
|
| "zeroline": False
|
| },
|
| "legend": {
|
| "orientation": "h",
|
| "yanchor": "bottom",
|
| "y": 1.02,
|
| "xanchor": "right",
|
| "x": 1
|
| },
|
| "margin": {"l": 60, "r": 30, "t": 60, "b": 50},
|
| "plot_bgcolor": COLORS["background"],
|
| "paper_bgcolor": COLORS["paper"],
|
| }
|
|
|
|
|
| def get_comparison_chart_layout() -> dict:
|
| """Get standard layout for batch comparison charts."""
|
| return {
|
| "template": "plotly_white",
|
| "font": {
|
| "family": FONTS["family"],
|
| "size": FONTS["size_axis"]
|
| },
|
| "title": {
|
| "font": {"size": FONTS["size_title"], "color": COLORS["data_primary"]}
|
| },
|
| "xaxis": {
|
| "title": {"text": "批次", "font": {"size": FONTS["size_axis"]}},
|
| },
|
| "yaxis": {
|
| "title": {"text": "评分", "font": {"size": FONTS["size_axis"]}},
|
| "range": [0, 105]
|
| },
|
| "margin": {"l": 50, "r": 30, "t": 60, "b": 50},
|
| "plot_bgcolor": COLORS["background"],
|
| "paper_bgcolor": COLORS["paper"],
|
| }
|
|
|
|
|
| def get_score_color(score: float) -> str:
|
| """Get color based on score value."""
|
| if score >= 80:
|
| return COLORS["compliant"]
|
| elif score >= 60:
|
| return COLORS["marginal"]
|
| else:
|
| return COLORS["non_compliant"]
|
|
|
|
|
| def get_risk_color(risk_level: str) -> str:
|
| """Get color based on risk level string."""
|
| risk_lower = risk_level.lower()
|
| if "compliant" in risk_lower or "合格" in risk_lower or "low" in risk_lower:
|
| return COLORS["compliant"]
|
| elif "marginal" in risk_lower or "临界" in risk_lower or "medium" in risk_lower:
|
| return COLORS["marginal"]
|
| else:
|
| return COLORS["non_compliant"]
|
|
|