mcpField
M
mapbox-data-visualization-patterns

mapbox-data-visualization-patterns

github.com/mapbox数据与数据库832.1k 次安装4 周前更新
代码仓库

关于 mapbox-data-visualization-patterns

为使用 Mapbox 地图进行数据可视化的开发者提供模式指南,涵盖专题图、热力图、3D 表达和动态样式,并包含大型数据集的性能建议。

主要功能

  1. 01专题分级设色地图
  2. 02热力图与点聚类
  3. 033D 挤出与数据驱动样式
  4. 04时间序列动画
  5. 05大型数据集性能优化
  6. 06提供图例及可视化参考

适用场景

  1. 01按区域比较人口或销售数据
  2. 02展示事件位置密度
  3. 03按属性设置地图要素样式
  4. 04呈现随时间变化的数据
  5. 05优化大型地图数据的加载与显示

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-data-visualization-patterns

安装后在 Claude Code 中输入/mapbox-data-visualization-patterns确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

AGENTS.md
evals/
evals.json
references/
3d-extrusions.md
animation.md
circles-lines.md
clustering.md
legends-use-cases.md
performance.md

详细介绍

数据可视化模式技能

全面介绍在 Mapbox 地图上可视化数据的模式,涵盖分级统计图、热力图、3D 拉伸、数据驱动样式、动态可视化,以及面向数据密集型应用的性能优化。

何时使用此技能

在以下情况下使用此技能:

  • 在地图上可视化统计数据(人口、销售额、人口统计数据)
  • 创建以颜色标示区域的分级统计图
  • 构建热力图或聚类图以可视化密度
  • 添加 3D 可视化(建筑高度、地形高程)
  • 根据属性实现数据驱动样式
  • 为时间序列数据添加动画
  • 处理需要优化的大型数据集

可视化类型

分级统计图

最适合: 区域数据(州、县、邮政编码区域)、统计对比

模式: 根据数据值为多边形着色

map.on('load', () => {
  // Add data source (GeoJSON with properties)
  map.addSource('states', {
    type: 'geojson',
    data: 'https://example.com/states.geojson' // Features with population property
  });

  // Add fill layer with data-driven color
  map.addLayer({
    id: 'states-layer',
    type: 'fill',
    source: 'states',
    paint: {
      'fill-color': [
        'interpolate',
        ['linear'],
        ['get', 'population'],
        0,
        '#f0f9ff', // Light blue for low population
        500000,
        '#7fcdff',
        1000000,
        '#0080ff',
        5000000,
        '#0040bf', // Dark blue for high population
        10000000,
        '#001f5c'
      ],
      'fill-opacity': 0.75
    }
  });

  // Add border layer
  map.addLayer({
    id: 'states-border',
    type: 'line',
    source: 'states',
    paint: {
      'line-color': '#ffffff',
      'line-width': 1
    }
  });

  // Add hover effect with reusable popup
  const popup = new mapboxgl.Popup({
    closeButton: false,
    closeOnClick: false
  });

  map.on('mousemove', 'states-layer', (e) => {
    if (e.features.length > 0) {
      map.getCanvas().style.cursor = 'pointer';

      const feature = e.features[0];
      popup
        .setLngLat(e.lngLat)
        .setHTML(
          `
          <h3>${feature.properties.name}</h3>
          <p>Population: ${feature.properties.population.toLocaleString()}</p>
        `
        )
        .addTo(map);
    }
  });

  map.on('mouseleave', 'states-layer', () => {
    map.getCanvas().style.cursor = '';
    popup.remove();
  });
});

step 与 interpolate: 上面的示例使用 interpolate 创建平滑的颜色渐变。对于离散的颜色分档(例如“低/中/高”),改用 ['step', ['get', 'population'], '#f0f0f0', 500000, '#fee0d2', 2000000, '#fc9272', 10000000, '#de2d26']。当数据具有自然分类,或需要关注精确的边界值时,优先使用 step。

颜色比例尺策略:

// Linear interpolation (continuous scale)
'fill-color': [
  'interpolate',
  ['linear'],
  ['get', 'value'],
  0, '#ffffcc',
  25, '#78c679',
  50, '#31a354',
  100, '#006837'
]

// Step intervals (discrete buckets)
'fill-color': [
  'step',
  ['get', 'value'],
  '#ffffcc',  // Default color
  25, '#c7e9b4',
  50, '#7fcdbb',
  75, '#41b6c4',
  100, '#2c7fb8'
]

// Case-based (categorical data)
'fill-color': [
  'match',
  ['get', 'category'],
  'residential', '#ffd700',
  'commercial', '#ff6b6b',
  'industrial', '#4ecdc4',
  'park', '#45b7d1',
  '#cccccc'  // Default
]
热力图

最适合: 点密度、事件位置、事故聚类

模式: 可视化点的密度

map.on('load', () => {
  // Add data source (points)
  map.addSource('incidents', {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: [-122.4194, 37.7749]
          },
          properties: {
            intensity: 1
          }
        }
        // ... more points
      ]
    }
  });

  // Add heatmap layer
  map.addLayer({
    id: 'incidents-heat',
    type: 'heatmap',
    source: 'incidents',
    maxzoom: 15,
    paint: {
      // Increase weight based on intensity property
      'heatmap-weight': ['interpolate', ['linear'], ['get', 'intensity'], 0, 0, 6, 1],
      // Increase intensity as zoom level increases
      'heatmap-intensity': ['interpolate', ['linear'], ['zoom'], 0, 1, 15, 3],
      // Color ramp for heatmap
      'heatmap-color': [
        'interpolate',
        ['linear'],
        ['heatmap-density'],
        0,
        'rgba(33,102,172,0)',
        0.2,
        'rgb(103,169,207)',
        0.4,
        'rgb(209,229,240)',
        0.6,
        'rgb(253,219,199)',
        0.8,
        'rgb(239,138,98)',
        1,
        'rgb(178,24,43)'
      ],
      // Adjust radius by zoom level
      'heatmap-radius': ['interpolate', ['linear'], ['zoom'], 0, 2, 15, 20],
      // Decrease opacity at higher zoom levels
      'heatmap-opacity': ['interpolate', ['linear'], ['zoom'], 7, 1, 15, 0]
    }
  });

  // Add circle layer for individual points at high zoom
  map.addLayer({
    id: 'incidents-point',
    type: 'circle',
    source: 'incidents',
    minzoom: 14,
    paint: {
      'circle-radius': ['interpolate', ['linear'], ['zoom'], 14, 4, 22, 30],
      'circle-color': '#ff4444',
      'circle-opacity': 0.8,
      'circle-stroke-color': '#fff',
      'circle-stroke-width': 1
    }
  });
});

最佳实践

颜色无障碍
// Use ColorBrewer scales for accessibility
// https://colorbrewer2.org/

// Good: Sequential (single hue)
const sequentialScale = ['#f0f9ff', '#bae4ff', '#7fcdff', '#0080ff', '#001f5c'];

// Good: Diverging (two hues)
const divergingScale = ['#d73027', '#fc8d59', '#fee08b', '#d9ef8b', '#91cf60', '#1a9850'];

// Good: Qualitative (distinct categories)
const qualitativeScale = ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00'];

// Avoid: Red-green for color-blind accessibility
// Use: Blue-orange or purple-green instead
错误处理
// Handle missing or invalid data
map.on('load', () => {
  map.addSource('data', {
    type: 'geojson',
    data: dataUrl
  });

  map.addLayer({
    id: 'data-viz',
    type: 'fill',
    source: 'data',
    paint: {
      'fill-color': [
        'case',
        ['has', 'value'], // Check if property exists
        ['interpolate', ['linear'], ['get', 'value'], 0, '#f0f0f0', 100, '#0080ff'],
        '#cccccc' // Default color for missing data
      ]
    }
  });

  // Handle map errors
  map.on('error', (e) => {
    console.error('Map error:', e.error);
  });
});

数据大小规则

  • < 1 MB:直接使用 GeoJSON
  • 1–10 MB:根据复杂程度考虑使用 GeoJSON 或矢量瓦片
  • > 10 MB:使用矢量瓦片(将数据上传到 Mapbox,作为瓦片集)

实现详情请参阅 references/performance.md。

参考文件

如需更多可视化模式,请加载相关参考文件:

资源

评论

支持 Markdown