File size: 2,500 Bytes
de6f1e8
60034d4
 
010071f
b8b8eab
de6f1e8
010071f
60034d4
 
 
 
 
 
 
 
 
de6f1e8
b8b8eab
de6f1e8
 
60034d4
 
de6f1e8
 
b8b8eab
de6f1e8
60034d4
 
de6f1e8
60034d4
 
b8b8eab
de6f1e8
60034d4
 
 
b04cfbb
de6f1e8
60034d4
 
 
 
 
 
 
 
 
de6f1e8
60034d4
 
 
 
 
 
b8b8eab
de6f1e8
b8b8eab
60034d4
 
 
 
 
 
 
de6f1e8
60034d4
 
b8b8eab
60034d4
de6f1e8
60034d4
 
 
 
 
 
de6f1e8
60034d4
de6f1e8
 
 
60034d4
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# tools/plot_generator.py
import os
import tempfile
import pandas as pd
import plotly.graph_objects as go
from typing import Tuple, Union


def plot_metric_tool(
    file_path: str,
    date_col: str,
    value_col: str,
    output_dir: str = "/tmp",
    title: str = None,
    line_width: int = 2,
    marker_size: int = 6
) -> Union[Tuple[go.Figure, str], str]:
    """
    Load CSV or Excel file, parse a time series metric, and return an interactive Plotly Figure
    plus a high-res PNG file path for static embedding.

    Returns:
      - (fig, img_path) on success
      - error string starting with '❌' on failure
    """
    # Load data
    ext = os.path.splitext(file_path)[1].lower()
    try:
        df = pd.read_excel(file_path) if ext in ('.xls', '.xlsx') else pd.read_csv(file_path)
    except Exception as exc:
        return f"❌ Failed to load file: {exc}"

    # Validate columns
    missing = [c for c in (date_col, value_col) if c not in df.columns]
    if missing:
        return f"❌ Missing column(s): {', '.join(missing)}"

    # Parse and clean
    try:
        df[date_col] = pd.to_datetime(df[date_col], errors='coerce')
    except Exception:
        return f"❌ Could not parse '{date_col}' as dates."
    df[value_col] = pd.to_numeric(df[value_col], errors='coerce')
    df = df.dropna(subset=[date_col, value_col])
    if df.empty:
        return f"❌ No valid data after cleaning '{date_col}'/'{value_col}'"

    # Aggregate duplicates and sort
    df = (
        df[[date_col, value_col]]
        .groupby(date_col, as_index=True)
        .mean()
        .sort_index()
    )

    # Build figure
    fig = go.Figure(
        data=[
            go.Scatter(
                x=df.index,
                y=df[value_col],
                mode='lines+markers',
                line=dict(width=line_width),
                marker=dict(size=marker_size),
                name=value_col,
            )
        ]
    )
    fig.update_layout(
        title=title or f"{value_col} Trend",
        xaxis_title=date_col,
        yaxis_title=value_col,
        template='plotly_dark',
        hovermode='x unified'
    )

    # Save PNG
    os.makedirs(output_dir, exist_ok=True)
    tmp = tempfile.NamedTemporaryFile(suffix='.png', prefix='trend_', dir=output_dir, delete=False)
    img_path = tmp.name
    tmp.close()
    try:
        fig.write_image(img_path, scale=2)
    except Exception as exc:
        return f"❌ Failed saving image: {exc}"

    return fig, img_path