เมื่อ Plot DataFrame ที่มี MultiIndex (เช่น Year-Month) บนแกน X โดยปกติ Matplotlib จะแสดง Tick ไม่ครบทุกค่า ต้องตั้งค่า set_xticks() และ set_xticklabels() เองเพื่อแสดง Label ทุกตัว
ขั้นตอน
- สร้าง DataFrame พร้อม MultiIndex (Year, Month)
- Plot ด้วย
df.plot() - ใช้
ax.set_xticks(range(len(df)))กำหนดตำแหน่ง Tick ทุกแถว - ใช้
ax.set_xticklabels()พร้อม Format Label และ Rotation
ตัวอย่างโค้ด
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = [14, 6]
plt.rcParams["figure.autolayout"] = True
# สร้าง Time Series Data 1000 จุด
idx = pd.date_range("2020-01-01", periods=1000, freq="D")
values = np.random.randn(1000).cumsum() + 100 # Random Walk
s = pd.Series(values, index=idx, name="Value")
# Group by Year-Month และหาค่าเฉลี่ย
g = s.groupby([s.index.year, s.index.month]).mean()
# Plot
fig, ax = plt.subplots()
g.plot(ax=ax, linewidth=1.5, color='steelblue', marker='o', markersize=3)
# สำคัญ: ตั้ง Xticks ทุกจุด
ax.set_xticks(range(len(g)))
# Format Label: "YYYY-MM" พร้อมหมุน 45 องศา
ax.set_xticklabels([f"{year}-{month:02d}" for year, month in g.index],
rotation=45, ha='right', fontsize=9)
ax.set_xlabel("Year-Month", fontsize=12)
ax.set_ylabel("Average Value", fontsize=12)
ax.set_title("Monthly Average with All Xticks Shown", fontsize=14, pad=15)
ax.grid(True, alpha=0.3)
plt.show()
ผลลัพธ์
กราฟแสดงข้อมูลรายเดือนพร้อม Label "YYYY-MM" ทุกจุดบนแกน X หมุน 45 องศา อ่านง่ายไม่ทับซ้อน
เทคนิคเพิ่มเติม
1. ใช้ DateFormatter แทน (สำหรับ DatetimeIndex ธรรมดา)
import matplotlib.dates as mdates
ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
plt.xticks(rotation=45)
2. แสดงเฉพาะบางเดือน (ทุก 3 เดือน)
# เลือกทุก 3 เดือน
step = 3
ax.set_xticks(range(0, len(g), step))
ax.set_xticklabels([f"{year}-{month:02d}" for year, month in g.index[::step]],
rotation=45, ha='right')
3. ใช้ Seaborn (จัดการ Label อัตโนมัติดีกว่า)
import seaborn as sns
sns.lineplot(data=g.reset_index(), x='level_0', y='Value', hue='level_1')
# หรือแปลง Index กลับเป็น Datetime
g.index = pd.to_datetime(g.index.map(lambda x: f"{x[0]}-{x[1]:02d}-01"))
sns.lineplot(data=g.reset_index(), x='index', y='Value')
คำแนะนำ
- MultiIndex ต้อง Reset เป็น Column หรือ Format เอง เพราะ Matplotlib ไม่จัดการ MultiIndex อัตโนมัติ
- ใช้
ha='right'ร่วมrotation=45ให้ Label จุติชิด Tick สวยงาม - หาก Label เยอะมาก ให้คัดกรอง (ทุก n เดือน) หรือใช้ Figure กว้างขึ้น
fig.autofmt_xdate()ช่วยปรับ Rotation อัตโนมัติสำหรับ Date