下面是详细讲解“Python 绘制北上广深的地铁路线动态图”的完整攻略。
1.准备工作
1.1 安装相关库
首先,我们需要安装几个相关的库,包括 matplotlib
,Pillow
,requests
,以及xlrd
和 openpyxl
。可以使用以下命令来进行安装:
pip install matplotlib pillow requests xlrd openpyxl
1.2 获取地铁数据
在绘制地铁路线动态图之前,我们需要获得相应的地铁数据。可以通过各种渠道获得,例如从国家或城市统计局、地铁官网或其他公开数据平台获取。此处我们以北京地铁为例,我们可以在 https://www.bjsubway.com/station/zjgls/#
获取到相应的数据。我们选择把数据保存在Excel中。
2.绘制地铁路线图
2.1 获取站点信息
首先,我们需要获取各个地铁站点的信息,包括站名、线路名、经纬度等。我们可以将这些信息保存在Excel文件中,方便后续使用。可以使用以下代码获取站点信息并保存到Excel文件中:
import requests
import xlrd
import xlwt
from xlutils.copy import copy
import time
# 获取地铁线路信息
def get_lines_info():
url = 'https://www.bjsubway.com/station/zjgls/#'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
response = requests.get(url, headers=headers)
response.encoding = 'gbk'
2.2 绘制地铁路线图
在获取站点信息之后,我们可以开始绘制地铁路线图。首先,我们需要将每一条地铁线路的站点连起来,形成一条曲线。这可以使用matplotlib
库中的plot
函数来实现。具体来说,我们可以定义一个绘制地铁线路的函数,使用plot
函数绘制站点之间的曲线。
import matplotlib.pyplot as plt
def draw_subway_lines(subway_data, filename):
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect('equal')
ax.set_xticks([])
ax.set_yticks([])
lines = list(subway_data.keys())
for line in lines:
# 逐条线路绘制
stations = subway_data[line]['stations']
x_list = []
y_list = []
for i in range(len(stations)):
station = stations[i]
station_name = station[0]
if station_name not in stations_locations:
continue
location = stations_locations[station_name]
x_list.append(location['longitude'])
y_list.append(location['latitude'])
ax.annotate(station_name, (location['longitude'], location['latitude'])) # 显示车站名称
ax.plot(x_list, y_list, color=subway_data[line]['color'], alpha=0.8)
plt.savefig(filename, dpi=300)
plt.show()
2.3 获取车站坐标信息
在将车站连线绘制出来之后,我们需要将车站的名称和经纬度对应起来,方便后续使用。我们可以从爬虫中获得车站的坐标,同时可以手动添加其他缺失的站点信息。具体来说,我们可以从Excel文件中读取车站信息,将车站名称和坐标存储到字典stations_locations
中。
# 加载车站信息
def load_stations_info(filename):
stations_locations = {}
with xlrd.open_workbook(filename) as workbook:
for sheetname in workbook.sheet_names():
sheet = workbook.sheet_by_name(sheetname)
for row in range(1, sheet.nrows):
station_name = sheet.cell_value(row, 0)
longitude = float(sheet.cell_value(row, 2))
latitude = float(sheet.cell_value(row, 3))
stations_locations[station_name] = {'longitude': longitude, 'latitude': latitude}
return stations_locations
3.绘制动态图
最后,我们可以将多张静态图片合成一张动态图,以便更好地展现地铁线路的变化。我们可以使用Pillow
库中的ImageSequence
类进行动态图的处理。具体来说,我们可以定义一个生成地铁路线动态图的函数generate_gif
,使用ImageSequence
类读取并合并多张静态图片,生成一张包含所有图片的动态图。
import os
from PIL import Image, ImageSequence
def generate_gif(image_files, output_gif):
images = []
for filename in image_files:
images.append(Image.open(filename))
images[0].save(output_gif, save_all=True, append_images=images[1:], optimize=False, duration=500, loop=0)
接下来是一个完整的示例,生成北京地铁路线的动态图:
import requests
import xlrd
import xlwt
from xlutils.copy import copy
import time
import matplotlib.pyplot as plt
from PIL import Image, ImageSequence
def get_lines_info():
url = 'https://www.bjsubway.com/station/zjgls/#'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
response = requests.get(url, headers=headers)
response.encoding = 'gbk'
# 获取地铁线路信息
subway_data = {}
tags = response.text.split('<a class="title"')
for tag in tags:
if tag.find('线</a>') == -1:
continue
color_pos = tag.find('background-color:')
if color_pos == -1:
continue
color_start = color_pos + len('background-color:#')
color_end = tag.find(';"><', color_start)
color = '#' + tag[color_start:color_end]
line_info = tag.split('class="station">')
stations = []
for station_info in line_info:
if station_info.find('站</a>') == -1:
continue
station_start = station_info.find('">') + len('">')
station_end = station_info.find('</a>', station_start)
station_name = station_info[station_start:station_end]
stations.append((station_name, color))
line_name = line_info[0].split('">')[1].split('线')[0]
subway_data[line_name] = {'color': color, 'stations': stations}
return subway_data
def draw_subway_lines(subway_data, stations_locations, filename):
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect('equal')
ax.set_xticks([])
ax.set_yticks([])
lines = list(subway_data.keys())
for line in lines:
# 逐条线路绘制
stations = subway_data[line]['stations']
x_list = []
y_list = []
for i in range(len(stations)):
station = stations[i]
station_name = station[0]
if station_name not in stations_locations:
continue
location = stations_locations[station_name]
x_list.append(location['longitude'])
y_list.append(location['latitude'])
ax.annotate(station_name, (location['longitude'], location['latitude'])) # 显示车站名称
ax.plot(x_list, y_list, color=subway_data[line]['color'], alpha=0.8)
plt.savefig(filename, dpi=300)
plt.show()
def load_stations_info(filename):
stations_locations = {}
with xlrd.open_workbook(filename) as workbook:
for sheetname in workbook.sheet_names():
sheet = workbook.sheet_by_name(sheetname)
for row in range(1, sheet.nrows):
station_name = sheet.cell_value(row, 0)
longitude = float(sheet.cell_value(row, 2))
latitude = float(sheet.cell_value(row, 3))
stations_locations[station_name] = {'longitude': longitude, 'latitude': latitude}
return stations_locations
def generate_gif(image_files, output_gif):
images = []
for filename in image_files:
images.append(Image.open(filename))
images[0].save(output_gif, save_all=True, append_images=images[1:], optimize=False, duration=500, loop=0)
if __name__ == '__main__':
# 1.准备工作
## 1.1 安装相关库
# pip install matplotlib pillow requests xlrd openpyxl
## 1.2 获取地铁数据
subway_data = get_lines_info()
# 2.绘制地铁路线图
## 2.1 获取站点信息
filename = 'stations.xlsx'
stations_locations = load_stations_info(filename)
## 2.2 绘制地铁路线图
image_files = []
for line in subway_data:
filename = f"{line}.png"
draw_subway_lines({line: subway_data[line]}, stations_locations, filename)
image_files.append(filename)
## 2.3 获取车站坐标信息
# 3.绘制动态图
output_gif = 'subway.gif'
generate_gif(image_files, output_gif)
以上是一个完整的示例,生成北京地铁路线的动态图。类似的方法也可以用于绘制其他城市的地铁路线图。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 绘制北上广深的地铁路线动态图 - Python技术站