Plotly绘制成都地铁全线路图

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

1. 开发环境

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

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

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

 3.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)
 3.2  为什么要进行坐标转换plotly用的是WGS-84坐标系,而百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理,百度转WGS-84还稍微有点复杂,不过有开源代码,直接拿来用就可以了。

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

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


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

#!/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']) #添加已绘制线路反向线路的uid

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

      3.4 使用plotly画出地铁线路图,需要先申请plotly的key,不知道怎么申请的可自行google。
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')

**重点提醒:

  1. 一定要进行坐标转换,要不然画出来的地铁线路是偏离的。
  2. plotly的底图是可以更换的,我更换到高德底图进行过对比,基本是准确的,如果不知道如何更换底图的朋友可私信联系。**

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

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

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

  2. Python绘制成都地铁全线路图!有路线图也搞不清楚啊!

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

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

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

  4. 【理论+实践】史上最全-论文中常用的图像分割评价指标-附完整代码

    图像分割的评价指标非常多,论文中常用的包括像素准确率(Pixel Accuracy, PA).交并比(Intersection-Over-Union,IOU).Dice系数(Dice Coeffcie ...

  5. R语言绘制沈阳地铁线路图

    ##使用leaflet绘制地铁线路图,要求 ##(1)图中绘制地铁线路 library(dplyr) library(leaflet) library(data.table) stations< ...

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

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

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

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

  8. 简单成都地铁信息查询系统,BFS算法实现最短路径查找

    前言 最近数据结构期末作业要求做一个成都地铁信息系统,在网上查阅了相关资料之后,做了出来,因为复用性极强,且代码注释都比较详细,于是决定分享出来 思路 总的来说就是从两个文本文件中读入站点和站点信息, ...

  9. Python地理可视化:plotly绘制mapbox地图热力密度图

    Python地理可视化:plotly绘制mapbox地图热力密度图 import plotly.graph_objects as go import numpy as npKEYS = ['中心点经纬 ...

最新文章

  1. Redis 集群方案
  2. 浅谈Docker:DockerLinux安装,镜像管理命令,镜像制作命令,容器管理命令,数据卷,DockerFile,Docker-compose
  3. go micro 学习笔记 2:环境搭建(可运行示例)
  4. CF1342E. Placing Rooks
  5. MySQL临时表(转)
  6. Java proxy 子类代理
  7. JAVA中的多线程(八):线程的优先级和yield方法
  8. 为什么需要API网关?
  9. 信捷PLC Modbus通讯 (Modbus_TCP与Modbus_RTU)
  10. E盾网络验证企业版个人版离线版对接好的自绘界面4加密防破解易语言源码加密
  11. 考勤日历插件 android,jQuery手机考勤日历插件
  12. nuc977 linux i9341 2.8寸lcd配置
  13. 【icem】非结构体网格的质量+混合网格的合并问题
  14. python识别图片中的人_Python实现识别图片中的所有人脸并显示出来
  15. 计算机网络 --- 物理层(学习笔记)
  16. bit1618c 功能简介_c 9中的新功能简介
  17. 【整理学习Hadoop】Hadoop学习基础之一:服务器集群技术
  18. 它来了!Flutter3.0新特性全接触
  19. wps文档漫游删除_WPS自带的文档漫游和在线模板怎么关闭?
  20. ARGB_8888(ARGB32)色彩格式

热门文章

  1. 苹果8大笔试题及答案
  2. 第二届(2023年)中国国际培育钻石产业发展与创新大会盛大召开!
  3. 如何避免NOPI 从Execl里面单元格取日期时出现日期反转
  4. 9.5 Python csv 文件的写入操作
  5. 逆向 qq 消息撤回
  6. ​李宏毅机器学习——对抗生成网络(GAN)
  7. java中常用的日期工具类
  8. 专访著名3D动画设计师DAVID LIU
  9. w311m linux驱动下载,腾达(Tenda)W311M V3.0网卡驱动(LINUX)
  10. 批量关闭公众号推送_微信推批量屏蔽公众号功能