最近做一个地图可视化的项目需要在地图上画出成都已开通的地铁线路图,中间还是踩了几个小坑,记录一下整个过程。

1. 开发环境

python 3.8
plotly(没安装的自行pip安装)
百度地图API(获取所有线路的地铁站点信息)

2. 效果展示
废话不多说,先上效果图。


3. 实现过程
百度地图开放平台获取站点信息(json格式)
百度坐标系转换到WGS-84坐标系
生成excel或csv表格
plotly绘制线路图

 3.1 百度地图开放平台获取站点信息,链接直接上代码:
1

city_code=75 #成都市城市代码
station_info = requests.get('http://map.baidu.com/?qt=bsi&c=%s&t=%s' % (city_code, int(time.time() * 1000)))
station_info_json = eval(station_info.content)
1234567
 3.2  为什么要进行坐标转换plotly用的是WGS-84坐标系,而百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理,百度转WGS-84还稍微有点复杂,不过有开源代码,直接拿来用就可以了。
12

简单科普一下国内常用的坐标系(至于为什么有几种不同坐标系请自行google):
地球坐标系——WGS84:常见于 GPS 设备,Google 地图等国际标准的坐标系。
火星坐标系——GCJ-02:中国国内使用的被强制加密后的坐标体系,高德坐标就属于该种坐标体系。
百度坐标系——BD-09:百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理。

3.3 将json数据存为excel文件,一遍mapbox调用,excel文件的格式如下:
1


获取站点信息的完整代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Nov  6 11:16:45 2020Chengdu Metro Lines by plotly with python@author: 进击的SB
"""import requests
import time
import numpy as np
import math
# import plotly.offline as py
# import plotly.graph_objs as go
import pandas as pdPI = math.pinull = None
city_code=75
station_info = requests.get('http://map.baidu.com/?qt=bsi&c=%s&t=%s' % (city_code, int(time.time() * 1000)))station_info_json = eval(station_info.content)# print(station_info_json)# 解析地铁线路站点信息
for line in station_info_json['content']:# i = 0plots = []plots_name = []for plot in line['stops']:plots.append([plot['x'], plot['y']])plots_name.append(plot['name'])# print(plots)plot_mercator = np.array(plots)def _transformlat(coordinates):lng = coordinates[ : , 0] - 105lat = coordinates[ : , 1] - 35ret = -100 + 2 * lng + 3 * lat + 0.2 * lat * lat + \0.1 * lng * lat + 0.2 * np.sqrt(np.fabs(lng))ret += (20 * np.sin(6 * lng * PI) + 20 *np.sin(2 * lng * PI)) * 2 / 3ret += (20 * np.sin(lat * PI) + 40 *np.sin(lat / 3 * PI)) * 2 / 3ret += (160 * np.sin(lat / 12 * PI) + 320 *np.sin(lat * PI / 30.0)) * 2 / 3return retdef _transformlng(coordinates):lng = coordinates[ : , 0] - 105lat = coordinates[ : , 1] - 35ret = 300 + lng + 2 * lat + 0.1 * lng * lng + \0.1 * lng * lat + 0.1 * np.sqrt(np.fabs(lng))ret += (20 * np.sin(6 * lng * PI) + 20 *np.sin(2 * lng * PI)) * 2 / 3ret += (20 * np.sin(lng * PI) + 40 *np.sin(lng / 3 * PI)) * 2 / 3ret += (150 * np.sin(lng / 12 * PI) + 300 *np.sin(lng / 30 * PI)) * 2 / 3return retdef gcj02_to_wgs84(coordinates):"""GCJ-02转WGS-84:param coordinates: GCJ-02坐标系的经度和纬度的numpy数组:returns: WGS-84坐标系的经度和纬度的numpy数组"""ee = 0.006693421622965943  # 偏心率平方a = 6378245  # 长半轴lng = coordinates[ : , 0]lat = coordinates[ : , 1]is_in_china= (lng > 73.66) & (lng < 135.05) & (lat > 3.86) & (lat < 53.55)_transform = coordinates[is_in_china]  #只对国内的坐标做偏移dlat = _transformlat(_transform)dlng = _transformlng(_transform)radlat = _transform[ : , 1] / 180 * PImagic = np.sin(radlat)magic = 1 - ee * magic * magicsqrtmagic = np.sqrt(magic)dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)dlng = (dlng * 180.0) / (a / sqrtmagic * np.cos(radlat) * PI)mglat = _transform[ : , 1] + dlatmglng = _transform[ : , 0] + dlngcoordinates[is_in_china] = np.array([_transform[ : , 0] * 2 - mglng, _transform[ : , 1] * 2 - mglat]).Treturn coordinatesdef bd09_to_gcj02(coordinates):"""BD-09转GCJ-02:param coordinates: BD-09坐标系的经度和纬度的numpy数组:returns: GCJ-02坐标系的经度和纬度的numpy数组"""x_pi = PI * 3000 / 180x = coordinates[ : , 0] - 0.0065y = coordinates[ : , 1] - 0.006z = np.sqrt(x * x + y * y) - 0.00002 * np.sin(y * x_pi)theta = np.arctan2(y, x) - 0.000003 * np.cos(x * x_pi)lng = z * np.cos(theta)lat = z * np.sin(theta)coordinates = np.array([lng, lat]).Treturn coordinatesdef bd09_to_wgs84(coordinates):"""BD-09转WGS-84:param coordinates: BD-09坐标系的经度和纬度的numpy数组:returns: WGS-84坐标系的经度和纬度的numpy数组"""return gcj02_to_wgs84(bd09_to_gcj02(coordinates))def mercator_to_bd09(mercator):"""BD-09MC转BD-09:param coordinates: GCJ-02坐标系的经度和纬度的numpy数组:returns: WGS-84坐标系的经度和纬度的numpy数组"""MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0]MC2LL = [[1.410526172116255e-08,   8.98305509648872e-06,    -1.9939833816331,        200.9824383106796,       -187.2403703815547,      91.6087516669843,-23.38765649603339,      2.57121317296198,        -0.03801003308653,17337981.2],[-7.435856389565537e-09,  8.983055097726239e-06,   -0.78625201886289,96.32687599759846,       -1.85204757529826,       -59.36935905485877,47.40033549296737,       -16.50741931063887,      2.28786674699375,10260144.86],[-3.030883460898826e-08,  8.98305509983578e-06,    0.30071316287616,59.74293618442277,       7.357984074871,          -25.38371002664745,13.45380521110908,       -3.29883767235584,       0.32710905363475,6856817.37],[-1.981981304930552e-08,  8.983055099779535e-06,   0.03278182852591,40.31678527705744,       0.65659298677277,        -4.44255534477492,0.85341911805263,        0.12923347998204,        -0.04625736007561,4482777.06], [3.09191371068437e-09,    8.983055096812155e-06,   6.995724062e-05,23.10934304144901,       -0.00023663490511,       -0.6321817810242,-0.00663494467273,       0.03430082397953,        -0.00466043876332,2555164.4],  [2.890871144776878e-09,   8.983055095805407e-06,   -3.068298e-08,7.47137025468032,        -3.53937994e-06,         -0.02145144861037,-1.234426596e-05,        0.00010322952773,        -3.23890364e-06,826088.5]] x = np.abs(mercator[ : , 0])y = np.abs(mercator[ : , 1])coef = np.array([MC2LL[index] for index in (np.tile(y.reshape((-1, 1)), (1, 6)) < MCBAND).sum(axis=1)])   return converter(x, y, coef)def converter(x, y, coef):x_temp = coef[ : ,0] + coef[ : ,1] * np.abs(x)x_n = np.abs(y) / coef[ : ,9]y_temp = coef[ : ,2] + coef[ : ,3] * x_n + coef[ : ,4] * x_n ** 2 + \coef[ : ,5] * x_n ** 3 + coef[ : ,6] * x_n ** 4 + coef[ : ,7] * x_n ** 5 + \coef[ : ,8] * x_n ** 6x[x < 0] = -1x[x >= 0] = 1y[y < 0] = -1y[y >= 0] = 1    x_temp *= xy_temp *= ycoordinates = np.array([x_temp, y_temp]).Treturn coordinatesdata = [] #绘制数据marked = set()
# cnt = 0
for line in station_info_json['content']:uid = line['line_uid']if uid in marked: #由于线路包括了来回两个方向,需要排除已绘制线路的反向线路continueplots = [] #站台BD-09MC坐标plots_name = [] #站台名称for plot in line['stops']:plots.append([plot['x'], plot['y']])plots_name.append(plot['name'])        df1 = pd.DataFrame(columns=['站名'], data=plots_name)plot_mercator = np.array(plots)# print(plot_mercator)plot_coordinates = bd09_to_wgs84(mercator_to_bd09(plot_mercator)) #站台经纬度list_lonlat = plot_coordinates.tolist()df2 = pd.DataFrame(columns=['经度', '纬度'], data=list_lonlat)df3 = pd.concat([df1, df2], axis=1)df3.to_csv('cdmerto_sites.csv', mode='a', index=False, encoding='gb2312')csv_to_excel = pd.read_csv('cdmerto_sites.csv', encoding='gb2312')csv_to_excel.to_excel('cdmerto_allsites.xlsx', sheet_name='Sheet1', index=False)marked.add(uid) #添加已绘制线路的uidmarked.add(line['pair_line_uid']) #添加已绘制线路反向线路的uid123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222

如果是windows系统,需要增加csv或excel文件的路径。

      3.4 使用plotly画出地铁线路图,需要先申请plotly的key,不知道怎么申请的可自行google。
1
import pandas as pd
import plotly.graph_objects as go
import plotly.express as pxprop = pd.read_excel(r'/Users/awesomeo/map/lonlat_gps84.xlsx') #此处为房源可视化数据,可忽略,只关注cd_metro
cd_metro = pd.read_excel(r'/Users/awesomeo/map/cdmerto_allsites.xlsx', encoding='gb2312', sheet_name='Sheet1')# print(prop.head())
token = 'pk.eyJ1IjoiZm94eGpqIiwiYSI6ImNraDJ1OXNhbzBhYzEydXA2Ymt6N2R0NHAifQ.VkK9tHG3fwSnVr2k2Zxleg'fig = px.scatter_mapbox(prop,lon='longitude',lat='latitude',size='起拍价/万元',color='面积/m²',hover_name='楼盘名称',hover_data=['district'],size_max=20,color_continuous_scale=px.colors.carto.Temps)# 使用unique去重得到线路条数
lines = cd_metro['线路'].unique()
# print(lines)
colors =['rgb(255,182,193)', 'rgb(138,43,226)', 'rgb(0,0,255)', 'rgb(0,191,255)', 'rgb(32,178,170)', 'rgb(230,230,250)','rgb(255,165,0)', 'rgb(255,69,0)', 'rgb(139,0,0)', 'rgb(240,128,128)', 'rgb(107,142,35)']# print(list(zip(lines, colors)))fig.add_traces([go.Scattermapbox(mode='markers + lines',#取对应每一条线路的经纬度信息lon = cd_metro.loc[lambda x: x['线路'] ==line]['经度'],lat = cd_metro.loc[lambda x: x['线路'] ==line]['纬度'],marker = {'color': color, 'size': 6},hovertext = cd_metro.loc[lambda x: x['线路'] ==line]['站名'],hoverinfo = 'text',showlegend = False) for line, color  in list(zip(lines,colors))])fig.update_layout(mapbox={'accesstoken':token, 'center':{'lon':104.072329, 'lat':30.65342}, 'zoom':11.8},margin={'l':0, 'r':0, 't':0, 'b':0})fig.write_html(r'cd_metro_all.html')
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

**重点提醒:

  1. 一定要进行坐标转换,要不然画出来的地铁线路是偏离的。

Python绘制成都地铁全线路图!有路线图也搞不清楚啊!相关推荐

  1. Plotly绘制成都地铁全线路图(线路可实时更新最新线路 + 完整代码)

    Plotly绘制成都地铁全线路图 最近做一个地图可视化的项目需要在地图上画出成都已开通的地铁线路图,中间还是踩了几个小坑,记录一下整个过程. 1. 开发环境 python 3.8 plotly(没安装 ...

  2. html绘制地铁线路图,Plotly绘制成都地铁全线路图(线路可实时更新最新线路 + 完整代码)...

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Fri Nov 6 11:16:45 2020 ...

  3. Python+OpenCV拼接图片:获取成都地铁全线网配线图

    身为一名地铁族,我对成都的地铁建设很关注. 今年八月份的时候,在 地铁族-成都区,程家大老爷(707984563)把他的作品: [轨道图RailMap]成都轨道交通全线网配线图 发布了出来. 但是这个 ...

  4. 【R语言】使用leaflet绘制沈阳地铁线路图——R实训第六次作业

    参考: 一.惭愧惭愧,基本都是抄自这个大牛学长,自己做了一部分改进--R语言绘制沈阳地铁线路图 二.这个发布的时间比学长还要早(学长可能也借鉴过)--上海地铁数据可视化 三.这个是真正的大牛,从他的文 ...

  5. WPF绘制深圳地铁路线图

    经常坐地铁,却不知道地铁多少条线路?哪个站下车?今天就带领大家熟悉并绘制深圳地铁路线图. WPF在绘制矢量图方面有非常强大的优势,利用WPF可以绘制出各种矢量图形,如线,圆,多边形,矩形,及组合图形. ...

  6. 最全Python绘制饼形图(饼状图)

    饼状图(pie chart)一般用于描述分类型数据的相对频数或百分数频数分布,呈现部分与总体的关系.    一.导入绘图数据 首先导入绘图所需的数据. import os import pandas ...

  7. 成都地铁线路图高清大图

    成都地铁(Chengdu Metro),是指服务于中国四川省成都市的城市轨道交通.其首条线路成都地铁1号线于2010年9月27日正式开通,也使成都成为了中国大陆第十个拥有城市轨道交通的城市. 2020 ...

  8. 最全Python绘制条形图(柱状图)

    条形图(bar chart)也称为柱状图,是一种以长方形的长度为变量的统计图表,长方形的长度与它所对应的数值呈一定比例.    一.导入绘图数据 首先导入绘图所需的数据. import os impo ...

  9. 记录一下python绘制地图

    看到比较清晰的文章:留以记录 使用 Python 地图绘制工具 -- folium 全攻略 - 云+社区 - 腾讯云 (tencent.com)

最新文章

  1. 怎样用matlab打开mw文,C# matlab混合编程 MWArray使用笔记
  2. Programming Pearls: Chatper3 Problem6 [Form letter generator]
  3. 131. 分割回文串(回溯算法)
  4. JPA 2.1: What is new
  5. mysql要怎么定义环境变量_mysql设置环境变量
  6. No module named pip
  7. 序列化 - 实现ISerializable
  8. Android 播放raw文件夹下音频文件,本地MP3文件播放,播放云端MP3文件,获取MP3文件播放时长
  9. python爬取csdn用户头像
  10. MakeItTalk:Adobe 语音驱动的头部动画
  11. 日本富士通正考虑将PC业务并入联想
  12. 模线性同余方程组求解
  13. Django 前后端数据传输、ajax、分页器
  14. win10怎样更改系统字体_简单六步,轻松更改Windows系统字体
  15. 详解-黑莓7290激活教程
  16. ts文件怎么合并转换成mp4?
  17. hive 添加字段_Hive分区表动态添加字段
  18. 删除控制面板java无效图标_win7系统删除控制面板中无效的图标的操作方法
  19. 利用LSTM自动生成中文文本
  20. 设置bing为chrome的默认搜索引擎

热门文章

  1. 平面设计和ui设计的区别:ui设计前景怎样
  2. 联想小新 Air 14 2023 超极本 评测
  3. 学校计算机实训室标语,学校实训室标语
  4. html中的购物车下拉菜单的图标如何实现???
  5. 元启发式算法的参数微调方法(tuners for meta-heuristic algorithms)
  6. 模板引擎beetl+springboot
  7. java excel 模板_java对Excel模板的读取
  8. 从零开始,在阿里云,腾讯云centos8系统上,利用docker部署asp.net core项目的一次实践,总结
  9. Java计算机毕业设计点餐系统源码+系统+数据库+lw文档
  10. 英国名菜“炸鱼薯条”陷入断供,炸鱼店被迫关门