分步指導 | 使用 MATLAB 面向對象編程創建專用圖表

2021-02-20 工科男的Matlab學習日誌

開發高級 MATLAB 可視化效果通常需要管理多個低層的圖形對象,包含動態更新圖形的應用程式更是如此。這種應用程式可能需要非常耗時的編程。Chart 對象可提供高級應用程式編程接口(API),實現可視化的自定義創建。圖表可為最終用戶提供方便的可視化 API,無需用戶執行低層圖形編程。

本文以包含最佳擬合線的散點圖為主要示例,通過分步指導展示如何使用 MATLAB 面向對象的編程創建和實現自定義圖表,包括:

  ◆  ◆  

圖表示例

MATLAB 提供幾種圖表,包括 heatmap 圖和 geobubble 圖,前者顯示疊放在彩色網格上的矩陣值,後者可快速在地圖上繪製離散數據點(圖1)。

圖1 heatmap 圖和 geobubble 圖

此外,我們還創建幾種特定於應用程式的圖表(圖2)。您可以從 File Exchange 中隨本文使用的 MATLAB 代碼一起,下載這些圖表。

圖2 可在 File Exchange 中下載自定義圖表:

https://ww2.mathworks.cn/matlabcentral/fileexchange/65857-creating-specialized-charts-with-matlab-object-oriented-programming

創建二維散點圖:函數或圖表?

假設我們要創建包含對應最佳擬合線的二維散點圖(圖 3)。我們可以使用 scatter 函數顯示離散 (x,y) 數據點,並使用 Statisticsand Machine Learning Toolbox™ 中的 fitlm 函數計算最佳擬合線。

圖3 最佳擬合線和底層的分散數據

以上代碼可滿足靜態可視化的需求。但是,如果應用程式要求對數據進行動態修改,我們會遇到幾個難題:

圖4 最佳擬合線在更改散點圖的 XData 後未更新

我們可以通過設計一個圖表 ScatterFit 來解決這些難題。

構建圖表代碼:函數或類?

函數將代碼封裝為可重用單元,用戶無需重複代碼即可創建多個圖表。

請注意,此函數需要輸入兩個數據(x 和 y)。您可以指定圖形父項 f(例如,圖形)作為第一個輸入參數。

scatterfit(x,y) 指定輸入的兩個數據

scatterfit(f,x,y) 指定圖形父項和數據

在第一種情況下,該函數展示自動生成的行為,即將自動創建圖表的圖形。

使用函數創建圖表具有某些缺點:

用類來實現圖表具有代碼封裝及方法可重用性等好處,同時支持對圖表進行修改。

定義圖表類

為了與 MATLAB 圖形對象保持一致,我們將圖表實現為 handle 類,以便在適當位置修改圖表。我們支持在圖表屬性中使用點記法和 get/set 語法。要實現這一目標,我們從預定義 matlab.mixin.SetGet 類(本身是 handle 類)中派生出 ScatterFit 圖表。

因此,任何屬性都將自動支持表 1 中顯示的語法。

表1 圖表屬性的訪問和修改語法

編寫圖表類的構造方法

構造方法是類定義中的一個函數,用於構造圖表對象。首先,將代碼從 scatterfit 函數複製到我們的圖表構造方法之中。隨後,進行以下修改支持所需圖表行為:

請注意,此行為與 plot 和 scatter 等便捷函數的行為不同,後兩者可以自動生成輸入。如果用戶將 Parent 指定為輸入參數,則隨後將在構造方法中對其進行設置。

如果用戶已作為名稱值對輸入參數提供數據屬性,在此處設置這些數據(XData 和 YData)。我們還注意到,此編碼方法可確保用戶在指定名稱值對時出現的任何錯誤都將被圖表的屬性 set 方法發現和解決(稍後討論)。

如可行,我們將使用基元對象創建圖表圖形,因為高級便捷函數在調用時將重置多個現有 axes 屬性(圖2)。但是,這條原則存在例外情況:在 ScatterFit 內部,我們將使用 scatter 函數創建 Scatter 圖形對象,因為它支持對個別標記的尺寸和顏色進行後續更改。

表2 基元和高級圖形函數的示例

封裝圖表數據和圖形

在大多數圖表中,底層圖形包含至少一個 axes 對象及其內容(例如線或面對象)或多個對等的 axes 對象(例如,圖例或彩條)。這些圖表還包含內部數據屬性,以確保公共屬性之間保持一致。我們存儲底層圖形和內部數據為專有圖表屬性。例如,ScatterFit 圖表會維護以下專有屬性:

我們使用命名約定 XData_ 指示該版本是圖表數據的專有內部版本。用戶可見的對應公共數據屬性將命名為 XData。

使用 private 屬性主要有三個目的:

提供可視化API

設計圖表的一個主要原因是提供方便、直觀的 API。我們使用與現有圖形對象屬性一致的名稱為 ScatterFit 圖表提供容易識別的屬性(圖 5)。

圖5 ScatterFit 圖表API

用戶可使用表 1 中所示的語法訪問或修改這些屬性。關聯的圖表圖形會動態更新,以響應屬性的修改。例如,更改圖表的 LineWidth 屬性會更新最佳擬合線的 LineWidth。

我們使用 Dependent 類屬性實現圖表 API。Dependent 屬性的值未進行顯式存儲,而是獲取自類中的其他屬性。在圖表中,Dependent 屬性依賴於低級別圖形等專有屬性或內部數據屬性。

要定義 Dependent 屬性,我們首先使用屬性 Dependent 在 properties 塊中聲明其名稱。這表明該屬性的值依賴於類中的其他屬性。

通過編寫對應的 get 方法,我們還可以指定依賴於其他屬性的屬性。此方法會返回單個輸出參數,即 Dependent 屬性的值。在 ScatterFit 圖表中,XData 屬性(圖表公共接口的一部分)就是底層 XData_ 屬性,它作為圖表的 private 屬性存儲在內部。

我們為每個可配置的圖表屬性編寫 set 方法。此方法將用戶指定的值分配到正確的內部圖表屬性,以在必要時觸發圖形更新。

對於 ScatterFit 圖表,我們支持對數據屬性(XData 和 YData)進行動態修改(包括長度更改)。當用戶設置圖表的(公共)XData 時,我們將根據比較新數據矢量與現有數據的長短,填充或截斷相對的(專有)數據屬性 YData_。請記住,如果用戶在創建圖表時已指定 XData,此 set 方法將被構造方法調用。

我們通過調用不同的 update 方法刷新圖表圖形。此方法包含在 Scatter 對象中設置新數據、重新計算最佳擬合線,以及在對應的 Line 對象中設置新數據所需的代碼。

我們以相同方式為 YData 實現 set 方法,以切換 X/YData 屬性的角色。還會從 set 方法中為 YData 調用 update 方法。

要創建適用於最終用戶的豐富 API,我們會實現一組廣泛的 Dependent 屬性。建議在每個圖表中至少包含表 3 中所示的屬性。

表3. 建議的 Dependent 屬性

請注意,在大多數情況下,這些屬性將直接映射到底層圖表 axes。例如,Parent 屬性的 get 和 set 方法將圖表對象的 Parent 映射到 axes 的 Parent。

我們通過定義額外公共接口屬性啟用對可視化設置的控制,其中每個屬性映射到圖表維護的特定低級別圖形對象。在此類別中,ScatterFit 圖表支持各種線相關屬性,如最佳擬合線相關 LineStyle、LineWidth 和 LineColor。例如,圖表對象的 LineColor 屬性會映射到線對象的 Color 屬性。

此類別中的典型圖表屬性包括:

視圖相關屬性——例如,axes 的 View、XLim 和 Ylim

注釋——例如,axes 的 Xlabel、Ylabel 和 Title

裝飾性屬性——例如,顏色、線寬,樣式、網格、透明效果和明暗度

管理圖表的生命周期

ScatterFit 圖表與其底層 axes 對象密切關聯,該對象作為圖表的 private 屬性之一存儲。要正確管理圖表的生命周期,我們需要確保兩種行為:

MATLAB 中的每個圖形對象都具有 DeleteFcn 屬性——一種在圖形對象超出範圍後被自動調用的回調函數。因此,在圖表構造方法中設置 axes 的 DeleteFcn 滿足第一個要求。

此處,onAxesDeleted 是 private 類方法,僅充當圖表析構方法周圍的包裝程序。如前所述,每個 handle 類在創建時都包含可自定義析構方法。當對象超過範圍後,析構方法將被調用。

通過編寫自定義圖表類的析構方法,我們可滿足第二個要求。在圖表析構時,我們將刪除圖表的 axes。

實現這兩個要求後,圖表對象與其底層 axes 將具有相同的生命周期(圖 6)。

圖6 管理圖表和 axes 生命周期

簡化附加表格的開發

在編寫幾個圖表後,我們能夠輕鬆識別相似性和重複的代碼段。通過在超類中集中放置通用代碼,我們可以加速編寫額外圖表的進程。每個新圖表可派生自此超類,這可使我們專注於實現該特定圖表的細節,減少重複編碼的需求。

我們的超類(即 Chart)具有以下結構:

Chart 派生自 matlab.mixin.SetGet。

Chart 將實現六個核心 Dependent 屬性 Parent、Position、Units、OuterPosition、ActivePositionProperty 和 Visible。

Chart 具有 protected 屬性 Axes(底層對等圖形)。

Chart 構造方法將創建對等的 axes 對象並將 axes 的 DeleteFcn 設置為 protected 方法 onAxesDeleted。此方法進而將刪除圖表對象。

請注意,使用超類 Chart 可能並不適用於所有圖表。例如,維護多個 axes 的圖表需要對上述體系結構進行某些更改。我們可以實現此類圖表,方法是使用 uipanel 替代 axes 對象作為圖表的對等底層圖形,並在面板內部創建多個 axes。

  ◆  ◆  

在本文中,我們以 ScatterFit 圖表為例介紹實現自定義圖表的設計模式。許多公共可視化任務,尤其是需要動態圖形的任務,可使用適當的圖表執行。設計和創建圖表需要事先投入開發時間和精力,但圖表可以大幅簡化大量可視化工作流。

相關焦點

  • 再見了,面向對象的編程
    通過使用包含和代理,我們從白箱編程到黑箱編程。使用白箱編程,我們需要查看基類的實現。使用黑箱編程,我們完全忽略基類的實現因為我們不能通過覆蓋子類的函數向其加入代碼。我們只需考慮接口。這個趨勢很惱人……繼承理應是代碼再利用的一大利器。面向對象的語言並沒有讓包含和代理功能簡單易行。它們被設計為讓繼承簡單易行。
  • 【譯】使用UIKit進行面向對象的編程
    Apple甚至建議儘可能的使用協議(protocol)來替換類(class)--這是面向協議編程的關鍵。我讀過許多文章,其中對協議擴展的定義講的很清晰。但都沒有說明面向協議編程真正能為UI開發帶來些什麼。當前可用的一些示例代碼並不是基於一些實際場景的,而且沒用應用任何框架。
  • 面向對象的Qt編程
    從BOP到OOP基於對象的Qt編程(不推薦)
  • JavaScript 的函數式編程與面向對象編程區別在哪?
    本文通過代碼來看一看JavaScript中函數式編程和面向對象編程的差異。
  • TIA Portal面向對象編程入門
    儘管時至今日依然有少數人質疑面向對象的編程思想,但我們看到的是面向對象技術發展的越來越好,無論是後端語言(JAVA、C#)或者前端語言(JavaScript、TypeScript),無一不是完全的支持面向對象技術。現在高校的PLC教材基本上採用的還是五六十年前的編程理念,將PLC定位為傳統繼電器控制的替代,以軟元件、寄存器這種古老落後的概念來講授這一門日新月異的現代工業控制編程技術。
  • C 語言面向對象編程 - 繼承
    點擊上方藍字,關注微聯智控可點擊右上角的 …,分享這篇文章上一篇文章主要講述了 C 語言面向對象編程
  • 15款經典圖表軟體推薦 創建最漂亮的圖表
    Fusion ChartsFusionCharts v3 幫助創建Web或企業應用的動畫/交互的圖表。企業級圖表組件支持PCs, Macs, iPads, iPhones,以及大量其他的手機設備。 2. MaanibXML/SWF 圖表是個簡單、強大的工具,支持XML數據創建吸引人的圖表。
  • 【編程基礎第五講】java面向對象思想如何理解?
    存在的疑惑:如何理解面向對象的思想?
  • 一步步分析:C語言如何面向對象編程
    ,在C++11版本之前,它們的語法是比較相似的,只不過C++提供了面向對象的編程方式。這篇文章,我們就來聊聊如何在C語言中利用面向對象的思想來編程。也許你在項目中用不到,但是也強烈建議你看一下,因為我之前在跳槽的時候就兩次被問到這個問題。
  • 史上最全 Python 面向對象編程
    .html面向對象編程和函數式編程(面向過程編程)都是程序設計的方法,不過稍有區別。面向對象編程:1. 導入各種外部庫2. 設計各種全局變量3. 決定你要的類4. 給每個類提供完整的一組操作5. 明確地使用繼承來表現不同類之間的共同點6.
  • Java面向對象編程開發認證考試項目介紹
    1、證書頒發機構介紹工業和信息化部人才交流中心(以下簡稱中心)創建於1985年1月,1992年10
  • 面向對象編程會被拋棄嗎?這五大問題不容忽視
    另外,如果你需要做很多事情,那麼你就不能使用過多的數據,否則計算機將會一直運行下去。接下來到了 1966、1967 年,Alan Kay 從理論上證明可以使用封裝的微型計算機。這些微型計算機不共享數據,而是通過消息傳遞進行通信。這樣就可以更加經濟地使用計算資源。儘管這個想法很巧妙,但直到 1981 年,面向對象編程才成為主流。在那之後,它就沒有停止過吸引新的和經驗豐富的軟體開發者。
  • Python面向對象編程指南
    Python面向對象編程指南第1部分 用特殊方法實現Python風格的類第1章 __init__方法1.1 隱式的積累——object
  • 面向對象編程已死,OOP 永存!
    這種「模式」經常會導致繼承的過度使用,而不會提及過度使用繼承,其實違反了OOP(OOP,Object Oriented Programming,面向對象編程,是一種計算機編程架構)原則。那麼如何避免這種情況呢?本文作者,會給大家介紹下真正的設計指南。
  • 是時候讓 JavaScript 面向對象了!
    以前使用 JavaScript 開發原生移動和桌面應用程式是駭人聽聞的事兒,可如今這種做法很常見,甚至比 Java 還流行,而且 JavaScript 也完全支持跨平臺。現在,JavaScript 無處不在。你可以輕鬆搞定 JavaScript,而且也非常實用。但是從長期來看這很可能造成很多問題。許多 JavaScript 程式設計師都沒有接受過面向對象編程方法的培訓。
  • 面向對象基礎 - Class使用及三大特性
    面向過程與面向對象的區別面向過程 Procedural programming在實際生活中,當我們遇到一個問題需要解決時,我們會進行一系列的工作來解決問題.面向對象 Object-oriented programming在面向過程編程中,解決不同的問題.過程也就不一樣,當有兩個比較類似的問題時,例如土豆炒肉絲和幹扁四季豆這兩道菜的做法的步驟雖然不一樣,一個直接炒,四季豆需要先煮一下.但是還是有部分的步驟是一樣的,雖然順序不一樣.
  • 面向對象聖經
    人類覺得Object大法好,創建了很多Object出來,讓他們互相調用。上帝發現很多Object的方法都是相同的,他們被重複地放在一個個對象當中,太浪費了。把這些重複的方法代碼從對象中剝離出來,放到一個公共的Class中! 」人類問:「那我們怎麼把這些Object給創建起來?並且讓Object 和 Class關聯?」上帝說:「可以用new 這個關鍵字: Stack object1 = new Stack(); 」
  • Matlab R2021a Mac中文破解版
    實時編輯器使用 matlab 實時編輯器以可執行記事本形式創建 matlab 腳本和函數,在其中綜合代碼、輸出和格式化文本。全新 基於 iOS 的實時編輯器:在 iPhone 或 iPad 上使用 matlab Mobile 創建、編輯和運行實時腳本 (2020b)全新 實時編輯器:使用實時腳本超連結以打開另一個實時腳本 (R2020b)
  • 32個實用matlab編程技巧
    今天給大家介紹一些編程小技巧,之前給大家介紹過matlab編程小技巧,本期是在之前的基礎之上做了修正和補充完善,下面一起來看看吧。1、能用矩陣計算的就用矩陣計算,不能用矩陣計算的想方設法也要往矩陣計算上靠。2、少用循環,尤其是避免多重循環嵌套,儘量用向量化的運算來代替循環操作。
  • matlab之隨心所欲創建QR二維碼
    感謝關注matlab愛好者公眾號!如果公眾號文章對您有幫助,別忘了點擊分享和「在看」哦!