آموزش Plotly؛ ساخت نمودار تعاملی و داشبورد با پایتون

در این آموزش جامع Plotly، ساخت نمودارهای تعاملی، داشبورد فروش، نمودار زمانی، Heatmap، خروجی HTML و PNG و ترکیب مصورسازی داده با هوش مصنوعی درواره را به‌صورت عملی یاد می‌گیرید.

Share
آموزش Plotly؛ ساخت نمودار تعاملی و داشبورد با پایتون

نمودارهای ثابت برای مقاله، گزارش و چاپ بسیار مناسب‌اند؛ اما وقتی کاربر می‌خواهد روی داده Zoom کند، مقدار دقیق هر نقطه را ببیند، بعضی سری‌ها را مخفی کند یا یک بازه زمانی خاص را بررسی کند، به نمودار تعاملی نیاز داریم.

Plotly یکی از محبوب‌ترین کتابخانه‌های پایتون برای ساخت نمودارهای تعاملی است. نمودارهای ساخته‌شده با Plotly در مرورگر نمایش داده می‌شوند و می‌توانند قابلیت‌هایی مانند Hover، Zoom، Pan، انتخاب نقاط، مخفی‌کردن سری‌ها و ذخیره تصویر را در اختیار کاربر قرار دهند.

در این آموزش یاد می‌گیرید:

  • Plotly چیست و چه تفاوتی با Matplotlib و Seaborn دارد
  • چگونه Plotly را نصب و پیکربندی کنید
  • تفاوت Plotly Express و Graph Objects چیست
  • چگونه نمودار خطی، میله‌ای، پراکندگی و توزیع بسازید
  • چگونه نمودار زمانی و Range Slider ایجاد کنید
  • چگونه Subplot و داشبورد چندبخشی بسازید
  • چگونه نمودار را در قالب HTML، PNG، SVG و PDF ذخیره کنید
  • چگونه Plotly را در Streamlit و FastAPI استفاده کنید
  • چگونه نمودارهای دارای داده زیاد را بهینه کنید
  • چگونه خلاصه داده را برای تحلیل متنی به API درواره بفرستید

Plotly چیست؟

Plotly یک اکوسیستم مصورسازی داده است که کتابخانه‌هایی برای زبان‌های مختلف، از جمله پایتون و JavaScript، ارائه می‌کند. کتابخانه Plotly برای پایتون می‌تواند نمودارهای تعاملی مبتنی بر وب تولید کند.

نمودار Plotly فقط یک تصویر نیست. هر نمودار شامل داده، Traceها و تنظیمات Layout است و در مرورگر با استفاده از فناوری‌های وب نمایش داده می‌شود.

قابلیت‌های متداول Plotly عبارت‌اند از:

  • نمایش مقدار دقیق نقاط با Hover
  • Zoom روی محورهای نمودار
  • حرکت یا Pan روی داده
  • انتخاب بخشی از نقاط
  • فعال و غیرفعال‌کردن سری‌ها از طریق Legend
  • ساخت Animation
  • نمایش Range Slider
  • ذخیره نمودار در فایل HTML
  • خروجی PNG، SVG، WebP و PDF
  • نمایش نمودار در Jupyter Notebook
  • استفاده در Streamlit، Dash و برنامه‌های تحت وب
  • ساخت نمودارهای دوبعدی و سه‌بعدی

تفاوت Plotly، Matplotlib و Seaborn

هر سه کتابخانه برای مصورسازی داده استفاده می‌شوند، اما کاربرد یکسانی ندارند.

ویژگیPlotlyMatplotlibSeaborn
تعامل در مرورگربسیار خوبمحدودمحدود
Hover و Zoomداخلیوابسته به Backendوابسته به Matplotlib
نمودار ثابت برای چاپخوببسیار خوببسیار خوب
تحلیل آماریخوبپایهبسیار خوب
کنترل جزئیاتبسیار خوببسیار خوبخوب
کار با Pandasبسیار خوبخوببسیار خوب
ساخت فایل HTMLداخلینداردندارد
ساخت داشبورد تحت وببسیار مناسبمعمولاً مناسب نیستمعمولاً مناسب نیست
شروع سریعآسان با Plotly Expressمتوسطآسان
خروجی برداریSVG و PDFSVG و PDFاز طریق Matplotlib

اگر هدف شما مقاله چاپی یا تصویر کاملاً ثابت است، Matplotlib انتخاب قدرتمندی است. برای تحلیل آماری سریع، Seaborn بسیار مناسب است. برای نمودار تعاملی و داشبورد تحت وب، Plotly معمولاً انتخاب بهتری خواهد بود.

نصب Plotly

ابتدا محیط مجازی بسازید:

python -m venv .venv

فعال‌سازی در ویندوز:

.venv\Scripts\activate

فعال‌سازی در Linux یا macOS:

source .venv/bin/activate

نصب Plotly و کتابخانه‌های موردنیاز:

python -m pip install plotly pandas numpy

برای کار در Jupyter:

python -m pip install jupyter anywidget

برای خروجی ثابت PNG، SVG یا PDF:

python -m pip install --upgrade kaleido

برای بررسی نسخه:

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

براساس راهنمای رسمی نصب Plotly، plotly را می‌توان مستقیماً از PyPI نصب کرد و Plotly Express نیز بخشی از همین پکیج است.

اولین نمودار تعاملی با Plotly Express

import pandas as pd
import plotly.express as px

df = pd.DataFrame({
    "month": [
        "Jan", "Feb", "Mar",
        "Apr", "May", "Jun"
    ],
    "sales": [
        120, 145, 138,
        172, 190, 215
    ]
})

fig = px.line(
    df,
    x="month",
    y="sales",
    markers=True,
    title="Monthly Sales"
)

fig.show()

پس از اجرای کد، نمودار در محیط Notebook یا مرورگر نمایش داده می‌شود. کاربر می‌تواند روی نقاط حرکت کند و مقدار دقیق هر ماه را ببیند.

ساختار Figure در Plotly

یک Figure در Plotly معمولاً دو بخش اصلی دارد:

Data

بخش data شامل یک یا چند Trace است. هر Trace یک سری داده یا لایه نمودار محسوب می‌شود؛ مانند یک خط، مجموعه نقاط یا سری میله‌ای.

Layout

بخش layout ظاهر و چیدمان نمودار را مشخص می‌کند:

  • عنوان
  • محور X و Y
  • Legend
  • رنگ پس‌زمینه
  • اندازه نمودار
  • Margin
  • Annotation
  • Hover Mode

برای مشاهده ساختار Figure:

print(fig)

یا تبدیل آن به Dictionary:

figure_dict = fig.to_dict()

print(figure_dict.keys())

خروجی شامل کلیدهای data و layout خواهد بود.

تفاوت Plotly Express و Graph Objects

Plotly دو رابط اصلی برای ساخت نمودار دارد.

Plotly Express

Plotly Express با نام px یک رابط سطح بالا برای ساخت سریع نمودار از DataFrame است.

import plotly.express as px

fig = px.scatter(
    df,
    x="advertising_cost",
    y="sales",
    color="channel",
    size="conversion_rate"
)

مزایا:

  • کد کمتر
  • ارتباط مستقیم با Pandas
  • ساخت خودکار Legend
  • گروه‌بندی آسان با color
  • Facet با facet_col و facet_row
  • مناسب تحلیل اکتشافی و داشبورد

Graph Objects

Graph Objects با نام go کنترل دقیق‌تری روی Traceها و Layout ارائه می‌دهد.

import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(
    go.Scatter(
        x=[1, 2, 3, 4],
        y=[10, 18, 15, 24],
        mode="lines+markers",
        name="Sales"
    )
)

fig.update_layout(
    title="Sales Trend",
    xaxis_title="Day",
    yaxis_title="Sales"
)

fig.show()

Graph Objects برای موارد زیر مناسب است:

  • ترکیب چند نوع نمودار
  • ساخت Subplotهای پیچیده
  • کنترل دقیق Hover
  • اضافه‌کردن Shape و Annotation
  • ساخت نمودارهایی که Plotly Express مستقیماً پوشش نمی‌دهد

در پروژه‌های واقعی می‌توانید نمودار را با Plotly Express بسازید و سپس با متدهای update_layout و update_traces شخصی‌سازی کنید.

ساخت داده نمونه پروژه

در مثال‌های بعدی از یک مجموعه داده فروش استفاده می‌کنیم:

import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
rows = 1800

dates = pd.date_range(
    "2026-01-01",
    periods=180,
    freq="D"
)

channels = np.array([
    "Organic",
    "Paid Search",
    "Social",
    "Referral"
])

categories = np.array([
    "Mobile",
    "Laptop",
    "Tablet",
    "Accessories"
])

cities = np.array([
    "Tehran",
    "Shiraz",
    "Tabriz",
    "Mashhad"
])

df = pd.DataFrame({
    "date": rng.choice(dates, rows),
    "channel": rng.choice(
        channels,
        rows,
        p=[0.36, 0.28, 0.20, 0.16]
    ),
    "category": rng.choice(
        categories,
        rows,
        p=[0.30, 0.24, 0.16, 0.30]
    ),
    "city": rng.choice(cities, rows),
    "visits": rng.integers(
        100,
        1600,
        rows
    ),
    "conversion_rate": rng.uniform(
        0.01,
        0.10,
        rows
    ),
    "average_order_value": rng.integers(
        1_500_000,
        20_000_000,
        rows
    )
})

df["orders"] = np.maximum(
    1,
    np.round(
        df["visits"]
        * df["conversion_rate"]
    )
).astype(int)

df["revenue"] = (
    df["orders"]
    * df["average_order_value"]
)

رسم نمودار خطی تعاملی

ابتدا درآمد روزانه را محاسبه می‌کنیم:

daily = (
    df.groupby(
        "date",
        as_index=False
    )
    .agg(
        revenue=("revenue", "sum"),
        orders=("orders", "sum"),
        visits=("visits", "sum")
    )
    .sort_values("date")
)

رسم نمودار:

import plotly.express as px

fig = px.line(
    daily,
    x="date",
    y="revenue",
    markers=True,
    title="Daily Revenue",
    labels={
        "date": "Date",
        "revenue": "Revenue"
    }
)

fig.update_traces(
    line={
        "width": 3,
        "color": "#6C4DF6"
    },
    marker={
        "size": 6
    }
)

fig.update_layout(
    hovermode="x unified",
    template="plotly_white"
)

fig.show()

گزینه hovermode="x unified" اطلاعات تمام سری‌های مربوط به یک مقدار X را داخل یک Hover Box نمایش می‌دهد.

رسم چند سری زمانی

daily_channel = (
    df.groupby(
        ["date", "channel"],
        as_index=False
    )["revenue"]
    .sum()
    .sort_values("date")
)

fig = px.line(
    daily_channel,
    x="date",
    y="revenue",
    color="channel",
    title="Daily Revenue by Channel"
)

fig.update_layout(
    hovermode="x unified",
    template="plotly_white",
    legend_title_text="Channel"
)

fig.show()

کاربر می‌تواند با کلیک روی نام هر کانال در Legend، آن سری را مخفی یا دوباره نمایش دهد.

افزودن Range Slider

برای داده زمانی می‌توان Range Slider اضافه کرد:

fig.update_xaxes(
    rangeslider_visible=True
)

همچنین می‌توان دکمه انتخاب بازه زمانی ایجاد کرد:

fig.update_xaxes(
    rangeselector={
        "buttons": [
            {
                "count": 7,
                "label": "7D",
                "step": "day",
                "stepmode": "backward"
            },
            {
                "count": 1,
                "label": "1M",
                "step": "month",
                "stepmode": "backward"
            },
            {
                "count": 3,
                "label": "3M",
                "step": "month",
                "stepmode": "backward"
            },
            {
                "step": "all",
                "label": "All"
            }
        ]
    },
    rangeslider_visible=True
)

رسم Bar Chart

مجموع درآمد هر کانال:

channel_summary = (
    df.groupby(
        "channel",
        as_index=False
    )
    .agg(
        revenue=("revenue", "sum"),
        orders=("orders", "sum")
    )
    .sort_values(
        "revenue",
        ascending=False
    )
)

رسم نمودار:

fig = px.bar(
    channel_summary,
    x="channel",
    y="revenue",
    color="channel",
    text_auto=".3s",
    title="Total Revenue by Channel",
    labels={
        "channel": "Channel",
        "revenue": "Revenue"
    }
)

fig.update_layout(
    showlegend=False,
    template="plotly_white"
)

fig.update_traces(
    textposition="outside",
    hovertemplate=(
        "<b>%{x}</b><br>"
        "Revenue: %{y:,.0f}"
        "<extra></extra>"
    )
)

fig.show()

بخش <extra></extra> نام اضافی Trace را از Hover حذف می‌کند.

نمودار میله‌ای افقی

برای عنوان‌های طولانی، Bar Chart افقی مناسب‌تر است:

category_summary = (
    df.groupby(
        "category",
        as_index=False
    )["revenue"]
    .sum()
    .sort_values(
        "revenue",
        ascending=True
    )
)

fig = px.bar(
    category_summary,
    x="revenue",
    y="category",
    orientation="h",
    color="revenue",
    color_continuous_scale="Purples",
    title="Revenue by Category"
)

fig.update_layout(
    template="plotly_white",
    coloraxis_showscale=False
)

fig.show()

رسم Grouped Bar Chart

برای مقایسه دسته‌ها در کانال‌های مختلف:

grouped = (
    df.groupby(
        ["channel", "category"],
        as_index=False
    )["revenue"]
    .sum()
)

fig = px.bar(
    grouped,
    x="channel",
    y="revenue",
    color="category",
    barmode="group",
    title="Revenue by Channel and Category"
)

fig.update_layout(
    template="plotly_white"
)

fig.show()

برای نمودار روی‌هم‌قرارگرفته:

fig.update_layout(
    barmode="stack"
)

نمودار Grouped برای مقایسه مستقیم دسته‌ها مناسب است. Stacked Bar برای نمایش ترکیب کل مقدار کاربرد دارد.

رسم Scatter Plot

plot_sample = df.sample(
    n=min(900, len(df)),
    random_state=42
)

fig = px.scatter(
    plot_sample,
    x="visits",
    y="revenue",
    color="channel",
    size="orders",
    hover_data={
        "category": True,
        "city": True,
        "conversion_rate": ":.2%",
        "average_order_value": ":,.0f"
    },
    title="Visits vs Revenue"
)

fig.update_layout(
    template="plotly_white"
)

fig.show()

در این نمودار:

  • محور X تعداد بازدید را نشان می‌دهد
  • محور Y درآمد را نمایش می‌دهد
  • رنگ مشخص‌کننده کانال است
  • اندازه نقطه تعداد سفارش را نمایش می‌دهد
  • Hover اطلاعات تکمیلی ارائه می‌کند

استفاده هم‌زمان از رنگ، اندازه و Symbol باید با احتیاط انجام شود؛ زیرا نمودار می‌تواند بیش از حد شلوغ شود.

افزودن Trendline

برای استفاده از Trendline باید statsmodels نصب باشد:

python -m pip install statsmodels

سپس:

fig = px.scatter(
    plot_sample,
    x="visits",
    y="revenue",
    color="channel",
    trendline="ols",
    title="Visits and Revenue Trend"
)

fig.show()

Trendline یک الگوی آماری را نمایش می‌دهد. وجود رابطه آماری یا همبستگی به‌تنهایی اثبات‌کننده رابطه علت و معلولی نیست.

رسم Histogram

fig = px.histogram(
    df,
    x="average_order_value",
    color="channel",
    nbins=35,
    marginal="box",
    opacity=0.65,
    barmode="overlay",
    title="Order Value Distribution"
)

fig.update_layout(
    template="plotly_white"
)

fig.show()

پارامتر marginal="box" یک Box Plot کوچک کنار توزیع قرار می‌دهد.

گزینه‌های دیگر:

marginal="rug"
marginal="violin"
marginal="histogram"

رسم Box Plot

fig = px.box(
    df,
    x="channel",
    y="average_order_value",
    color="channel",
    points="outliers",
    title="Order Value by Channel"
)

fig.update_layout(
    template="plotly_white",
    showlegend=False
)

fig.show()

برای نمایش تمام نقاط:

points="all"

در داده‌های بزرگ، نمایش تمام نقاط باعث شلوغی و افزایش حجم نمودار می‌شود.

رسم Violin Plot

fig = px.violin(
    plot_sample,
    x="channel",
    y="average_order_value",
    color="channel",
    box=True,
    points=False,
    title="Order Value Distribution"
)

fig.update_layout(
    template="plotly_white",
    showlegend=False
)

fig.show()

Violin Plot شکل تخمینی توزیع را نمایش می‌دهد. برای گروه‌هایی با نمونه کم، تفسیر آن باید با احتیاط انجام شود.

رسم Heatmap همبستگی

ابتدا ماتریس همبستگی را محاسبه کنید:

numeric_columns = [
    "visits",
    "conversion_rate",
    "orders",
    "average_order_value",
    "revenue"
]

correlation = (
    df[numeric_columns]
    .corr()
)

سپس Heatmap را بسازید:

fig = px.imshow(
    correlation,
    text_auto=".2f",
    color_continuous_scale="RdBu_r",
    zmin=-1,
    zmax=1,
    aspect="auto",
    title="Correlation Matrix"
)

fig.update_layout(
    template="plotly_white"
)

fig.show()

نکات مهم در تفسیر:

  • مقدار نزدیک مثبت یک نشان‌دهنده رابطه خطی مثبت است
  • مقدار نزدیک منفی یک رابطه خطی منفی را نشان می‌دهد
  • مقدار نزدیک صفر فقط نبود رابطه خطی قوی را نشان می‌دهد
  • همبستگی به معنای علت و معلول نیست

ساخت نمودار ترکیبی با Graph Objects

گاهی می‌خواهیم نمودار میله‌ای و خطی را با دو محور Y ترکیب کنیم.

from plotly.subplots import make_subplots
import plotly.graph_objects as go

monthly = (
    df.set_index("date")
      .resample("MS")
      .agg(
          revenue=("revenue", "sum"),
          orders=("orders", "sum")
      )
      .reset_index()
)

ساخت نمودار:

fig = make_subplots(
    specs=[
        [
            {
                "secondary_y": True
            }
        ]
    ]
)

fig.add_trace(
    go.Bar(
        x=monthly["date"],
        y=monthly["revenue"],
        name="Revenue",
        marker_color="#B8A9FF"
    ),
    secondary_y=False
)

fig.add_trace(
    go.Scatter(
        x=monthly["date"],
        y=monthly["orders"],
        name="Orders",
        mode="lines+markers",
        line={
            "color": "#EF476F",
            "width": 3
        }
    ),
    secondary_y=True
)

fig.update_layout(
    title="Monthly Revenue and Orders",
    template="plotly_white",
    hovermode="x unified"
)

fig.update_yaxes(
    title_text="Revenue",
    secondary_y=False
)

fig.update_yaxes(
    title_text="Orders",
    secondary_y=True
)

fig.show()

محور دوم زمانی مناسب است که دو شاخص واحدهای متفاوت داشته باشند. استفاده بی‌دلیل از دو محور می‌تواند نمودار را گمراه‌کننده کند.

ساخت Subplot

from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(
    rows=2,
    cols=2,
    subplot_titles=[
        "Daily Revenue",
        "Revenue by Channel",
        "Orders by Category",
        "Visits vs Revenue"
    ],
    specs=[
        [
            {"type": "xy"},
            {"type": "xy"}
        ],
        [
            {"type": "xy"},
            {"type": "xy"}
        ]
    ]
)

افزودن نمودار خطی:

fig.add_trace(
    go.Scatter(
        x=daily["date"],
        y=daily["revenue"],
        mode="lines",
        name="Daily Revenue",
        line={
            "color": "#6C4DF6",
            "width": 2.5
        }
    ),
    row=1,
    col=1
)

افزودن نمودار کانال‌ها:

fig.add_trace(
    go.Bar(
        x=channel_summary["channel"],
        y=channel_summary["revenue"],
        name="Channel Revenue",
        marker_color="#00A6A6"
    ),
    row=1,
    col=2
)

مجموع سفارش هر دسته:

category_orders = (
    df.groupby(
        "category",
        as_index=False
    )["orders"]
    .sum()
)

افزودن نمودار:

fig.add_trace(
    go.Bar(
        x=category_orders["category"],
        y=category_orders["orders"],
        name="Category Orders",
        marker_color="#FF9F1C"
    ),
    row=2,
    col=1
)

افزودن Scatter Plot:

fig.add_trace(
    go.Scattergl(
        x=plot_sample["visits"],
        y=plot_sample["revenue"],
        mode="markers",
        name="Visits vs Revenue",
        marker={
            "color": "#EF476F",
            "size": 7,
            "opacity": 0.55
        }
    ),
    row=2,
    col=2
)

تنظیم نهایی:

fig.update_layout(
    title="E-commerce Performance Dashboard",
    height=850,
    template="plotly_white",
    showlegend=False
)

fig.update_xaxes(
    title_text="Date",
    row=1,
    col=1
)

fig.update_yaxes(
    title_text="Revenue",
    row=1,
    col=1
)

fig.update_xaxes(
    title_text="Channel",
    row=1,
    col=2
)

fig.update_yaxes(
    title_text="Revenue",
    row=1,
    col=2
)

fig.update_xaxes(
    title_text="Category",
    row=2,
    col=1
)

fig.update_yaxes(
    title_text="Orders",
    row=2,
    col=1
)

fig.update_xaxes(
    title_text="Visits",
    row=2,
    col=2
)

fig.update_yaxes(
    title_text="Revenue",
    row=2,
    col=2
)

fig.show()

شخصی‌سازی Hover

می‌توان متن Hover را دقیقاً کنترل کرد:

fig.update_traces(
    hovertemplate=(
        "<b>Date:</b> %{x|%Y-%m-%d}<br>"
        "<b>Revenue:</b> %{y:,.0f}<br>"
        "<extra></extra>"
    )
)

قالب‌های متداول:

%{y:,.0f}
%{y:.2f}
%{y:.1%}
%{x|%Y-%m-%d}

استفاده از Hover مناسب باعث می‌شود نیازی به نوشتن تمام اعداد روی خود نمودار نباشد.

افزودن Annotation

max_row = daily.loc[
    daily["revenue"].idxmax()
]

fig = px.line(
    daily,
    x="date",
    y="revenue",
    title="Daily Revenue"
)

fig.add_annotation(
    x=max_row["date"],
    y=max_row["revenue"],
    text="Highest revenue",
    showarrow=True,
    arrowhead=2,
    ax=-50,
    ay=-55,
    bgcolor="#FFF2B2"
)

fig.show()

Annotation برای مشخص‌کردن قله، افت، تغییر مهم یا یک رویداد خاص مناسب است.

افزودن خط هدف

target = daily["revenue"].mean()

fig.add_hline(
    y=target,
    line_dash="dash",
    line_color="#EF476F",
    annotation_text="Average"
)

برای مشخص‌کردن بازه:

fig.add_vrect(
    x0="2026-03-01",
    x1="2026-03-15",
    fillcolor="#FFD166",
    opacity=0.18,
    line_width=0,
    annotation_text="Campaign"
)

نمایش متن فارسی در Plotly

Plotly نمودار را در مرورگر رندر می‌کند. در نتیجه، پشتیبانی از متن فارسی معمولاً بهتر از بعضی موتورهای رسم ثابت است.

persian_df = pd.DataFrame({
    "شهر": [
        "تهران",
        "شیراز",
        "تبریز",
        "مشهد"
    ],
    "فروش": [
        820,
        470,
        390,
        610
    ]
})

fig = px.bar(
    persian_df,
    x="شهر",
    y="فروش",
    color="فروش",
    color_continuous_scale="Purples",
    title="فروش به تفکیک شهر"
)

fig.update_layout(
    font={
        "family": "Vazirmatn, Tahoma, Arial",
        "size": 14
    },
    title={
        "x": 0.95,
        "xanchor": "right"
    },
    xaxis_title="شهر",
    yaxis_title="میزان فروش",
    template="plotly_white"
)

fig.show()

اگر نمودار در وب‌سایت نمایش داده می‌شود، باید فونت موردنظر در CSS صفحه نیز بارگذاری شده باشد. نوشتن نام فونت در Layout باعث نصب یا بارگذاری خودکار آن نمی‌شود.

تنظیم Template اختصاصی

import plotly.io as pio

darvareh_template = {
    "layout": {
        "font": {
            "family": (
                "Vazirmatn, Tahoma, Arial"
            ),
            "color": "#1A1A2E"
        },
        "paper_bgcolor": "#FFFFFF",
        "plot_bgcolor": "#FFFFFF",
        "colorway": [
            "#6C4DF6",
            "#00A6A6",
            "#EF476F",
            "#FF9F1C",
            "#118AB2"
        ],
        "xaxis": {
            "gridcolor": "#ECECF4",
            "zerolinecolor": "#DADAE6"
        },
        "yaxis": {
            "gridcolor": "#ECECF4",
            "zerolinecolor": "#DADAE6"
        }
    }
}

pio.templates[
    "darvareh"
] = darvareh_template

pio.templates.default = "darvareh"

پس از آن، نمودارهای جدید از این Template استفاده می‌کنند.

ذخیره نمودار تعاملی در HTML

یکی از قابلیت‌های مهم Plotly ذخیره نمودار همراه با تعامل کامل در یک فایل HTML است.

fig.write_html(
    "sales_dashboard.html"
)

فایل تولیدشده را می‌توان با مرورگر باز کرد.

مطابق راهنمای رسمی خروجی HTML در Plotly، متد write_html می‌تواند Figure را به یک فایل HTML تعاملی تبدیل کند.

فایل مستقل برای استفاده آفلاین

fig.write_html(
    "dashboard_offline.html",
    include_plotlyjs=True,
    full_html=True
)

این روش کد Plotly.js را داخل فایل قرار می‌دهد؛ بنابراین فایل بدون اینترنت نیز قابل استفاده است، اما حجم آن بیشتر خواهد بود.

فایل کوچک‌تر با CDN

fig.write_html(
    "dashboard.html",
    include_plotlyjs="cdn",
    full_html=True
)

این فایل کوچک‌تر است، اما برای بارگذاری کتابخانه JavaScript به اینترنت نیاز دارد.

خروجی قطعه HTML

برای قراردادن نمودار داخل Template وب:

chart_html = fig.to_html(
    full_html=False,
    include_plotlyjs="cdn"
)

متغیر chart_html را می‌توان داخل Template برنامه قرار داد.

خروجی PNG، SVG و PDF

برای خروجی تصویر ثابت از Kaleido استفاده می‌شود:

python -m pip install --upgrade kaleido

خروجی PNG:

fig.write_image(
    "chart.png",
    width=1600,
    height=900,
    scale=2
)

خروجی SVG:

fig.write_image(
    "chart.svg"
)

خروجی PDF:

fig.write_image(
    "chart.pdf"
)

خروجی WebP:

fig.write_image(
    "chart.webp",
    width=1600,
    height=900
)

براساس مستندات رسمی خروجی ثابت Plotly، نسخه‌های جدید Kaleido برای رندر تصویر به Chrome یا Chromium سازگار روی سیستم نیاز دارند.

اگر Chrome پیدا نشد، پس از نصب Kaleido می‌توانید از دستور ارائه‌شده توسط آن استفاده کنید:

kaleido_get_chrome

در سرور بهتر است وجود Chrome یا Chromium در Docker Image و مسیر اجرای برنامه از قبل بررسی شود.

خروجی چند نمودار

برای تعداد کمی نمودار:

fig1.write_image("chart-1.png")
fig2.write_image("chart-2.png")

برای تعداد زیاد Figure، نسخه‌های جدید Plotly امکان استفاده از write_images را فراهم می‌کنند:

import plotly.io as pio

pio.write_images(
    [
        fig1,
        fig2
    ],
    [
        "chart-1.png",
        "chart-2.png"
    ]
)

این روش برای خروجی دسته‌ای می‌تواند کارآمدتر از اجرای جداگانه write_image باشد.

نمایش Plotly در Streamlit

نصب Streamlit:

python -m pip install streamlit

فایل app.py:

import pandas as pd
import plotly.express as px
import streamlit as st

st.set_page_config(
    page_title="Sales Dashboard",
    layout="wide"
)

st.title("Sales Dashboard")

df = pd.read_csv(
    "sales.csv",
    parse_dates=["date"]
)

selected_channels = st.multiselect(
    "Select channels",
    options=sorted(
        df["channel"].dropna().unique()
    ),
    default=sorted(
        df["channel"].dropna().unique()
    )
)

filtered_df = df[
    df["channel"].isin(
        selected_channels
    )
]

daily = (
    filtered_df.groupby(
        ["date", "channel"],
        as_index=False
    )["revenue"]
    .sum()
)

fig = px.line(
    daily,
    x="date",
    y="revenue",
    color="channel",
    title="Daily Revenue"
)

fig.update_layout(
    hovermode="x unified",
    template="plotly_white"
)

st.plotly_chart(
    fig,
    width="stretch"
)

اجرا:

streamlit run app.py

Streamlit فیلترهای انتخاب‌شده را دریافت و نمودار Plotly را دوباره تولید می‌کند.

ارائه نمودار با FastAPI

در این مثال Figure را به JSON تبدیل می‌کنیم تا برنامه Frontend بتواند آن را دریافت کند.

نصب:

python -m pip install fastapi uvicorn plotly pandas

فایل main.py:

import json

import pandas as pd
import plotly.express as px
import plotly.utils
from fastapi import FastAPI

app = FastAPI()

@app.get("/chart")
def get_chart():
    df = pd.DataFrame({
        "month": [
            "Jan",
            "Feb",
            "Mar",
            "Apr",
            "May"
        ],
        "sales": [
            120,
            145,
            138,
            180,
            215
        ]
    })

    fig = px.line(
        df,
        x="month",
        y="sales",
        markers=True,
        title="Monthly Sales"
    )

    figure_json = json.loads(
        json.dumps(
            fig,
            cls=plotly.utils.PlotlyJSONEncoder
        )
    )

    return {
        "figure": figure_json
    }

اجرای API:

uvicorn main:app --reload

آدرس:

http://127.0.0.1:8000/chart

Frontend می‌تواند مقدار figure.data و figure.layout را به Plotly.js بدهد.

تولید HTML نمودار در FastAPI

from fastapi.responses import HTMLResponse

@app.get(
    "/chart/view",
    response_class=HTMLResponse
)
def view_chart():
    fig = px.bar(
        x=["A", "B", "C"],
        y=[10, 18, 14],
        labels={
            "x": "Category",
            "y": "Value"
        }
    )

    chart = fig.to_html(
        full_html=True,
        include_plotlyjs="cdn"
    )

    return HTMLResponse(
        content=chart
    )

این روش برای نمایش سریع نمودار مناسب است. در برنامه‌های بزرگ‌تر بهتر است نمودار داخل Template یا کامپوننت Frontend قرار گیرد.

بهینه‌سازی Plotly برای داده‌های بزرگ

تعامل کامل با صدها هزار یا میلیون‌ها نقطه می‌تواند مرورگر را کند کند.

نمونه‌برداری

plot_df = df.sample(
    n=min(20_000, len(df)),
    random_state=42
)

تجمیع داده

daily = (
    df.set_index("date")
      .resample("D")["revenue"]
      .sum()
      .reset_index()
)

استفاده از WebGL

در Plotly Express:

fig = px.scatter(
    plot_df,
    x="visits",
    y="revenue",
    render_mode="webgl"
)

در Graph Objects:

import plotly.graph_objects as go

fig = go.Figure(
    go.Scattergl(
        x=plot_df["visits"],
        y=plot_df["revenue"],
        mode="markers",
        marker={
            "size": 4,
            "opacity": 0.45
        }
    )
)

کاهش اطلاعات Hover

ارسال تعداد زیادی فیلد برای هر نقطه، حجم Figure را افزایش می‌دهد. فقط ستون‌های موردنیاز را در hover_data قرار دهید.

جلوگیری از تکرار Plotly.js

اگر چند فایل HTML را در یک پوشه ذخیره می‌کنید، قراردادن جداگانه Plotly.js داخل هر فایل می‌تواند حجم کلی را زیاد کند. گزینه‌های cdn یا directory را متناسب با محیط استفاده بررسی کنید.

ارسال داده خلاصه‌شده به مرورگر

محاسبات سنگین را در Backend یا Pandas انجام دهید و فقط داده لازم برای نمودار را به مرورگر بفرستید.

اتصال Plotly به هوش مصنوعی درواره

Plotly مسئول نمایش داده است. هوش مصنوعی می‌تواند خلاصه آماری محاسبه‌شده را توضیح دهد یا برای ادامه تحلیل پیشنهاد ارائه کند.

معماری مناسب:

  1. خواندن و اعتبارسنجی داده با Pandas
  2. محاسبه شاخص‌های دقیق
  3. ساخت نمودار تعاملی با Plotly
  4. ارسال خلاصه ساختاریافته به مدل
  5. نمایش گزارش مدل کنار نمودار

برای دسترسی API به مدل‌های مختلف می‌توانید در درواره ثبت‌نام کنید. فهرست مدل‌ها و قیمت به‌روز آن‌ها در صفحه مدل‌های درواره قرار دارد.

نگهداری API Key

در Linux یا macOS:

export DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"

در PowerShell:

$env:DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"

API Key را مستقیماً داخل کد یا مخزن Git قرار ندهید.

محاسبه خلاصه با Pandas

summary = {
    "total_revenue": float(
        df["revenue"].sum()
    ),
    "total_orders": int(
        df["orders"].sum()
    ),
    "total_visits": int(
        df["visits"].sum()
    ),
    "average_conversion_rate": float(
        df["conversion_rate"].mean()
    ),
    "median_order_value": float(
        df["average_order_value"].median()
    ),
    "top_channel": str(
        channel_summary.iloc[0][
            "channel"
        ]
    ),
    "top_channel_revenue": float(
        channel_summary.iloc[0][
            "revenue"
        ]
    )
}

ارسال خلاصه به API درواره

import json
import os
import requests

response = requests.post(
    "https://api.darvareh.ir/v1/chat/completions",
    headers={
        "Authorization": (
            f"Bearer "
            f"{os.environ['DARVAREH_API_KEY']}"
        ),
        "Content-Type": "application/json"
    },
    json={
        "model": "YOUR_MODEL_ID",
        "messages": [
            {
                "role": "system",
                "content": (
                    "تو یک دستیار تحلیل داده هستی. "
                    "فقط براساس اطلاعات ورودی پاسخ بده. "
                    "هیچ عدد یا علت جدیدی اختراع نکن. "
                    "همبستگی را علیت معرفی نکن."
                )
            },
            {
                "role": "user",
                "content": (
                    "خلاصه زیر مربوط به عملکرد "
                    "فروشگاه آنلاین است. چهار یافته "
                    "مهم، سه پرسش برای بررسی بیشتر "
                    "و یک خلاصه مدیریتی کوتاه بنویس."
                    "\n\n"
                    + json.dumps(
                        summary,
                        ensure_ascii=False
                    )
                )
            }
        ],
        "temperature": 0.2
    },
    timeout=60
)

response.raise_for_status()

result = response.json()

analysis_text = (
    result["choices"][0]
          ["message"]
          ["content"]
)

print(analysis_text)

نمایش گزارش هوش مصنوعی کنار نمودار در Streamlit

import streamlit as st

left_column, right_column = st.columns(
    [2, 1]
)

with left_column:
    st.plotly_chart(
        fig,
        width="stretch"
    )

with right_column:
    st.subheader("تحلیل هوش مصنوعی")
    st.write(analysis_text)

این الگو یک داشبورد ترکیبی ایجاد می‌کند:

  • سمت اصلی: نمودار تعاملی
  • کنار نمودار: خلاصه و تفسیر متنی

محاسبات عددی را با Pandas انجام دهید و از مدل برای توضیح و پیشنهاد استفاده کنید.

تولید پیشنهاد نمودار با هوش مصنوعی

می‌توانید Schema داده و سؤال کسب‌وکار را برای مدل ارسال کنید:

schema = {
    "date": "تاریخ ثبت سفارش",
    "channel": "کانال جذب کاربر",
    "category": "دسته محصول",
    "city": "شهر",
    "visits": "تعداد بازدید",
    "conversion_rate": "نرخ تبدیل",
    "orders": "تعداد سفارش",
    "revenue": "درآمد"
}

پرامپت پیشنهادی:

برای مجموعه داده‌ای با ستون‌های ارائه‌شده، پنج نمودار تعاملی مناسب با Plotly پیشنهاد بده.

برای هر نمودار مشخص کن:
1. سؤال تحلیلی چیست
2. تابع مناسب Plotly Express چیست
3. محور X و Y چه باشند
4. آیا color یا facet لازم است
5. چه GroupBy یا Resample باید با Pandas انجام شود
6. چه خطای تفسیری ممکن است رخ دهد

هیچ عددی تولید نکن و فقط از ستون‌های معرفی‌شده استفاده کن.

خروجی مدل باید به‌عنوان پیشنهاد بررسی شود. کد نهایی، محاسبات و نمودار باید روی داده واقعی آزمایش شوند.

ساخت تابع قابل استفاده مجدد

from pathlib import Path

import pandas as pd
import plotly.express as px

def create_daily_revenue_chart(
    df: pd.DataFrame,
    output_path: str
) -> Path:
    required_columns = {
        "date",
        "revenue"
    }

    missing = (
        required_columns
        - set(df.columns)
    )

    if missing:
        raise ValueError(
            f"Missing columns: "
            f"{sorted(missing)}"
        )

    clean_df = df.copy()

    clean_df["date"] = pd.to_datetime(
        clean_df["date"],
        errors="coerce"
    )

    clean_df["revenue"] = pd.to_numeric(
        clean_df["revenue"],
        errors="coerce"
    )

    clean_df = clean_df.dropna(
        subset=[
            "date",
            "revenue"
        ]
    )

    if clean_df.empty:
        raise ValueError(
            "No valid data to plot"
        )

    daily = (
        clean_df.groupby(
            "date",
            as_index=False
        )["revenue"]
        .sum()
        .sort_values("date")
    )

    fig = px.line(
        daily,
        x="date",
        y="revenue",
        markers=True,
        title="Daily Revenue"
    )

    fig.update_layout(
        template="plotly_white",
        hovermode="x unified"
    )

    path = Path(output_path)

    path.parent.mkdir(
        parents=True,
        exist_ok=True
    )

    fig.write_html(
        path,
        include_plotlyjs=True,
        full_html=True
    )

    return path

استفاده:

chart_path = (
    create_daily_revenue_chart(
        df=df,
        output_path=(
            "reports/"
            "daily-revenue.html"
        )
    )
)

print(chart_path)

تست ساده تابع تولید نمودار

def test_create_daily_revenue_chart(
    tmp_path
):
    test_df = pd.DataFrame({
        "date": [
            "2026-01-01",
            "2026-01-02"
        ],
        "revenue": [
            100,
            150
        ]
    })

    output = (
        tmp_path
        / "chart.html"
    )

    result = (
        create_daily_revenue_chart(
            test_df,
            str(output)
        )
    )

    assert result.exists()
    assert result.stat().st_size > 0

تست کمک می‌کند مطمئن شوید تابع با داده معتبر، فایل HTML واقعی تولید می‌کند.

خطاهای رایج Plotly

خطای نصب نبودن Plotly

ModuleNotFoundError: No module named 'plotly'

راه‌حل:

python -m pip install plotly

باز نشدن نمودار

در اسکریپت معمولی:

fig.show()

اگر Renderer محیط به‌درستی کار نمی‌کند:

import plotly.io as pio

pio.renderers.default = "browser"

پیدا نشدن ستون

ValueError: Value of 'x' is not the name of a column

ستون‌ها را بررسی کنید:

print(df.columns.tolist())

حذف فاصله ابتدا و انتهای نام ستون:

df.columns = (
    df.columns
      .str.strip()
)

مرتب نبودن تاریخ

df["date"] = pd.to_datetime(
    df["date"],
    errors="coerce"
)

df = df.sort_values("date")

حجم زیاد فایل HTML

علت احتمالی:

  • قراردادن Plotly.js داخل هر فایل
  • تعداد بسیار زیاد نقطه
  • Hover Data حجیم
  • چند Trace بزرگ

برای فایل آنلاین:

fig.write_html(
    "chart.html",
    include_plotlyjs="cdn"
)

برای داده، از تجمیع یا نمونه‌برداری استفاده کنید.

خطای Kaleido یا Chrome

ابتدا بسته‌ها را به‌روز کنید:

python -m pip install --upgrade plotly kaleido

نسخه‌های جدید Kaleido به Chrome یا Chromium سازگار نیاز دارند. در صورت نبود Chrome:

kaleido_get_chrome

خروجی PNG با فونت متفاوت

موتور تولید تصویر باید به فونت دسترسی داشته باشد. فونت موردنظر را روی سرور یا داخل Docker Image نصب کنید.

کندشدن مرورگر

راهکارها:

  • نمونه‌برداری
  • تجمیع داده
  • استفاده از WebGL
  • کاهش Traceها
  • حذف ستون‌های غیرضروری از Hover
  • ارسال داده خلاصه‌شده به Frontend

اشتباهات رایج در طراحی نمودار تعاملی

قراردادن همه اطلاعات در Hover

Hover باید اطلاعات تکمیلی مهم را نمایش دهد، نه کل رکورد را.

استفاده زیاد از رنگ و اندازه

نمایش بیش از چهار یا پنج بُعد در یک نمودار باعث کاهش خوانایی می‌شود.

استفاده از دو محور Y بدون ضرورت

محور دوم می‌تواند رابطه ظاهری گمراه‌کننده ایجاد کند. واحد هر محور باید کاملاً مشخص باشد.

رسم میلیون‌ها نقطه

تعامل به معنای نمایش تمام داده خام نیست. هدف نمودار کمک به تصمیم‌گیری است، نه انتقال کل دیتابیس به مرورگر.

اتکا به نمودار بدون پاک‌سازی داده

نوع داده نادرست، مقدار گمشده یا رکورد تکراری می‌تواند نمودار تعاملی زیبا اما اشتباه تولید کند.

استفاده از نمودار سه‌بعدی برای جذابیت

نمودار سه‌بعدی همیشه اطلاعات بیشتری ارائه نمی‌دهد و ممکن است مقایسه مقادیر را دشوار کند.

ارسال مستقیم داده حساس به مرورگر

داده‌ای که داخل Figure قرار می‌گیرد می‌تواند در سمت کاربر قابل مشاهده باشد. فقط اطلاعات لازم برای نمودار را ارسال کنید.

چک‌لیست ساخت نمودار حرفه‌ای Plotly

  • سؤال تحلیل پیش از ساخت نمودار مشخص شده است
  • نوع داده ستون‌ها صحیح است
  • داده‌های گمشده و تکراری بررسی شده‌اند
  • داده زمانی مرتب شده است
  • تجمیع با Pandas انجام شده است
  • محور و واحد اندازه‌گیری مشخص‌اند
  • عنوان نمودار واضح است
  • Hover فقط اطلاعات ضروری را نمایش می‌دهد
  • تعداد Traceها کنترل شده است
  • Legend قابل فهم است
  • رنگ‌ها معنای مشخص دارند
  • نمودار در صفحه کوچک بررسی شده است
  • داده زیاد نمونه‌برداری یا تجمیع شده است
  • نسخه HTML آفلاین و آنلاین آگاهانه انتخاب شده است
  • خروجی ثابت در محیط Deployment آزمایش شده است
  • Chrome یا Chromium برای Kaleido آماده است
  • اعداد توسط کد محاسبه می‌شوند
  • تفسیر هوش مصنوعی فقط براساس خلاصه معتبر انجام می‌شود

پرسش‌های متداول

Plotly چیست؟

Plotly یک کتابخانه مصورسازی داده است که امکان ساخت نمودارهای تعاملی با قابلیت Hover، Zoom، Pan و انتخاب داده را فراهم می‌کند.

Plotly رایگان است؟

کتابخانه متن‌باز Plotly برای پایتون را می‌توان در پروژه‌های پایتون استفاده کرد. محصولات و سرویس‌های تجاری مرتبط ممکن است شرایط جداگانه داشته باشند.

تفاوت Plotly Express و Graph Objects چیست؟

Plotly Express برای ساخت سریع نمودار از DataFrame مناسب است. Graph Objects کنترل دقیق‌تری روی Traceها، Layout، Subplot و نمودارهای ترکیبی ارائه می‌دهد.

آیا Plotly به اینترنت نیاز دارد؟

خود کتابخانه می‌تواند نمودار را محلی تولید کند. فایل HTML اگر با include_plotlyjs=True ساخته شود، می‌تواند مستقل و آفلاین باشد. اگر از CDN استفاده شود، برای بارگذاری Plotly.js به اینترنت نیاز دارد.

چگونه نمودار Plotly را در HTML ذخیره کنیم؟

fig.write_html(
    "chart.html"
)

چگونه نمودار را به PNG تبدیل کنیم؟

Kaleido را نصب و سپس از write_image استفاده کنید:

fig.write_image(
    "chart.png"
)

نسخه‌های جدید Kaleido به Chrome یا Chromium سازگار نیاز دارند.

آیا Plotly متن فارسی را نمایش می‌دهد؟

بله. چون نمودار در مرورگر رندر می‌شود، متن فارسی معمولاً به‌خوبی نمایش داده می‌شود. برای ظاهر یکسان باید فونت فارسی در صفحه یا محیط خروجی در دسترس باشد.

آیا Plotly برای داده‌های بزرگ مناسب است؟

برای داده متوسط مناسب است. برای تعداد بسیار زیاد نقاط باید از تجمیع، نمونه‌برداری، WebGL و کاهش اطلاعات Hover استفاده کنید.

آیا می‌توان Plotly را در Streamlit استفاده کرد؟

بله. متد st.plotly_chart نمودار تعاملی Plotly را در برنامه Streamlit نمایش می‌دهد.

چگونه Plotly را با FastAPI استفاده کنیم؟

می‌توانید Figure را به JSON تبدیل و برای Frontend ارسال کنید یا خروجی HTML آن را با HTMLResponse برگردانید.

چگونه از هوش مصنوعی کنار Plotly استفاده کنیم؟

شاخص‌های قطعی را با Pandas محاسبه کنید، نمودار را با Plotly بسازید و خلاصه آماری را برای تولید گزارش متنی به API درواره ارسال کنید.

جمع‌بندی

Plotly یکی از بهترین گزینه‌ها برای ساخت نمودار تعاملی و داشبورد داده‌محور با پایتون است. Plotly Express شروع کار را ساده می‌کند و Graph Objects کنترل لازم برای نمودارهای پیچیده، ترکیبی و چندبخشی را در اختیار توسعه‌دهنده قرار می‌دهد.

یک جریان کاری قابل اعتماد می‌تواند چنین ساختاری داشته باشد:

  • Pandas برای خواندن، پاک‌سازی و تجمیع داده
  • NumPy برای محاسبات عددی
  • Plotly برای نمودار تعاملی
  • Streamlit یا Frontend برای رابط کاربری
  • FastAPI برای ارائه داده و Figure
  • هوش مصنوعی برای توضیح و خلاصه‌سازی
  • درواره برای دسترسی API یکپارچه به مدل‌های موردنیاز

برای شروع، در درواره ثبت‌نام کنید، API Key بگیرید و مدل مناسب پروژه را از صفحه مدل‌ها و قیمت‌ها انتخاب کنید.

مقالات مرتبط

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.