Tree widgets and check-state

I have conundrum; figured I’d solicit feedback publicly.

Here’s the context:

I am working on a new Extract Block filter that extracts blocks using names/paths instead of some internal ids (as it currently does) which are overly sensitive to the data hierarchy.

Consider the following hierarchy from a Ioss/Exodus reader as an example:
image

Here, in this new ExtractBlock filter, to extract nodelist_1, for example, one can specify the full-path, /Ioss/node_sets/nodelist_1 or a shorter version, //nodelist_1. Multiple such paths may be specified to select multiple nodes. Thus, to select both the nodelists, one can add two paths as follows: [//nodelist_1, //nodelist_2], or simply select the parent node using a single path //node_sets.

While for this file, the result will be identical no matter how the 2 nodelists are selected, the result may be totally different on a different file with differently named nodelists or different number of nodelists. Specifying paths as [//nodelist_1, //nodelist_2] will ensure that no matter what the file, only the blocks for nodelists named nodelist_1 and nodelist_2 will be extracted. While using the //node_sets as the path results in all blocks under the node_sets being extracted no matter their names or count.

Now, the problem: how to make it clear in the UI which of the two ways has the user made the selection, i.e. has the user chosen the two nodelists explicitly or has the user chosen all nodelists by checking node_sets node instead?

Option 1: The standard behavior for tree-views is that for any node, if all children are checked, then the parent node is rendered as checked as well, if none are checked it’s rendered as unchecked and if some are checked and some are unchecked, it’s rendered as partially-checked. This is what ParaView does currently. This is definitely a no-go since the widgets appear exactly the same no matter which of the aforementioned two ways the nodelists were selected.

image

Option 2: Only show check marks for nodes that user explicitly checked. Here, the widget in the two cases will render as follows:

image image

It’s fairly obvious which mode the user is going for here, so that’s good. However, note child nodes don’t reflect the check-state of the parent at all e.g. when node_sets was checked, nodelist_1 and nodelist_2 still appear unchecked.

Option 3A: Only show check marks for nodes that the user explicitly checked. However, if a parent-node is checked, for all child nodes, render them as partially-checked.

image image

Option 3B: Same as 3A, except we use the paritionally-checked representation for parent nodes of the explicitly checked nodes as well.

image image

What do people think? Note, this goes beyond just Extract Block and check-states. All properties that one sets up using the Multiblock Inspector such as color, opacity etc. also will start using these paths/path-expressions in time so we should think of an solution that is widely applicable.

I have a personal preference, of course, but I’ll hold that back for now.

I’m very mildly leaning towards 2. I think that filled and checked has unclear meaning in 3. After you look at 2 for a bit, it is clear what the meaning is.

I will say I can live with any of the 2 or 3 options. People will get use to it.

I agree. While originally I was thinking 3B, you’re right, the filled boxes are unclear. Option 2 is far more explicit and, thankfully for me, the easiest to implement. I am going to go with 2 for now. We can revisit if new and more convincing arguments/options are posted.

I also asked Ken and Watney to look at this. Haven’t heard back yet.

I will say that I don’t quite understand the use case. Regardless of whether you select both nodelists as [ //nodelist_1 , //nodelist_2 ] or as //node_sets results in the same behavior from the user’s perspective. It only makes a difference if you save this as a script and then re apply it to a similar but different data set. Anyone sophisticated to care should be able to play with the script enough to fix it.

True, but only if the user never went back to the reader to change the nodesets to load. For example, if the file has 100 nodesets, and one only chose 2 on them to read, the tree view will only show the two nodesets chosen, not the other 98 nodesets not read [1]. Now, if you go back to the reader to enable a few more nodesets, the result will be different based on how the selection is defined.

Note the issue is beyond just check-states and Extract Block filter. For example, soon we’ll have ability to set opacity / color for any of these items. There too, there is a difference between explicit set color/opacity for a node and those that get inherited. The Multiblock Inspector currently does a reasonable job with these by rendering explicitly set values and inherited values differently for color/opacity. It doesn’t do that for checkboxes, however. That isn’t a big deal now since the visibility is set using composite-id which is tightly coupled with the structure. Once we start supporting setting colors/opacity/visibility using paths, we have the same challenge as this Extract Block case. Training users to realize this difference is probably a good idea. Most won’t care, but I there are always those advanced users who would.

[1] this is the new IossReader behavior, and not what the ExodusReader currently does. I think I prefer this new behavior for the reason that output doesn’t get cluttered with empty datasets for blocks/sets that are not read.

I had not considered the possibility of changing the reader state that changes the assembly, but I’m still of the opinion that this is not a strong enough reason to do some goofy crap in the GUI that makes the user distinguish between selecting a subtree and selecting everything in a subtree.

So I think we should go with option 1 with the exception that if someone selects all items in a subtree, that subtree itself gets selected. So in your example if a user selects nodelist1 and nodelist100, then the whole node_sets subtree automatically gets selected. This means if the user then goes back to the reader and turns on the other 98 nodesets, they will all be selected.

What this means is that there is no way to express that all the existing items in a tree are selected but if new items are added they should not be selected. But that seems like such a small use case it does not seem worth supporting.

Naturally, 3 outside opinions and 3 different opinions :slight_smile:

I like 3B. I’m just thinking if the tree gets collapsed that I have a way of figuring out things vs. if 2 is collapsed I don’t know what’s going on underneath. 3B also provides finer-grained control over 1.

Want me to put on the list for tomorrow?

Fair point. Let’s stick with the familiar option 1 then. What we can easily offer is an alternate view e.g. in a tab or something that simply shows the raw paths instead of the tree widget and user can then enter whatever paths they want to fine-tune the selection.

image

That way is user specified weird expressions in Python script and loaded that in the GUI, the GUI can still faithfully support them.

This table view can have columns too, thus, can be extended to support the complete Multiblock Inspector use-case too.

That’s exactly why my original preference was 3B too. But Ken has convinced me, preserving user’s intuition is probably more important than some adding new idiosyncrasies. Plus, the explicit values view helps us avoid sacrificing flexibility for advanced users.

Hi

I did a small plugin for our company last year, when I was trying to display a named block. We had a similar struggle.

Option 2 seems to be the best one for me, since it’s telling us that you have selected the “group”.

My version didn’t have the visual representation since I was struggling a bit so I removed it.


I added a small property “Ignore Compose DataSet”, An user would only be able to select a child which isn’t a multi-block dataset

Everyone seems to have understood each option.

I’m in the Option 1 camp as well. It is the common GUI design for this type of tree-based selection - and changing the meaning of commonly understood selection symbols seems like a recipe for confusion among ParaView users.

Couldn’t the fact that a node is explicitly selected be tracked internally and used to prevent this if it is a concern?

That is exactly the problem: if we track the state differently, and the GUI doesn’t show the difference, I think it’s even more confusing. Hence, if user individually checked all child nodes, which results in checking the parent node, and if we go with option 1, it really should not be any different than the user selecting the parent node.

Fully agree. I was speaking to the issue expressed by Ken:

If we are really worried about this case, then newly available tree items could be flagged as not explicitly selected. When rebuilding the tree model you could check all the children’s explicit selection status to see if the parent should be partially checked or fully checked. It’s probably more trouble than it is worth, and might not be what users expect.

The “issue” I raised is not so much an issue but just a consequence of the change. Honestly, I think this behavior will affect a sum total of 0 users and we should just let it be. As @utkarsh.ayachit said, trying to track which way the tree is selected will just create confusion and fix no real issue.

Thanks for the input, folks. Here’s the current implementation using option 1 together with an advanced list view for those few users who want more control. Note how the two tabs stay in sync as edits are made in 1 tab or the other.

Peek 2020-04-23 17-58

If people have suggestions for the tab-names, I am all ears.

Looks good to me. A follow-up question on this – for a Python trace, if I select element_blocks in the example above and then run the generated Python script on a different input dataset with more than 2 blocks under the element_block node (e.g. block_1, block_2 and block_3), will all of them be selected here? That was a pain before and one of the problems I think you’re trying to solve, which would be a nice improvement in my mind.

yes, they will. Selecting element_blocks will extract all element-blocks even after the input dataset changes and new blocks appear.

1 Like

@utkarsh.ayachit - two questions (one on-topic, one off-topic):

  1. how close is this to being adding into VTK tree? Looking a recent master, it seems that it still has the select by indices only setup.
  2. I would like to replace the very long selector list for the OpenFOAM reader to have a tree hierarchy since the current flat list gets really confusing with multi-region systems with a number of boundaries. Is there a suitable selection+GUI element that I be looking for?

cheers,
/mark

The implementation is in. See vtkDataAssembly. On ParaView side, see vtkSMDataAssemblyDomain. However this is not meant for selection on readers, but rather selection for filters like extract blocks and other places like multiblock inspector. Those components still use the old composite id and I am working on it actively these days.

Can you elaborate on your use-case? Maybe we can use the same vtkDataAssembly for reader block selection too, if it’s necessary. But I’d like to understand what you’re thinking for OpenFOAM reader.