ในยุคที่ข้อมูลคือสินทรัพย์สำคัญของธุรกิจ การสร้าง Dashboard ที่สามารถแสดงผลข้อมูลแบบ Interactive และอัปเดตแบบ Real-time เป็นสิ่งจำเป็นอย่างยิ่งสำหรับทีม Data Science และ Developer หลายคนอาจคุ้นเคยกับการใช้ Matplotlib หรือ Seaborn ในการสร้างกราฟแบบ Static แต่สำหรับ Dashboard ที่ต้องการความ Interactive สูง Plotly Dash คือตัวเลือกที่ยอดเยี่ยมที่สุดในปัจจุบัน ในบทความนี้เราจะมาเรียนรู้วิธีการใช้ Tardis API เพื่อดึงข้อมูลและสร้าง Interactive Dashboard ด้วย Plotly Dash กันอย่างละเอียด

Tardis API คืออะไร และทำไมต้องใช้กับ Data Visualization

Tardis API เป็น API ที่ให้บริการข้อมูล Real-time สำหรับการวิเคราะห์ในหลากหลายอุตสาหกรรม รวมถึงการวิเคราะห์พฤติกรรมลูกค้า E-commerce การติดตามตลาดการเงิน และการวิเคราะห์ระบบ AI/RAG เมื่อนำมารวมกับ Plotly Dash เราจะได้ Dashboard ที่สามารถ:

การติดตั้ง Plotly Dash และการเตรียม Environment

ก่อนจะเริ่มสร้าง Dashboard เราต้องติดตั้ง Package ที่จำเป็นก่อน โดย Plotly Dash ต้องการ Python เวอร์ชัน 3.6 ขึ้นไป

# ติดตั้ง Plotly Dash และ Dependencies
pip install dash plotly pandas requests

หรือใช้ pipenv

pipenv install dash plotly pandas requests

ตรวจสอบเวอร์ชันที่ติดตั้ง

python -c "import dash; print(dash.__version__)"

โครงสร้างโปรเจกต์ที่แนะนำควรมีลักษณะดังนี้:

dashboard_project/
├── app.py              # ไฟล์หลักของ Dash Application
├── callbacks/
│   └── __init__.py
├── components/
│   └── __init__.py
├── data/
│   └── cache/          # เก็บข้อมูล Cache ชั่วคราว
├── pages/
│   └── analytics.py   # หน้าสำหรับ Analytics
├── services/
│   └── tardis_api.py  # Service สำหรับเรียก Tardis API
├── utils/
│   └── helpers.py
└── requirements.txt

การเชื่อมต่อ Tardis API เพื่อดึงข้อมูล

ในการใช้งาน Tardis API อย่างมีประสิทธิภาพ เราควรสร้าง Service Layer ที่จัดการเรื่อง Authentication, Error Handling และ Caching อย่างเป็นระบบ ต่อไ�นี้คือตัวอย่างการสร้าง Tardis API Service ที่ใช้งานได้จริง:

import requests
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
import pandas as pd
import json
import hashlib

class TardisAPIService:
    """
    Service สำหรับเชื่อมต่อกับ Tardis API
    รองรับการดึงข้อมูล Real-time และ Historical Data
    """
    
    BASE_URL = "https://api.tardis.io/v1"  # ตัวอย่าง Tardis API
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        })
        self._cache: Dict[str, Any] = {}
        self._cache_ttl = 300  # Cache TTL ในวินาที
    
    def _generate_cache_key(self, endpoint: str, params: Dict) -> str:
        """สร้าง Cache Key จาก Endpoint และ Parameters"""
        key_string = f"{endpoint}:{json.dumps(params, sort_keys=True)}"
        return hashlib.md5(key_string.encode()).hexdigest()
    
    def _is_cache_valid(self, cache_key: str) -> bool:
        """ตรวจสอบว่า Cache ยัง valid หรือไม่"""
        if cache_key not in self._cache:
            return False
        cached_time = self._cache[cache_key].get("timestamp")
        if cached_time is None:
            return False
        elapsed = (datetime.now() - cached_time).total_seconds()
        return elapsed < self._cache_ttl
    
    def get_realtime_metrics(self, metric_type: str = "all") -> Dict:
        """
        ดึงข้อมูล Metrics แบบ Real-time
        
        Args:
            metric_type: ประเภทของ metric (all, sales, users, performance)
        
        Returns:
            Dictionary ที่มีข้อมูล Metrics
        """
        cache_key = self._generate_cache_key("realtime_metrics", {"type": metric_type})
        
        if self._is_cache_valid(cache_key):
            return self._cache[cache_key]["data"]
        
        try:
            response = self.session.get(
                f"{self.BASE_URL}/metrics/realtime",
                params={"type": metric_type},
                timeout=10
            )
            response.raise_for_status()
            data = response.json()
            
            # เก็บใน Cache
            self._cache[cache_key] = {
                "data": data,
                "timestamp": datetime.now()
            }
            return data
            
        except requests.exceptions.Timeout:
            # Fallback ไปยัง Cache เก่า หาก Timeout
            if cache_key in self._cache:
                return self._cache[cache_key]["data"]
            raise ConnectionError("Tardis API Timeout - กรุณาลองใหม่อีกครั้ง")
            
        except requests.exceptions.RequestException as e:
            raise ConnectionError(f"Tardis API Error: {str(e)}")
    
    def get_historical_data(
        self,
        start_date: datetime,
        end_date: datetime,
        data_type: str = "transactions"
    ) -> pd.DataFrame:
        """
        ดึงข้อมูล Historical Data ในรูปแบบ DataFrame
        
        Args:
            start_date: วันที่เริ่มต้น
            end_date: วันที่สิ้นสุด
            data_type: ประเภทข้อมูล (transactions, users, products)
        
        Returns:
            Pandas DataFrame ที่มีข้อมูล Historical
        """
        try:
            response = self.session.get(
                f"{self.BASE_URL}/data/historical",
                params={
                    "start": start_date.isoformat(),
                    "end": end_date.isoformat(),
                    "type": data_type
                },
                timeout=30
            )
            response.raise_for_status()
            data = response.json()
            
            # แปลงเป็น DataFrame
            df = pd.DataFrame(data.get("records", []))
            
            if not df.empty and "timestamp" in df.columns:
                df["timestamp"] = pd.to_datetime(df["timestamp"])
                df = df.sort_values("timestamp")
            
            return df
            
        except requests.exceptions.RequestException as e:
            raise ConnectionError(f"Failed to fetch historical data: {str(e)}")
    
    def get_ai_analytics(self, use_cache: bool = True) -> Dict:
        """
        ดึงข้อมูล Analytics จากระบบ AI โดยเชื่อมต่อผ่าน HolySheep API
        
        ตัวอย่างการใช้ HolySheep AI สำหรับ AI Analytics:
        - ราคาถูกกว่า 85%+ เมื่อเทียบกับ OpenAI
        - Latency ต่ำกว่า 50ms
        - รองรับ WeChat/Alipay
        """
        cache_key = "ai_analytics"
        
        if use_cache and self._is_cache_valid(cache_key):
            return self._cache[cache_key]["data"]
        
        try:
            # ใช้ HolySheep AI สำหรับ AI Analytics
            holysheep_response = self._call_holysheep_ai(
                prompt="วิเคราะห์ข้อมูลลูกค้าต่อไปนี้และสรุป Insights"
            )
            
            self._cache[cache_key] = {
                "data": holysheep_response,
                "timestamp": datetime.now()
            }
            return holysheep_response
            
        except Exception as e:
            raise RuntimeError(f"AI Analytics Error: {str(e)}")
    
    def _call_holysheep_ai(self, prompt: str) -> Dict:
        """เรียก HolySheep AI API สำหรับการวิเคราะห์"""
        holysheep_url = "https://api.holysheep.ai/v1/chat/completions"
        
        payload = {
            "model": "gpt-4.1",
            "messages": [
                {"role": "system", "content": "คุณคือ AI Analyst ที่ช่วยวิเคราะห์ข้อมูล"},
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.7
        }
        
        response = self.session.post(
            holysheep_url,
            headers={
                "Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY",
                "Content-Type": "application/json"
            },
            json=payload,
            timeout=15
        )
        response.raise_for_status()
        return response.json()


ตัวอย่างการใช้งาน

tardis_service = TardisAPIService(api_key="your_tardis_api_key") metrics = tardis_service.get_realtime_metrics(metric_type="sales")

การสร้าง Plotly Dash Dashboard - โครงสร้างพื้นฐาน

ต่อไ�จะเป็นตัวอย่างการสร้าง Dash Application ที่มีโครงสร้างครบถ้วน รองรับ Callback หลายตัว และสามารถเรียกใช้งาน Tardis API ได้อย่างมีประสิทธิภาพ:

from dash import Dash, html, dcc, callback, ctx, Input, Output, State, ALL
import plotly.express as px
import plotly.graph_objects as go
from dash.exceptions import PreventUpdate
import pandas as pd
from datetime import datetime, timedelta
from services.tardis_api import TardisAPIService

สร้าง Dash Application

app = Dash(__name__, title="Tardis Analytics Dashboard") app.suppress_callback_exceptions = True

Initialize Service

tardis_service = TardisAPIService(api_key="your_tardis_api_key")

สไตล์ CSS

external_stylesheets = [ "https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700&display=swap", "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" ] app.layout = html.Div([ # Header Section html.Header([ html.Div([ html.H1("📊 Tardis Analytics Dashboard", className="dashboard-title"), html.P("Real-time Data Visualization powered by Plotly Dash", className="dashboard-subtitle") ], className="header-content") ], className="dashboard-header"), # Controls Section html.Div([ html.Div([ html.Label("เลือกช่วงเวลา:", className="control-label"), dcc.Dropdown( id="time-range-selector", options=[ {"label": "วันนี้", "value": "today"}, {"label": "7 วันล่าสุด", "value": "7days"}, {"label": "30 วันล่าสุด", "value": "30days"}, {"label": "90 วันล่าสุด", "value": "90days"}, {"label": "กำหนดเอง", "value": "custom"} ], value="7days", className="dropdown-control" ) ], className="control-group"), html.Div([ html.Label("ประเภทข้อมูล:", className="control-label"), dcc.Dropdown( id="data-type-selector", options=[ {"label": "ยอดขาย", "value": "sales"}, {"label": "ผู้ใช้งาน", "value": "users"}, {"label": "ประสิทธิภาพ", "value": "performance"}, {"label": "AI Analytics", "value": "ai"} ], value="sales", className="dropdown-control" ) ], className="control-group"), # Refresh Button html.Button( [html.Span("🔄", className="btn-icon"), " อัปเดตข้อมูล"], id="refresh-button", n_clicks=0, className="btn btn-primary refresh-btn" ), # Auto-refresh Interval dcc.Interval( id="auto-refresh", interval=60 * 1000, # อัปเดตทุก 60 วินาที n_intervals=0 ) ], className="controls-section"), # Metrics Cards html.Div([ html.Div([ html.Div([ html.Span("💰", className="metric-icon"), html.Div([ html.H3(id="total-sales", className="metric-value"), html.P("ยอดขายรวม", className="metric-label") ], className="metric-content") ], className="metric-card metric-sales") ], className="col-md-3"), html.Div([ html.Div([ html.Span("👥", className="metric-icon"), html.Div([ html.H3(id="total-users", className="metric-value"), html.P("ผู้ใช้งาน", className="metric-label") ], className="metric-content") ], className="metric-card metric-users") ], className="col-md-3"), html.Div([ html.Div([ html.Span("📈", className="metric-icon"), html.Div([ html.H3(id="conversion-rate", className="metric-value"), html.P("อัตราการแปลง", className="metric-label") ], className="metric-content") ], className="metric-card metric-conversion") ], className="col-md-3"), html.Div([ html.Div([ html.Span("⚡", className="metric-icon"), html.Div([ html.H3(id="avg-response-time", className="metric-value"), html.P("เวลาตอบสนองเฉลี่ย", className="metric-label") ], className="metric-content") ], className="metric-card metric-performance") ], className="col-md-3") ], className="metrics-row"), # Charts Section html.Div([ # Main Chart - Line Chart html.Div([ html.H2("📈 แนวโน้มข้อมูล", className="chart-title"), dcc.Graph(id="main-line-chart", className="main-chart") ], className="chart-container col-lg-8"), # Pie Chart html.Div([ html.H2("🥧 สัดส่วนประเภทสินค้า", className="chart-title"), dcc.Graph(id="pie-chart", className="pie-chart") ], className="chart-container col-lg-4"), # Bar Chart html.Div([ html.H2("📊 เปรียบเทียบรายภูมิภาค", className="chart-title"), dcc.Graph(id="bar-chart", className="bar-chart") ], className="chart-container col-lg-6"), # Heatmap html.Div([ html.H2("🔥 แผนที่ความร้อนกิจกรรม", className="chart-title"), dcc.Graph(id="heatmap-chart", className="heatmap-chart") ], className="chart-container col-lg-6") ], className="charts-section"), # Data Table html.Div([ html.H2("📋 รายละเอียดข้อมูล", className="chart-title"), html.Div(id="data-table-container") ], className="table-container"), # Loading State dcc.Loading( id="loading-overlay", type="default", children=html.Div(id="loading-output"), fullscreen=True, overlay_style={"visibility": "visible", "opacity": 0.5} ), # Store for caching data dcc.Store(id="cached-data") ], className="dashboard-container")

==================== CALLBACKS ====================

@callback( Output("main-line-chart", "figure"), Output("pie-chart", "figure"), Output("bar-chart", "figure"), Output("heatmap-chart", "figure"), Output("total-sales", "children"), Output("total-users", "children"), Output("conversion-rate", "children"), Output("avg-response-time", "children"), Output("data-table-container", "children"), Output("cached-data", "data"), Input("time-range-selector", "value"), Input("data-type-selector", "value"), Input("refresh-button", "n_clicks"), Input("auto-refresh", "n_intervals") ) def update_dashboard(time_range, data_type, n_clicks, n_intervals): """ Callback หลักสำหรับอัปเดต Dashboard ทั้งหมด """ try: # คำนวณช่วงเวลา end_date = datetime.now() if time_range == "today": start_date = end_date - timedelta(days=1) elif time_range == "7days": start_date = end_date - timedelta(days=7) elif time_range == "30days": start_date = end_date - timedelta(days=30) elif time_range == "90days": start_date = end_date - timedelta(days=90) else: start_date = end_date - timedelta(days=7) # ดึงข้อมูลจาก Tardis API df_historical = tardis_service.get_historical_data( start_date=start_date, end_date=end_date, data_type=data_type ) # ดึง Metrics metrics = tardis_service.get_realtime_metrics(metric_type=data_type) # สร้าง Line Chart line_fig = create_line_chart(df_historical, data_type) # สร้าง Pie Chart pie_fig = create_pie_chart(df_historical) # สร้าง Bar Chart bar_fig = create_bar_chart(df_historical) # สร้าง Heatmap heatmap_fig = create_heatmap(df_historical) # สร้าง Data Table table = create_data_table(df_historical) return ( line_fig, pie_fig, bar_fig, heatmap_fig, f"฿{metrics.get('total_sales', 0):,.0f}", f"{metrics.get('total_users', 0):,}", f"{metrics.get('conversion_rate', 0):.2f}%", f"{metrics.get('avg_response_time', 0):.0f}ms", table, df_historical.to_dict("records") ) except Exception as e: # กรณีเกิด Error แสดง Empty State return create_empty_figures() def create_line_chart(df: pd.DataFrame, data_type: str) -> go.Figure: """สร้าง Line Chart พร้อม Interactive Features""" if df.empty: return go.Figure() fig = go.Figure() colors = { "sales": "#4F46E5", "users": "#10B981", "performance": "#F59E0B" } color = colors.get(data_type, "#4F46E5") fig.add_trace(go.Scatter( x=df["timestamp"] if "timestamp" in df.columns else df.index, y=df["value"] if "value" in df.columns else df.iloc[:, 0], mode="lines+markers", name=f"{data_type.upper()}", line=dict(color=color, width=3), marker=dict(size=8, symbol="circle"), hovertemplate="%{x}
" + f"{data_type}: " + "%{y:,.2f}" )) # เพิ่ม Trend Line if len(df) > 1: x_numeric = range(len(df)) y_values = df["value"] if "value" in df.columns else df.iloc[:, 0] fig.add_trace(go.Scatter( x=list(x_numeric), y=[y_values.iloc[0] + (y_values.iloc[-1] - y_values.iloc[0]) / len(df) * i for i in x_numeric], mode="lines", name="Trend", line=dict(color="rgba(255,107,107,0.5)", width=2, dash="dash"), showlegend=True )) fig.update_layout( template="plotly_white", hovermode="x unified", legend=dict(orientation="h", yanchor="bottom", y=1.02), margin=dict(l=20, r=20, t=40, b=20), height=400 ) return fig def create_pie_chart(df: pd.DataFrame) -> go.Figure: """สร้าง Pie Chart แสดงสัดส่วน""" if df.empty or "category" not in df.columns: return go.Figure() category_data = df.groupby("category")["value"].sum().reset_index() fig = go.Figure(data=[go.Pie( labels=category_data["category"], values=category_data["value"], hole=0.4, marker=dict(colors=px.colors.qualitative.Set3), textinfo="label+percent", textposition="outside" )]) fig.update_layout( template="plotly_white", margin=dict(l=20, r=20, t=40, b=20), height=350, showlegend=True ) return fig def create_bar_chart(df: pd.DataFrame) -> go.Figure: """สร้าง Bar Chart เปรียบเทียบรายภูมิภาค""" if df.empty: return go.Figure() regions = ["กรุงเทพ", "ภาคกลาง", "ภาคเหนือ", "ภาคอีสาน", "ภาคใต้"] values = [df["value"].sum() * p for p in [0.35, 0.25, 0.15, 0.15, 0.10]] fig = go.Figure(data=[go.Bar( x=regions, y=values, marker_color=["#4F46E5", "#10B981", "#F59E0B", "#EF4444", "#8B5CF6"], text=[f"฿{v:,.0f}" for v in values], textposition="outside" )]) fig.update_layout( template="plotly_white", margin=dict(l=20, r=20, t=40, b=20), height=350, xaxis_title="ภูมิภาค", yaxis_title="ยอดขาย (บาท)" ) return fig def create_heatmap(df: pd.DataFrame) -> go.Figure: """สร้าง Heatmap แสดงกิจกรรมตามช่วงเวลา""" hours = list(range(24)) days = ["จันทร์", "อังคาร", "พุธ", "พฤหัสบดี", "ศุกร์", "เสาร์", "อาทิตย์"] # สร้างข้อมูลตัวอย่าง import numpy as np np.random.seed(42) data = np.random.randint(10, 100, size=(7, 24)) fig = go.Figure(data=go.Heatmap( z=data, x=hours, y=days, colorscale="Viridis", hovertemplate="ชั่วโมง: %{x}:00
วัน: %{y}
กิจกรรม: %{z}" )) fig.update_layout( template="plotly_white", margin=dict(l=20, r=20, t=40, b=20), height=350, xaxis_title="ชั่วโมง", yaxis_title="วันในสัปดาห์" ) return fig def create_data_table(df: pd.DataFrame) -> html.Div: """สร้าง Data Table ที่สามารถ Sort ได้""" if df.empty: return html.Div("ไม่มีข้อมูล", className="empty-state") return html.Div([ html.Table([ html.Thead( html.Tr([ html.Th(col.replace("_", " ").title()) for col in df.columns[:6] # แสดงเฉพาะ 6 คอลัมน์แรก ]) ), html.Tbody([ html.Tr([ html.Td(str(row[col])[:50] + "..." if len(str(row[col])) > 50 else row[col]) for col in df.columns[:6] ]) for _, row in df.head(10).iterrows() ]) ], className="data-table") ], className="table-responsive") def create_empty_figures() -> tuple: """สร้าง Empty Figures สำหรับกรณี Error""" empty_fig = go.Figure() empty_fig.update_layout( template="plotly_white", annotations=[dict(text="ไม่มีข้อมูล", x=0.5, y=0.5, showarrow=False, font=dict(size=20))] ) return (empty_fig, empty_fig, empty_fig, empty_fig, "฿0", "0", "0%", "0ms", html.Div("Error loading data"), {}) if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=8050)

การปรับแต่ง CSS ให้ Dashboard สวยงาม

หากต้องการให้ Dashboard มีความสวยงามและเป็นมืออาชีพ สามาร�