Identify the portion of the uitree in CheckedNodes

10 次查看(过去 30 天)
When creating a tree with multiple treenodes, how can one identify the specific node that a checked item comes from?
Given the tree generated from the sample code in matlab (see below), How can I know the parent node for each checked node? Specifically, "train" could be under either vehicle or action in the example. tr.CHeckedNodes appears to return an array without indicating the parent node.
Thanks for the help.
fig = uifigure;
gl = uigridlayout(fig,[1 2]);
gl.ColumnWidth = {'2x','1x'};
vehicle=["train" "train" "plane" "plane" "plane"]';
action=["test" "test" "test" "train" "train"]';
T=table(vehicle, action);
tbl = uitable(gl,"Data",T);
tr = uitree(gl,'checkbox');
vars = string(T.Properties.VariableNames);
for k1 = 1:length(vars)
var = vars{k1};
varnode = uitreenode(tr,"Text",var);
rows = T{:,var};
names = categories(categorical(rows));
for k2 = 1:length(names)
text = names{k2};
uitreenode(varnode,"Text",text);
end
end
% manually check vehicle.train and action.test in tree
>> tr.CheckedNodes
ans =
2×1 TreeNode array:
TreeNode (train)
TreeNode (test)
  5 个评论
Everett Weber
Everett Weber 2023-1-24
@Peter Perkins, OK, I looked at this more closely. I think pulling code from elsewhere was my downfall. I will see if I can simplify the code with your suggestions. To be honest, there may be too many ways to access information, and the way data is accessed results in different data. Thank you for your comments. I do appreciate the time you took looking at the code.
Everett Weber
Everett Weber 2023-1-24
@Peter Perkins I found the code source. If you would like to change the Matlab documentation to better reflect optimal coding, that would be great.
see "Generate Tree Nodes Based on Table Data"
I am updating the code to reflect a more refined mechanism for pulling the data. I beleive it is important to note that the T{:,["vehicle" "action"]} can pull data that the dot notation cannot.
I am also passing the name of the variable rather than the number of the variable, because the var_list does not necesarily have the same number or order of variables as the source table. I therefore need to pass the name rather than the number of the variable. Once again, thank you for your alert eyes.
As you can see I used both your suggestion for dot notation and unique rows.
function populate_tree(source_table, var_list, tree_obj)
% populate nodes in tree object based upon a source table and
% variable list
% Inputs
% source_table: data source where options will be pulled from
% var_list: list of variables used to populate tree
% tree_obj: target for created tree
% can gt variable names with vars = string(source_table.Properties.VariableNames);
% Note: this will add nodes to teh existing tree. To remove all
% nodes first. Use the delete method on the children of the
% tree.
% tree_obj=app.myTree; % make reference to tree, can use
% in function call.
% myTree.Children.delete; % delete children of tree.
for var_num = 1:length(var_list)
var = var_list{var_num};
varnode = uitreenode(tree_obj,"Text",var);
names=unique(source_table.(var));
for k2 = 1:length(names)
text = names(k2);
uitreenode(varnode,"Text",text);
end
end
end

请先登录,再进行评论。

采纳的回答

Everett Weber
Everett Weber 2023-1-19
编辑:Everett Weber 2023-1-24
Thank you @Rohan, That was helpful information, but because the object sent back is not an actual heirarchical array, One cannot know whether a leaf is a parent or child leaf without more processing. It is also not a quick check on the location of the checked options. I therefore created the functions below to process treenode data.
My ultimate goal is to use the information from the tree object to filter a table. I created 2 functions to 1) identify the options that are checked, ignoring any parent nodes that are checked (because that means no filtering on that field) and 2, create a logical array to filter the source table. Both functions were designed to be used in app designer, the first variable in the function is therefore app. If someone wants to adapt them more generally, they could remove the app option from function variable lists. The functions using trees assume a 2 level heirarchy (ie it would need to be adjusted if 3 or more levels were used).
I also threw in 2 other functions:the populate_tree function to simplify creating nodes and get_table_varinfo to get information about the tables in a form that is more easily usable (in particular the variable type of each field in the table). I anticipate repopulating trees on a regular basis, so this is an important function.
I added this infor hoping that the added info would he helpful for others.
% Jan 20, 2023
% - updated get_checked_nodes to return empty sets if tree object is
% empty
% - updated get_filtered_rows to return trues for all rows if
% filter_criteria is empty
% Jan 23, 2023. update to get_filtered_rows
% - changed "any" to "all" in last line of function
% (thank you for catching that Sanket!)
% - also changed num_vars=size(filter_criteria,1);
% to num_vars=size(filter_criteria,2);
% Jan 24, 2023. Updated populate tree to be more efficient, no functional
% change.
% on a callback to populate the tree
% app.data is an imported excel spreadsheet
% app.selecteddocfield_EditField.Value is the field
% selected for text analysis, so I do not
% want to add it to the list of fields to
% filter on.
% get source data table and variable list
source_table=app.data;
doc_field=app.selecteddocfield_EditField.Value;
var_info = get_table_varinfo(app, source_table);
var_list=var_info.VarNames(var_info.VarType=="string"); % only take the string fields
var_list=var_list(var_list~=doc_field);
tree_obj=app.comp1_filter_Tree;
tree_obj.Children.delete;
populate_tree(app,source_table,var_list, tree_obj);
% on callback to pull the checked options
% app.comp1_filter_Tree.CheckedNodes gets the checked nodes
% from the uitree of interest
% app.data is an imported excel spreadsheet
%
checkedNodes = app.comp1_filter_Tree.CheckedNodes;
filter_criteria=get_checked_nodes(app,checkedNodes);
unfiltered_data=app.data;
filtered_rows=get_filtered_rows(app, unfiltered_data, filter_criteria);
% this is the filtered data that can be used in a visualization
filtered_data=unfiltered_data(filtered_rows,:);
% functions to create and use uitree node data
function [filter_criteria, checked_nodes] = get_checked_nodes(app, checked)
% checked = checked nodes object from tree
% if tr = tree, checked=tr.CheckedNodes
% filter_criteria = structure with variables and values objects,
% each record has the name of the variable in variables as a
% string and a string array of the values for those items
% checked in the nodes.
% checked_nodes = table with all checked nodes. Table Structure
% includes node level (only level 2 is included), Parent
% (variable name), and leaf (selected string option in
% treee).
% Note: if the parent node is checked, the values will not be
% returned, because all records would be returned and there
% are no criteria to folter on. Also, CheckedNodes only
% returnes checked nodes, not unchecked nodes.
% if no nodes are checked, both outputs are empty
if size(checked,1)==0
filter_criteria=[];
checked_nodes=[];
return
end
node_num=size(checked,1);
checked_nodes=table(Size=[ node_num 3],VariableTypes=["double" "string" "string"],VariableNames=["node_level" "parent_node" "leaf"]);
for node_id=1:node_num
if checked(node_id).Parent.Type~="uitreenode" % if parent node is not uitreenode, then top level
checked_nodes.node_level(node_id)=1;
checked_nodes.parent_node(node_id)=checked(node_id).Text; % note parent nodes have themselves as parent here
checked_nodes.leaf(node_id)=checked(node_id).Text;
else
checked_nodes.node_level(node_id)=2;
checked_nodes.parent_node(node_id)=checked(node_id).Parent.Text;
checked_nodes.leaf(node_id)=checked(node_id).Text;
end
end
check_parents=checked_nodes.leaf(checked_nodes.node_level==1);
node_rows=~ismember(checked_nodes.parent_node,check_parents);
checked_nodes=checked_nodes(node_rows,:); % removes parents from checked_nodes
clear filter_criteria
varnames=unique(checked_nodes.parent_node);
for varnum=1:size(varnames,1)
filter_criteria(varnum).variables=varnames(varnum);
filter_criteria(varnum).values=checked_nodes.leaf(checked_nodes.parent_node==varnames(varnum))';
end
end
function [filtered_rows] = get_filtered_rows(app,source_table, filter_criteria)
% create a logical array of filtered rows based upon a source
% table and filter criteria. The array can then be used to
% select specific rows from a table or array. The filter
% criteria are logical or within a variable and logical and
% between fields. In other words, it selects fields that have
% any option in the values within a field, but if multiple
% fields are used, the row must be selected for each
% variables used in the filter.
% ( filter_criteria(1).variables="vehicle",
% filter_criteria(1).values=["car" "train"],
% filter_criteria(2).variables="action",
% filter_criteria(2).values=["drive"]
% ) results in only cars and trains whose action is drive
% inputs
% source_table: source of data. Must contain the
% variables listed in filter_criteria and the
% filtered columns must be strings.
% filter_criteria: structured array with one record per
% variable. Fields in structured array are variables
% (name of variables) and values (the specific values
% to be included in the filtered rows).
% outputs
% filtered_rows: logical array of those rows to be
% included.if filter_criteria is empty, output is true
% for every row of source_table.
if isempty(filter_criteria)
filtered_rows=true(size(source_table,1),1);
return;
end
num_vars=size(filter_criteria,2);
filtered_matrix=[];
for varnum=1:num_vars
filtered_matrix(:,varnum)=ismember(source_table.(filter_criteria(varnum).variables),filter_criteria(varnum).values);
end
filtered_rows=all(filtered_matrix,2);
end
function populate_tree(app,source_table, var_list, tree_obj)
% populate nodes in tree object based upon a source table and
% variable list
% Inputs
% source_table: data source where options will be pulled from
% var_list: list of variables used to populate tree
% tree_obj: target for created tree
% can gt variable names with vars = string(source_table.Properties.VariableNames);
% Note: this will add nodes to teh existing tree. To remove all
% nodes first. Use the delete method on the children of the
% tree.
% tree_obj=app.myTree; % make reference to tree, can use
% in function call.
% myTree.Children.delete; % delete children of tree.
for var_num = 1:length(var_list)
var = var_list{var_num};
varnode = uitreenode(tree_obj,"Text",var);
names=unique(source_table.(var));
for k2 = 1:length(names)
text = names(k2);
uitreenode(varnode,"Text",text);
end
end
end
function var_info = get_table_varinfo(app, source_table)
% function to get variable information for the source_table
% Information similar to what would pull when pulling from
% system tables in database.
var_info=table();
var_info.VarNames=string(source_table.Properties.VariableNames');
var_info.VarPos=[1:size(var_info,1)]';
% set property info to empty or null value as default
% then replace if not missing
var_info(:,'VarDesc')={""};
var_info(:,'VarUnit')={""};
if size(source_table.Properties.VariableUnits,2)>0
var_info.VarUnit=string(source_table.Properties.VariableUnits');
end
if size(source_table.Properties.VariableDescriptions,2)>0
var_info.VarDesc=string(source_table.Properties.VariableDescriptions');
end
var_types=[];
for varnum=1:size(source_table,2)
var_types=[var_types string(underlyingType(source_table.(varnum)))];
end
var_info.VarType=var_types';
end
  6 个评论
Sanket
Sanket 2023-1-23
Hi Everett, thanks for the description of “filter_criteria”.
Since the second dimension determines the number of fields, I believe the following line:
num_vars=size(filter_criteria,1);
Should be replaced with:
num_vars=size(filter_criteria,2);
You can definitely attach an example that uses the functions, if it is not too much to add.
Everett Weber
Everett Weber 2023-1-23
Thanks, made the change to the code and will put together quick example later today or tomorrow.

请先登录,再进行评论。

更多回答(1 个)

Rohan
Rohan 2023-1-19
编辑:Rohan 2023-1-19
The parent information is inherently present in each checked node. Since "tr.CheckedNodes" returns an array of checked nodes, the parent information can be found by accessing the "Parent" property of each node in this array, as shown below:
>> parent = tr.CheckedNodes(2).Parent
parent =
TreeNode (action) with properties:
Text: 'action'
Icon: ''
NodeData: []
Show all properties
Even if "train" is checked under both "vehicle" and "action", the parent of both "train" nodes can be found using the same syntax:
>> tr.CheckedNodes
ans =
2×1 TreeNode array:
TreeNode (train)
TreeNode (train)
>> tr.CheckedNodes(1).Parent
ans =
TreeNode (vehicle) with properties:
Text: 'vehicle'
Icon: ''
NodeData: []
Show all properties
>> tr.CheckedNodes(2).Parent
ans =
TreeNode (action) with properties:
Text: 'action'
Icon: ''
NodeData: []
Show all properties

类别

Help CenterFile Exchange 中查找有关 Text Data Preparation 的更多信息

产品


版本

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by