前言

大部分时间我都是使用Pyecharts去做可视化,不过一直有个比较头疼的问题没法解决。

在pyecharts中是需要把所有的坐标点的数据加载到图表中,当数据量特别大的时候,那么这样一个图表可能会有好几百MB,使用起来会非常卡顿。虽然在Echarts中有ScatterGL来支持大数据量大可视化,不过在Pyecharts中没法直接支持,只能找一些曲线救国的方法,改善效果也不是很明显。

最近使用了一下plotly,发现了超大地理数据集可视化的解决办法,我们先来看下效果:

数据总共包含100W个数据点,地图缩放或者拖拽也不会存在卡顿。

其实这个解决办法也很好理解,datashader是将所有的数据点转换成为了包含所有点的一张图片,然后将这个图片与Plotly结合到一起,就相当于是在整个地图上加了一个图层,这样切换起来就不会卡顿了。

GIS图层这里是使用了Mapbox,Mapbox是一家非常优秀的地图厂商,各位可以去Mapbox定制属于自己的地图效果。

实现方法

接下来我们就详细说一下实现方法。

Mapbox图层

这个需要各位自己去Mapbox注册,免费的,注册完之后就可以定制自己的地图了。

定制完成后点击右上角的SHARE,复制出如下两个位置的数据就可以了!

 在plotly中使用Mapbox的代码

import plotly.express as px

# 自己去Mapbox申请一个Token
px.set_mapbox_access_token('pk.eyJ1IjoiYA....')

fig = px.scatter_mapbox(
    df,
    lat='Lat',
    lon='Lon',
    # 缩放比例
    zoom=12,
    # 地图中心位置
    center=dict(lat=40.74000520746974, lon=-73.97681683902668),
    mapbox_style="mapbox://styles/awesometang/cjb4fvg3o5m392tpjetxzaqgz"
)


fig.show()

datashader的使用

datashader的作用是将坐标点数据转换为像素密度栅格,栅格可以叠加在MapBox图层。

实现代码:

# 设置画布大小
cvs = ds.Canvas(plot_width=1980, plot_height=1000)
# 坐标点聚合
agg = cvs.points(dff, x='Lon', y='Lat')
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
# 四个角的坐标,用于在Mapbox中定位
coordinates = [[coords_lon[0], coords_lat[0]],
               [coords_lon[-1], coords_lat[0]],
               [coords_lon[-1], coords_lat[-1]],
               [coords_lon[0], coords_lat[-1]]]

# 生成的图层
img = tf.shade(agg, cmap=fire)[::-1].to_pil()

颜色这里我是使用了https://github.com/holoviz/colorcet中的配色方案fire。

 完整代码

将上面两部分和在一起,便完成了我们的图表了。

需要数据的可以自行去下载:

import pandas as pd 
import plotly.express as px
import datashader as ds
from colorcet import fire
import datashader.transfer_functions as tf


# 替换成你们自己的数据链接
df = pd.DataFrame()
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-apr14.csv'))
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-aug14.csv'))
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-jul14.csv'))
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-jun14.csv'))
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-may14.csv'))
df = df.append(pd.read_csv('/home/mw/input/uber5306/uber-pickups-in-new-york-city/uber-raw-data-sep14.csv'))


# 限制一下区域
# 有些离得很远的点,将整个画布范围拉的很大
# 最后会导致数据点都集中在很小一块
dff = df.query('Lat < 40.82').query('Lat > 40.70').query('Lon > -74.07').query('Lon < -73.86')
# 设置画布大小
cvs = ds.Canvas(plot_width=1980, plot_height=1000)
# 坐标点聚合
agg = cvs.points(dff, x='Lon', y='Lat')
coords_lat, coords_lon = agg.coords['Lat'].values, agg.coords['Lon'].values
# 四个角的坐标,用于在Mapbox中定位
coordinates = [[coords_lon[0], coords_lat[0]],
               [coords_lon[-1], coords_lat[0]],
               [coords_lon[-1], coords_lat[-1]],
               [coords_lon[0], coords_lat[-1]]]

# 生成的图层
img = tf.shade(agg, cmap=fire)[::-1].to_pil()

# 自己去申请一个Token
px.set_mapbox_access_token('pk.eyJ1Ijo')

fig = px.scatter_mapbox(
    dff[:1],
    lat='Lat',
    lon='Lon',
    zoom=12,
    center=dict(lat=40.74000520746974, lon=-73.97681683902668),
    height=800)

fig.update_layout(mapbox_style="mapbox://styles/awesometang/cjb4fvg3o5m392tpjetxzaqgz",
                  mapbox_layers=[
                      {
                          "sourcetype": "image",
                          "source": img,
                          "coordinates": coordinates
                      }],
                    title='Uber Pickups In New-York'
                  )
fig.show()
# 保存图片
pio.write_image(fig, 'Uber Pickups In New-York.png', width=1980,height=1000)

Logo

永洪科技,致力于打造全球领先的数据技术厂商,具备从数据应用方案咨询、BI、AIGC智能分析、数字孪生、数据资产、数据治理、数据实施的端到端大数据价值服务能力。

更多推荐