四步走,墨跡天氣雷達數據可視化指南

客戶故事 | 四步走,墨跡天氣雷達數據可視化指南

談起墨跡天氣,想必人人都不陌生,除了展示空氣質量指數(AQI)等天氣相關信息,人們最愛它的短時臨近預報。該預報精準度能夠達到分鐘級別,給咱們的出行帶來了極大的便利。android

短時臨近預報以雷達圖像的形式展示,卻不知,雷達數據是最難在原生 App 中快速呈現的數據之一。墨跡天氣卻克服了這個挑戰,使用 Mapbox GL 實現了在 Mapbox 中國街景地圖(Mapbox Streets Chinese)的快速、流暢、高分辨率的可視化效果,並上線 Android 和 iOS App 中。ios

下面咱們邀請到 Mapbox 中國解決方案工程師 Macro Shen,帶你們詳細剖析一下技術細節吧!git

傳統柵格圖像可視化方案

來自雷達源的數據格式一般是柵格圖像(Raster Image),在對這類數據進行可視化的時候,常見的方法是在地圖上添加多個圖像做爲柵格源,或者生成圖像圖塊並設置每幀顯示不一樣的圖像實現具備延時效果的數據。github

許多天氣 App 都使用相似的辦法來顯示雷達數據,包括墨跡天氣的歷史版本。可是這樣的方案有下面兩個主要缺點:npm

  1. 在縮放放大的時候,分辨率會顯得很低
  2. 動畫效果不夠流暢

那麼 Mapbox 爲墨跡天氣提供了怎樣的解決方案呢?json

矢量瓦片可視化方案

Mapbox 提供了矢量瓦片的解決方案,使數據密集型地圖可以快速渲染。由於 Mapbox 的開源特性,這個過程具有了高度的設計靈活性。api

那麼矢量瓦片爲何會有優點呢?瀏覽器

根據 Mapbox 文檔所述,這些矢量瓦片數據與用於 Web 端展現的圖像是等效的,可是在緩存,縮放和快速呈現地圖圖像方面具備優點。矢量瓦片以緊湊的結構化格式、包含了幾何與元數據,好比道路名稱、地名、門牌號等,只有在客戶端(好比 Web 瀏覽器或者移動 App)請求的時候,纔會呈現矢量切片。渲染過程發生在客戶端(Mapbox GL JS, Mapbox iOS SDK , Mapbox Android SDK)或者動態服務器(map API)上。緩存

相對於完整渲染的柵格圖像,矢量瓦片有下面的兩大優點:服務器

  1. 樣式(Styling):矢量的特性,能夠在被請求的時候再進行樣式化。
  2. 大小(Size):矢量瓦片很是小,可以實現高分辨率地圖、快速地圖加載、高效緩存。

既然如此,咱們能夠經過矢量瓦片可視化雷達數據。

首先,咱們須要將柵格圖像轉換爲矢量格式(GeoJSON),而後生成矢量瓦片。

第一步:矢量化雷達數據

有不少的開源工具可以矢量化柵格圖像。好比 d3-contour 能夠從 Node.js 環境中的圖像生成輪廓多邊形,或者在 Python 環境中使用 numpy / rasterio 從圖像生成像素多邊形。

這是一個使用 d3-contour 的示例代碼:

const contours = require('d3-contour').contours;
let w = 1100;
let h = 900;
let polygons = contours()
    .size([w, h])
    .thresholds(smoothValues)
    (pixel_data);

let resultgeojson = {
    type: 'FeatureCollection',
    features: []
};
polygons.forEach((polygon) => {
    //...
    resultgeojson.features.push({
        type: 'Feature',
        properties: {
            value: polygon.value,
            idx: 0
        },
        geometry: {
            type: 'Polygon',
            coordinates: polygon.coordinates
        }
    });
});
複製代碼

除了矢量化以外,咱們還須要在生成 GeoJSON 數據以前將座標系從像素轉換爲地理座標系。

const proj4 = require('proj4');
let pixel_position = [10, 20];
let geo_position = proj4('EPSG:3857', 'EPSG:4326',[
    minLng + (maxLng - minLng) * (p[0] / w),
    maxLat - (maxLat - minLat) * (p[1] / h)
]);
複製代碼

第二步:對雷達數據進行插值,以平滑過渡

傳統的雷達圖像幀與幀之間的跳動很是明顯,爲了更加平滑的動畫效果,咱們須要提升數據幀的頻率,所以,咱們嘗試建立中間雷達圖像(intermediate radar images)以提升幀率,得到更流暢的動畫效果。而後,咱們運行處理腳本並生成更多向量,動畫就能夠以更多的步驟運行,看起來更流暢。

最簡單的方法是在相鄰幀之間插入數據,以下代碼。

let current_data = [...];//An h * w array from current step of radar image
let next_data = [...];//An h * w array from next step of radar image

let new_data = [];
for (let i = 0; i < h; i++) {
    for (let j = 0; j < w; j++) {
        new_data[i * w + j] = parseInt((current_data[i * w + j] + next_data[i * w + j]) / 2);
    }
}
let polygons = contours()
    .size([w, h])
    .thresholds(smoothValues)
    (new_data);
複製代碼

請注意,咱們在原始幀之間建立了不止一個過渡幀,以實現更流暢的動畫,但代價就是數據大小會增長,這是須要權衡的。

第三步:從 GeoJSON 建立矢量瓦片

咱們這裏使用 tippecanoe 建立矢量瓦片,這個工具很是強大,能從大量的 GeoJSON、Geobuf 或 CSV 特徵集合中建立矢量瓦片。

在 Mac OSX 系統上安裝 tippecanoe 最簡單的辦法就是在 Terminal(終端)中輸入下面的代碼。

$ brew install tippecanoe
複製代碼

安裝好 tippecanoe 以後,咱們用下面的代碼來生成 mbtiles(一種 OSM 中的數據格式,能夠在一個單獨的文件中存放地圖切片)。

$ tippecanoe -o output.mbtiles -zg --drop-densest-as-needed radar.geojso
複製代碼

請注意,-e 可用於將 tile 寫入指定的目錄而不是 mbtiles 文件,想要將矢量瓦片發佈到 Web 服務的開發者可使用這個功能。

第四步:使用 Mapbox 將雷達矢量瓦片可視化

用於 Web 端的 Mapbox GL JS 和用於移動端的 Mapbox Maps SDK for iOS 和 Android 能夠加載雷達矢量瓦片,並將其可視化。

下面是一個使用 Mapbox GL JS 可視化的源碼,也能夠參考一個使用 Maps SDK for Android 的案例

map.addSource('radar-data', {
    type: 'vector',
    url: 'mapbox://examples.dwtmhwpu'
});
map.addLayer({
    "id": "radarpolygon",
    "type": "fill",
    "source": "raddar-data",
    "source-layer": "0",
    "filter": ["==", "idx", 0],
    'layout': {
        "visibility": "visible"
    },
    'paint': {
        'fill-opacity': 0.7,
        'fill-color': [
            "step",
            ["get", "value"],
            "hsl(0, 0%, 100%)", 8,
            "hsl(202, 88%, 51%)", 18,
            "hsl(194, 88%, 51%)", 36,
            "hsl(185, 88%, 51%)", 54,
            "hsl(177, 96%, 53%)", 72,
            "hsl(157, 96%, 53%)", 90,
            "hsl(101, 94%, 65%)", 108,
            "hsl(60, 100%, 49%)", 126,
            "hsl(43, 100%, 49%)", 144,
            "hsl(26, 100%, 49%)", 162,
            "hsl(10, 100%, 49%)", 180,
            "hsl(0, 64%, 43%)", 198,
            "hsl(326, 47%, 29%)", 216,
            "hsl(274, 47%, 29%)", 234,
            "hsl(246, 56%, 35%)"
        ]
    }
}, 'place-village');
複製代碼

最後,咱們使用 Mapbox GL 的 setFilter 功能實現雷達數據的平滑動畫效果。

let theinterval = setInterval(function() {
    map.setFilter('radarpolygon', ['==', 'idx', currentidx]);
}, 500);
複製代碼

下面就是輸出結果,具備更好的用戶體驗,相對於傳統可視化,實現了更加平滑、分辨率更高的渲染效果。

這就是矢量瓦片的魅力,不只僅是雷達圖,也會有不少相似的圖像展現能夠採用這樣的方法,找一個時間試試看?若是你有更多商務方面的問題,歡迎經過 Mapbox 微信公衆號(Mapbox_China)聯繫咱們,關注回覆【技術】便可。

原文:blog.mapbox.com/visualizing…

相關文章
相關標籤/搜索