三、示例學習
3.響應用戶選擇
有了學習(一)和學習(二)的基礎,我直接開門見山,分析其中的核心部分。
(1)界面
相比之前兩個的界面,這個界面要高級很多了。首先是整個界面分為兩個面板,左面板和右面板。
左面板部分從上到下依次是控件:
標簽Data Selection
三個小面板,第一個面板上的title 為location,放着下拉框;
第二個面板的title是Gender,放着兩個復選框Male 和 female;
第三個面板的title是smoker,放着兩個復選框yes和no
右面板部分上方有圖窗工具菜單欄,在第一個子項plot中,從上到下依次是
儀器工具中的開關
繪圖區
button組
滑塊
菜單第二個子項data中,放的是
表
如下圖。
對控件進行相應的命名、屬性的修改。
(2)代碼
先把源代碼貼過來,代碼分析見后。
classdef PatientsDisplay < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
PatientsDisplayUIFigure matlab.ui.Figure
GridLayout matlab.ui.container.GridLayout
LeftPanel matlab.ui.container.Panel
Panel2 matlab.ui.container.Panel
FemaleCheckBox matlab.ui.control.CheckBox
MaleCheckBox matlab.ui.control.CheckBox
Panel2_2 matlab.ui.container.Panel
NoCheckBox matlab.ui.control.CheckBox
YesCheckBox matlab.ui.control.CheckBox
Panel2_4 matlab.ui.container.Panel
HospitalNameDropDownLabel matlab.ui.control.Label
HospitalNameDropDown matlab.ui.control.DropDown
DataSelectionLabel matlab.ui.control.Label
RightPanel matlab.ui.container.Panel
TabGroup matlab.ui.container.TabGroup
PlotTab matlab.ui.container.Tab
UIAxes matlab.ui.control.UIAxes
BinWidthSliderLabel matlab.ui.control.Label
BinWidthSlider matlab.ui.control.Slider
ButtonGroup matlab.ui.container.ButtonGroup
ScatterButton matlab.ui.control.RadioButton
HistogramButton matlab.ui.control.RadioButton
BloodPressureSwitchLabel matlab.ui.control.Label
BloodPressureSwitch matlab.ui.control.Switch
DataTab matlab.ui.container.Tab
UITable matlab.ui.control.Table
end
% Properties that correspond to apps with auto-reflow
properties (Access = private)
onePanelWidth = 576;
end
% The app displays the data by using the scatter plot, histogram, and table.
% It makes use of tabs to separate the ploting options output from the table display of the data.
% There are several graphical elements used such as checkboxes, slider, switch, dropdown, and radiobutton group.
% The data used in the app is shiped with the product.
properties (Access = private)
% Declare properties of the PatientsDisplay class.
Data
SelectedGenders
SelectedColors
BinWidth
Histogram = gobjects(0)
displayedIndices
end
methods (Access = private)
function NBins = numhistbins(app,data)
% Utility function to compute the number of histogram bins
binwidth = app.BinWidth;
range2plot = floor(min(data)):binwidth:ceil(max(data));
NBins = size(range2plot,2);
end
function annotateScatterPlot(app)
% Update X and Y Labels
app.UIAxes.XLabel.String = 'Weight';
app.UIAxes.YLabel.String = app.BloodPressureSwitch.Value;
% Dont show the histogram slider
app.BinWidthSliderLabel.Visible = 'off';
app.BinWidthSlider.Visible = 'off';
end
function annotateHistogram(app)
% Update X and Y Labels
app.UIAxes.XLabel.String = app.BloodPressureSwitch.Value;
app.UIAxes.YLabel.String = '# of Patients';
% Show histogram slider
app.BinWidthSliderLabel.Visible = 'on';
app.BinWidthSlider.Visible = 'on';
end
function filterData(app)
% Utility function to filter the data according to the controls
% Initially assume that all data will be displayed and then, subsequently, filter the data
% based on the controls
tempIndices = ones([size(app.Data,1),1]);
% Append a column to tempIndices to indicate data that satisfies the smoker control
if app.NoCheckBox.Value && ~app.YesCheckBox.Value
tempIndices = [tempIndices, app.Data.Smoker == 0];
elseif app.YesCheckBox.Value && ~app.NoCheckBox.Value
tempIndices = [tempIndices, app.Data.Smoker == 1];
elseif ~app.YesCheckBox.Value && ~app.NoCheckBox.Value
tempIndices = [tempIndices, zeros([size(app.Data,1),1])];
end
% Append a column to tempIndices to indicate data that satisfies the gender control
if app.MaleCheckBox.Value && ~app.FemaleCheckBox.Value
tempIndices = [tempIndices, app.Data.Gender == "Male"];
elseif app.FemaleCheckBox.Value && ~app.MaleCheckBox.Value
tempIndices = [tempIndices, app.Data.Gender == "Female"];
elseif ~app.FemaleCheckBox.Value && ~app.MaleCheckBox.Value
tempIndices = [tempIndices, zeros([size(app.Data,1),1])];
end
% Append a column to tempIndices to indicate data that satisfies the location control
if app.HospitalNameDropDown.Value ~= "All"
tempIndices = [tempIndices, app.Data.Location == string(app.HospitalNameDropDown.Value)];
end
% Determine which data points satisfy all requirements
app.displayedIndices = (sum(tempIndices,2)/size(tempIndices,2) == 1);
end
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
% Load the data.
load('patients.mat','LastName','Gender','Smoker','Age','Height','Weight','Diastolic','Systolic','Location');
% Store the data in a table and display it in one of the App's tabs.
app.Data = table(LastName,Gender,Smoker,Age,Height,Weight,Diastolic,Systolic,Location);
app.UITable.Data = app.Data;
app.BinWidth = app.BinWidthSlider.Value;
% Update the axes with the corresponding data.
updateSelectedGenders(app)
refreshplot(app)
end
% Changes arrangement of the app based on UIFigure width
function updateAppLayout(app, event)
currentFigureWidth = app.PatientsDisplayUIFigure.Position(3);
if(currentFigureWidth <= app.onePanelWidth)
% Change to a 2x1 grid
app.GridLayout.RowHeight = {400, 400};
app.GridLayout.ColumnWidth = {'1x'};
app.RightPanel.Layout.Row = 2;
app.RightPanel.Layout.Column = 1;
else
% Change to a 1x2 grid
app.GridLayout.RowHeight = {'1x'};
app.GridLayout.ColumnWidth = {282, '1x'};
app.RightPanel.Layout.Row = 1;
app.RightPanel.Layout.Column = 2;
end
end
% Value changing function: BinWidthSlider
function SliderValueChanging(app, event)
% Update the histogram as the slider value for bindwidth changes.
app.BinWidth = event.Value;
for ii=1:length(app.Histogram)
app.Histogram(ii).NumBins = numhistbins(app,app.Histogram(ii).Data);
end
end
% Callback function: BinWidthSlider, BloodPressureSwitch,
% ButtonGroup, UITable
function refreshplot(app, event)
Genders = app.SelectedGenders;
Colors = app.SelectedColors;
% Start with a fresh plot
cla(app.UIAxes)
hold(app.UIAxes,'on')
app.Histogram = gobjects(0);
% Select relevant segment of data
xdata = app.Data.Weight;
ydata = app.Data.(app.BloodPressureSwitch.Value);
% Filter the data according to the controls
filterData(app);
% Create either a scatter plot or histogram, based on selection
switch app.ButtonGroup.SelectedObject.Text
case 'Scatter'
% Build a scatter plot for each selected gender
for ii = 1:length(Genders)
selectedpatients = ((app.Data.Gender == Genders(ii)) & (app.displayedIndices));
scatter(app.UIAxes,xdata((selectedpatients)),ydata(selectedpatients),Colors{ii});
end
annotateScatterPlot(app)
case 'Histogram'
% Build a histogram for each selected gender
for ii = 1:length(Genders)
selectedpatients = ((app.Data.Gender == Genders(ii)) & (app.displayedIndices));
NBins = numhistbins(app,ydata(selectedpatients));
h = histogram(app.UIAxes,ydata(selectedpatients),NBins,'BinLimits',[floor(min(ydata)) ceil(max(ydata))]);
h.EdgeColor = Colors{ii};
h.FaceColor = Colors{ii};
app.Histogram = [app.Histogram h];
end
annotateHistogram(app)
end
% Update the table to show only the data that satisfies the controls
app.UITable.Data = app.Data(app.displayedIndices,:);
drawnow;
end
% Value changed function: FemaleCheckBox,
% HospitalNameDropDown, MaleCheckBox, NoCheckBox,
% YesCheckBox
function updateSelectedGenders(app, event)
% List which genders and colors to use
Genders = [];
Colors = [];
Smoker = [];
if app.MaleCheckBox.Value
Genders = "Male";
Colors = "blue";
end
if app.FemaleCheckBox.Value
Genders = [Genders "Female"];
Colors = [Colors "red"];
end
if app.YesCheckBox.Value
Smoker = "Yes";
end
if app.NoCheckBox.Value
Smoker = [Smoker "No"];
end
if isempty(Genders) || isempty(Smoker)
% Disable the switches and buttons if they were on
app.BloodPressureSwitch.Enable = 'off';
app.ScatterButton.Enable = 'off';
app.HistogramButton.Enable = 'off';
app.BinWidthSliderLabel.Enable = 'off';
app.BinWidthSlider.Enable = 'off';
else
% Enable the switches and buttons if they were off
app.BloodPressureSwitch.Enable = 'on';
app.ScatterButton.Enable = 'on';
app.HistogramButton.Enable = 'on';
app.BinWidthSliderLabel.Enable = 'on';
app.BinWidthSlider.Enable = 'on';
end
app.SelectedGenders = Genders;
app.SelectedColors = Colors;
refreshplot(app)
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create PatientsDisplayUIFigure and hide until all components are created
app.PatientsDisplayUIFigure = uifigure('Visible', 'off');
app.PatientsDisplayUIFigure.AutoResizeChildren = 'off';
app.PatientsDisplayUIFigure.Position = [100 100 703 400];
app.PatientsDisplayUIFigure.Name = 'Patients Display';
app.PatientsDisplayUIFigure.SizeChangedFcn = createCallbackFcn(app, @updateAppLayout, true);
% Create GridLayout
app.GridLayout = uigridlayout(app.PatientsDisplayUIFigure);
app.GridLayout.ColumnWidth = {282, '1x'};
app.GridLayout.RowHeight = {'1x'};
app.GridLayout.ColumnSpacing = 0;
app.GridLayout.RowSpacing = 0;
app.GridLayout.Padding = [0 0 0 0];
app.GridLayout.Scrollable = 'on';
% Create LeftPanel
app.LeftPanel = uipanel(app.GridLayout);
app.LeftPanel.Layout.Row = 1;
app.LeftPanel.Layout.Column = 1;
app.LeftPanel.Scrollable = 'on';
% Create Panel2
app.Panel2 = uipanel(app.LeftPanel);
app.Panel2.AutoResizeChildren = 'off';
app.Panel2.Title = 'Gender';
app.Panel2.Position = [9 123 269 97];
% Create FemaleCheckBox
app.FemaleCheckBox = uicheckbox(app.Panel2);
app.FemaleCheckBox.ValueChangedFcn = createCallbackFcn(app, @updateSelectedGenders, true);
app.FemaleCheckBox.Text = 'Female';
app.FemaleCheckBox.Position = [12 14 60 16];
% Create MaleCheckBox
app.MaleCheckBox = uicheckbox(app.Panel2);
app.MaleCheckBox.ValueChangedFcn = createCallbackFcn(app, @updateSelectedGenders, true);
app.MaleCheckBox.Text = 'Male';
app.MaleCheckBox.Position = [12 44 46 16];
app.MaleCheckBox.Value = true;
% Create Panel2_2
app.Panel2_2 = uipanel(app.LeftPanel);
app.Panel2_2.AutoResizeChildren = 'off';
app.Panel2_2.Title = 'Smoker';
app.Panel2_2.Position = [9 7 268 97];
% Create NoCheckBox
app.NoCheckBox = uicheckbox(app.Panel2_2);
app.NoCheckBox.ValueChangedFcn = createCallbackFcn(app, @updateSelectedGenders, true);
app.NoCheckBox.Text = 'No';
app.NoCheckBox.Position = [12 12 60 22];
app.NoCheckBox.Value = true;
% Create YesCheckBox
app.YesCheckBox = uicheckbox(app.Panel2_2);
app.YesCheckBox.ValueChangedFcn = createCallbackFcn(app, @updateSelectedGenders, true);
app.YesCheckBox.Text = 'Yes';
app.YesCheckBox.Position = [12 42 46 22];
app.YesCheckBox.Value = true;
% Create Panel2_4
app.Panel2_4 = uipanel(app.LeftPanel);
app.Panel2_4.AutoResizeChildren = 'off';
app.Panel2_4.Title = 'Location';
app.Panel2_4.Position = [9 242 269 97];
% Create HospitalNameDropDownLabel
app.HospitalNameDropDownLabel = uilabel(app.Panel2_4);
app.HospitalNameDropDownLabel.HorizontalAlignment = 'right';
app.HospitalNameDropDownLabel.Position = [8 27 84 22];
app.HospitalNameDropDownLabel.Text = 'Hospital Name';
% Create HospitalNameDropDown
app.HospitalNameDropDown = uidropdown(app.Panel2_4);
app.HospitalNameDropDown.Items = {'County General Hospital', 'St. Mary''s Medical Center', 'VA Hospital', 'All'};
app.HospitalNameDropDown.ValueChangedFcn = createCallbackFcn(app, @updateSelectedGenders, true);
app.HospitalNameDropDown.Position = [107 27 153 22];
app.HospitalNameDropDown.Value = 'All';
% Create DataSelectionLabel
app.DataSelectionLabel = uilabel(app.LeftPanel);
app.DataSelectionLabel.HorizontalAlignment = 'center';
app.DataSelectionLabel.FontSize = 15;
app.DataSelectionLabel.FontWeight = 'bold';
app.DataSelectionLabel.Position = [9 356 267 22];
app.DataSelectionLabel.Text = 'Data Selection';
% Create RightPanel
app.RightPanel = uipanel(app.GridLayout);
app.RightPanel.Layout.Row = 1;
app.RightPanel.Layout.Column = 2;
app.RightPanel.Scrollable = 'on';
% Create TabGroup
app.TabGroup = uitabgroup(app.RightPanel);
app.TabGroup.Position = [7 6 408 387];
% Create PlotTab
app.PlotTab = uitab(app.TabGroup);
app.PlotTab.Title = 'Plot';
% Create UIAxes
app.UIAxes = uiaxes(app.PlotTab);
xlabel(app.UIAxes, 'Weight')
ylabel(app.UIAxes, 'Diastolic')
app.UIAxes.GridAlpha = 0.15;
app.UIAxes.MinorGridAlpha = 0.25;
app.UIAxes.Box = 'on';
app.UIAxes.Position = [19 89 376 215];
% Create BinWidthSliderLabel
app.BinWidthSliderLabel = uilabel(app.PlotTab);
app.BinWidthSliderLabel.HorizontalAlignment = 'center';
app.BinWidthSliderLabel.VerticalAlignment = 'top';
app.BinWidthSliderLabel.Position = [241 63 76 15];
app.BinWidthSliderLabel.Text = 'Bin Width';
% Create BinWidthSlider
app.BinWidthSlider = uislider(app.PlotTab);
app.BinWidthSlider.Limits = [1 11];
app.BinWidthSlider.MajorTicks = [1 2 3 4 5 6 7 8 9 10 11];
app.BinWidthSlider.ValueChangedFcn = createCallbackFcn(app, @refreshplot, true);
app.BinWidthSlider.ValueChangingFcn = createCallbackFcn(app, @SliderValueChanging, true);
app.BinWidthSlider.MinorTicks = [];
app.BinWidthSlider.Position = [183 46 192 3];
app.BinWidthSlider.Value = 5;
% Create ButtonGroup
app.ButtonGroup = uibuttongroup(app.PlotTab);
app.ButtonGroup.AutoResizeChildren = 'off';
app.ButtonGroup.SelectionChangedFcn = createCallbackFcn(app, @refreshplot, true);
app.ButtonGroup.Title = 'Plotting Options';
app.ButtonGroup.Position = [18 4 148 79];
% Create ScatterButton
app.ScatterButton = uiradiobutton(app.ButtonGroup);
app.ScatterButton.Text = 'Scatter';
app.ScatterButton.Position = [11 34 103 15];
app.ScatterButton.Value = true;
% Create HistogramButton
app.HistogramButton = uiradiobutton(app.ButtonGroup);
app.HistogramButton.Text = 'Histogram';
app.HistogramButton.Position = [11 12 103 15];
% Create BloodPressureSwitchLabel
app.BloodPressureSwitchLabel = uilabel(app.PlotTab);
app.BloodPressureSwitchLabel.HorizontalAlignment = 'center';
app.BloodPressureSwitchLabel.VerticalAlignment = 'top';
app.BloodPressureSwitchLabel.Position = [132 340 151 15];
app.BloodPressureSwitchLabel.Text = 'Blood Pressure';
% Create BloodPressureSwitch
app.BloodPressureSwitch = uiswitch(app.PlotTab, 'slider');
app.BloodPressureSwitch.Items = {'Systolic', 'Diastolic'};
app.BloodPressureSwitch.ValueChangedFcn = createCallbackFcn(app, @refreshplot, true);
app.BloodPressureSwitch.Position = [190 309 34 15];
app.BloodPressureSwitch.Value = 'Systolic';
% Create DataTab
app.DataTab = uitab(app.TabGroup);
app.DataTab.Title = 'Data';
% Create UITable
app.UITable = uitable(app.DataTab);
app.UITable.ColumnName = {'Last Name'; 'Gender'; 'Smoker'; 'Age'; 'Height'; 'Weight'; 'Diastolic'; 'Systolic'; 'Location'};
app.UITable.RowName = {};
app.UITable.ColumnSortable = true;
app.UITable.RowStriping = 'off';
app.UITable.CellSelectionCallback = createCallbackFcn(app, @refreshplot, true);
app.UITable.Position = [1 1 407 358];
% Show the figure after all components are created
app.PatientsDisplayUIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = PatientsDisplay
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.PatientsDisplayUIFigure)
% Execute the startup function
runStartupFcn(app, @startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.PatientsDisplayUIFigure)
end
end
end
(3)知識點分析
略去之前已經分析過的部分,在Properties部分,我們看到,除了前面提及的控件屬性、窗口寬度外,增加了很大一部分內容,這部分是關於數據載入、直方圖/散點圖/表格等內容的輔助程序。
properties (Access = private)
% Declare properties of the PatientsDisplay class.
Data
SelectedGenders
SelectedColors
BinWidth
Histogram = gobjects(0)
displayedIndices
end
這個app類叫做PatientsDisplay,這部分聲明這個類里私有成分,包括Data、SelectedGenders、SelectedColors、BinWidth、Histogram = gobjects(0)、displayedIndices。
function NBins = numhistbins(app,data)
% Utility function to compute the number of histogram bins
binwidth = app.BinWidth;
range2plot = floor(min(data)):binwidth:ceil(max(data));
NBins = size(range2plot,2);
end
這個函數是用於計算 直方圖 每一條柱的數據: 將滑塊讀取的BinWidth的值賦值給binwidth,range2plot是最小值到最大值的范圍的向量,NBins是直方圖每一個條形的寬度。
floor()這個函數是向下取整。
function annotateScatterPlot(app) % Update X and Y Labels app.UIAxes.XLabel.String = 'Weight'; app.UIAxes.YLabel.String = app.BloodPressureSwitch.Value; % Dont show the histogram slider app.BinWidthSliderLabel.Visible = 'off'; app.BinWidthSlider.Visible = 'off'; end
繪制散點圖時,坐標區的x的名稱為Weight,Y坐標的名稱根據控件開關的狀態更新;滑塊及其標簽隱藏。
function annotateHistogram(app) % Update X and Y Labels app.UIAxes.XLabel.String = app.BloodPressureSwitch.Value; app.UIAxes.YLabel.String = '# of Patients'; % Show histogram slider app.BinWidthSliderLabel.Visible = 'on'; app.BinWidthSlider.Visible = 'on'; end
繪制直方圖時,坐標區的x的名稱根據控件狀態變化,Y坐標的名稱為# of Patients;滑塊及其標簽顯示。
重點: 控制某個控件是否可見,采用:app.XXX.Visible='on'或者 'off';坐標區的X、Y坐標名稱也可以根據控件的狀態進行更改,方式為app.XXX.XLabel.String = 'Weight'
讀取開關控件的值采用的程序語句為:XXX= app.xxx.Value。
function filterData(app) % Utility function to filter the data according to the controls % Initially assume that all data will be displayed and then, subsequently, filter the data % based on the controls tempIndices = ones([size(app.Data,1),1]); % Append a column to tempIndices to indicate data that satisfies the smoker control if app.NoCheckBox.Value && ~app.YesCheckBox.Value tempIndices = [tempIndices, app.Data.Smoker == 0]; elseif app.YesCheckBox.Value && ~app.NoCheckBox.Value tempIndices = [tempIndices, app.Data.Smoker == 1]; elseif ~app.YesCheckBox.Value && ~app.NoCheckBox.Value tempIndices = [tempIndices, zeros([size(app.Data,1),1])]; end % Append a column to tempIndices to indicate data that satisfies the gender control if app.MaleCheckBox.Value && ~app.FemaleCheckBox.Value tempIndices = [tempIndices, app.Data.Gender == "Male"]; elseif app.FemaleCheckBox.Value && ~app.MaleCheckBox.Value tempIndices = [tempIndices, app.Data.Gender == "Female"]; elseif ~app.FemaleCheckBox.Value && ~app.MaleCheckBox.Value tempIndices = [tempIndices, zeros([size(app.Data,1),1])]; end % Append a column to tempIndices to indicate data that satisfies the location control if app.HospitalNameDropDown.Value ~= "All" tempIndices = [tempIndices, app.Data.Location == string(app.HospitalNameDropDown.Value)]; end % Determine which data points satisfy all requirements app.displayedIndices = (sum(tempIndices,2)/size(tempIndices,2) == 1); end end
這部分程序的功能是數據選用。ones(x,y)定義x行y列的單元向量。
接下來的if語句是判別復選框狀態的語句。其中,~ app.YesCheckBox.Value中前面的~是非的意思。
其余部分自行理解,這里需要重點說明:
復選框的程序調用方法:
if app.A.Value && ~app.B.Value xxxx;
elseif app.B.Value && ~app.A.Value YYYY; elseif ~app.A.Value && ~app.B.Value 0000; end
下拉框的程序調用方法:
XXX == string(app.DropDown.Value)
% Callbacks that handle component events methods (Access = private) % Code that executes after component creation function startupFcn(app) % Load the data. load('patients.mat','LastName','Gender','Smoker','Age','Height','Weight','Diastolic','Systolic','Location'); % Store the data in a table and display it in one of the App's tabs. app.Data = table(LastName,Gender,Smoker,Age,Height,Weight,Diastolic,Systolic,Location); app.UITable.Data = app.Data; app.BinWidth = app.BinWidthSlider.Value; % Update the axes with the corresponding data. updateSelectedGenders(app) refreshplot(app) end
加載數據:load(‘文件名’,‘XXX’);
現將數據賦值給app.Data,再導入table中。
更新數據:updateSelectedGenders(app) 刷新繪圖:refreshplot(app)
% Changes arrangement of the app based on UIFigure width function updateAppLayout(app, event) currentFigureWidth = app.PatientsDisplayUIFigure.Position(3); if(currentFigureWidth <= app.onePanelWidth) % Change to a 2x1 grid app.GridLayout.RowHeight = {400, 400}; app.GridLayout.ColumnWidth = {'1x'}; app.RightPanel.Layout.Row = 2; app.RightPanel.Layout.Column = 1; else % Change to a 1x2 grid app.GridLayout.RowHeight = {'1x'}; app.GridLayout.ColumnWidth = {282, '1x'}; app.RightPanel.Layout.Row = 1; app.RightPanel.Layout.Column = 2; end end
根據界面調整布局,之前在學習(二)中已經詳細講解。
% Value changing function: BinWidthSlider function SliderValueChanging(app, event) % Update the histogram as the slider value for bindwidth changes. app.BinWidth = event.Value; for ii=1:length(app.Histogram) app.Histogram(ii).NumBins = numhistbins(app,app.Histogram(ii).Data); end end
根據滑塊的值變動直方圖的寬度。
% Callback function: BinWidthSlider, BloodPressureSwitch, % ButtonGroup, UITable function refreshplot(app, event) Genders = app.SelectedGenders; Colors = app.SelectedColors; % Start with a fresh plot cla(app.UIAxes) hold(app.UIAxes,'on') app.Histogram = gobjects(0); % Select relevant segment of data xdata = app.Data.Weight; ydata = app.Data.(app.BloodPressureSwitch.Value); % Filter the data according to the controls filterData(app);
重點內容:
清空坐標區內的繪圖數據:cla(app.UIAxes)
% Create either a scatter plot or histogram, based on selection switch app.ButtonGroup.SelectedObject.Text case 'Scatter' % Build a scatter plot for each selected gender for ii = 1:length(Genders) selectedpatients = ((app.Data.Gender == Genders(ii)) & (app.displayedIndices)); scatter(app.UIAxes,xdata((selectedpatients)),ydata(selectedpatients),Colors{ii}); end annotateScatterPlot(app) case 'Histogram' % Build a histogram for each selected gender for ii = 1:length(Genders) selectedpatients = ((app.Data.Gender == Genders(ii)) & (app.displayedIndices)); NBins = numhistbins(app,ydata(selectedpatients)); h = histogram(app.UIAxes,ydata(selectedpatients),NBins,'BinLimits',[floor(min(ydata)) ceil(max(ydata))]); h.EdgeColor = Colors{ii}; h.FaceColor = Colors{ii}; app.Histogram = [app.Histogram h]; end annotateHistogram(app) end
重點:按鈕組的程序調用方法:
采用switch語句,對按鈕組進行程序操作
% Update the table to show only the data that satisfies the controls app.UITable.Data = app.Data(app.displayedIndices,:); drawnow; end
drawnow; 更新圖窗並處理回調
% Value changed function: FemaleCheckBox, % HospitalNameDropDown, MaleCheckBox, NoCheckBox, % YesCheckBox function updateSelectedGenders(app, event) % List which genders and colors to use Genders = []; Colors = []; Smoker = []; if app.MaleCheckBox.Value Genders = "Male"; Colors = "blue"; end if app.FemaleCheckBox.Value Genders = [Genders "Female"]; Colors = [Colors "red"]; end if app.YesCheckBox.Value Smoker = "Yes"; end if app.NoCheckBox.Value Smoker = [Smoker "No"]; end if isempty(Genders) || isempty(Smoker) % Disable the switches and buttons if they were on app.BloodPressureSwitch.Enable = 'off'; app.ScatterButton.Enable = 'off'; app.HistogramButton.Enable = 'off'; app.BinWidthSliderLabel.Enable = 'off'; app.BinWidthSlider.Enable = 'off'; else % Enable the switches and buttons if they were off app.BloodPressureSwitch.Enable = 'on'; app.ScatterButton.Enable = 'on'; app.HistogramButton.Enable = 'on'; app.BinWidthSliderLabel.Enable = 'on'; app.BinWidthSlider.Enable = 'on'; end app.SelectedGenders = Genders; app.SelectedColors = Colors; refreshplot(app) end end
isempty()函數是判斷數組是否為空,如果為空,返回邏輯真,值為1,如果數組不為空,返回邏輯假,值為0,其他內容便比較容易理解了。
這部分學習的內容包括 下拉框、復選框、按鈕組、滑塊值、開關、菜單欄、表格、散點圖和直方圖的繪制等功能。另外對輔助功能如清空繪圖區、刷線圖窗更新等命令也做了學習。
但是這部分關於編程思想並沒有學習透徹,我們之后會專門提到這個問題。因此,本節內容只要掌握這些控件的程序調用方式即可。
下一節我們學習其他的控件,我另起文檔介紹,繼續跟緊我!