☰
Datashader 示例指南:从环境搭建到大数据可视化管线实战(Data-Analysis 仓库 datashader-examples 全解析)
2026/10/15 3:02:50 网站建设 项目流程
  • 示例工程
  • 数据科学
  • 数据分析

【免费下载链接】Data-Analysis

Data Science Using Python

项目地址:https://gitcode.com/gh_mirrors/da/Data-Analysis
点击查看免费下载

Datashader 是一套面向超大数据的图形渲染管线库:它先把海量记录聚合(rasterize/aggregate)成固定大小的网格数组,再着色成图像,从而在普通笔记本电脑上也能以秒级速度忠实呈现十亿级数据点的分布。本文以当前仓库datashader-work/datashader-examples目录下的官方示例套件为主体,完整讲解示例环境的搭建(conda 环境、示例数据拉取)、Notebook 的运行方式,并结合仓库内的 Getting Started、User Guide、Topics 与 Dashboard 代码,深入剖析 Datashader 从 Projection 到 Embedding 的完整数据流水线,帮助读者在本地复现并扩展这一大数据可视化方案。

一、为什么需要 Datashader:大数据绘图的六大陷阱

在进入示例之前,先回答仓库内 FAQ.ipynb 中的核心问题:什么时候该用 Datashader?

  • 应该使用:数据量极大,你最关心的是忠实还原数据的分布形态;或者你已经在被迫"抽样子采样"才能完成绘图,又或者只能按块(chunk)迭代数据而无法一次性查看全部——这时候 Datashader 几乎必然能帮到你。Datashader 会生成一个与原始记录数无关的固定大小数据结构,再传给浏览器显示,因此数据再大也不会撑爆前端。
  • 不应该使用:数据量很小(数百到数千个点、数十条曲线)时,Bokeh 这类传统绘图库更合适——它把全部数据点直接传给浏览器,每个点/每条曲线都可以单独交互、查看元数据。Datashader 生成的是图像而非矢量对象,交互能力(如 hover 单点信息)会受限。

为什么要如此强调"分布"而非"散点"?user_guide/1_Plotting_Pitfalls.ipynb 用同一份数据演示了传统绘图在小数据上无伤大雅、在数据量增大后却会系统性误导的六类问题:

  1. Overplotting(过度叠绘):后绘制的点遮挡先绘制的点,导致两块分布相同的数据因绘制顺序不同而呈现出完全不同的"谁更密集"的印象;
  2. Oversaturation(过度饱和):用透明度(alpha)缓解叠绘时,一旦叠加点数超过阈值就"饱和",只剩下最后若干点影响颜色;
  3. Undersampling(欠采样):数据太多时常见的"随机抽 1 万个点再画"的做法,会丢失窄分布区域的形状;
  4. Undersaturation(欠饱和):高低密度相差悬殊时,低密度区域几乎不可见;
  5. Underutilized range(动态范围利用不足):最大 bin 数值把线性色标撑满,其余像素只落到色标前 24 个颜色上;
  6. Nonuniform colormapping(非均匀着色):不适合的色带把高密度区域映射成难以分辨的亮黄/白。

该 Notebook 的结论一针见血:"For big data, you don't know when the viz is lying(面对大数据,你无法判断图表什么时候在说谎)"。而 Datashader 之所以能规避这些问题,是因为它不做任何"魔法参数"调整——它把数据原原本本地聚合到网格中,再用how='log'、how='eq_hist'(直方图均衡)等有明确数学含义的变换映射到颜色,保证每个像素都反映真实的密度。HoloViews 的datashade(hv.Points(dist))一行即可复现上述全部纠偏效果,且对 5000 万点数据集同样有效。

二、环境准备:用 Conda 一键创建 ds 环境

示例运行环境由仓库内的 environment.yml 定义。该文件声明了环境名ds,并从bokeh、conda-forge、ioam三个 channel 拉取依赖:

name: ds channels: - bokeh - conda-forge - ioam dependencies: - attrs - beautifulsoup4 - bokeh - cartopy - colorcet - conda-forge::graphviz - conda-forge::pytest - conda-forge::pytest-benchmark - conda-forge::python-graphviz - dask>=0.15.4 - datashader - dill - distributed - fastparquet - flake8 - geoviews - ioam::holoviews>=1.8.3 - ipython - iris - jupyter - jupyter_dashboards - krb5 - matplotlib - nbconvert - nbformat - networkx>=2.0 - numba - numpy - pandas - param>=1.5.1 - paramnb - pyproj - pytables - python-snappy - python=3.6 - rasterio - requests - scikit-image - scipy - shapely - snappy - statsmodels - tblib - xarray - yaml - pip: - cachey - streamz==0.2.0 - webargs

从依赖清单可以看到 Datashader 示例的完整技术栈:

  • datashader 本体,以及支撑其高性能实现的numba(把 Python 热路径透明编译为机器码)与dask/distributed(跨核、跨进程并行与分布式调度);
  • 可视化与集成层:holoviews、geoviews、bokeh、param/paramnb、matplotlib;
  • 数据读写层:pandas、xarray、fastparquet、pytables、bcolz(由filetimes.py基准脚本使用)、python-snappy(Parquet Snappy 压缩);
  • 地理与栅格:cartopy、pyproj、shapely、rasterio、scikit-image(eq_hist直方图均衡依赖)、iris;
  • 附带的 pip 依赖cachey(Dask 内存缓存)、streamz==0.2.0(流式聚合示例使用)与webargs。

1. 创建环境的完整命令

按官方 README(即本文主题文档 datashader-examples/README.md)的指引,先下载环境文件(也可直接从本仓库复制 environment.yml 到本地),然后在存放该文件的目录下依次执行:

# 1. 根据 environment.yml 创建名为 ds 的 Conda 环境 conda env create --file environment.yml # 2. 激活 ds 环境(后续所有命令都在该环境中执行) conda activate ds # 3. 拷贝官方示例并下载示例数据 datashader examples # 4. 进入示例目录 cd datashader-examples

几点重要说明(均出自原 README):

  • Python 版本:environment.yml默认指定python=3.6。可以手动编辑该文件改用其他 Python 版本,但某些依赖在部分版本组合下可能需要相应调整;
  • 环境激活:conda activate ds只对当前终端会话生效,关闭终端或重启机器后需重新执行。旧版 conda 在 mac/Linux 上可能需要source activate ds,Windows 上则为activate ds;
  • 命令语义:第 3 步的datashader examples是以下两条命令的简写:
    datashader copy-examples --path datashader-examples \ && datashader fetch-data --path datashader-examples

    前者把 Datashader 包内附带的示例拷贝到当前目录的datashader-examples子目录,后者按清单下载示例所需的数据集;

  • 不使用 Conda 时:README 明确说明,上述流程基于 conda,但可相应改用 pip 与 virtualenv 完成同样安装(依赖清单以environment.yml为准)。

2. 示例数据清单:datasets.yml 与下载规模

示例数据由 datasets.yml 逐项列出。README 强调:当前总下载量约 4GB,解压后占用约 10GB 磁盘空间,实际耗时取决于网络速度。清单中的典型数据集包括:

数据用途
nyc_taxi.csv纽约出租车轨迹(Getting Started 与 NYC Taxi 主题示例)
nyc_crime.csv纽约犯罪数据
austin_dem.tif奥斯汀数字高程栅格
census.snappy.parq美国人口普查合成人口数据
opensky.parqOpenSky 航班轨迹(2016-09-05 ~ 09-13)
calvert_uk_research2017_nodes/edges英国科研合作网络(边捆绑图示例)
maccdc2012_*.parq网络安全攻防竞赛流量图(网络包示例)
cb_2015_us_cd114_5m.shp2015 年美国国会选区边界
Chesapeake_and_Delaware_Bays.3dm切萨皮克湾水深不规则三角网
MERCATOR_LC80210392016114LGN00_B*.TIFMobile 地区 Landsat8 多波段影像

所有数据都需要放在示例目录的data/子目录下,示例代码才能找到它们。datasets.yml本身是纯文本清单,你可以编辑它,或按其中 URL 手动下载单个文件放入data/,效果等同。仓库内还提供了一个辅助脚本 get_raster_data.sh,演示了手动wget + unzip栅格数据的完整流程:

mkdir -p data cd data wget http://s3.amazonaws.com/bokeh_data/geotiff_example.zip unzip geotiff_example.zip cd ..

三、运行示例 Notebook:在线与离线两种模式

下载完成后即可启动 Jupyter:

cd datashader-examples jupyter notebook

大部分示例都是可运行的 Jupyter Notebook。示例目录的组织非常清晰:

  • getting_started/index.ipynb:入门指南(共三篇,总计约 1 小时阅读量);
  • user_guide/index.ipynb:用户手册(Plotting Pitfalls、Points、Timeseries、Trajectories、Rasters、Trimesh、Networks、Geography、Extending、Performance 共 10 章);
  • topics/index.ipynb:主题实战示例(NYC Taxi、OSM 十亿点、Landsat、Gerrymandering、Strange Attractors、UK Researchers、网络数据包等)。

离线/弱网环境运行

Bokeh 后端绘图依赖从 CDN 加载 BokehJS 资源。如果你的网络不稳定,会在浏览器中一直看到Loading BokehJS ...而始终不出现BokehJS sucessfully loaded。此时需要让 Notebook 内联(inline)加载 BokehJS,并提高 Jupyter 的 IOPub 数据速率上限(Datashader 交互绘图会推送较大的图像数据):

BOKEH_RESOURCES=inline jupyter notebook --NotebookApp.iopub_data_rate_limit=100000000

交互式绘图的前提:必须保留"活"的 Python 进程

需要特别注意的是:Datashader 的交互缩放、平移依赖正在运行的 Python 进程。Bokeh 的工作方式是:Python 端给出绘图规格 → 浏览器端生成对应的 JavaScript 可视化。Datashader 每次只把一张图像交给浏览器,因此:

  • 在带实时 Python 内核的 Notebook 中缩放/平移时,回调会把新的视口范围传回 Python,Datashader 重新聚合、重新着色,再更新图像——看起来就像全部数据都在浏览器中交互可用;
  • 在静态导出的 HTML(如网站上的示例页)中缩放,只会把原有像素放大,看不到更细粒度的重渲染。

这也是"加载 BokehJS 但始终卡住"之外,运行示例时需要理解的最关键概念之一。

四、Datashader 核心管线:五个阶段把数据变成图像

Getting Started 的第 2 篇 getting_started/2_Pipeline.ipynb 用一个 5 万行的合成高斯分布数据集,把 Datashader 从数据到图像的完整流程拆解为五个阶段。其架构与 3D 图形渲染中的"着色管线(graphics pipeline)"同构:

这种"分阶段"设计正是 Datashader 能处理任意规模数据的根本原因:五步中只有 Aggregation 需要接触全部数据,其余各阶段都只操作固定大小的中间结构,因此无论数据集多大,后续阶段的计算成本都不变。

1. Projection(投影)

把数据映射到二维矩形网格上。这一阶段"主要是概念性的",由使用者决定两件事:

  • 变量选择:哪一列做 x 轴、哪一列做 y 轴;若需坐标变换(如经纬度转 Web Mercator),应先在 DataFrame 中准备好对应列;
  • 范围选择:x_range/y_range。强烈建议显式指定范围,理由有三:① 省略时 Datashader 需要完整扫一遍数据才能算出范围,耗时接近聚合本身,显式指定可让绘图快约一倍;② 真实数据常含异常离群值,指定有效范围能避免离群点把画面压缩得无法观看;③ 固定范围便于跨数据集对比。
canvas = ds.Canvas(plot_width=300, plot_height=300, x_range=(-8, 8), y_range=(-8, 8), x_axis_type='linear', y_axis_type='linear')

此时尚未发生任何计算——Canvas对象是纯声明式的,只记录后续阶段要用的偏好。

2. Aggregation(聚合)

Canvas指定好后即可把数据聚合进固定大小的网格。首先要决定数据点以何种"图元"映射到网格,目前支持三种:

  • Canvas.points:每个数据点落入离它最近的那个网格单元;
  • Canvas.lines:每个数据点映射到从该点到下一点之间穿过的所有网格单元(时间序列、轨迹);
  • Canvas.raster:每个数据点映射为一个轴对齐矩形,形成与相邻点连续的规则网格。

其他图元(网络图、时间序列等)都由这三种基础图元组合而来。接着选择**归约算子(reduction)**决定多个数据点落入同一像素时如何合并:

canvas.points(df, 'x', 'y', agg=ds.count()) # 每个 bin 的计数 canvas.points(df, 'x', 'y', agg=ds.any()) # 有数据就点亮 canvas.points(df, 'x', 'y', agg=ds.mean('y')) # 对 y 列求平均 canvas.points(df, 'x', 'y', agg=ds.mean('val')) # 对 val 列求平均

所有归约算子都是增量式的,因此可以在单次遍历中高效处理任意大的数据集(实际为批量处理,但数学结果等价于逐点应用)。聚合结果是一个 xarrayDataArray:包含每个 bin 的值、轴范围与轴类型信息。

3. Transformation(变换)

聚合完成后、着色之前,数据仍是 bin 值而非像素,因此可以任意变换。典型用法包括:

agg = canvas.points(df, 'x', 'y') # 只显示计数前 99 百分位的 bin tf.shade(agg.where(agg >= np.percentile(agg, 99)), name="99th Percentile") # 对 bin 值应用任意 NumPy ufunc tf.shade(np.power(agg, 2), name="Numpy square ufunc") tf.shade(np.sin(agg), name="Numpy sin ufunc")

分类数据则产生每个 bin 对每个类别各有一个值:

aggc = canvas.points(df, 'x', 'y', ds.count_cat('cat')) aggc.sel(cat='d3') # 单独选一个类别 aggc.sel(cat=['d3', 'd5']).sum(dim='cat') # 折叠多个类别

多个聚合只要基于同一个Canvas(保证网格尺寸一致、轴范围一致),还可以互相组合与掩膜:

mask = aggc.sel(cat='d3') == aggc.sel(cat='d5') # d3 与 d5 计数相等的 bin agg_d3_d5.where(mask)

由于聚合数组是固定大小的网格,此阶段几乎无需担心优化问题。

4. Colormapping(着色)

tf.shade()把标量 bin 值映射为 RGB + alpha。默认行为:

  • 默认色带为['lightblue', 'darkblue'](#ADD8E6→#00008B),RGB 三通道各自线性插值;
  • 空 bin 的 alpha 为 0(露出页面背景),非空 bin 的 alpha 为 1;
  • 色带可替换为 Bokeh 调色板、Matplotlib 色图或任意颜色列表(颜色名、RGB 整数三元组、十六进制字符串皆可):
from bokeh.palettes import RdBu9 tf.shade(agg, cmap=["darkred", "yellow"], name="darkred, yellow") tf.shade(agg, cmap=[(230,230,0), "orangered", "#300030"], name="yellow, orange red, dark purple") tf.shade(agg, cmap=RdBu9, name="Bokeh RdBu9")

分类数据着色可以直接把aggc交给tf.shade,它会为每个类别分配颜色并按各 bin 中类别的值混合颜色;也可显式提供color_key:

color_key = dict(d1='blue', d2='green', d3='red', d4='orange', d5='purple') tf.shade(aggc, color_key=color_key)

how变换参数是tf.shade的内置"魔法"所在,对 2D 非分类聚合,其流程为:

  1. Mask:掩掉 NaN(浮点数组)或 0 值(整数数组)的 bin,使其不参与后续计算;
  2. Transform:对"每个 bin 值 − 最小非掩值"应用标量函数how;
  3. Map:把变换后的数值范围映射进色带,掩掉的部分 alpha 全透明。

默认how='linear'会把最大 bin 映射到色带顶端,其余 bin 全部挤在前 24 个颜色里,几乎看不出结构。因此实际中几乎总要改用:

tf.shade(agg, how='log') # 对数变换,适合数值跨度大的计数数据 tf.shade(agg, how='eq_hist') # 直方图均衡,保证每个颜色都被均匀使用 # 也支持任意可调用对象,如 23 次方根 tf.shade(agg, how=lambda d, m: np.where(m, np.nan, d)**(1/23.))

how只服务于最终可视化步骤,让聚合数组保持原始量纲;同时它决定了 Embedding 阶段可用的图例类型(linear→线性、log→对数、eq_hist→百分位)。

**Spreading(扩散)**是着色后的常用后处理:把每个非透明像素替换成指定形状(默认圆形,可改方形),解决放大后单点难以辨认的问题:

img = tf.shade(aggc) tf.spread(img) # 默认扩散 1px tf.spread(img, px=2) # 扩散 2px tf.spread(img, px=3, shape='square') tf.spread(img, mask=mask) # 自定义掩膜(须为奇数边长方形)

交互缩放下密度会变化,则用dynspread动态计算扩散尺寸(通过统计"有非掩邻居的非掩 bin 比例"决定)。其他常用图像函数还有tf.set_background(img, "black")(设背景色)、tf.stack(img1, img2, how='over'|'source'|'add'|'saturate')(图像合成)。

5. Embedding(嵌入)

最后一步是把图像嵌入外部绘图库,以获得坐标轴、图例、交互缩放等能力。这一步有多种实现路径,详见下一节。

五、交互式可视化:Bokeh 直连与 HoloViews 高层 API

Getting Started 的第 3 篇 getting_started/3_Interactivity.ipynb 指出:裸图像没有坐标轴与标签,难以解读,而且只是静态图;要把图像嵌入 Matplotlib 或 Bokeh 获得坐标轴与交互能力,最便捷的途径是HoloViews。下图展示了 Datashader 与 HoloViews、Bokeh 三者的分层关系:

1. 原生 Bokeh:InteractiveImage

首先演示 Datashader 自带的原生 Bokeh 支持。核心是编写一个"回调"函数:给定视口范围与像素尺寸,返回一张 Datashader 图像:

def image_callback(x_range, y_range, w, h, name=None): cvs = ds.Canvas(plot_width=w, plot_height=h, x_range=x_range, y_range=y_range) agg = cvs.points(df, 'x', 'y', ds.count_cat('cat')) img = tf.shade(agg) return tf.dynspread(img, threshold=0.50, name=name)

传入不同范围即可得到不同缩放级别的图像(原图 / 缩放到 (0,4) / 缩放到 (1.9,2.1)),可以看到原图中一个"红点"其实是 10 万个重叠点。但用手动猜数值范围的方式探索数据很笨拙,于是引入InteractiveImage:

from datashader.bokeh_ext import InteractiveImage import bokeh.plotting as bp bp.output_notebook() p = bp.figure(tools='pan,wheel_zoom,reset', x_range=(-5,5), y_range=(-5,5), plot_width=500, plot_height=500) InteractiveImage(p, image_callback)

每次缩放/平移,回调都会拿到新的可见视口,Datashader 重新渲染以更新显示——浏览器中始终只存一张图像,却表现成像全部数据都在本地交互。但InteractiveImage有两个明显限制:只能在 Jupyter Notebook 中使用(无法部署到 Bokeh Server),且难以与其他 Bokeh 图组合,因此示例文档明确建议新项目改用 HoloViews 方案。

2. HoloViews + Bokeh:声明式操作符链

HoloViews 采取"数据为中心"的声明式方法:先用hv.Points包装数据,再用datashade等"操作(operation)"动态调用 Datashader:

import holoviews as hv import holoviews.operation.datashader as hd points = hv.Points(df.sample(10000)) hd.datashade(points) # 最简单的 datashader 绘图

hd.datashade不是一次性函数调用,而是每次 Bokeh 需要新图时动态重新执行 Datashader 的操作,无需手写回调。更强大的是操作符可以链式组合:

datashaded = hd.datashade(points, aggregator=ds.count_cat('cat')).redim.range(x=(-5,5), y=(-5,5)) hd.dynspread(datashaded, threshold=0.50, how='over').opts(plot=dict(height=500, width=500))

图例:由于底层绘图库只看到图像,图例需要额外构造——用一组带标签的"哑点"拼出分类色键:

from datashader.colors import Sets1to3 datashaded = hd.datashade(points, aggregator=ds.count_cat('cat'), color_key=Sets1to3) gaussspread = hd.dynspread(datashaded, threshold=0.50, how='over').opts(plot=dict(height=400, width=400)) color_key = [(name, color) for name, color in zip(["d1","d2","d3","d4","d5"], Sets1to3)] color_points = hv.NdOverlay({n: hv.Points([0,0], label=str(n)).opts(style=dict(color=c)) for n, c in color_key}) color_points * gaussspread

Hover 信息:数据一旦变成图像,浏览器层面就没有原始点可以 hover 了。替代方案是对空间区域提供统计信息——用hd.aggregate在网格上计算 count 等统计量,再叠上hv.QuadMesh:

%%opts QuadMesh [tools=['hover']] (alpha=0 hover_alpha=0.2) from holoviews.streams import RangeXY pts = hd.datashade(points, width=400, height=400) (pts * hv.QuadMesh(hd.aggregate(points, width=10, height=10, dynamic=False))).relabel("Fixed hover") + \ (pts * hv.util.Dynamic(hd.aggregate(points, width=10, height=10, streams=[RangeXY]), operation=hv.QuadMesh)).relabel("Dynamic hover")

左图为固定空间尺度的 hover,右图 hover 区域随缩放级别动态缩放,可检查任意小区域,实用性更强。示例还演示了HoloViews + Matplotlib的静态渲染三种等价路径:A)hd.datashade(points)直接聚合着色;B)hd.shade(hv.Image(agg))接收预计算聚合;C)hv.RGB(np.array(tf.shade(agg).to_pil()))接收预计算 PIL 图像。

3. 完整示例:NYC Taxi 十分钟级数据

入门第 1 篇 getting_started/1_Introduction.ipynb 用标准"大数据"例子——纽约 1000 万次出租车行程——展示全程。先用 Pandas 读取数据,仅取dropoff_x/dropoff_y两列(Web Mercator 坐标):

import datashader as ds import pandas as pd from colorcet import fire from datashader import transfer_functions as tf df = pd.read_csv('../data/nyc_taxi.csv', usecols=['dropoff_x', 'dropoff_y']) agg = ds.Canvas().points(df, 'dropoff_x', 'dropoff_y') tf.set_background(tf.shade(agg, cmap=fire), "black")

两行代码即可看到:数据严格对齐街道网格、部分区域流量远高于其他区域、某些街区出现模糊斑块(GPS 误差,可能由高楼遮挡导致)——无需任何参数调优、魔法数字、子采样或近似,分辨率可达显示器极限。在此基础上叠加 Web 墨卡托地图瓦片并接入 HoloViews/GeoViews,即可得到可缩放交互地图:

import holoviews as hv import geoviews as gv from holoviews.operation.datashader import datashade hv.extension('bokeh') url = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.jpg' map_tiles = gv.WMTS(url).opts(style=dict(alpha=0.5)) points = hv.Points(df, ['dropoff_x', 'dropoff_y']) taxi_trips = datashade(points, x_sampling=1, y_sampling=1, cmap=fire, width=1000, height=600) map_tiles * taxi_trips

六、进阶:性能优化与数据准备

1. 存储格式与压缩建议

user_guide/10_Performance.ipynb 给出了基于基准测试的明确建议:大型列式数据集尽量使用 Apache Parquet 格式,配合 fastparquet 与 Snappy 压缩:

import dask.dataframe as dd dd.to_parquet(filename, df, compression="SNAPPY")

分类列(取值有限固定,如 "Male"/"Female")在 Parquet 中使用更省内存的表示,并对排序、去重等常见操作做了优化,保存前把这类列转为categorydtype 即可受益。

2. 读写与聚合基准:filetimes.py

仓库内的 filetimes.py 是一个完整的 I/O 与聚合性能基准工具,用法为:

python filetimes.py <filepath> [pandas|dask [hdf5base [xcolumn [ycolumn [categories...]]]]]

它支持parq、snappy.parq、gz.parq、bcolz、feather、h5、csv七种格式的 pandas/dask 读写计时,并测量 Datashader 聚合耗时、输入/输出文件大小与峰值内存。其命令行参数进一步揭示了 Datashader 性能调优的关键开关:

  • --recalc-ranges:每次聚合时重算范围(默认会缓存范围,从而省掉一次全量扫描——与 README/Getting Started 中"显式指定范围可快约一倍"的建议呼应);
  • --cache=persist:强制把 Dask 数据帧加载进内存;
  • --cache=cachey:使用 Dask 的 cachey 缓存(默认缓存上限 9GB,见脚本中cachesize=9e9);
  • --distributed:启用 Dask 分布式调度器(LocalCluster(n_workers=cpu_count, threads_per_worker=1)),替代默认的线程调度器。

脚本中的聚合函数还演示了范围缓存的实现细节:首次聚合后把Canvas算出的x_range/y_range缓存起来,后续聚合直接复用。

3. 网络包数据预处理:pcap_to_parquet.py

topics/network_packets.ipynb 对应的数据预处理脚本是 pcap_to_parquet.py。它把 PCAP 抓包文本输出转成无向图并保存为 Parquet:

  • 逐行解析,过滤掉unreachable行与非IP记录,识别tcp/udp/eigrp/icmp协议;
  • 用struct.unpack("!I", socket.inet_aton(s))把 IPv4 地址转成整数,并归并源/目标地址(src, dst = sorted(addresses)),保证无向性;
  • 按(protocol, src, dst)键聚合字节数(weight);
  • 输出*_nodes.parq(节点 id 表)与*_edges.parq(source、target、protocol、weight列,protocol转为 category),直接作为 Datashader 网络图示例的输入。

这个脚本是理解"如何把自己的原始数据整理成 Datashader 可用的列式格式"的绝佳范本。

七、Dashboard:零前端代码的交互式数据浏览

仓库内 dashboard.ipynb 提供了一个面向地理数据的交互式 Dashboard 参考实现,其技术栈组合本身就是一个完整的现代可视化应用范式:

  • Intake:通过 dashboard.yml 以文本文件声明各数据集的字段与绘图信息,屏蔽文件格式、路径、列名等细节;
  • Param:声明可调参数及其与代码的依赖关系,构建响应式界面;
  • HoloViews + GeoViews + Datashader + Bokeh:声明式生成基于 Bokeh 的交互图;
  • Panel:把参数控件与图布局成 Dashboard。

在 Notebook 中运行

dataset = os.getenv("DS_DATASET", "nyc_taxi") catalog = intake.open_catalog('dashboard.yml') source = getattr(catalog, dataset) source.to_dask().persist();

在 Notebook 中直接运行explorer.viewable()即可获得可交互的图;调整任一控件(如explorer.spreading=4)会只重跑受影响的代码,而不必重跑整个 Datashader 管线。内存不足 16GB 的机器建议去掉.persist(),让 Dask 走 out-of-core 路径。

独立部署

DS_DATASET=nyc_taxi panel serve --show dashboard.ipynb

nyc_taxi可替换为dashboard.yml中声明的任一数据集:nyc_taxi(完整版)、nyc_taxi_50k(小样本)、census、opensky、osm-1b(十亿点 OpenStreetMap GPS 数据)。同时启动多个实例时需用-p 5001等参数指定不同端口。

dashboard.yml 的声明式数据目录

dashboard.yml 展示了"数据即配置"的思想。以osm-1b为例:

osm-1b: description: 1-billion-point OpenStreetMap GPS dataset driver: parquet args: urlpath: '{{ CATALOG_DIR }}/data/osm-1billion.snappy.parq' columns: ['x','y'] metadata: plot: xlim: !!python/tuple [-8240227, -8231284] ylim: !!python/tuple [ 4974203, 4979238] kind: points plots: counts: label: 1 billion OpenStreetMap GPS locations x: x y: y

每个数据集声明了 driver(parquet/netcdf)、文件路径、坐标列、视野范围(xlim/ylim)、绘图类型与多个可选视图。nyc_taxi条目还演示了多视图(dropoff/pickup)、hover_cols与分类着色(census 的race字段用cmap映射各人种颜色;opensky 的ascending布尔字段用cat_colors区分爬升/下降)。流式场景下,streaming-aggregation.ipynb 与配套的 streaming.py 演示了基于streamz的增量聚合。

八、性能自查:一个可直接上手的最小示例

综合以上各节,一个"跑得又快又准"的 Datashader 工作流通常包含:Parquet + Snappy 存储、category 分类列、显式Canvas范围、how='eq_hist'着色,以及 HoloViews 声明式交互。入门篇的完整骨架如下:

import datashader as ds import datashader.transfer_functions as tf import pandas as pd df = pd.read_csv('user_data.csv') # 或 dd.read_parquet(...) cvs = ds.Canvas(plot_width=400, plot_height=400) # 声明画布(可加 x_range/y_range) agg = cvs.points(df, 'x_col', 'y_col', ds.mean('z_col')) img = tf.shade(agg, cmap=['lightblue', 'darkblue'], how='log')

示例套件中,topics/osm-1billion.ipynb 以 10 亿点 OpenStreetMap GPS 数据展示了 Datashader 在单机(16GB 内存笔记本)上的极限能力;topics/nyc_taxi.ipynb、topics/strange_attractors.ipynb 与 topics/landsat.ipynb 则分别覆盖点、线、栅格三种图元在实际场景中的运用,均可作为上手后的进阶练习。

结语

从本文可以梳理出一条完整的学习与落地路径:先用conda env create --file environment.yml与datashader examples一键获得"环境 + 示例 + 数据"的完整运行栈,再按 Getting Started 三篇依次理解"为什么需要 Datashader → 五阶段管线 → 如何嵌入交互可视化",随后借助 User Guide 深入具体图元(点、时间序列、轨迹、栅格、网格、网络、地理)与性能优化,最后用 Topics 与 Dashboard 作为实战模板。需要再次强调:所有交互式重渲染都依赖实时 Python 进程,离线浏览只能看到固定图像;而数据规模一旦真正达到百万、十亿级,Datashader "先聚合、后着色、再嵌入"的管线设计,将是传统绘图库难以替代的高效答案。

  • 示例工程
  • 数据科学
  • 数据分析

【免费下载链接】Data-Analysis

Data Science Using Python

项目地址:https://gitcode.com/gh_mirrors/da/Data-Analysis
点击查看免费下载
上一篇:HunterPie:终极指南!如何用数据可视化提升《怪物猎人:世界》游戏体验
下一篇:如何通过代码驱动可视化技术提升算法学习效率:深入解析Algorithm Visualizer架构设计

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询