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

การวาด Time Series 2 ชุดบนกราฟเดียวพร้อม Legend และ Secondary Y-axis

การวาด Time Series 2 ชุดที่มีมาตราสเกลต่างกันบนกราฟเดียว ใช้ Secondary Y-axis (Twin Axes) ใน Pandas/Matplotlib พร้อมรวม Legend จากทั้ง 2 แกน

ขั้นตอนหลัก

  1. สร้าง DataFrame พร้อม DatetimeIndex
  2. Plot ชุดแรกบน Axes หลัก (ax1)
  3. Plot ชุดที่สองด้วย secondary_y=True สร้าง ax2 อัตโนมัติ
  4. รวม Legend จาก ax1 และ ax2 ด้วย get_legend_handles_labels()

ตัวอย่างโค้ด

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams["figure.figsize"] = [12, 6]
plt.rcParams["figure.autolayout"] = True

# สร้าง Time Series Data
dates = pd.date_range('2023-01-01', periods=50, freq='D')
np.random.seed(42)

df = pd.DataFrame({
    'Temperature': 20 + 10 * np.sin(np.arange(50) * 0.3) + np.random.randn(50) * 1.5,
    'Humidity': 50 + 20 * np.cos(np.arange(50) * 0.2) + np.random.randn(50) * 3,
    'Pressure': 1013 + np.random.randn(50) * 2,
    'Rainfall': np.maximum(0, np.random.randn(50) * 5 + 2)
}, index=dates)

fig, ax1 = plt.subplots()

# 1. Plot Temperature บนแกนซ้าย (Primary)
color1 = 'tab:red'
ax1.set_xlabel('Date', fontsize=12)
ax1.set_ylabel('Temperature (°C)', color=color1, fontsize=12)
line1 = ax1.plot(df.index, df['Temperature'], color=color1, linewidth=2, label='Temperature (°C)')
ax1.tick_params(axis='y', labelcolor=color1)

# 2. Plot Rainfall บนแกนขวา (Secondary)
ax2 = ax1.twinx()
color2 = 'tab:blue'
ax2.set_ylabel('Rainfall (mm)', color=color2, fontsize=12)
line2 = ax2.plot(df.index, df['Rainfall'], color=color2, linewidth=2, linestyle='--', label='Rainfall (mm)')
ax2.tick_params(axis='y', labelcolor=color2)

# 3. รวม Legend จากทั้ง 2 Axes
lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper left', fontsize=11)

# Format Date Axis
import matplotlib.dates as mdates
ax1.xaxis.set_major_locator(mdates.WeekdayLocator(interval=1))
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.xticks(rotation=45)

ax1.set_title('Temperature vs Rainfall (Dual Y-Axis)', fontsize=14, pad=15)
ax1.grid(True, alpha=0.3)

plt.show()

วิธีใช้ Pandas Plot Built-in (สั้นกว่า)

# ใช้ DataFrame.plot() โดยตรง
ax = df[['Temperature']].plot(color='red', linewidth=2, label='Temperature (°C)', figsize=(12,6))
ax2 = df[['Rainfall']].plot(secondary_y=True, color='blue', linewidth=2, linestyle='--', 
                            label='Rainfall (mm)', ax=ax)

# รวม Legend
h1, l1 = ax.get_legend_handles_labels()
h2, l2 = ax2.get_legend_handles_labels()
ax.legend(h1+h2, l1+l2, loc='upper left')

ax.set_ylabel('Temperature (°C)', color='red')
ax2.set_ylabel('Rainfall (mm)', color='blue')
plt.show()

ผลลัพธ์

กราฟเดียวแสดง Temperature (เส้นแดง แกนซ้าย) และ Rainfall (เส้นน้ำเงินประกบ แกนขวา) พร้อม Legend รวมและ Date Formatter

Best Practices

  • ใช้สีที่แตกต่างชัดเจนสำหรับ 2 แกน (Red/Blue, Orange/Green)
  • ตั้ง Label สีให้ตรงกับ Line Color
  • ใช้ Linestyle ต่างกัน (Solid vs Dashed) ช่วยแยกแยะได้ดีขึ้น
  • ax1.tick_params(axis='y', labelcolor=color) ทำให้ Tick Labels สีตรงกับ Line
  • ใช้ sharex=True หากแยก Subplots

ตัวอย่าง: 3+ Time Series กับ Multiple Secondary Axes

# สร้าง Twin Axes เพิ่มเติม (Offset Spines)
ax3 = ax1.twinx()
ax3.spines['right'].set_position(('axes', 1.1))  # เลื่อนแกนที่ 3 ไปขวา
ax3.set_ylabel('Pressure (hPa)', color='green')
ax3.plot(df.index, df['Pressure'], color='green', linewidth=1.5, label='Pressure')
ax3.tick_params(axis='y', labelcolor='green')

# รวม Legend ทั้ง 3
lines = line1 + line2 + line3
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='upper left')