博客
关于我
(在模仿中精进数据可视化03)OD数据的特殊可视化方式
阅读量:431 次
发布时间:2019-03-06

本文共 3940 字,大约阅读时间需要 13 分钟。

本文完整代码及数据已上传至我的GitHub仓库。

1 简介

OD数据是交通、城市规划以及GIS等领域常见的一类数据,特点是每一条数据都记录了一次OD(Origin即起点,Destination即终点)行为的起点与终点坐标信息。而针对OD数据的常见可视化表达方式为弧线图,例如纽约曼哈顿等区域的某时间段Uber打车记录上下车点数据的展示方式(如图1所示)。

但这种传统的表达方式存在局限性:当OD记录数量众多时,由于不同线之间的彼此堆叠,导致很多区域之间的OD模式被遮盖而难以被读出。前一段时间,我在观看一场学术直播的过程中,注意到一种特别的表达区域间OD数据的方式,原始文献比较老(发表于2010年),其思想是通过对研究区域进行网格化划分,再将整个区域的原始网格映射到每个单一网格中(如图2所示)。

以坐标为( E,5 )的网格为例,到达坐标为( A,2 )的网格的所有OD数据记录,可以在右图中对应左图( E,5 )位置的大网格中,划分出的对应( A,2 )相对位置的小网格中进行记录。通过这种方式,原始文献将图3所示原始OD线图转换为图4所示的结果,使得我们可以非常清楚地观察到每个网格区域对其他网格区域的OD模式。本文将利用Python,在图1对应的Uber上下车点分布数据的基础上,实践这种表达OD数据的特别方式。

2 模仿过程

2.1 过程分解

首先,我们需要梳理整体逻辑。原始数据中我们主要用到的字段包括上车点经纬度pickup_longitudepickup_latitude,以及下车点经纬度dropoff_longitudedropoff_latitude。我的思路是首先对所有经纬度点进行去重,然后保存为GeoDataFrame并统一坐标参考系为Web墨卡托(EPSG:3857)。

具体实现如下:

from shapely.geometry import Pointfrom geopandas import GeoDataFrameod_points = pd.concat([    taxi_trip_flow[['pickup_longitude', 'pickup_latitude']]    .rename(columns={'pickup_longitude': 'lng', 'pickup_latitude': 'lat'}),     taxi_trip_flow[['dropoff_longitude', 'dropoff_latitude']]    .rename(columns={'dropoff_longitude': 'lng', 'dropoff_latitude': 'lat'})], ignore_index=True)od_points = od_points.drop_duplicates()od_points['geometry'] = od_points.apply(lambda row: Point(row['lng'], row['lat']), axis=1)od_points = gpd.GeoDataFrame(od_points, crs='EPSG:4326').to_crs('EPSG:3857')od_points.head()

接下来,我们为研究区域创建网格面矢量数据。思路是利用numpy先创建出x和y方向上的等间距坐标,例如我们这里创建5行5列:

from shapely.geometry import MultiLineStringfrom shapely.ops import polygonizexmin, ymin, xmax, ymax = od_points.total_boundsx = np.linspace(xmin, xmax, 6)y = np.linspace(ymin, ymax, 6)hlines = [((x1, yi), (x2, yi)) for x1, x2 in zip(x[:-1], x[1:]) for yi in y]vlines = [((xi, y1), (xi, y2)) for y1, y2 in zip(y[:-1], y[1:]) for xi in x]manhattan_grids = GeoDataFrame({    'geometry': list(polygonize(MultiLineString(hlines + vlines)))}, crs='EPSG:3857')manhattan_grids['id'] = manhattan_grids.index

创建出的网格效果如图7所示。接下来是最关键的部分:计算每个原始网格内部的上车点记录,并利用仿射变换得到镶嵌在其内部的小网格。

以id=21的网格为例(对应肯尼迪国际机场的区域),我们需要完成以下步骤:

  • 提取目标网格的重心坐标
  • 基于空间连接,提取目标网格中包含到的所有上车点记录
  • 关联这些记录对应的下车点信息
  • 提取下车点矢量信息
  • 利用空间连接,得到所需的网格下车点分布结果
  • i = 21center_grid = (manhattan_grids.unary_union.centroid.x, manhattan_grids.unary_union.centroid.y)dropoff = (    gpd.sjoin(manhattan_grids.loc[i:i, :], od_points, op='contains')    [['lng', 'lat', 'geometry']]    .merge(taxi_trip_flow[['pickup_longitude', 'pickup_latitude', 'dropoff_longitude', 'dropoff_latitude']],            left_on=['lng', 'lat'], right_on=['pickup_longitude', 'pickup_latitude'])    [['dropoff_longitude', 'dropoff_latitude']]    .merge(od_points, left_on=['dropoff_longitude', 'dropoff_latitude'], right_on=['lng', 'lat'])    [['geometry']])grid_distrib = (    gpd.sjoin(manhattan_grids, GeoDataFrame(dropoff, crs='EPSG:3857'), op='contains')    .groupby('id', as_index=False)    .agg({'index_right': 'count'})    .rename(columns={'index_right': '下车记录数'}))grid_distrib.head()

    通过上述步骤,我们得到了id为21的网格下车点分布结果。将上述过程推广到每个网格,并将最后的计算结果合并为一张GeoDataFrame,即表draw_base

    2.2 绘制图像

    最终,我们对draw_base表进行可视化。为了显示更加自然,对下车记录进行了对数化+自然间断处理:

    import matplotlib.pyplot as pltimport contextily as ctxfig, ax = plt.subplots(figsize=(12, 12), dpi=200)draw_base.plot(facecolor='none', edgecolor='lightgrey', ax=ax, linewidth=0.3)draw_base.assign(下车记录数=np.log(draw_base.下车记录数))draw_base.plot(column='下车记录数', scheme='NaturalBreaks', k=5, cmap='YlOrRd', ax=ax, alpha=0.7)manhattan_grids.plot(ax=ax, facecolor='none', edgecolor='black', linewidth=0.8)draw_base.query('是否为目标网格 == 1').plot(facecolor='none', edgecolor='black', linestyle='--', ax=ax)minx, miny, maxx, maxy = manhattan_grids.total_boundsax.set_xlim(minx, maxx)ax.set_ylim(miny, maxy)ax.axis('off')ctx.add_basemap(ax, source='https://d.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', zoom=12)fig.savefig('图10.png', dpi=500, bbox_inches='tight', pad_inches=0)

    通过这种表达方式,我们可以很明显地看出不同区域相对其他区域出行模式的不同。你还可以根据自己的需要,对上述绘图逻辑进行调整,例如每个原始网格内部色彩独立映射等。

    以上就是本文的全部内容,欢迎在评论区与我进行讨论~

    转载地址:http://sxcuz.baihongyu.com/

    你可能感兴趣的文章
    ngrok | 内网穿透,支持 HTTPS、国内访问、静态域名
    查看>>
    NHibernate学习[1]
    查看>>
    NHibernate异常:No persister for的解决办法
    查看>>
    NIFI1.21.0_Mysql到Mysql增量CDC同步中_日期类型_以及null数据同步处理补充---大数据之Nifi工作笔记0057
    查看>>
    NIFI1.21.0_NIFI和hadoop蹦了_200G集群磁盘又满了_Jps看不到进程了_Unable to write in /tmp. Aborting----大数据之Nifi工作笔记0052
    查看>>
    NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增删改数据分发及删除数据实时同步_通过分页解决变更记录过大问题_02----大数据之Nifi工作笔记0054
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现数据实时delete同步_实际操作04---大数据之Nifi工作笔记0043
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
    查看>>
    NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
    查看>>
    NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
    查看>>
    NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
    查看>>
    Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
    查看>>
    NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
    查看>>
    NIFI大数据进阶_NIFI的模板和组的使用-介绍和实际操作_创建组_嵌套组_模板创建下载_导入---大数据之Nifi工作笔记0022
    查看>>
    NIFI大数据进阶_NIFI监控的强大功能介绍_处理器面板_进程组面板_summary监控_data_provenance事件源---大数据之Nifi工作笔记0025
    查看>>
    NIFI大数据进阶_内嵌ZK模式集群1_搭建过程说明---大数据之Nifi工作笔记0015
    查看>>
    NIFI大数据进阶_外部ZK模式集群1_实际操作搭建NIFI外部ZK模式集群---大数据之Nifi工作笔记0017
    查看>>
    NIFI大数据进阶_离线同步MySql数据到HDFS_01_实际操作---大数据之Nifi工作笔记0029
    查看>>
    NIFI大数据进阶_离线同步MySql数据到HDFS_02_实际操作_splitjson处理器_puthdfs处理器_querydatabasetable处理器---大数据之Nifi工作笔记0030
    查看>>