先來看兩張圖:php
(1)10年世界盃決賽,冠軍西班牙隊中門將、後衛、中場及前鋒的跑位熱圖html
經過熱圖,咱們能夠很清楚的看出四個球員在比賽中跑動位置的差別。git
(2)歷史地震震源位置的熱圖github
也能夠很清楚的看出,哪一個地方是地震的高發地區(頻率最高)。web
上面兩張就是熱圖的典型應用,經過熱圖能夠簡單地聚合大量數據,並使用一種漸進的色帶來優雅地表現,最終效果通常優於離散點的直接顯示,能夠很直觀地展示空間數據的疏密程度或頻率高低。但也因爲很直觀,熱圖在數據表現的準確性並不能保證。api
熱圖已經不是什麼新鮮的概念了,不少領域都在使用。例如記錄用戶在Web頁面內鼠標的點擊位置,各類空間離散點數據的顯示等等。app
其生成的原理簡單歸納爲四個步驟:異步
(1)爲離散點設定一個半徑,建立一個緩衝區;函數
(2)對每一個離散點的緩衝區,使用漸進的灰度帶(完整的灰度帶是0~255)從內而外,由淺至深地填充;post
(3)因爲灰度值能夠疊加(值越大顏色越亮,在灰度帶中則顯得越白。在實際中,能夠選擇ARGB模型中任一通道做爲疊加灰度值),從而對於有緩衝區交叉的區域,能夠疊加灰度值,於是緩衝區交叉的越多,灰度值越大,這塊區域也就越「熱」;
(4)以疊加後的灰度值爲索引,從一條有256種顏色的色帶中(例如彩虹色)映射顏色,並對圖像從新着色,從而實現熱點圖。
能夠經過幾張圖來展示這個過程:
(1)灰度帶和彩虹色帶
(2)單熱點顯示
單熱點的顯示,至少要肯定它的中心灰度值、半徑,固然還有xy和色帶。中心灰度值默認設爲50(過小顯示效果很差)。根據半徑的大小(通常是25,屏幕座標),由中心(50)到邊界(0)漸進地填充灰度。我使用黑色(任何顏色均可以)的Alpha通道來進行灰度值的累加,填充後中心位置的ARGB值是(50,0,0,0),邊界處是(0,0,0,0),這樣就能獲得上圖左邊的灰度圖了。最後根據灰度值映射色帶獲得彩虹帶中對應位置的顏色。50的灰度值,只能映射到彩虹帶的前1/5處,於是上圖右邊單熱點的顏色以藍色爲主,略帶青色。
每一個單一熱點有一個Weight,默認設爲1,目前暫時沒有用到(ArcGIS Flex的熱圖實現中,Weight用來在地圖縮小時累加多個離散點聚合後中心灰度值的大小。我沒去實現地圖縮放的功能,但我以爲Weight會有別的用處,如今還沒徹底考慮好,之後有機會再說)。Weight不是相似一般二維空間數據中的第三維屬性數據,熱圖只能表現離散點空間上的頻率,而不能表現其屬性在空間上的分佈。例如地震震源的熱圖,並不能表示其震級大小的空間分佈,而只能表現地震次數的多少。
(3)多熱點疊加顯示
疊加顯示,點位置及權重是隨機給的,半徑是指定的。圖中有422個點,半徑是50。點越密集的的區域,疊加的灰度也就越多,映射後也顯得比較「熱」。
原理其實蠻簡單的,但實現起來就要考慮一些比較瑣碎的東西(作任何事情都同樣的,看似簡單,作起來結果到處是坑!)。我是用C#和GDI+實現的,網上也有不少實例代碼,常見語言的版本都有,我也從中參考了很多,獲益匪淺。
首先設計一個顏色輔助類ColorUtil:
上面是類中的部分代碼,主要的三個函數,其中,
(1)GetGrayRamp是獲取0~50的單熱點的灰度帶,該灰度帶將用於填充單點的緩衝區;
(2)GetColorInRamp是根據灰度值去色帶中映射顏色(表示色帶的代碼太長了,copy自Esri Flex API的源代碼中);
(3)AdjustOpacity調整圖片的透明度,使用了顏色矩陣。
另外還有一個是HeatMapMaker類:
其中,
(1)makeGrayMap先生成灰度圖,使用了前面生成的灰度帶、半徑以及漸進畫刷;
(2)MakeHeatMap生成熱圖,在灰度圖的基礎上,根據灰度去映射色帶,並調整透明度,獲得最終的熱圖。
還有一些別的代碼,特別是用到了.net 4.5中新的異步功能,可能有所疏漏。話說ms的東西真是簡單,有時簡單到讓人用起來沒底氣。
我把代碼放到了GitHub上(https://github.com/hmfly/HeatMap),歡迎有興趣的同窗fork,或直接戳這裏下載。指出錯誤或繼續改進。固然我本身也會繼續改進。雖然有點重複造輪子的感受,並且我本身也並不喜歡造輪子,但我以爲對有興趣的東西,瞭解其原理、實現方法,也是蠻有意思的事情。何況哪有這麼多創新的東西,真正有創新也是在你充分了解了前人工做的基礎上,加上一點點本身的想法,最終體如今一個點上的微創新吧。
下面是測試界面,能夠控制點數、半徑、透明度及色帶:
測試程序也包含在源代碼中。
最後,感謝如下連接及連接的主人: