رسم نمودار در پایتون با Matplotlib؛ خطی، میلهای، دایرهای و هیستوگرام

🗓 آخرین بهروزرسانی:
دادهای که فقط بهصورت عدد در جدول باشد، بهسختی فهمیده میشود؛ اما همان داده روی یک نمودار، در یک نگاه روند و الگو را نشان میدهد. در پایتون، پرکاربردترین کتابخانه رسم نمودار Matplotlib است. در این آموزش انواع اصلی نمودار را با مثالهای اجراشده رسم میکنیم: خطی، میلهای، دایرهای، پراکندگی و هیستوگرام. سپس چند نمودار را در یک شکل کنار هم میگذاریم، ظاهر نمودار را تنظیم میکنیم و آن را بهصورت تصویر ذخیره میکنیم.
همه کدها با پایتون 3.13.5 و Matplotlib 3.11.2 اجرا شدهاند و تصویرهای این صفحه، خروجی واقعی همان کدها هستند. برای نمایش در این صفحه بهجای plt.show() از plt.savefig() استفاده کردهایم؛ روی کامپیوتر خودتان میتوانید plt.show() بنویسید تا نمودار در یک پنجره باز شود.
نصب Matplotlib
python -m pip install matplotlibimport matplotlib
print("matplotlib", matplotlib.__version__)خروجی:
matplotlib 3.11.2قرارداد رایج این است که زیرماژول pyplot را با نام کوتاه plt وارد کنید: import matplotlib.pyplot as plt. همه مثالهای این صفحه با همین نام نوشته شدهاند.
چطور نمودار مناسب را انتخاب کنیم؟
پیش از نوشتن کد، از خودتان بپرسید «میخواهم بیننده چه چیزی را بفهمد؟». اگر پاسخ «تغییر در طول زمان» است، نمودار خطی بکشید و محور افقی را به ترتیب زمان مرتب کنید. اگر «کدام بزرگتر است» است، نمودار میلهای با میلههای مرتبشده از بزرگ به کوچک بهترین انتخاب است. اگر «هر بخش چه سهمی از کل دارد» است و تعداد بخشها کم است، نمودار دایرهای جواب میدهد. برای «آیا این دو متغیر به هم ربط دارند» نمودار پراکندگی و برای «دادهها بیشتر کجا جمع شدهاند» هیستوگرام مناسب است.
چند قاعده ساده کیفیت هر نمودار را بالا میبرد: همیشه عنوان و برچسب محورها را بنویسید و واحد را ذکر کنید؛ محور عمودی نمودار میلهای را از صفر شروع کنید تا تفاوتها اغراقآمیز دیده نشوند؛ از سهبعدی کردن نمودارهای ساده پرهیز کنید چون خواندن مقدارها را سخت میکند؛ و اگر داده نمونه یا شبیهسازیشده است، مثل مثالهای این صفحه، آن را در عنوان یا توضیح بنویسید.
نمودار خطی؛ نمایش روند
نمودار خطی برای نمایش تغییر یک مقدار در طول زمان مناسب است؛ مثل فروش ماهانه یا دمای روزانه. تابع plt.plot دو لیست میگیرد: مقدارهای محور افقی و عمودی.
import matplotlib.pyplot as plt
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
sales = [120, 150, 130, 180, 210, 195]
costs = [90, 100, 110, 115, 140, 150]
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
ax.plot(months, sales, marker="o", label="Sales")
ax.plot(months, costs, marker="s", linestyle="--", label="Costs")
ax.set_title("Monthly sales vs costs")
ax.set_xlabel("Month")
ax.set_ylabel("Amount")
ax.grid(alpha=0.3)
ax.legend()
fig.tight_layout()
fig.savefig("line.png")
print("saved line.png, best month:", months[sales.index(max(sales))])خروجی:
saved line.png, best month: May
markerشکل نقطهها را تعیین میکند ("o"دایره،"s"مربع).linestyle="--"خطچین میکشد.labelنام هر خط است وlegend()راهنما را نمایش میدهد.gridخطوط راهنمای پسزمینه را اضافه میکند وalphaشفافیت آن را.
دو روش نوشتن: plt یا fig, ax
Matplotlib دو سبک دارد. سبک سریع که مستقیماً plt.plot و plt.title را صدا میزند و سبک شیءگرا که با fig, ax = plt.subplots() شروع میشود و روی ax کار میکند. برای نمودارهای تکی هر دو جواب میدهند، اما وقتی چند نمودار در یک شکل دارید، سبک ax واضحتر و قابلکنترلتر است. توصیه ما این است که از همان ابتدا به سبک ax عادت کنید.
نمودار میلهای؛ مقایسه دستهها
وقتی میخواهید چند دسته را با هم مقایسه کنید (مثلاً تعداد دانشجویان هر دوره)، نمودار میلهای انتخاب مناسبی است. با bar_label میتوانید عدد هر میله را بالای آن بنویسید:
import matplotlib.pyplot as plt
courses = ["Python", "WordPress", "SQL", "Git", "Linux"]
students = [340, 260, 150, 120, 90]
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
bars = ax.bar(courses, students, color=["#3b8cff", "#ffc928", "#ff7043", "#22b573", "#7c4dff"])
ax.bar_label(bars)
ax.set_title("Students per course (sample data)")
ax.set_ylabel("Students")
fig.tight_layout()
fig.savefig("bar.png")
print("total students:", sum(students))خروجی:
total students: 960
داده این مثال نمونه و ساختگی است و فقط برای نمایش نمودار آمده است. برای میلههای افقی که با برچسبهای طولانی خواناترند، از ax.barh استفاده کنید.
نمودار دایرهای؛ سهم هر بخش از کل
نمودار دایرهای نشان میدهد هر بخش چند درصد از کل است. پارامتر autopct درصد را خودکار روی هر بخش مینویسد. این نمودار وقتی تعداد بخشها کم است (حداکثر پنج یا شش) خوانا است؛ برای بخشهای زیاد، نمودار میلهای بهتر است.
import matplotlib.pyplot as plt
labels = ["Rent", "Food", "Transport", "Other"]
expenses = [45, 30, 15, 10]
fig, ax = plt.subplots(figsize=(6, 6), dpi=100)
ax.pie(expenses, labels=labels, autopct="%1.0f%%", startangle=90)
ax.set_title("Monthly expenses")
fig.savefig("pie.png")
for l, e in zip(labels, expenses):
print(f"{l}: {e / sum(expenses):.0%}")خروجی:
Rent: 45%
Food: 30%
Transport: 15%
Other: 10%
نمودار پراکندگی؛ رابطه بین دو متغیر
نمودار پراکندگی (Scatter) هر داده را بهصورت یک نقطه نشان میدهد و برای دیدن رابطه بین دو متغیر کاربرد دارد؛ مثلاً ساعت مطالعه و نمره. در مثال زیر داده را با ماژول random و بذر ثابت تولید کردهایم تا خروجی تکرارپذیر باشد:
import random
import matplotlib.pyplot as plt
random.seed(7)
hours = [random.uniform(0, 10) for _ in range(40)]
scores = [min(100, 40 + 5.5 * h + random.gauss(0, 7)) for h in hours]
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
ax.scatter(hours, scores, c=scores, cmap="viridis")
ax.set_title("Study hours vs score (simulated)")
ax.set_xlabel("Hours")
ax.set_ylabel("Score")
fig.tight_layout()
fig.savefig("scatter.png")
print(f"avg score: {sum(scores) / len(scores):.1f}")خروجی:
avg score: 60.1
هیستوگرام؛ توزیع دادهها
هیستوگرام نشان میدهد دادهها در چه بازههایی بیشتر جمع شدهاند. دادهها به چند بازه (bin) تقسیم و تعداد هر بازه بهصورت میله رسم میشود. خروجی ax.hist تعداد هر بازه را هم برمیگرداند:
import random
import matplotlib.pyplot as plt
random.seed(1)
heights = [random.gauss(170, 8) for _ in range(500)]
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
counts, edges, _ = ax.hist(heights, bins=12, color="#3b8cff", edgecolor="white")
ax.set_title("Height distribution (simulated, n=500)")
ax.set_xlabel("cm")
fig.tight_layout()
fig.savefig("hist.png")
i = list(counts).index(max(counts))
print(f"most common range: {edges[i]:.0f}-{edges[i+1]:.0f} cm ({int(counts[i])} people)")خروجی:
most common range: 169-173 cm (94 people)
چند نمودار در یک شکل با subplots
گاهی میخواهید چند نمودار را کنار هم ببینید. plt.subplots(1, 2) یک ردیف با دو ستون میسازد و axes آرایهای از محورهاست:
import matplotlib.pyplot as plt
x = list(range(1, 11))
fig, axes = plt.subplots(1, 2, figsize=(10, 4), dpi=100)
axes[0].plot(x, [n ** 2 for n in x], color="#ff7043")
axes[0].set_title("y = x^2")
axes[1].bar(x, [n % 3 for n in x], color="#22b573")
axes[1].set_title("x % 3")
fig.suptitle("Two charts in one figure")
fig.tight_layout()
fig.savefig("subplots.png")
print("axes:", len(axes))خروجی:
axes: 2
نمودار میلهای گروهی؛ مقایسه دو سری داده
اگر بخواهید برای هر دسته دو مقدار را کنار هم ببینید، مثلاً ثبتنام دورهها در دو سال پیاپی، باید میلهها را کمی به چپ و راست جابهجا کنید. ترفند کار این است که بهجای نام دستهها از شماره موقعیت استفاده کنیم، هر سری را به اندازه نصف عرض میله جابهجا کنیم و در پایان نامها را با set_xticks زیر میلهها بنویسیم:
import matplotlib.pyplot as plt
courses = ["Python", "WordPress", "SQL", "Git"]
year1 = [200, 180, 90, 70]
year2 = [340, 260, 150, 120]
pos = range(len(courses))
w = 0.38
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
ax.bar([p - w / 2 for p in pos], year1, width=w, label="Year 1")
ax.bar([p + w / 2 for p in pos], year2, width=w, label="Year 2")
ax.set_xticks(list(pos), courses)
ax.set_title("Enrollments by year (sample data)")
ax.legend()
fig.tight_layout()
fig.savefig("grouped.png")
for c, a, b in zip(courses, year1, year2):
print(f"{c:10} growth: {(b - a) / a:+.0%}")خروجی:
Python growth: +70%
WordPress growth: +44%
SQL growth: +67%
Git growth: +71%
این الگو برای مقایسه قبل و بعد، دو شعبه یک فروشگاه یا دو گروه آزمایشی بسیار پرکاربرد است. اگر تعداد سریها بیشتر از سه شد، احتمالاً نمودار خطی یا جدا کردن نمودارها با subplots خواناتر است.
حاشیهنویسی و برجسته کردن نقطه مهم
نمودار خوب فقط داده را نشان نمیدهد، بلکه نکته اصلی را هم به بیننده میگوید. تابع annotate یک متن همراه با پیکان به نقطه دلخواه اضافه میکند. در گزارشهای کاری، برجسته کردن بیشترین یا کمترین مقدار، یا لحظهای که اتفاق مهمی افتاده، توجه خواننده را دقیقاً به همان جایی میبرد که میخواهید:
import matplotlib.pyplot as plt
days = list(range(1, 8))
visits = [320, 340, 310, 560, 400, 380, 360]
peak = visits.index(max(visits))
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=100)
ax.plot(days, visits, marker="o", color="#3b8cff")
ax.annotate("New post published", xy=(days[peak], visits[peak]),
xytext=(days[peak] + 0.6, visits[peak] - 60),
arrowprops=dict(arrowstyle="->"))
ax.set_title("Daily visits (sample data)")
ax.set_xlabel("Day")
fig.tight_layout()
fig.savefig("annotate.png")
print("peak day:", days[peak], "visits:", visits[peak])خروجی:
peak day: 4 visits: 560
سبکهای آماده و انتخاب رنگ
Matplotlib چند سبک آماده دارد که با یک خط ظاهر همه نمودارها را تغییر میدهند. فهرست کامل را با plt.style.available ببینید و با plt.style.use("ggplot") یکی را فعال کنید. چند توصیه برای رنگ: برای دادههای پیوسته از نقشههای رنگی مثل viridis استفاده کنید که برای افراد دارای کوررنگی هم قابل تشخیص است؛ تعداد رنگها را کم نگه دارید؛ و رنگ پررنگ را فقط برای دادهای بگذارید که میخواهید دیده شود و بقیه را خاکستری کنید.
import matplotlib.pyplot as plt
styles = plt.style.available
print(len(styles), "styles, e.g.:", ", ".join(s for s in styles if s in ("ggplot", "bmh", "fivethirtyeight", "grayscale")))خروجی:
28 styles, e.g.: bmh, fivethirtyeight, ggplot, grayscaleذخیره نمودار بهصورت تصویر
تابع savefig نمودار را با فرمت دلخواه ذخیره میکند؛ فرمت از پسوند نام فایل تشخیص داده میشود. چند پارامتر مهم:
dpi=200: وضوح بالاتر برای چاپ یا ارائه.bbox_inches="tight": حذف حاشیه سفید اضافه.transparent=True: پسزمینه شفاف برای قرار دادن روی اسلاید.- پسوند
.svgیا.pdf: خروجی برداری که با بزرگنمایی کیفیتش کم نمیشود.
نکته مهم: savefig را قبل از show صدا بزنید. در بسیاری از محیطها بعد از بسته شدن پنجره نمایش، شکل خالی میشود و تصویر سفید ذخیره خواهد شد.
نمایش متن فارسی در Matplotlib
Matplotlib بهطور پیشفرض حروف فارسی را جدا از هم و چپبهراست نمایش میدهد. دو کار لازم است: انتخاب یک فونت فارسی نصبشده با plt.rcParams["font.family"] و چسباندن و راستبهچپ کردن متن با دو کتابخانه arabic-reshaper و python-bidi. تابع reshape حروف را به شکل چسبیده تبدیل میکند و get_display ترتیب نمایش را راستبهچپ میکند. اگر نیازی به فارسی ندارید، برچسبها را انگلیسی بنویسید تا کار سادهتر شود؛ مثل مثالهای همین صفحه.
کار با داده واقعی از فایل CSV
در عمل دادهها معمولاً در فایل هستند. با ماژول داخلی csv میتوانید ستونها را بخوانید و رسم کنید. در کد زیر ابتدا یک فایل نمونه میسازیم و بعد آن را میخوانیم و خلاصهاش را چاپ میکنیم؛ رسم آن با همان ax.plot بالا انجام میشود. برای دادههای بزرگتر کتابخانه pandas گزینه قدرتمندتری است. خواندن و نوشتن فایل را در این آموزش توضیح دادهایم.
import csv
with open("temps.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["day", "temp"])
for day, t in enumerate([18, 21, 19, 24, 26, 23, 20], start=1):
w.writerow([day, t])
with open("temps.csv") as f:
rows = list(csv.DictReader(f))
days = [int(r["day"]) for r in rows]
temps = [int(r["temp"]) for r in rows]
print("days:", days)
print("max temp:", max(temps), "on day", days[temps.index(max(temps))])خروجی:
days: [1, 2, 3, 4, 5, 6, 7]
max temp: 26 on day 5اشتباههای رایج
- طول لیستهای x و y برابر نیست: خطای
ValueError: x and y must have same first dimensionمیگیرید. طول هر دو را بررسی کنید. - نمودار نمایش داده نمیشود: در اسکریپت معمولی
plt.show()را فراموش کردهاید. - نمودارها روی هم رسم میشوند: برای هر نمودار جدید
plt.subplots()تازه بسازید یاplt.close()را صدا بزنید. - ModuleNotFoundError: matplotlib: کتابخانه در مفسر دیگری نصب شده است؛ راهنما در این صفحه.
📌 همچنین بخوانید: دانلود ویدیو از یوتیوب با پایتون و yt-dlp و ساخت ربات تلگرام با پایتون
سوالات متداول
Matplotlib چیست؟
Matplotlib کتابخانه متنباز پایتون برای رسم نمودارهای دوبعدی مثل خطی، میلهای، دایرهای، پراکندگی و هیستوگرام است و پایه بسیاری از ابزارهای علم داده است.
چطور نمودار را در پایتون ذخیره کنم؟
از fig.savefig(“chart.png”) یا plt.savefig استفاده کنید و آن را قبل از plt.show صدا بزنید. با پارامتر dpi کیفیت را بالا ببرید.
چرا متن فارسی در Matplotlib بههمریخته است؟
چون Matplotlib حروف عربی و فارسی را نمیچسباند و راستبهچپ نمیکند. یک فونت فارسی انتخاب کنید و متن را با کتابخانههای arabic-reshaper و python-bidi آماده کنید.
کدام نمودار برای داده من مناسب است؟
روند زمانی: خطی؛ مقایسه دستهها: میلهای؛ سهم از کل: دایرهای؛ رابطه دو متغیر: پراکندگی؛ توزیع یک متغیر: هیستوگرام.