cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
  • Register to attend Discovery Summit 2025 Online: Early Users Edition, Sept. 24-25.
  • New JMP features coming to desktops everywhere this September. Sign up to learn more at jmp.com/launch.
Choose Language Hide Translation Bar
BabyDoragon
Level II

Searching elements in Tree box

Is it feasible to search for elements in a tree box?
The method shown in the link below searches for user-entered elements in a list box, but this approach does not apply to a tree box.

Searching elements in listbox 

This is because a list box can easily use a loop to search through all items. What methods can be used to search for elements in a tree box?

The following JSL is an example of creating a simple tree box.
dt=New Table( "Food Tree",
	Add Rows( 8 ),
	New Column( "Name",
		Character,
		"Nominal",
		Set Selected,
		Set Values(
			{"Apple", "Banana", "Watermelon", "Fruit", "Broccoli", "Lettuce",
			"Potato", "Vegetable"}
		)
	),
	New Column( "Category",
		Character,
		"Nominal",
		Set Values(
			{"Fruit", "Fruit", "Fruit", "", "Vegetable", "Vegetable", "Vegetable",
			""}
		)
	),
	New Column( "Level",
		Numeric,
		"Continuous",
		Format( "Best", 12 ),
		Set Values( [2, 2, 2, 1, 2, 2, 2, 1] )
	),
	Set Row States( [0, 0, 0, 1, 0, 0, 0, 0] )
);
relations = [=>];
For Each Row( dt,
	relations[:Name] = Tree Node( :Name );
	relations[:Name] <<Set Data( Eval List( {:Name, :Category,  :Level} ) );
);
roots = {};
For Each Row( dt,
	If( :Category != "" & relations << Contains( :Category ),
		relations[:Category] << Append( relations[:Name] )
	,
		roots[N Items( roots ) + 1] = relations[:Name]
	);
);
New Window( "TreeBox Tests", 
	tree = Tree Box( roots, Size( 300, 500 ) ) );

key = relations << First;
While( !Is Empty( key ),
	Try( tree << Expand( relations[key] ) );
	key = relations << Next( key )
);
tree << Set Node Select Script(
	Function( {this, node},
		Print( node << Get Data )
	)
);



15 REPLIES 15
BabyDoragon
Level II

Re: Searching elements in Tree box

The meaning seems to suggest that even if the Clone Box method is used, it cannot avoid the fact that when a copied tree node is removed, the original tree and its root are also removed.
This means that each time a keyword is changed, a new tree must be established, and then the nodes that match the keyword are removed. As a result, if there are many nodes, searching for keywords becomes very time-consuming in terms of computation.

Are there any alternative methods to create a completely independent copy of the original tree?
jthi
Super User

Re: Searching elements in Tree box

You can go over the tree box and create copy "manually" (loop over the tree and build a copy) or rebuild it based on some other data structure (data table / associative array / your own custom class for example). Or you can try if there are methods to prevent this from happening by using expressions / functions.

-Jarmo
BabyDoragon
Level II

Re: Searching elements in Tree box

It seems that I can only regenerate a new tree each time. I changed it to the following JSL, and it works properly when the keyword is 1, but if I enter 2, 4, or something similar, it doesn't succeed. Could you please let me know what the problem might be?

root1 = Tree Node( "Parent 1" );
root2 = Tree Node( "Parent 2" );

c1 = Tree Node( "Child 1" );
c2 = Tree Node( "Child 2" );
c3 = Tree Node( "Child 11" );
c4 = Tree Node( "Child 4" );

filter_itemsSensorListTree = Function( {this, searchText},
	{filtered_items, i}, 
	// only attempt to filter if there is any text
	If( searchText != "",
		tree << delete;
		search_term = searchText;
		root1 = Tree Node( "Parent 1" );
		root2 = Tree Node( "Parent 2" );

		c1 = Tree Node( "Child 1" );
		c2 = Tree Node( "Child 2" );
		c3 = Tree Node( "Child 11" );
		c4 = Tree Node( "Child 4" );
		root1 << Append( c1 );
		root1 << Append( c2 );
		root2 << Append( c3 );
		root2 << Append( c4 );
		tree = Tree Box( {root1, root2}, Size( 300, 200 ) );
		For Each( {root}, tree << get roots,
			is_hidden = 1;
			For( i = 1, i <= root << Get Child Count, i++,
				cur_child = root << get child( i );
				If( Contains( cur_child << get label, search_term ),
					is_hidden = 0, 
			
					cur_child << remove
				);
			);
			If( is_hidden,
				tree << Collapse( root ),
				tree << Expand( root )
			);
		);
		vlb << append( tree );
	, 
		
	);
	
);


root1 << Append( c1 );
root1 << Append( c2 );
root2 << Append( c3 );
root2 << Append( c4 );
tree = Tree Box( {root1, root2}, Size( 300, 200 ) );
tree << Expand( root1 );
tree << Expand( root2 );

nw = New Window( "TreeBox",
	H List Box(
		Icon Box( "SearchIndex" ),
		Spacer Box( size( 5, 10 ) ),
		item_search_teb_AllSensorTree = Text Edit Box( "",
			<<set width( 150 ), 

			<<set text changed( filter_itemsSensorListTree )
		),
		reset_button_AllSensorTree = Button Box( "",
			<<set icon( "DebuggerDeleteBreakpoint" ),
			<<set script(

				item_search_teb_AllSensorTree << set text( "" );
				tree << delete;
				root1 = Tree Node( "Parent 1" );
				root2 = Tree Node( "Parent 2" );

				c1 = Tree Node( "Child 1" );
				c2 = Tree Node( "Child 2" );
				c3 = Tree Node( "Child 11" );
				c4 = Tree Node( "Child 4" );
				root1 << Append( c1 );
				root1 << Append( c2 );
				root2 << Append( c3 );
				root2 << Append( c4 );
				tree = Tree Box( {root1, root2}, Size( 300, 200 ) );
				tree << Expand( root1 );
				tree << Expand( root2 );
				vlb << append( tree );
			),
			<<set tip( "Clear filter" ), 

		),
		Spacer Box( size( 5, 10 ) ), 

	),
	vlb = V List Box( tree );
	
);

 

jthi
Super User

Re: Searching elements in Tree box

This very quick example might give some ideas

Names Default To Here(1);

initialize_tree = function({}, {Default Local},
	root1 = Tree Node("Parent 1");
	root2 = Tree Node("Parent 2");

	c1 = Tree Node("Child 1");
	c2 = Tree Node("Child 2");
	c3 = Tree Node("Child 11");
	c4 = Tree Node("Child 4");
	root1 << Append(c1);
	root1 << Append(c2);
	root2 << Append(c3);
	root2 << Append(c4);
	tree = Tree Box({root1, root2}, Size(300, 200));
	
	tree << Expand(root1);
	tree << Expand(root2);
	
	return(tree);
);


filter_itemsSensorListTree = Function({vlb, search_term}, {Default Local}, 
	If(search_term != "", 
		new_tree = initialize_tree();
		For Each({root}, new_tree << get roots,
			For(i = root << Get Child Count, i >= 1 , i--,
				cur_child = root << get child(i);
				If(Contains(cur_child << get label, search_term),
					new_tree << Make Visible(cur_child);
				,
					cur_child << remove;
				);
			);
			If(root << Get Child Count == 0,
				new_tree << remove root(root);
			);
		);
	,
		new_tree = initialize_tree();
	);
	vlb_new = V List Box(new_tree);
	vlb << Inval;
	(vlb << Child) << Delete Box();
	vlb << Append(vlb_new);
	vlb << Update Window;
);

nw = New Window( "TreeBox",
	H List Box(
		Icon Box( "SearchIndex" ),
		Spacer Box( size( 5, 10 ) ),
		item_search_teb_AllSensorTree = Text Edit Box("",
			<<set width( 150 ), 
			<<set function(function({this},
				filter_itemsSensorListTree(vlb, this << get text)
			))
		),
		Spacer Box(size( 5, 10 )), 

	),
	vlb = V List Box(
		V List Box(
			initialize_tree()
		)
	);
);

 

-Jarmo
BabyDoragon
Level II

Re: Searching elements in Tree box

I tried to change it to the following JSL. I want to get the label name by pressing a button after selecting a node. However, this results in an error when selecting a new option on the tree after entering keywords for filtering, possibly because `new_tree` is just a local variable. How should I fix it so that I can obtain the selected label from the new tree after the keyword search?

Names Default To Here( 1 );

initialize_tree = Function( {},
	{Default Local},
	root1 = Tree Node( "Parent 1" );
	root2 = Tree Node( "Parent 2" );

	c1 = Tree Node( "Child 1" );
	c2 = Tree Node( "Child 2" );
	c3 = Tree Node( "Child 11" );
	c4 = Tree Node( "Child 4" );
	root1 << Append( c1 );
	root1 << Append( c2 );
	root2 << Append( c3 );
	root2 << Append( c4 );
	tree = Tree Box( {root1, root2}, Size( 300, 200 ) );
	
	tree << Expand( root1 );
	tree << Expand( root2 );
	
	Return( tree );
);


filter_itemsSensorListTree = Function( {vlb, search_term},
	{Default Local},
	If( search_term != "",
		new_tree = initialize_tree();
		For Each( {root}, new_tree << get roots,
			For( i = root << Get Child Count, i >= 1, i--,
				cur_child = root << get child( i );
				If( Contains( cur_child << get label, search_term ),
					new_tree << Make Visible( cur_child ),
					cur_child << remove
				);
			);
			If( root << Get Child Count == 0,
				new_tree << remove root( root )
			);
		);
	,
		new_tree = initialize_tree()
	);
	vlb_new = V List Box( new_tree );
	vlb << Inval;
	(vlb << Child) << Delete Box();
	vlb << Append( vlb_new );
	vlb << Update Window;
);

nw = New Window( "TreeBox",
	H List Box(
		Icon Box( "SearchIndex" ),
		Spacer Box( size( 5, 10 ) ),
		item_search_teb_AllSensorTree = Text Edit Box( "",
			<<set width( 150 ),
			<<set function( Function( {this}, filter_itemsSensorListTree( vlb, this << get text ) ) )
		),
		Spacer Box( size( 5, 10 ) ), 

	),
	vlb = V List Box( V List Box( tree=initialize_tree() ) ),
	Button Box( "Select", 						
		SelectNode = (tree << GetSelected) << Get label;
		try (ShowText<<delete);
		VLB2<<Append(ShowText=Text Box( SelectNode ));
	),
	VLB2=vlistbox(),
);
jthi
Super User

Re: Searching elements in Tree box

Your Button Box is referencing wrong display box as the tree it is referencing to has been deleted. There are good ways around this via updating the reference but you can also make it dynamic and always look for the latest tree box inside vlb for example. 

Button Box("Select",
	label_selected = (vlb[TreeBox(1)] << get selected) << get label;
	Try(ShowText << delete);
	VLB2 << Append(ShowText = Text Box(label_selected));
),
-Jarmo

Recommended Articles