
1. 項目概述為什么平面填充圖值得你花時間掌握在數據可視化和工程繪圖中我們常常需要展示一個區域的范圍、數據的分布區間或者幾個變量之間的重疊關系。這時候線條圖就顯得有些單薄了。比如你想展示一天內不同溫度區間的持續時間或者一個機械部件在應力下的安全區域又或者是幾組數據置信區間的對比。在這些場景下平面填充圖——也就是用顏色或圖案填充一個封閉區域——能瞬間讓信息的層次和對比變得一目了然。MATLAB作為科學計算和工程繪圖的利器提供了不止一種方式來實現平面填充。新手可能會在fill、area、patch這幾個函數之間犯迷糊而老手也可能對如何精確控制填充的邊界、顏色透明度Alpha以及處理復雜多邊形時遇到的“空洞”問題感到頭疼。我見過不少工程師和研究人員他們的數據本身很漂亮但最終呈現的圖表卻因為填充效果不佳而大打折扣要么邊界鋸齒明顯要么顏色搭配突兀要么在多圖疊加時一團糟。這篇內容我就結合自己多年在仿真報告和論文配圖中的實戰經驗帶你從零開始徹底搞懂MATLAB里繪制平面填充圖的那些門道。我們不止要會畫還要畫得精準、畫得美觀、畫得高效。無論你是要處理簡單的三角填充還是復雜的、帶孔洞的多邊形區域甚至是動態變化的填充動畫這里都有可以直接“抄作業”的解決方案和避坑指南。2. 核心函數選型fill、area與patch的深度解析當你決定要畫一個填充圖時面對fill、area和patch這三個核心函數第一反應可能是“用哪個都一樣”。但實際上它們的設計初衷和適用場景有顯著區別選錯了工具后續的精細調整會事倍功半。2.1 fill函數多邊形填充的“直球選手”fill函數是最直觀的“填充”命令。它的邏輯非常簡單你給我一系列點的坐標我按順序把它們連起來形成一個封閉多邊形然后把里面涂上顏色。它的基本語法是fill(X, Y, C)。其中X和Y是頂點的坐標向量C則指定顏色。關鍵點在于對C的理解。C可以是一個顏色字符如‘r’代表紅色或RGB向量如[1 0 0]這時整個多邊形被填充為單一顏色。但C也可以是一個與X、Y長度相同的向量這時MATLAB會進行顏色插值填充。這是fill一個強大但常被忽略的特性。% 示例1單一顏色填充一個五邊形 theta linspace(0, 2*pi, 6); % 6個點首尾重合形成5邊 x cos(theta); y sin(theta); figure fill(x, y, ‘cyan‘) % 填充為青色 axis equal title(‘單一顏色填充‘) % 示例2根據頂點數據插值填充模擬高度場 x2 [0 1 1 0]; y2 [0 0 1 1]; c2 [0 0.3 0.7 1]; % 每個頂點對應一個標量值 figure fill(x2, y2, c2, ‘EdgeColor‘, ‘none‘) % 關閉邊線更清晰 colorbar title(‘基于頂點數據的插值填充‘)在示例2中MATLAB根據四個頂點處的c2值在四邊形內部進行了平滑的線性插值生成了一個顏色漸變的效果。這非常適合用于可視化像溫度場、高度場這類在空間上連續變化的數據。實操心得使用fill時務必確保X和Y向量的首尾點坐標相同以形成封閉圖形。雖然MATLAB有時會自動閉合但顯式聲明是良好的習慣能避免意外。另外‘EdgeColor‘屬性常用于控制多邊形邊線的顏色設為‘none‘可以得到無邊框的純色塊這在多層疊加時非常有用。2.2 area函數堆疊與基線填充的“專業戶”area函數生來就是為了處理“堆積面積圖”和“與基線圍成的區域”。它的核心思想是有一條基線默認為Y軸的0然后填充從基線到數據點之間的區域。語法area(X, Y)會繪制一條曲線并填充曲線和X軸之間的面積。它的強大之處在于自動堆疊。當你傳入一個矩陣Y給area時它會將每一列的數據在上一列的基礎上進行堆疊直觀展示各組成部分對總量的貢獻。這是fill函數需要復雜計算才能實現的功能。% 示例繪制堆疊面積圖展示三類產品季度銷量貢獻 quarters 1:4; productA [20 25 22 30]; productB [15 18 25 22]; productC [10 22 18 25]; Y_matrix [productA‘, productB‘, productC‘]; % 轉換為列向量組 figure area(quarters, Y_matrix) legend(‘產品A‘, ‘產品B‘, ‘產品C‘, ‘Location‘, ‘northwest‘) xlabel(‘季度‘) ylabel(‘銷量‘) title(‘季度銷量堆疊面積圖‘)在這段代碼中area自動完成了堆疊計算。第一個區域是產品A的銷量第二個區域是從產品A的頂部即其數據點開始向上堆疊產品B的銷量以此類推。圖形清晰地展示了總銷量增長的同時各產品份額的變化。注意事項area的基線可以通過area(X, Y, baseline)來指定其中baseline是一個標量。這在你想展示數據相對于某個特定閾值如盈虧平衡線的分布時非常方便。但要注意area填充的區域邊界是由折線連接的如果你需要非常平滑的曲線邊界可能需要先使用spline等工具對數據進行插值再用fill繪制。2.3 patch函數底層圖形對象的“萬能瑞士軍刀”如果說fill和area是便捷工具那么patch就是背后的底層圖形對象。事實上fill函數創建的就是一個patch圖形對象。patch的語法更底層功能也更強大尤其是在處理多面體、復雜多邊形帶孔洞以及設置頂點和面片數據時。patch有兩種主要的數據組織方式頂點模式類似于fill指定每個頂點的坐標 (XData,YData) 和顏色。當頂點共享時這種方式效率高。面片-頂點模式這是處理復雜形狀的推薦方式。你需要定義兩個矩陣一個Vertices矩陣存儲所有頂點的坐標每行一個點一個Faces矩陣定義每個面由哪些頂點索引構成每行定義一個面。這種方式可以高效地描述共享頂點的多個多邊形。% 示例使用面片-頂點模式繪制兩個共享一條邊的三角形 vertices [0 0; 1 0; 0.5 1; 1.5 0.5]; % 4個頂點 faces [1 2 3; 2 4 3]; % 第一個三角形由頂點1,2,3構成第二個由2,4,3構成 figure p patch(‘Faces‘, faces, ‘Vertices‘, vertices, ‘FaceColor‘, ‘flat‘, ... ‘FaceVertexCData‘, [1 0 0; 0 1 0; 0 0 1; 1 1 0], ‘EdgeColor‘, ‘k‘); axis equal title(‘使用Patch面片-頂點模式繪制共享邊的三角形‘)在這個例子中我們只定義了4個頂點但通過faces矩陣復用頂點2和3構造了兩個相鄰的三角形。‘FaceColor‘, ‘flat‘配合‘FaceVertexCData‘可以為每個面或每個頂點指定獨立的顏色。選型總結追求簡單快捷填充任意多邊形用fill。繪制與基線圍成的區域或堆疊面積圖用area。需要處理復雜幾何體、帶孔洞的多邊形或進行極精細的圖形屬性控制如每頂點顏色用patch。3. 從入門到精通平面填充圖的完整繪制流程掌握了核心工具我們來走一遍從數據準備到圖形輸出的完整流程。我將以一個工程中常見的場景為例可視化某個傳感器信號及其置信區間。3.1 數據準備與邊界計算假設我們有一組時間序列信號y以及通過某種算法計算出的上界y_upper和下界y_lower構成了信號的置信帶。我們的目標是填充上下界之間的區域。首先我們需要構造填充多邊形的頂點坐標。填充區域的邊界由[time, y_upper]和[time, flip(y_lower)]兩條曲線圍成。這里的關鍵技巧是使用flip函數將下界數據反轉從而與上界數據首尾相連形成一個閉合的多邊形路徑。% 生成示例數據 time linspace(0, 10, 100); % 時間軸100個點 y sin(time) 0.1 * randn(size(time)); % 帶噪聲的信號 y_upper y 0.3; % 置信上界 y_lower y - 0.3; % 置信下界 % 構造填充多邊形的完整坐標 X_fill [time, fliplr(time)]; % 注意fliplr用于行向量 Y_fill [y_upper, fliplr(y_lower)];fliplr左右翻轉確保了當我們從時間起點走到終點繪制上界然后需要“折返”回來繪制下界時下界的點是從終點反向回到起點從而與起點閉合。3.2 基礎圖形繪制與屬性設置有了頂點數據我們就可以用fill函數進行繪制了。基礎繪制之后立即進行屬性設置是獲得專業圖表的關鍵。figure(‘Position‘, [100 100 800 400]) % 設置圖形窗口大小和位置 hold on % 保持圖形以便疊加繪制信號線 % 1. 繪制填充區域 h_fill fill(X_fill, Y_fill, [0.8 0.9 1], ‘EdgeColor‘, ‘none‘, ‘DisplayName‘, ‘95% 置信區間‘); % [0.8 0.9 1] 是一個淺藍色的RGB值比純‘b‘更柔和。 % ‘EdgeColor‘, ‘none‘ 移除多邊形邊線使填充區域更干凈。 % ‘DisplayName‘ 為圖例準備標簽。 % 2. 繪制原始信號線 h_line plot(time, y, ‘b-‘, ‘LineWidth‘, 1.5, ‘DisplayName‘, ‘傳感器信號‘); hold off % 3. 設置圖形屬性 xlabel(‘時間 (s)‘, ‘FontSize‘, 11) ylabel(‘信號幅值‘, ‘FontSize‘, 11) title(‘傳感器信號及其置信區間‘, ‘FontSize‘, 12, ‘FontWeight‘, ‘bold‘) legend(‘show‘, ‘Location‘, ‘best‘) % 顯示圖例 grid on box on % 給坐標區加上邊框這里有幾個細節顏色選擇直接使用‘b‘藍色填充可能過于刺眼且與信號線顏色沖突。我選擇了一個RGB向量[0.8 0.9 1]這是一個非常淺的藍色既能清晰標識區域又不會喧賓奪主。繪圖順序先畫填充 (fill)再畫線條 (plot)。因為fill創建的是面片對象默認會遮擋住之前繪制的線條。通過hold on和調整繪圖順序可以確保信號線在填充區域之上清晰可見。圖例通過‘DisplayName‘屬性預先為圖形對象設置好標簽最后用legend(‘show‘)一鍵生成圖例比事后用legend({‘A‘, ‘B‘})的方式更不容易出錯。3.3 高級美化透明度、漸變色與多圖層疊加基礎圖形已經可用但要達到出版物或報告級別還需要進一步美化。3.3.1 使用透明度Alpha當有多個填充區域重疊時透明度至關重要。它允許你看到重疊部分避免信息被完全遮擋。% 假設有第二個置信區間例如99%區間 y_upper2 y 0.5; y_lower2 y - 0.5; X_fill2 [time, fliplr(time)]; Y_fill2 [y_upper2, fliplr(y_lower2)]; figure hold on h_fill1 fill(X_fill, Y_fill, [0.8 0.9 1], ‘EdgeColor‘, ‘none‘, ‘FaceAlpha‘, 0.6, ‘DisplayName‘, ‘95% CI‘); h_fill2 fill(X_fill2, Y_fill2, [1 0.9 0.8], ‘EdgeColor‘, ‘none‘, ‘FaceAlpha‘, 0.4, ‘DisplayName‘, ‘99% CI‘); h_line plot(time, y, ‘k-‘, ‘LineWidth‘, 1.5, ‘DisplayName‘, ‘Signal‘); hold off xlabel(‘Time‘); ylabel(‘Amplitude‘); legend(‘show‘); grid on;‘FaceAlpha‘屬性值在0完全透明到1完全不透明之間。這里95%區間用了0.6的透明度99%區間用了更低的0.4使得更寬的區間顏色更淡視覺層次分明。3.3.2 創建顏色漸變填充雖然fill的插值填充可以實現漸變但有時我們需要更復雜的漸變方向如從上到下。這時可以借助patch和顏色映射。% 創建一個從紅色漸變到黃色的垂直漸變填充矩形 x_rect [0 1 1 0]; y_rect [0 0 2 2]; z_rect zeros(size(x_rect)); % 對于2DZ坐標可以設為0 % 為每個頂點分配一個顏色索引對應colormap中的行 c_rect [1; 1; 64; 64]; % 頂點1和2用colormap第1行紅色頂點3和4用第64行黃色 figure p patch(x_rect, y_rect, z_rect, c_rect, ‘FaceColor‘, ‘interp‘, ‘EdgeColor‘, ‘none‘); colormap(jet(64)) % 使用64色的jet色圖你也可以用parula, hot等 axis equal colorbar這里的關鍵是‘FaceColor‘, ‘interp‘它告訴MATLAB在頂點顏色之間進行插值。c_rect是一個與頂點數相同的列向量其值映射到當前色圖 (colormap) 的索引上。3.3.3 多圖層疊加的順序控制圖形對象的繪制順序 (Children屬性) 決定了誰在上層。默認后繪制的在上層。你可以手動調整順序。% 假設繪制順序亂了填充區域蓋住了重要的標記點 figure hold on h_fill fill(X_fill, Y_fill, ‘y‘); h_scatter scatter(time(1:10:end), y(1:10:end), 40, ‘r‘, ‘filled‘); % 一些散點 hold off % 此時散點可能被填充區域遮擋 % 將散點對象提到最前面 ax gca; ax.Children [h_scatter; h_fill]; % 調整子對象順序通過直接操作坐標軸的Children屬性你可以精確控制所有圖形對象的疊放次序。4. 實戰進階處理復雜多邊形與孔洞問題在實際應用中你遇到的填充區域可能不是簡單的凸多邊形。例如地理信息系統中的區域、機械零件的截面常常是帶有“孔洞”的復雜多邊形。MATLAB的patch函數是處理這類問題的唯一選擇但它對頂點順序有嚴格要求。4.1 繪制帶孔洞的多邊形MATLAB規定定義帶孔洞多邊形時外邊界頂點按逆時針順序排列內邊界孔洞頂點按順時針順序排列并且用一個NaN分隔不同的邊界。% 定義一個帶矩形孔洞的方形多邊形 % 外邊界方形逆時針 outer_x [0 3 3 0 0]; outer_y [0 0 3 3 0]; % 內邊界孔洞矩形順時針 inner_x [1 2 2 1 1]; inner_y [1 1 2 2 1]; % 合并邊界用NaN分隔 x_complex [outer_x, NaN, inner_x]; y_complex [outer_y, NaN, inner_y]; figure patch(x_complex, y_complex, ‘green‘, ‘EdgeColor‘, ‘black‘, ‘LineWidth‘, 1) axis equal title(‘帶矩形孔洞的多邊形‘)NaN在這里起到了“提筆”的作用告訴MATLAB當前邊界已結束下一個點開始是新的邊界。務必遵守頂點順序規則否則填充結果會出錯可能孔洞區域也被填充。4.2 從離散點云生成填充邊界邊界提取與簡化很多時候你的數據不是現成的邊界點而是一堆離散的、定義了一個區域的點云。你需要從這些點中提取出用于填充的邊界。boundary函數和convhull函數是得力助手。convhull計算凸包即包含所有點的最小凸多邊形。boundary更靈活它通過 alpha shape 算法可以生成更貼合點云形狀的邊界可以是凹的。它有一個關鍵參數k或shrink factor(s) 來控制邊界的緊密度。% 生成一個非凸的點云例如月牙形 theta linspace(0.2*pi, 1.8*pi, 50)‘; x_cloud [cos(theta); 0.5*cos(theta)0.5]; y_cloud [sin(theta); 0.5*sin(theta)]; % 添加一些噪聲 x_cloud x_cloud 0.05*randn(size(x_cloud)); y_cloud y_cloud 0.05*randn(size(y_cloud)); figure subplot(1,3,1) scatter(x_cloud, y_cloud, ‘.‘) title(‘原始點云‘) axis equal % 使用 convhull 計算凸包 k_conv convhull(x_cloud, y_cloud); subplot(1,3,2) scatter(x_cloud, y_cloud, ‘.‘) hold on plot(x_cloud(k_conv), y_cloud(k_conv), ‘r-‘, ‘LineWidth‘, 2) fill(x_cloud(k_conv), y_cloud(k_conv), ‘r‘, ‘FaceAlpha‘, 0.3) hold off title(‘凸包邊界‘) axis equal % 使用 boundary 計算更貼合的邊界 (shrink factor0.5) k_bound boundary(x_cloud, y_cloud, 0.5); % shrink factor 越小邊界越緊縮 subplot(1,3,3) scatter(x_cloud, y_cloud, ‘.‘) hold on plot(x_cloud(k_bound), y_cloud(k_bound), ‘g-‘, ‘LineWidth‘, 2) fill(x_cloud(k_bound), y_cloud(k_bound), ‘g‘, ‘FaceAlpha‘, 0.3) hold off title(‘boundary函數邊界 (s0.5)‘) axis equal通過調整boundary的收縮因子你可以在“包裹所有點”和“邊界平滑度”之間取得平衡。這個功能在從實驗數據或仿真數據點中界定區域范圍時極其有用。5. 性能優化與常見問題排查當需要繪制大量填充對象例如在循環中生成動畫或處理高分辨率地圖數據時性能會成為瓶頸。此外一些看似奇怪的現象也常常困擾使用者。5.1 性能優化技巧批量繪制避免循環這是最重要的原則。盡量將多個多邊形的頂點數據組合起來通過一次patch調用完成繪制而不是在循環中多次調用fill或patch。% 低效做法 % for i 1:100 % fill(x_i, y_i, color_i); % hold on % end % 高效做法使用 patch 的‘Faces‘/‘Vertices‘模式 all_verts []; % 收集所有頂點 all_faces []; % 收集所有面 face_offset 0; for i 1:100 [x_i, y_i] getPolygonData(i); % 假設的函數 num_verts length(x_i); verts_i [x_i(:), y_i(:)]; % 當前多邊形的頂點 faces_i (1:num_verts)‘ face_offset; % 當前多邊形的面索引 all_verts [all_verts; verts_i]; all_faces [all_faces; faces_i]; face_offset face_offset num_verts; end patch(‘Faces‘, all_faces, ‘Vertices‘, all_verts, ‘FaceColor‘, ‘flat‘, ...);一次繪制成百上千個多邊形性能差異可以達到數量級。簡化圖形對象對于靜態圖表在繪制完成后可以考慮將patch對象的‘Vertices‘和‘Faces‘數據導出然后刪除圖形對象需要時再重新創建。對于動態更新使用set函數更新patch對象的‘XData‘,‘YData‘,‘CData‘屬性遠比刪除重繪高效。% 創建初始圖形 h_patch patch(x_data, y_data, ‘r‘); % ... 在動畫循環中 ... for t 1:100 [new_x, new_y] updateData(t); % 計算新數據 set(h_patch, ‘XData‘, new_x, ‘YData‘, new_y); % 高效更新 drawnow pause(0.05) end合理使用渲染器MATLAB有不同的圖形渲染器‘painters‘,‘opengl‘,‘zbuffer‘。對于復雜的、帶透明度和光照的3Dpatch對象‘opengl‘硬件加速渲染器通常更快。可以通過set(gcf, ‘Renderer‘, ‘opengl‘)設置。但在某些2D簡單場景下‘painters‘可能矢量輸出質量更高。5.2 常見問題與解決方案速查表問題現象可能原因解決方案填充區域出現意外“空洞”或扭曲頂點順序不正確尤其是帶孔洞的多邊形未遵守“外逆內順”規則或頂點未正確閉合。檢查并確保外邊界頂點按逆時針排列內邊界孔洞按順時針排列。使用ispolycw函數判斷多邊形頂點順序。確保首尾點坐標相同。填充顏色不符合預期如全黑顏色數據C的維度或含義設置錯誤。例如在patch中使用‘FaceColor‘, ‘flat‘但‘FaceVertexCData‘數據維度不對。確認C的格式單一顏色用字符或1x3 RGB每面一色時C是 nFaces x 3 矩陣每頂點一色時C是 nVertices x 3 矩陣。檢查‘FaceColor‘是‘flat‘還是‘interp‘。圖形保存為矢量格式如PDF/EPS后填充區域錯亂某些PDF/EPS查看器或打印機對復雜patch對象的渲染支持不佳特別是使用了透明度或復雜漸變時。嘗試將渲染器設置為‘painters‘(set(gcf, ‘Renderer‘, ‘painters‘))。如果問題依舊考慮將圖形保存為位圖格式如PNG設置高DPI。對于必須的矢量輸出可以嘗試簡化多邊形或避免使用透明度。更新patch數據時圖形閃爍或變慢在循環中頻繁調用drawnow或沒有使用set更新屬性而是重新創建對象。使用set更新現有patch對象的屬性。考慮使用drawnow limitrate代替drawnow它限制重繪頻率能提升動畫流暢度。area圖基線不對或堆疊順序錯誤誤用了area的輸入參數或者Y數據不是列向量組。確認area(X,Y)中Y是列向量。如果需要指定基線使用三參數形式area(X,Y,baseline)。堆疊時Y的每一列會疊加到前一列的頂部。填充區域邊緣有白色縫隙Aliasing鋸齒這是屏幕顯示的抗鋸齒問題在保存高分辨率圖片時通常不會出現。對于屏幕顯示可以嘗試開啟OpenGL的抗鋸齒set(gcf, ‘GraphicsSmoothing‘, ‘on‘)。這不能完全消除但會改善。最終輸出時保存為高DPI的位圖如print(‘-dpng‘, ‘-r300‘, ‘filename.png‘)。踩坑實錄我曾經在處理一個包含數百個島嶼的海岸線地圖填充時因為直接用fill循環繪制導致圖形窗口卡頓近一分鐘。后來改用patch的‘Faces/Vertices‘模式將所有多邊形數據預處理成一個頂點列表和一個面片列表一次繪制時間縮短到一秒以內。這個教訓讓我深刻理解到在MATLAB中向量化操作和減少圖形對象調用次數是性能優化的黃金法則。對于靜態圖多花點時間在數據預處理上是絕對值得的。