據(jù)組織到交互驗(yàn)證)
簡(jiǎn)介這份資源聚焦MATLAB三維數(shù)據(jù)可視化面向需要繪制三維熱力圖的學(xué)生、科研人員與工程技術(shù)人員幫助解決三維曲面數(shù)據(jù)難以直觀呈現(xiàn)的問題。資源包共3個(gè)文件包含1個(gè)m腳本、1個(gè)mat數(shù)據(jù)文件和1個(gè)png效果圖壓縮包約219KB體積輕巧便于快速下載與本地復(fù)現(xiàn)。其中腳本文件演示了從數(shù)據(jù)準(zhǔn)備到繪圖輸出的完整流程mat文件提供可直接加載的示例數(shù)據(jù)png圖片則給出預(yù)期效果參考。核心思路是先對(duì)x軸與y軸數(shù)據(jù)進(jìn)行網(wǎng)格化處理要求兩軸數(shù)組等長通常為1n維z軸數(shù)據(jù)需與網(wǎng)格一一對(duì)應(yīng)一般為nn矩陣再通過surf函數(shù)完成曲面繪制顏色深淺直觀反映z軸數(shù)值大小。目前已有1339人學(xué)習(xí)下載適合作為三維熱力圖入門與課程實(shí)驗(yàn)的參考素材也可在此基礎(chǔ)上替換自有數(shù)據(jù)快速驗(yàn)證可視化效果。1. 三維熱力圖到底在畫什么從一次組會(huì)翻車說起去年幫某實(shí)驗(yàn)室做數(shù)據(jù)可視化A同學(xué)把實(shí)驗(yàn)測(cè)得的溫度場(chǎng)數(shù)據(jù)丟進(jìn)surf直接出圖結(jié)果導(dǎo)師看了一眼說“你這圖看不出任何梯度”。問題不在數(shù)據(jù)在于他把三維熱力圖當(dāng)成了三維曲面圖。三維熱力圖的核心不是把曲面立起來而是用顏色映射表達(dá)第四維數(shù)值——X、Y 是平面坐標(biāo)Z 是高度或任意第三變量顏色才是你要傳達(dá)的熱度信息。MATLAB 里能畫三維熱力圖的函數(shù)不止一個(gè)surf、mesh、pcolor、scatter3、slice各有適用邊界選錯(cuò)了圖數(shù)據(jù)里的規(guī)律就全被埋了。這篇筆記拆的是 MATLAB 三維熱力圖從數(shù)據(jù)組織到出圖調(diào)參的完整鏈路適合手里有矩陣數(shù)據(jù)、需要做溫度場(chǎng)/應(yīng)力場(chǎng)/密度分布可視化的從業(yè)者也適合剛接觸 MATLAB 繪圖、被colormap和shading搞暈的新手。下面按“數(shù)據(jù)怎么擺 → 圖怎么選 → 參數(shù)怎么調(diào) → 坑在哪”的順序推一遍每一步都給可復(fù)現(xiàn)的代碼。2. 數(shù)據(jù)組織與函數(shù)選型矩陣朝向決定圖的方向2.1 三維熱力圖的數(shù)據(jù)本質(zhì)是三個(gè)矩陣MATLAB 畫三維熱力圖底層吃的是三個(gè)同尺寸矩陣X、Y定義網(wǎng)格坐標(biāo)Z或C定義每個(gè)網(wǎng)格點(diǎn)上的數(shù)值。很多人第一次翻車就翻在矩陣朝向——meshgrid生成的X、Y和從文件讀進(jìn)來的數(shù)據(jù)矩陣維度對(duì)不上圖要么轉(zhuǎn) 90 度要么直接報(bào)維度不匹配。常見做法是先用meshgrid把坐標(biāo)軸向量展開成網(wǎng)格矩陣再確認(rèn)數(shù)據(jù)矩陣的行列與X、Y一致。% 定義坐標(biāo)軸向量 x linspace(0, 10, 50); % X 方向 50 個(gè)采樣點(diǎn) y linspace(0, 5, 30); % Y 方向 30 個(gè)采樣點(diǎn) % 展開成網(wǎng)格矩陣注意 meshgrid 的輸出順序 [X, Y] meshgrid(x, y); % X 和 Y 都是 30x50 矩陣 % 構(gòu)造一個(gè)模擬溫度場(chǎng)中心高、邊緣低疊加一點(diǎn)波動(dòng) Z 80 * exp(-((X-5).^2 (Y-2.5).^2) / 8) 5 * sin(X) .* cos(Y); % 確認(rèn)維度 disp(size(X)); % 30 50 disp(size(Z)); % 30 50這段代碼里meshgrid(x, y)返回的X是 30×50行數(shù)對(duì)應(yīng)y的長度列數(shù)對(duì)應(yīng)x的長度。Z必須同尺寸否則surf(X,Y,Z)會(huì)直接報(bào)錯(cuò)。參數(shù)上linspace的第三個(gè)參數(shù)決定網(wǎng)格分辨率——50×30 大概夠看趨勢(shì)如果要出論文圖建議至少 200×200否則顏色過渡會(huì)有明顯棱角。exp那項(xiàng)模擬高斯熱源sin、cos疊加的是噪聲波動(dòng)實(shí)際數(shù)據(jù)換成你的測(cè)量矩陣即可。2.2 surf、mesh、pcolor、scatter3 怎么選選錯(cuò)函數(shù)是三維熱力圖最常見的“玄學(xué)”來源。surf畫的是帶顏色映射的曲面適合連續(xù)場(chǎng)數(shù)據(jù)顏色和高度綁定mesh只畫網(wǎng)格線顏色默認(rèn)不映射數(shù)值想看拓?fù)浣Y(jié)構(gòu)時(shí)用pcolor本質(zhì)是二維偽彩色圖在三維視角下是平的適合俯視看分布scatter3畫散點(diǎn)每個(gè)點(diǎn)單獨(dú)著色適合不規(guī)則采樣點(diǎn)slice做切片適合三維體數(shù)據(jù)內(nèi)部結(jié)構(gòu)。函數(shù)適用場(chǎng)景顏色是否映射數(shù)值數(shù)據(jù)要求surf連續(xù)曲面場(chǎng)是規(guī)則網(wǎng)格mesh看網(wǎng)格拓?fù)淠J(rèn)否規(guī)則網(wǎng)格pcolor俯視分布是規(guī)則網(wǎng)格scatter3散點(diǎn)采樣是任意點(diǎn)集slice體數(shù)據(jù)切片是三維體矩陣我一般先問一句你的數(shù)據(jù)是規(guī)則網(wǎng)格還是散點(diǎn)規(guī)則網(wǎng)格優(yōu)先surf散點(diǎn)優(yōu)先scatter3體數(shù)據(jù)用slice。如果只是想在平面上看顏色分布pcolor加view(2)比硬轉(zhuǎn)三維更清晰。2.3 從文件讀數(shù)據(jù)時(shí)的維度對(duì)齊實(shí)際項(xiàng)目里數(shù)據(jù)多半從 CSV 或 MAT 文件來。CSV 讀進(jìn)來是二維矩陣行是 Y、列是 X直接丟給surf沒問題但要注意meshgrid的X、Y順序別搞反。% 從 CSV 讀取溫度場(chǎng)數(shù)據(jù)假設(shè)第一行是 X 坐標(biāo)第一列是 Y 坐標(biāo) raw readmatrix(temperature_field.csv); x_vec raw(1, 2:end); % 第一行去掉左上角空位 y_vec raw(2:end, 1); % 第一列去掉左上角空位 Z raw(2:end, 2:end); % 數(shù)據(jù)塊 % 用實(shí)際坐標(biāo)向量生成網(wǎng)格 [X, Y] meshgrid(x_vec, y_vec); % 檢查維度是否匹配 assert(isequal(size(X), size(Z)), X 與 Z 維度不匹配檢查 CSV 行列方向);readmatrix是 R2019a 之后推薦的讀法老版本用csvread或xlsread。assert那行是后悔藥——維度不匹配時(shí)直接報(bào)錯(cuò)比等到surf報(bào)一堆看不懂的錯(cuò)要快。如果 CSV 里第一行第一列是表頭文字readmatrix會(huì)自動(dòng)處理成NaN這時(shí)候用raw(1,2:end)取坐標(biāo)向量剛好跳過。3. 出圖與調(diào)參colormap、shading、光照三件套3.1 基礎(chǔ)出圖與顏色映射數(shù)據(jù)擺好之后最簡(jiǎn)出圖就一行surf(X,Y,Z)但默認(rèn)的parula色圖未必適合你的數(shù)據(jù)。溫度場(chǎng)常用jet或hot應(yīng)力場(chǎng)常用coolwarm風(fēng)格MATLAB 內(nèi)置的turbo在 R2020b 之后可用色彩過渡比jet均勻。figure(Position, [100 100 800 600]); surf(X, Y, Z, EdgeColor, none); % 去掉網(wǎng)格線避免干擾顏色 colormap(turbo); % 用 turbo 色圖 colorbar; % 顯示顏色條 xlabel(X (mm)); ylabel(Y (mm)); zlabel(溫度 (°C)); title(三維溫度場(chǎng)分布); view(-37.5, 30); % 設(shè)置視角方位角 -37.5仰角 30EdgeColor設(shè)為none是關(guān)鍵一步——默認(rèn)surf會(huì)畫黑色網(wǎng)格線數(shù)據(jù)點(diǎn)一多就糊成一片顏色信息全被蓋住。view的兩個(gè)參數(shù)分別是方位角和仰角-37.5, 30是 MATLAB 默認(rèn)三維視角想突出某個(gè)方向可以調(diào)比如view(0, 90)就是正俯視等價(jià)于看pcolor。colorbar建議每次都加否則讀者不知道顏色對(duì)應(yīng)什么數(shù)值范圍。3.2 shading 與 lighting讓曲面不再“塑料感”默認(rèn)surf出圖是平面著色每個(gè)網(wǎng)格面一個(gè)顏色網(wǎng)格密的時(shí)候還好網(wǎng)格稀的時(shí)候能看到明顯色塊。shading interp做顏色插值過渡平滑shading flat是默認(rèn)shading faceted保留網(wǎng)格線。配合light和lighting能做出立體感。surf(X, Y, Z, EdgeColor, none); shading interp; % 顏色插值過渡平滑 colormap(turbo); light(Position, [1 1 1], Style, infinite); % 加一個(gè)無限遠(yuǎn)光源 lighting gouraud; % 逐頂點(diǎn)光照比 phong 快 material dull; % 材質(zhì)設(shè)為啞光避免高光過曝 colorbar;shading interp在數(shù)據(jù)量大時(shí)會(huì)讓渲染變慢如果只是快速看趨勢(shì)用默認(rèn)flat就行。lighting gouraud和lighting phong的區(qū)別在于計(jì)算方式gouraud逐頂點(diǎn)算、快phong逐像素算、慢但更細(xì)膩。material dull去掉鏡面高光適合科學(xué)可視化想要金屬質(zhì)感可以用material shiny但溫度場(chǎng)一般不需要。3.3 顏色范圍與非線性映射有時(shí)候數(shù)據(jù)動(dòng)態(tài)范圍很大比如大部分區(qū)域在 20 到 30 之間少數(shù)熱點(diǎn)到 200線性色圖會(huì)把大部分區(qū)域壓成一個(gè)顏色。這時(shí)候要么手動(dòng)設(shè)caxis要么用對(duì)數(shù)映射。% 手動(dòng)限制顏色范圍突出關(guān)鍵區(qū)間 caxis([20 60]); % 只映射 20 到 60 的顏色超出部分用端點(diǎn)色 % 對(duì)數(shù)映射適合跨數(shù)量級(jí)的數(shù)據(jù) Z_log log10(Z - min(Z(:)) 1); % 平移后取對(duì)數(shù)避免負(fù)值 surf(X, Y, Z_log, EdgeColor, none); colormap(turbo); colorbar; title(對(duì)數(shù)映射后的溫度場(chǎng));caxis在 R2022a 之后改名為clim老版本用caxis新版本兩個(gè)都能用但clim更推薦。對(duì)數(shù)映射那行min(Z(:))取全局最小值做平移保證對(duì)數(shù)輸入非負(fù)1是防止log10(0)報(bào)負(fù)無窮。如果數(shù)據(jù)里有負(fù)值先平移再取對(duì)數(shù)別直接log。3.4 導(dǎo)出高分辨率圖與視角復(fù)現(xiàn)出圖之后導(dǎo)出是另一個(gè)坑。saveas導(dǎo)出的分辨率不可控論文投稿一般要求 300 dpi 以上。用exportgraphics或print更穩(wěn)。% 方法一exportgraphicsR2020a 之后推薦 exportgraphics(gcf, thermal_3d.png, Resolution, 300); % 方法二print老版本通用 print(gcf, thermal_3d.tif, -dtiff, -r300); % 保存視角下次直接復(fù)現(xiàn) view_angle get(gca, View); save(view_setting.mat, view_angle); % 下次加載 load(view_setting.mat); view(view_angle);exportgraphics的Resolution參數(shù)單位是 dpi300 夠大部分期刊用。print的-r300同理。保存視角這個(gè)習(xí)慣是我被反復(fù)要求“把圖轉(zhuǎn)回上次那個(gè)角度”之后養(yǎng)成的get(gca,View)拿到當(dāng)前方位角和仰角存成 MAT 文件下次view(view_angle)直接還原省得來回拖鼠標(biāo)。4. 避坑與排查那些讓圖“看起來不對(duì)”的細(xì)節(jié)4.1 圖是全黑的或者顏色只有一種現(xiàn)象surf出圖后整個(gè)曲面是單一顏色colorbar顯示范圍正常但圖上沒變化。原因通常是數(shù)據(jù)矩陣?yán)锼兄祹缀跸嗤蛘遚axis被設(shè)成了極窄區(qū)間。解決先disp([min(Z(:)), max(Z(:))])看數(shù)據(jù)范圍如果范圍正常但圖沒變化檢查caxis是否被之前的代碼改過用caxis auto恢復(fù)自動(dòng)范圍。另一個(gè)可能是EdgeColor沒關(guān)網(wǎng)格線太密蓋住了顏色。4.2 曲面有黑色網(wǎng)格線干擾顏色現(xiàn)象數(shù)據(jù)點(diǎn)一多圖上全是黑線顏色看不清。原因surf默認(rèn)EdgeColor是黑色網(wǎng)格密的時(shí)候線比面還顯眼。解決surf(..., EdgeColor, none)或者用shading interp配合EdgeColor設(shè)為none。如果還想保留一點(diǎn)網(wǎng)格感可以把EdgeColor設(shè)成k但LineWidth調(diào)到 0.1不過一般直接關(guān)掉最干凈。4.3 顏色條范圍和實(shí)際數(shù)據(jù)對(duì)不上現(xiàn)象colorbar顯示 0 到 100但數(shù)據(jù)明明只到 60。原因caxis被手動(dòng)設(shè)過沒恢復(fù)或者多個(gè)子圖共用一個(gè)colorbar時(shí)范圍被最后一個(gè)圖覆蓋。解決每次出圖前caxis auto或者顯式caxis([min(Z(:)) max(Z(:))])。多子圖場(chǎng)景用linkaxes或統(tǒng)一設(shè)clim別讓 MATLAB 自己猜。4.4 導(dǎo)出圖片分辨率不夠或白邊太大現(xiàn)象saveas導(dǎo)出的 PNG 放大后模糊或者圖周圍白邊占了一半。原因saveas默認(rèn)屏幕分辨率且figure的Position沒設(shè)好。解決用exportgraphics指定Resolution同時(shí)設(shè)figure(Position,[100 100 800 600])控制畫布比例。白邊問題可以用exportgraphics的Padding參數(shù)或者導(dǎo)出后用圖像工具裁但最好在figure階段就把Position調(diào)合適。4.5 大數(shù)據(jù)量渲染卡死現(xiàn)象網(wǎng)格超過 500×500 后旋轉(zhuǎn)視角卡頓shading interp直接卡死。原因surf渲染的面片數(shù)是網(wǎng)格數(shù)的四倍左右interp還要額外插值計(jì)算。解決出圖前用downsample降采樣或者改用pcolor加view(2)看分布三維只用來確認(rèn)趨勢(shì)。如果必須保留高分辨率用reducepatch減面或者導(dǎo)出時(shí)用opengl硬件加速opengl hardware。5. 進(jìn)階技巧把三維熱力圖做成可交互的驗(yàn)證工具出靜態(tài)圖只是第一步真正省時(shí)間的是把圖變成能轉(zhuǎn)、能查數(shù)值的交互工具。MATLAB 的rotate3d on是最簡(jiǎn)單的交互但只能轉(zhuǎn)視角查不了具體點(diǎn)的數(shù)值。我一般用datacursormode加自定義回調(diào)鼠標(biāo)點(diǎn)哪個(gè)點(diǎn)就顯示坐標(biāo)和數(shù)值。figure; surf(X, Y, Z, EdgeColor, none); shading interp; colormap(turbo); colorbar; % 開啟數(shù)據(jù)游標(biāo) dcm_obj datacursormode(gcf); set(dcm_obj, UpdateFcn, myDataCursor); function txt myDataCursor(~, event_obj) pos event_obj.Position; txt {[X: num2str(pos(1), %.2f)], ... [Y: num2str(pos(2), %.2f)], ... [Z: num2str(pos(3), %.2f)]}; enddatacursormode的回調(diào)函數(shù)接收event_objPosition是當(dāng)前點(diǎn)的三維坐標(biāo)返回的txt是顯示在游標(biāo)旁邊的文字。num2str的%.2f控制小數(shù)位數(shù)數(shù)據(jù)精度高就多留幾位。這個(gè)工具在排查異常點(diǎn)時(shí)特別有用——圖上看某個(gè)區(qū)域顏色異常鼠標(biāo)一點(diǎn)就知道具體數(shù)值不用回去翻原始矩陣。另一個(gè)進(jìn)階用法是把多個(gè)切面疊在一起看內(nèi)部結(jié)構(gòu)。slice函數(shù)可以在三維體數(shù)據(jù)里切任意平面配合contourslice還能在切面上畫等值線。% 構(gòu)造三維體數(shù)據(jù) [x, y, z] meshgrid(-2:0.2:2, -2:0.2:2, -2:0.2:2); V x .* exp(-x.^2 - y.^2 - z.^2); % 在三個(gè)方向各切一刀 figure; slice(x, y, z, V, [-1 0 1], 0, 0); shading interp; colormap(turbo); colorbar; view(-37.5, 30);slice的前三個(gè)參數(shù)是網(wǎng)格第四個(gè)是體數(shù)據(jù)后面三組是切面位置——[-1 0 1]表示在 X 方向切三刀0表示 Y 方向切一刀0表示 Z 方向切一刀。切面位置可以按需改比如想看中心截面就設(shè)0想看邊緣就設(shè)±1.5。shading interp對(duì)slice同樣有效能讓切面顏色過渡更自然。驗(yàn)證三維熱力圖對(duì)不對(duì)我有個(gè)習(xí)慣先看colorbar范圍是否和數(shù)據(jù)min/max一致再用datacursormode隨機(jī)點(diǎn)幾個(gè)點(diǎn)核對(duì)原始矩陣值最后轉(zhuǎn)一圈視角確認(rèn)沒有遮擋導(dǎo)致的誤判。從那以后我每次出三維熱力圖都強(qiáng)制走一遍“范圍核對(duì) → 游標(biāo)抽查 → 多視角確認(rèn)”省得被問“這個(gè)顏色對(duì)應(yīng)多少度”時(shí)答不上來。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取