本文将介绍如何使用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/n/373579.html
微信扫一扫
支付宝扫一扫