Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

การวาด Multi-Index DataFrame พร้อม Xticks ทั้งหมดใน Matplotlib

เมื่อ Plot DataFrame ที่มี MultiIndex (เช่น Year-Month) บนแกน X โดยปกติ Matplotlib จะแสดง Tick ไม่ครบทุกค่า ต้องตั้งค่า set_xticks() และ set_xticklabels() เองเพื่อแสดง Label ทุกตัว

ขั้นตอน

  1. สร้าง DataFrame พร้อม MultiIndex (Year, Month)
  2. Plot ด้วย df.plot()
  3. ใช้ ax.set_xticks(range(len(df))) กำหนดตำแหน่ง Tick ทุกแถว
  4. ใช้ 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