昨天我們已經知道 API 抓回來的數字資料,直接看並不直觀。
因此今天我要用之前練習過的天氣 API 當例子,實作把資料轉換成折線圖,讓趨勢更清楚。
把天氣數據用圖表表示出來,有幾個重要原因:
比方說某一天的溫度突然降很多或升很多,透過圖表可以馬上發現,不需要一筆筆數字比對。
如果想知道這一週和上一週的氣溫有什麼不一樣,用圖表比用表格看來得直覺。
像是決定今天要不要帶傘、要不要開冷氣,甚至可以幫忙我們規劃假日出遊的時間,視覺化資料提供很好的參考。
透過圖表,我們可以快速比較不同日期的高低溫差,或者同一天不同時間的氣溫變化。
步驟 1:準備環境
pip install requests matplotlib
day18_weather_plot.py
。步驟 2:呼叫天氣 API
用免費且免金鑰的 Open-Meteo API,查詢台北市過去14天的最高氣溫。
這些資料是以 JSON 格式回傳的,裡面包含日期(time
)和當天最高溫度(temperature_2m_max
)。
import argparse
from datetime import date, timedelta
import requests
import matplotlib
import matplotlib.pyplot as plt
matplotlib.rcParams['font.sans-serif'] = [
'Microsoft JhengHei', 'PingFang TC', 'Noto Sans CJK TC',
'SimHei', 'WenQuanYi Zen Hei', 'DejaVu Sans'
]## 設定中文字型,避免中文變成亂碼或空白框。
matplotlib.rcParams['axes.unicode_minus'] = False
GEO_API = "https://geocoding-api.open-meteo.com/v1/search"
# Open-Meteo 的地理編碼 API,把地名換成經緯度
WX_API = "https://api.open-meteo.com/v1/forecast"
# Open-Meteo 的天氣預報 API,用經緯度查天氣
# 1) 地名換成經緯度
def geocode_city(name: str, count=1, lang="zh", timeout=10):
# 用 Open-Meteo Geocoding 取得經緯度(取最符合的第一筆)
params = {"name": name, "count": count, "language": lang, "format": "json"}
# 組出要帶給地理編碼 API 的查詢參數(地名、筆數、語言、回傳格式)
r = requests.get(GEO_API, params=params, timeout=timeout)
# 發送 GET 請求到 GEO_API,把 params 放到 query string,並設定逾時
r.raise_for_status() # 若回應不是 2xx,直接丟出例外
data = r.json() # 把回應內容轉成 Python 物件
results = data.get("results") or [] # 回應中取出 results 清單;如果沒有,給空清單避免報錯
if not results:
raise ValueError(f"查無地名:{name}") #如果清單是空的,代表找不到地名,主動拋出錯誤訊息
top = results[0] # 取清單的第一筆,最符和的那一筆。
return {
"name": top.get("name"),
"lat": top["latitude"],
"lon": top["longitude"],
"country": top.get("country", ""),
} # 回傳一個字典,包含城市名稱、緯度 lat、經度 lon,以及國家名稱
步驟 3:整理資料
把日期放到 X 軸當作時間軸。
把氣溫放到 Y 軸表示溫度。
這對應資料會像這樣,例如:
2025-09-17 → 36.2℃
2025-09-18 → 35.5℃
# 2) 抓近 14 天的 daily 資料
DAILY_MAP = {
"temp_max": "temperature_2m_max",
"temp_min": "temperature_2m_min",
"precip": "precipitation_sum",
}
Y_LABEL = {
"temp_max": "日最高氣溫 (°C)",
"temp_min": "日最低氣溫 (°C)",
"precip": "日累積降水量 (mm)",
}
def fetch_daily_series(lat, lon, metric_key: str, start: date, end: date, timeout=10):
"""抓指定日期區間的 daily 欄位,回傳 (dates, values)"""
daily_var = DAILY_MAP[metric_key] # 例如 temperature_2m_max
params = {
"latitude": lat,
"longitude": lon,
"daily": daily_var,
"start_date": start.isoformat(),
"end_date": end.isoformat(),
"timezone": "auto", # 依座標自動挑時區
}
r = requests.get(WX_API, params=params, timeout=timeout)
r.raise_for_status()
js = r.json()
daily = js.get("daily") or {}
dates = daily.get("time") or [] # 把日期清單放進 dates
values = daily.get(daily_var) or [] # 把對應欄位的數值清單放進 values
if not dates or not values:
raise ValueError("API 回傳無資料,請換指標或日期範圍再試")
return dates, values
步驟 4:畫折線圖
使用 Matplotlib 的 plot() 函式畫出折線圖。
加上圖表標題、X 軸(日期)、Y 軸(氣溫),還有網格線讓圖更清楚。
# 3) 畫圖(折線 / 長條)
def plot_line(dates, values, title, ylabel):
# 定義一個函式:輸入 X 軸日期 dates、Y 軸數值 values、標題 title、以及 Y 軸標籤 ylabel
plt.figure() # 開一張新的圖,避免跟上一張重疊
plt.plot(dates, values, marker="o") # 畫折線圖;marker="o" 讓每個點加上圓點
plt.title(title) # 設定圖表標題
plt.xlabel("日期") # 設定 X 軸標籤為日期
plt.ylabel(ylabel) # 設定 Y 軸標籤為日最高氣溫 (°C)
plt.grid(True) # 開啟網格線,方便讀數
plt.xticks(rotation=45, ha="right")
plt.tight_layout() # 開啟網格線,方便讀數
plt.show()
def plot_bar(dates, values, title, ylabel):
plt.figure()
plt.bar(dates, values) # 畫長條圖
plt.title(title)
plt.xlabel("日期")
plt.ylabel(ylabel)
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
步驟 5:執行成果
在執行 Python 程式後,螢幕會跳出一張折線圖
X 軸是過去14天的日期,Y 軸是每天的最高氣溫
折線連接每天溫度的變化趨勢
# CLI 入口
def main():
ap = argparse.ArgumentParser(description="近兩週天氣圖表(Open-Meteo)")
# 建立參數解析器,讓我們可以用指令列選項控制城市、圖表型態等
ap.add_argument("--city", default="Taipei", help="地名(支援中文/英文,預設 Taipei)")
ap.add_argument("--metric", choices=["temp_max","temp_min","precip"],
default="temp_max", help="指標:temp_max / temp_min / precip")
ap.add_argument("--chart", choices=["line","bar"], default="line",
help="圖表:line=折線 / bar=長條") # 決定用折線圖還是長條圖,預設是折線圖
ap.add_argument("--days", type=int, default=14, help="回溯天數(預設 14)")
# 要看幾天的資料,這裡是設定 14 天
args = ap.parse_args() # 實際解析指令列輸入,把結果放進 args
# 計算日期區間(含今天)
end = date.today()
start = end - timedelta(days=args.days - 1)
try:
place = geocode_city(args.city)
dates, values = fetch_daily_series(place["lat"], place["lon"], args.metric, start, end)
except requests.exceptions.RequestException as e: # 錯誤處理
print("API 連線失敗:", e)
return
except Exception as e:
print("錯誤:", e)
return
title = f"{place['name']} 近 {args.days} 天 — " + {
"temp_max":"日最高溫",
"temp_min":"日最低溫",
"precip":"日降水量",
}[args.metric]
ylabel = Y_LABEL[args.metric]
if args.chart == "line": # 依 chart 選擇要畫折線或長條,帶入剛組好的標題與 Y 軸標籤
plot_line(dates, values, title, ylabel)
else:
plot_bar(dates, values, title, ylabel)
if __name__ == "__main__":
main()
畫圖時,如果標題或是文字是中文,要記得設定中文字體,不然會顯示成看不懂的方塊。
如果是想要把折線圖呈現更清楚,可以在每個點上加一個小圓點(marker='o'
)。
畫好圖後,可以用 plt.savefig("weather.png")
把圖存成圖片檔,這樣可以更方便我們傳送,或是放在報告裡。
學會呼叫天氣 API,抓取歷史氣溫。
練習用 Matplotlib 畫出折線圖。