轉(zhuǎn)換到等值線填充)
簡介本資源是一套基于MATLAB實現(xiàn)三元相圖可視化繪制的完整代碼實踐包面向計算機、電子信息工程、應(yīng)用數(shù)學(xué)等專業(yè)的本科生與研究生適用于課程設(shè)計、期末大作業(yè)及畢業(yè)設(shè)計中的材料科學(xué)或熱力學(xué)可視化需求。壓縮包共34個文件包含10個核心MATLAB腳本.m、23張示例輸出圖像.png及1份說明文檔.md總大小2.18MB其中STernary.m為通用三元坐標(biāo)繪圖函數(shù)多個ternDemo*.m文件覆蓋不同數(shù)據(jù)格式與標(biāo)注風(fēng)格的典型用例PNG圖像直觀展示各類相圖效果便于快速驗證與參考。已有630人學(xué)習(xí)下載資源結(jié)構(gòu)清晰、即開即用提供從原始數(shù)據(jù)輸入、坐標(biāo)變換、區(qū)域著色到標(biāo)簽標(biāo)注的全流程實現(xiàn)邏輯特別適合具備MATLAB基礎(chǔ)、需自主調(diào)試與拓展功能的學(xué)習(xí)者作為技術(shù)參照。 打開那份掛著“源碼圖片”字樣的壓縮包之前我一直覺得用Matlab畫三元相圖應(yīng)該跟普通散點圖差不多找個自帶函數(shù)直接畫就完事。真正上手才發(fā)現(xiàn)Matlab并沒有內(nèi)置“三元坐標(biāo)軸”這樣現(xiàn)成的圖形類型所有三角形邊框、刻度線、網(wǎng)格線都要自己一筆一畫算出來。這也是為什么網(wǎng)上能找到一堆零散代碼但很少有人把完整邏輯講清楚。這個項目標(biāo)題很典型說明很多做材料、化工、地質(zhì)、食品、制藥相關(guān)實驗的人都會遇到同一個需求手里有A、B、C三個組分的比例數(shù)據(jù)想把它們展示在一個等邊三角形里順便把相邊界、等溫線這類信息也疊上去。這篇文章我就把整個方案拆開揉碎從數(shù)學(xué)原理講到完整可運行的代碼再講我實際調(diào)試時踩過的坑。適合那些剛接觸三元相圖或者已經(jīng)會畫散點但想進一步畫等值線、填充相區(qū)的讀者。1. 為什么說畫三元相圖的關(guān)鍵是坐標(biāo)轉(zhuǎn)換1.1 三元相圖在表達什么從成分點到相區(qū)邊界三元相圖的本質(zhì)是把三組分體系的成分信息映射到一個等邊三角形平面里。比如一個體系包含A、B、C三種物質(zhì)三角形三個頂點分別代表純A、純B、純C三角形內(nèi)部任意一個點就代表一組具體的三元比例比如40% A、30% B、30% C。在實際科研和工程里這種圖最常見的用途是看“相區(qū)”也就是在什么樣的成分組合下體系處于單相區(qū)、兩相區(qū)還是三相區(qū)。材料科學(xué)里的合金設(shè)計、物理化學(xué)里的液液相平衡、制藥領(lǐng)域的輔料配比篩選都會用到。很多人一開始以為三元相圖很復(fù)雜其實它跟普通二維圖最大的區(qū)別只有一個普通圖用兩個正交坐標(biāo)軸表達兩個變量而三元相圖用三個“非正交”的方向表達三個組分只不過這三個組分之間有一個天然的約束——加起來等于100%。因為有這個約束三元體系真正的自由度只有兩個所以它在二維平面上完全可以表達。這個“壓縮到二維平面”的過程就是坐標(biāo)轉(zhuǎn)換。1.2 等邊三角形坐標(biāo)系的幾何直覺我習(xí)慣先畫一個等邊三角形來找感覺。假設(shè)三個頂點分別記作頂點A、頂點B、頂點C那么三角形內(nèi)任意一點P它距離三條邊的相對位置就可以對應(yīng)三組分的含量。越靠近頂點AA的占比越高越靠近對邊BCA的占比越低。這種“距離定比例”的直覺真正轉(zhuǎn)換到計算機坐標(biāo)里卻有個麻煩我們知道的是三組分比例比如A0.4、B0.3、C0.3這是一個三維空間里的點在平面上的投影。計算機畫圖時只知道x軸和y軸沒有“三角形坐標(biāo)”這種原生概念所以必須先找到一個映射關(guān)系把三維的比例坐標(biāo)映射到二維的屏幕坐標(biāo)。等邊三角形的好處是三個方向?qū)ΨQ刻度均勻。很多人問為什么不用等腰直角三角形用當(dāng)然可以用但三個軸的比例尺會變得不均勻刻度間隔也難統(tǒng)一不利于閱讀。所以絕大多數(shù)三元相圖都默認(rèn)畫成等邊三角形。1.3 Matlab沒有原生三元坐標(biāo)軸所以要自己做變換Matlab的plot、scatter、contourf這類函數(shù)全部建立在直角坐標(biāo)系上。你給它們一個三元比例它們并不知道這個比例應(yīng)該畫在哪。我們需要的是先把三元比例換算成直角坐標(biāo)再調(diào)用普通的繪圖函數(shù)。這就是整個項目里最核心、也最容易被忽略的技術(shù)點。很多網(wǎng)上的半成品代碼問題都出在這一步有人直接把A含量當(dāng)x、B含量當(dāng)y畫出來是一個被壓縮變形的直角坐標(biāo)圖根本不是三元相圖有人轉(zhuǎn)換公式寫錯了數(shù)據(jù)全落在三角形外還有人算對了坐標(biāo)但忘了歸一化導(dǎo)致ABC不等于1時整個圖形比例混亂。所以這篇文章所有代碼都圍繞一個核心函數(shù)展開——ternary2cartesian它負(fù)責(zé)把任意三元比例映射到二維坐標(biāo)。只要這個函數(shù)是對的后面所有畫邊框、畫網(wǎng)格、畫等值線都只是沿用它。2. 坐標(biāo)轉(zhuǎn)換公式與刻度網(wǎng)格的完整推導(dǎo)2.1 從三元比例到二維坐標(biāo)的矩陣表達我先給出最常用的等邊三角形坐標(biāo)定義。設(shè)三個頂點的二維坐標(biāo)分別為頂點A代表100% A在 (1, 0)頂點B代表100% B在 (0.5, sqrt(3)/2)頂點C代表100% C在 (0, 0)這個三角形是一個邊長1的等邊三角形底邊是C到A右斜邊是A到B左斜邊是B到C看起來比較舒服?,F(xiàn)在給定任意一組三元比例 a、b、c它們可以是0到1之間的小數(shù)也可以是0到100之間的百分?jǐn)?shù)。只要先做歸一化得到三者比例歸一化后的值a_norm a / (a b c) b_norm b / (a b c) c_norm c / (a b c)那么該點在二維直角坐標(biāo)系里的坐標(biāo)就是x a_norm * 1 b_norm * 0.5 c_norm * 0 y a_norm * 0 b_norm * sqrt(3)/2 c_norm * 0翻譯成代碼非常簡潔function [x, y] ternary2cartesian(a, b, c) % 輸入三組分比例歸一化后轉(zhuǎn)換為二維直角坐標(biāo) total a b c; if any(total(:) 0) error(三元比例之和不能為0); end a a ./ total; b b ./ total; x a 0.5 * b; y (sqrt(3) / 2) * b; end注意這里c沒有直接出現(xiàn)在x、y表達式里因為c被約束為1 - a - b只要a和b確定c自然確定。這也再次說明三元體系只有兩個自由度。很多初學(xué)者會堅持把c也寫進公式最后反而把坐標(biāo)搞亂。如果你不喜歡這個頂點位置想把三角形擺成正三角形且三個頂點均勻分布也可以換一套坐標(biāo)比如把頂點A放正上方、頂點B放右下、頂點C放左下。但代碼邏輯完全一樣只是三個頂點的二維坐標(biāo)不同。我建議統(tǒng)一用上面這套因為x坐標(biāo)在0到1之間y坐標(biāo)在0到0.866之間后續(xù)做插值、裁剪都很方便。2.2 刻度位置為什么用線性插值三角形邊框畫好后需要加刻度線。三元相圖的刻度跟普通坐標(biāo)軸不太一樣它沿三條邊分布C-A邊反映的是C和A的比例變化B為0A-B邊反映的是A和B的比例變化C為0B-C邊反映的是B和C的比例變化A為0每條邊上的刻度位置本質(zhì)上就是“在兩個頂點之間做線性插值”。這個思想很關(guān)鍵因為它不需要重新推導(dǎo)任何幾何公式只要知道兩個端點的坐標(biāo)就能算出任意比例對應(yīng)的位置。以A-B邊為例假設(shè)要從A點走向B點步長參數(shù)t從0變到1當(dāng)t0時在A點當(dāng)t1時在B點。如果要在A-B邊上標(biāo)出“B含量為20%”的刻度因為B頂點本身代表100% BA頂點代表0% B所以這個刻度點的參數(shù)就是t 0.2坐標(biāo)就是P (1 - t) * 頂點A坐標(biāo) t * 頂點B坐標(biāo)寫成代碼p (1 - t) * v(1, :) t * v(2, :);其中v矩陣保存三個頂點的坐標(biāo)。同理B-C邊上的“C含量”刻度也是從B點向C點插值C-A邊上的“A含量”刻度從C點向A點插值。這里面有個容易搞混的細(xì)節(jié)不同邊上的插值方向決定了t對應(yīng)的是哪一個組分。比如A-B邊上t對應(yīng)B含量B-C邊上t對應(yīng)C含量C-A邊上t對應(yīng)A含量。方向反了刻度標(biāo)簽的位置就會錯位畫出來特別別扭。我自己的做法是固定按“前一個頂點到后一個頂點”的方向插值并在注釋里寫清楚每一段對應(yīng)哪個組分。2.3 網(wǎng)格線的參數(shù)化算法三元相圖里的網(wǎng)格線通常是一組平行于三角形三條邊的虛線分別表示A、B、C某一組分的恒定比例線。例如“A20%”的網(wǎng)格線是所有A含量為20%的點連成的線段它平行于B-C邊。畫這些線的參數(shù)化算法也很直觀。以“固定A含量”為例假設(shè)A比例固定為a那么B含量b可以從0掃到1-a對應(yīng)的C含量就是c 1 - a - b。每取一個b就得到一個三元比例(a, b, c)調(diào)用ternary2cartesian得到二維坐標(biāo)把所有點連起來就是一條平行于B-C邊的線段。代碼大概是這樣的思路function plot_ternary_grid(step) vals step:step:(100-step); % 固定A for a vals bVec linspace(0, 100 - a, 50); cVec 100 - a - bVec; [x, y] ternary2cartesian(a * ones(size(bVec)), bVec, cVec); plot(x, y, --, Color, [0.8 0.8 0.8]); end % 固定B、固定C同理 end注意這一步不需要特別精確到50個點因為三元比例到二維坐標(biāo)是線性變換連線段只需要兩個端點就夠了。用linspace(0, 100-a, 2)完全可以但多取幾個點也不會出錯反而在某些邊緣情況下看起來更平滑。網(wǎng)格線要不要畫取決于你的圖用途。如果只是展示散點成分網(wǎng)格會顯得擁擠如果是做相圖分析網(wǎng)格線能幫助讀者快速讀取某個點的大致成分建議保留。網(wǎng)格線的密度用步長10%比較合適我用過5%的整張圖會糊成一片。3. 完整源碼實現(xiàn)從0到1搭一個三元相圖繪制函數(shù)3.1 第一個函數(shù)坐標(biāo)轉(zhuǎn)換與基礎(chǔ)畫布我建議把這套代碼拆成幾個獨立函數(shù)放在同一個文件夾里這樣以后畫任何三元圖都能復(fù)用。第一個函數(shù)就是前面寫的ternary2cartesian它只做坐標(biāo)轉(zhuǎn)換不畫任何圖形保證單純可靠。第二個函數(shù)負(fù)責(zé)畫三角形邊框、刻度和頂點標(biāo)簽我叫它ternary_axes。這個函數(shù)的關(guān)鍵點是畫完邊框后要用axis equal保證橫縱比例一致否則等邊三角形會被拉成歪三角形。然后用axis off把默認(rèn)坐標(biāo)刻度隱藏否則會在圖旁邊出現(xiàn)一堆多余的x、y數(shù)值。頂點標(biāo)簽我習(xí)慣用英文大寫字母A、B、C放在頂點外側(cè)稍遠(yuǎn)的位置避免跟網(wǎng)格線重疊。function h ternary_axes(tickStep) % 繪制等邊三角形邊框、刻度和頂點標(biāo)簽 if nargin 1 tickStep 10; end v [1, 0; 0.5, sqrt(3)/2; 0, 0]; % 頂點A、B、C hold on; axis equal; axis off; % 邊框 plot(v([1 2 3 1], 1), v([1 2 3 1], 2), k-, LineWidth, 1.5); % 刻度 labels tickStep:tickStep:(100-tickStep); for k 1:length(labels) t labels(k) / 100; % AB邊從A到Bt對應(yīng)B含量 pAB (1 - t) * v(1, :) t * v(2, :); % BC邊從B到Ct對應(yīng)C含量 pBC (1 - t) * v(2, :) t * v(3, :); % CA邊從C到At對應(yīng)A含量 pCA (1 - t) * v(3, :) t * v(1, :); % 畫短刻度線這里簡化處理用小圓點代替 plot(pAB(1), pAB(2), k., MarkerSize, 8); plot(pBC(1), pBC(2), k., MarkerSize, 8); plot(pCA(1), pCA(2), k., MarkerSize, 8); % 刻度標(biāo)簽 text(pAB(1), pAB(2) - 0.02, num2str(labels(k)), FontSize, 8, ... HorizontalAlignment, center); text(pBC(1) - 0.02, pBC(2), num2str(labels(k)), FontSize, 8, ... HorizontalAlignment, right); text(pCA(1), pCA(2) - 0.02, num2str(labels(k)), FontSize, 8, ... HorizontalAlignment, center); end % 頂點標(biāo)簽 text(v(1,1) 0.04, v(1,2) - 0.04, A, FontSize, 14, FontWeight, bold); text(v(2,1), v(2,2) 0.04, B, FontSize, 14, FontWeight, bold); text(v(3,1) - 0.04, v(3,2) - 0.04, C, FontSize, 14, FontWeight, bold); end這里刻度線我用了小圓點而不是真正的短線段嚴(yán)謹(jǐn)一點應(yīng)該畫垂直于邊的短線但圓點在大多數(shù)情況下已經(jīng)能看得清楚。如果你要發(fā)表在期刊上建議改成真正的刻度短線垂直于邊向外延伸大約0.02個單位這樣更符合期刊制圖規(guī)范。3.2 第二個函數(shù)散點、網(wǎng)格、自定義標(biāo)簽基礎(chǔ)畫布有了接下來是往圖上添加核心內(nèi)容。我把網(wǎng)格和散點分開寫這樣用戶可以自由選擇疊加哪些元素。網(wǎng)格函數(shù)plot_ternary_grid負(fù)責(zé)畫三組平行虛線。散點函數(shù)ternary_scatter則是對scatter的封裝輸入三組分比例內(nèi)部自動轉(zhuǎn)換坐標(biāo)再畫點。function h ternary_scatter(a, b, c, varargin) % 三元散點圖繪制 [x, y] ternary2cartesian(a, b, c); h scatter(x, y, varargin{:}); end如果你需要在每個點旁邊標(biāo)上樣品編號或名稱可以再寫一個ternary_textfunction ternary_text(a, b, c, labels) % 在三元散點旁添加文本標(biāo)簽 [x, y] ternary2cartesian(a, b, c); text(x, y, labels, FontSize, 9, HorizontalAlignment, left, ... VerticalAlignment, bottom, Clipping, on); end注意Clipping設(shè)置為on防止某些標(biāo)簽跑到三角形外面去。標(biāo)簽重疊是常見問題尤其當(dāng)樣品點密集時我會先做一個簡單的偏移或抖動或者用Matlab的text函數(shù)逐點微調(diào)位置。更高級的方案是用開源布局算法做標(biāo)簽避讓但大多數(shù)時候手動微調(diào)夠用了。3.3 運行結(jié)果和圖形說明把所有函數(shù)組合起來一個最基本的調(diào)用腳本長這樣% 模擬一組樣品成分?jǐn)?shù)據(jù) A [10, 20, 30, 40, 50, 60, 70, 80, 55, 65]; B [30, 40, 20, 10, 40, 20, 10, 10, 25, 15]; C 100 - A - B; figure; ternary_axes(10); plot_ternary_grid(10); hold on; ternary_scatter(A, B, C, 60, filled, ... MarkerFaceColor, [0.8500 0.3250 0.0980], ... MarkerEdgeColor, k);運行后你會看到一張標(biāo)準(zhǔn)的等邊三角形圖底邊C-A、右斜邊A-B、左斜邊B-C網(wǎng)格線交叉樣品點落在對應(yīng)成分位置。這就是三元相圖最基礎(chǔ)、最常用的樣式。有兩點經(jīng)驗供參考。第一scatter的MarkerFaceColor可以選擇帶透明的顏色比如[0.8500 0.3250 0.0980]這樣多個點重疊也能看出密集程度。第二如果樣品點很多比如上千個建議把MarkerEdgeColor改成none否則全部描邊會讓圖看起來很臟。4. 進階把溫度、濃度等第四維信息畫進三元相圖4.1 用scatteredInterpolant做三角形區(qū)域插值單純畫散點只能展示成分分布但很多相圖真正的價值在于展示某個性質(zhì)隨成分的變化比如液相線溫度、黏度、界面張力、析出率。這類數(shù)據(jù)通常只在有限幾個成分點上測得要畫成平滑的等值線圖必須先做插值。我推薦用Matlab自帶的scatteredInterpolant。它接受散點的x、y坐標(biāo)和對應(yīng)的z值生成一個插值函數(shù)之后可以在這個函數(shù)上取任意位置的值。F scatteredInterpolant(xData, yData, zData);其中xData、yData是三元數(shù)據(jù)轉(zhuǎn)換后的二維坐標(biāo)zData是對應(yīng)點的性質(zhì)值。默認(rèn)插值方法是線性如果想要平滑曲面可以換成natural。但要注意如果原始數(shù)據(jù)信噪比很低插值曲面會有一堆毛刺我一般建議先用二次多項式擬合一個趨勢面再畫插值結(jié)果。4.2 等溫線、等值線的繪制代碼繪制等值線的基本流程是在三角形覆蓋的矩形區(qū)域內(nèi)生成規(guī)則網(wǎng)格點調(diào)用插值函數(shù)計算這些網(wǎng)格點上的z值裁剪掉三角形外部區(qū)域用contourf或contour繪制等值線我直接給一個能跑的完整例子。這個例子里我用了一個模擬的z值函數(shù)實際使用時替換成你的實驗數(shù)據(jù)即可。% 生成模擬散點數(shù)據(jù) A rand(200,1) * 100; B rand(200,1) * (100 - A); C 100 - A - B; [x, y] ternary2cartesian(A, B, C); % 模擬性質(zhì)值例如液相線溫度 Z 30 0.4*A 0.6*B 0.3*C 0.005*A.*B - 0.002*C.^2 randn(size(A))*2; % 構(gòu)造插值函數(shù) F scatteredInterpolant(x, y, Z, natural); % 生成三角形區(qū)域內(nèi)的網(wǎng)格點 [xq, yq] meshgrid(0:0.005:1, 0:0.005:0.866); in inpolygon(xq, yq, [1 0.5 0], [0 0.866 0]); zq F(xq, yq); zq(~in) NaN; % 繪圖 figure; hold on; ternary_axes(10); contourf(xq, yq, zq, 15, LineWidth, 0.5); % 再把散點疊上去 ternary_scatter(A, B, C, 20, filled, MarkerFaceColor, k);這里有幾個細(xì)節(jié)值得說。第一meshgrid生成的是直角坐標(biāo)系下覆蓋三角形的規(guī)則網(wǎng)格但插值函數(shù)只能保證在原有數(shù)據(jù)凸包范圍內(nèi)有效三角形邊界附近可能因為缺少數(shù)據(jù)點出現(xiàn)明顯畸變這需要通過合理設(shè)計實驗點來避免。第二inpolygon裁剪很重要如果不裁剪圖會出現(xiàn)一個矩形的彩色背景而不是三角形區(qū)域。第三contourf的等值線數(shù)量要適當(dāng)15層左右對于大多數(shù)相圖來說已經(jīng)足夠太多容易顯得雜亂。4.3 相區(qū)填充與圖例標(biāo)注的小技巧等值線只是第四維信息的一種表達方式。另一種常見需求是給不同相區(qū)填充不同顏色比如把單相區(qū)涂成淺藍色把兩相區(qū)涂成淺黃色。這本質(zhì)上是一個多邊形填充問題只要知道相區(qū)邊界上的點坐標(biāo)按順序連成一個封閉多邊形用patch或fill填充即可。patch(xPolygon, yPolygon, [0.8 0.9 1], EdgeColor, k, LineWidth, 1);這里最容易犯的錯誤是頂點順序錯亂。patch要求多邊形頂點按順時針或逆時針連續(xù)排列如果順序亂了會出現(xiàn)填充區(qū)域互相交叉的亂象。我在實際畫相區(qū)時會先在一個臨時圖上畫邊界散點確認(rèn)走向后再生成封閉多邊形。圖例方面我一般不用Matlab自帶legend。三元相圖的圖例經(jīng)常要放在三角形外面但三角形圖本身信息密度高旁邊的空白區(qū)域有限。我習(xí)慣手動用text加注釋或者用annotation在figure級別放置這樣靈活性更高。5. 踩坑與排查為了這組圖我交過的學(xué)費5.1 圖全跑到三角形外面去了這是新手最容易遇到的問題。數(shù)據(jù)點畫出來后全都落在三角形外面或者有一部分在三角形外面。通常原因有兩個一個是忘了歸一化比如ABC的和等于200但你的輸入沒有除以總和另一個是三元比例里混入了非法值比如某些樣品本來就是二元體系C0那么點會落在三角形邊上這不算錯誤但看慣了內(nèi)部散點的人會誤以為數(shù)據(jù)有問題。排查方法很簡單在調(diào)用ternary2cartesian之前先檢查輸入數(shù)據(jù)的最小值和最大值并打印總和范圍。如果總和不是100也不是1說明數(shù)據(jù)不干凈。還可以對轉(zhuǎn)換后的x、y坐標(biāo)做一次范圍檢查正常情況下x的范圍是0到1y的范圍是0到0.866超出這個范圍一定有問題。5.2 網(wǎng)格線把圖搞得沒法看網(wǎng)格線本身不會出錯但參數(shù)選不好會讓圖很難看。我試過把網(wǎng)格步長設(shè)成2%結(jié)果整張圖被密密麻麻的虛線蓋住數(shù)據(jù)點完全淹沒在網(wǎng)格里。后來我調(diào)整了策略網(wǎng)格步長設(shè)為10%而且把網(wǎng)格線顏色設(shè)成淺灰色線型用點線而不是虛線這樣既有參考價值又不搶主數(shù)據(jù)的注意力。另外如果圖形要投期刊很多雜志要求網(wǎng)格線不可見或者只能有少量刻度輔助線。這時候可以做一個總的開關(guān)參數(shù)發(fā)布前把網(wǎng)格關(guān)掉只保留邊框和刻度。5.3 中文標(biāo)簽變成方框Matlab默認(rèn)字體在Windows下對中文支持不夠好經(jīng)常出現(xiàn)標(biāo)簽全是空心方框的情況。這個問題在繪制三元相圖時特別突出因為相圖里的組分名常常是化學(xué)式或材料名如果不是純英文很容易踩雷。最簡單粗暴的解決辦法是圖內(nèi)標(biāo)簽全部用英文或希臘字母比如A、B、C組分名用元素符號替代。如果一定要顯示中文用set(gca, FontName, SimHei)或text(..., FontName, SimHei)指定中文字體。我常用的是SimHei和Microsoft YaHei前者是黑體后者是微軟雅黑在大多數(shù)Windows機器上都有。5.4 萬級散點數(shù)據(jù)畫不動三元相圖不總是只有幾十個點有時候我們會在一個體系里做幾千甚至上萬個成分點的計算比如用熱力學(xué)計算軟件掃出整個相圖區(qū)域。這時候scatter的渲染速度會明顯下降圖片縮放也會卡頓。我的優(yōu)化方案有三個方向第一如果數(shù)據(jù)點不需要精確到每個像素就用先抽樣再繪圖的方法比如從一萬個點里隨機抽2000個畫出來趨勢基本不變第二用密度圖的思路把三角形區(qū)域劃分成小格子統(tǒng)計每個格子里有多少個點然后用patch或pcolor畫密度色塊觀感比裸散點更好第三把圖形導(dǎo)出為矢量圖時不要直接導(dǎo)出散點圖先縮小Marker尺寸再導(dǎo)出不然生成的文件會非常大。5.5 等值線插值結(jié)果在邊界上異常突起用scatteredInterpolant做插值靠近三角形邊界的區(qū)域經(jīng)常會出現(xiàn)不自然的突起或凹陷原因是邊界附近缺少數(shù)據(jù)點插值函數(shù)在數(shù)據(jù)稀疏區(qū)域會表現(xiàn)得很不穩(wěn)定。我常用的緩解辦法是在實驗設(shè)計階段就確保邊界上有足夠的采樣點比如在每條邊上等間隔多測幾個點。如果數(shù)據(jù)已經(jīng)固定無法補測可以嘗試用帶約束的插值方法比如先用fit做一個二項式曲面擬合再在擬合結(jié)果上畫等值線?;蛘吒纱鄬⑦吔缣幍臄?shù)據(jù)點做一次鏡像補充在三角形外對稱地補幾個虛擬點插值結(jié)果會更平滑。這個方法比較“野”但我在實際中確實用過效果不錯。提示補充虛擬點時建議保持z值不變或者按照插值趨勢外推不要隨意編造數(shù)值否則可能引入錯誤信息。6. 最后說點個人習(xí)慣做這套代碼的過程中我最大的體會是三元相圖的難點不在繪圖本身而在坐標(biāo)轉(zhuǎn)換以及對數(shù)據(jù)規(guī)范性的理解。只要把ternary2cartesian這個函數(shù)想透了其他所有環(huán)節(jié)都是錦上添花。我現(xiàn)在拿到一份三元數(shù)據(jù)第一件事不是畫圖而是先做數(shù)據(jù)檢查算一遍各組分的總和、范圍看看有沒有NaN和負(fù)值。這些臟數(shù)據(jù)如果不處理后面畫出來的圖怎么修飾都沒用。代碼組織上我習(xí)慣把所有三元繪圖相關(guān)的函數(shù)放在一個獨立的文件夾里比如叫ternary_plot_tools里面只放函數(shù)文件。每個腳本通過addpath引入這個文件夾這樣多個項目可以共用同一套繪圖邏輯改一個刻度樣式所有圖全部同步。最后再分享一個小技巧當(dāng)你需要生成多張三元相圖批量輸出時可以寫一個簡單的循環(huán)把數(shù)據(jù)文件逐個讀進來然后調(diào)用同一套繪圖函數(shù)最后用exportgraphics導(dǎo)出PNG。這樣一天出幾十張圖也不用手工改圖了。導(dǎo)出時分辨率建議至少300dpi期刊夠用屏幕上看也清晰。本文還有配套的精品資源點擊獲取