本文將介紹如何使用Python繪製天氣關係圖,通過分析和可視化天氣數據,幫助我們更好地了解天氣的變化和趨勢。
一、數據準備
首先我們需要從數據源中獲取天氣數據。我們可以使用爬蟲技術從網站上抓取相關數據,或者使用已有的公開數據。以下是一份包含2019年全國200個城市每日白天和夜間氣溫、天氣狀況等數據的天氣數據樣例:
date,city,day_temp,night_temp,weather 20190101,安慶,8,-2,晴 20190101,北京,-3,-11,晴 20190101,重慶,12,5,晴 …
為了繪製天氣關係圖,我們需要進行數據清洗和處理。下面是一個簡單的Python片段,來讀取天氣數據並將其轉換為適合繪製關係圖的格式:
import pandas as pd # 讀取天氣數據 df = pd.read_csv("weather.csv") # 處理數據,只保留指定的列 df = df[["city", "weather"]] # 計算每個城市出現次數 count = df.groupby("city").count() count.columns = ["value"] # 按值排序 count.sort_values("value", ascending=False, inplace=True) # 取前N個城市 count = count[:N] # 生成關係圖的節點和邊 nodes = [{"name": row[0]} for index, row in count.iterrows()] links = [] for index, row in df.iterrows(): if row["city"] in count.index: links.append({"source": row["city"], "target": row["weather"]})
二、繪圖過程
繪製天氣關係圖的過程需要使用到Python的可視化庫。這裡我們使用D3.js,它是一個JavaScript圖形庫,專門用於網站可視化,感謝Mike Bostock的貢獻!
下面是如何使用D3.js來繪製天氣關係圖的Python代碼:
import json import webbrowser # 轉換為D3.js所需的格式 data = {"nodes": nodes, "links": links} json_str = json.dumps(data) # 生成HTML代碼 html = f""" .node {{ transition: all 0.2s ease-out; cursor: pointer; }} .node:hover {{ opacity: 0.6; }} .link {{ stroke: #999; stroke-opacity: 0.3; fill: none; }} .link.source {{ stroke-width: 3; stroke: #f00; stroke-opacity: 1; }} var width = {width}; var height = {height}; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .attr("viewBox", [-width / 2, -height / 2, width, height]); var link = svg.append("g") .attr("class", "links") .selectAll("line") .data(data.links) .enter().append("line") .attr("class", "link"); var node = svg.append("g") .attr("class", "nodes") .selectAll("circle") .data(data.nodes) .enter().append("circle") .attr("class", "node") .attr("r", function(d) {{ return Math.sqrt(d.size) / 10 || 4.5; }}) .on("mouseover", mouseover) .on("mouseout", mouseout) .on("click", click); var simulation = d3.forceSimulation(data.nodes) .force("link", d3.forceLink(data.links).id(function(d) {{ return d.id; }}).distance(50)) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(0, 0)); simulation.on("tick", ticked); function ticked() {{ link .attr("x1", function(d) {{ return d.source.x; }}) .attr("y1", function(d) {{ return d.source.y; }}) .attr("x2", function(d) {{ return d.target.x; }}) .attr("y2", function(d) {{ return d.target.y; }}); node .attr("cx", function(d) {{ return d.x; }}) .attr("cy", function(d) {{ return d.y; }}) }} function mouseover(d) {{ d3.select(this).attr("r", function(d) {{ return Math.sqrt(d.size) / 10 * 1.5 }}); link .filter(function(l) {{ return l.source === d || l.target === d; }}) .attr("class", "link source"); }} function mouseout(d) {{ d3.select(this).attr("r", function(d) {{ return Math.sqrt(d.size) / 10 || 4.5 }}); link.attr("class", "link"); }} function click(d) {{ var url = "https://www.baidu.com/s?wd=" + d.id; window.open(url); }} """ # 保存HTML文件並打開 with open("weather.html", "w") as f: f.write(html) webbrowser.open("weather.html")
三、優化和擴展
除了繪製關係圖之外,我們還可以通過添加多個可交互的組件和過濾器來優化和擴展這個圖表。
1. 搜索輸入框
搜索框可以讓用戶輕鬆地找到特定城市或者天氣狀況的節點。
// 添加搜索框 d3.select("body").append("input") .attr("type", "text") .attr("placeholder", "Search...") .on("input", function() {{ var keyword = this.value.toLowerCase(); node.attr("opacity", function(d) {{ return d.name.toLowerCase().includes(keyword) ? 1 : 0.2; }}); link.attr("opacity", function(d) {{ return d.source.name.toLowerCase().includes(keyword) || d.target.name.toLowerCase().includes(keyword) ? 1 : 0.2; }}); }});
2. 城市選擇器
城市選擇器可以讓用戶快速選擇感興趣的城市。
// 添加城市選擇器 d3.select("body").append("select") .selectAll("option") .data(data.nodes) .enter().append("option") .attr("value", function(d) {{ return d.id; }}) .text(function(d) {{ return d.name; }}); document.querySelector("select").addEventListener("change", function() {{ var selected = this.value; node.attr("opacity", function(d) {{ return d.id === selected || links.some(function(l) {{ return l.source.id === selected && l.target.id === d.id; }}) ? 1 : 0.2; }}); link.attr("opacity", function(d) {{ return d.source.id === selected || d.target.id === selected ? 1 : 0.2; }}); }});
3. 天氣過濾器
天氣過濾器可以讓用戶過濾某一種天氣狀況的節點。
// 添加天氣選擇器 d3.select("body").append("div") .style("margin-top", "20px") .selectAll("input") .data(["晴", "多雲", "雨", "雪"]) .enter().append("label") .text(function(d) {{ return d; }}) .insert("input") .attr("type", "checkbox") .on("change", function() {{ var checked = document.querySelectorAll("input[type=checkbox]:checked"); var keywords = Array.from(checked).map(function(c) {{ return c.nextSibling.data.trim(); }}); node.attr("opacity", function(d) {{ return keywords.includes(d.group) ? 1 : 0.2; }}); link.attr("opacity", function(d) {{ return keywords.includes(d.source.group) && keywords.includes(d.target.group) ? 1 : 0.2; }}); }});
四、完整代碼示例
以下是整個天氣關係圖的Python示例代碼,包括數據準備、繪圖過程、優化擴展三部分內容。
import pandas as pd import json import webbrowser # 定義常量與參數 N = 50 # 前N個城市 width = 800 # 圖形寬度 height = 600# 圖形高度 # 讀取天氣數據 df = pd.read_csv("weather.csv") # 處理數據,只保留指定的列 df = df[["city", "weather"]] # 計算每個城市出現次數 count = df.groupby("city").count() count.columns = ["value"] # 按值排序 count.sort_values("value", ascending=False, inplace=True) # 取前N個城市 count = count[:N] # 生成關係圖的節點和邊 nodes = [{"name": row[0]} for index, row in count.iterrows()] links = [] for index, row in df.iterrows(): if row["city"] in count.index: links.append({"source": row["city"], "target": row["weather"], "group": row["weather"]}) # 轉換為D3.js所需的格式 data = {"nodes": nodes, "links": links} json_str = json.dumps(data) # 生成HTML代碼 html = f""" .node {{ transition: all 0.2s ease-out; cursor: pointer; }} .node:hover {{ opacity: 0.6; }} .link {{ stroke: #999; stroke-opacity: 0.3; fill: none; }} .link.source {{ stroke-width: 3; stroke: #f00; stroke-opacity: 1; }}
原創文章,作者:XPDZB,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/373579.html