Welcome, Guest. Please Login
Tinderbox
  News:
IMPORTANT MESSAGE! This forum has now been replaced by a new forum at http://forum.eastgate.com and no further posting or member registration is allowed. The forum is still accessible via read-only access for reference purposes. If you wish to discuss content here, please use the new forum. N.B. - posting in the new forum requires a fresh registration in the new forum (sorry - member data can't be ported).
  HomeHelpSearchLogin  
 
Pages: 1
Send Topic Print
Doing a conditional count of container (Read 4715 times)
J Fallows
Full Member
*
Offline



Posts: 418

Doing a conditional count of container
Jan 28th, 2013, 1:32am
 
I have been reading my way through the invaluable aTbRef, and I know the answer to what I'm about to ask is included therein. But for clarity and on the chance that this might be clarifying to others, I'll ask in "public."

- I have a number of containers, each representing a project I want to do. They are based on a common prototype, *Projects.

- Their child notes are the task and to-do items for each respective project. They have the prototype *Tasks.

- I have the Display Expression for these containers set up to show the number of child items. The Display Expression is $Name+" ("+$ChildCount+")"

- These child items have a Boolean attribute $Done, which is "false" by default but is switched to "true" when an item is completed

My goal: I would like to change the look of a container's name, depending on whether any of its child items are still un-done. For instance, the container's name might be in boldface if there are undone items, and regular font if all the child items are done.

How, exactly, do I set a Rule for the container items to do a conditional count? That is, to count the child items for which $Done=="false", and then change the look of the parent container based on whether that count is >0 or not?

Thank you.
__
I recognize too that the clue might be in this part of aTbRef, on "Rules":
Quote:
A note might have a rule
     <code>$Urgent=any(children,$Urgent)</code> 
…meaning, "this note is urgent if any of its immediate children are urgent."
Another rule might be
     <code>$Urgent=$Urgent(parent)</code> 
…meaning, "this note is urgent if its parent is urgent."
Back to top
 
« Last Edit: Jan 28th, 2013, 1:39am by J Fallows »  
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Doing a conditional count of container
Reply #1 - Jan 28th, 2013, 5:26am
 
OK, we want to count the number of $Done child items, and toggle $NameBold to bold the parent's container if any child items are not done. Rather than do sums in the display expression (which can be less efficient as your document grows), we'll add a Number attribute $DoneCount. Now in the container prototype's $Rule:

$DoneCount = sum_if("children", $Done,1)

Each child is polled and if $Done is ticked (true) 1 is added to the container's $DoneCount. The '$Done' argument is simply a shorthand form of $Done==true. Then, the Display Expression could now be something like:

$Name+" ("+$DoneCount+" of "+$ChildCount+")"

Next to check degree of completion, bolding the container title if any child is not 'done'. Add this to the (prototype) container $Rule:

$Done=every("children",$Done);
if($Done){$NameBold=;}else{$NameBold=true"


Another route might be to compare $DoneCount and $ChildCount. If doing that, be aware that $ChildCount (and $DescendantCount) include in their count any adornments which won't be visible other than in Maps and for which you probably won't set $Done. Codes any() and every() seem to exclude adornment count.

Lastly, if you're using prototypes and have been experimenting with display expressions in notes, ensure all notes using the prototype have their $DisplayExpression reset to inherit.
Back to top
 
« Last Edit: Jan 28th, 2013, 5:28am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
J Fallows
Full Member
*
Offline



Posts: 418

Re: Doing a conditional count of container
Reply #2 - Jan 28th, 2013, 9:42am
 
Once again, thanks very much. Very clear and instructive.
Back to top
 
 
  IP Logged
Mark Bernstein
YaBB Administrator
*
Offline

designer of
Tinderbox

Posts: 2871
Eastgate Systems, Inc.
Re: Doing a conditional count of container
Reply #3 - Jan 28th, 2013, 10:08am
 
Quote:
My goal: I would like to change the look of a container's name, depending on whether any of its child items are still un-done


If this is literally the goal, try

    if( any(children,$Done==false) ) {$NameBold=true} else {$NameBold=false}

or, more concisely:

     $NameBold=  any(children,$Done==false)

This can be a little more efficient than counting the undone children, because sum_if() always looks at every child, were any() can stop as soon as it looks at a child task that isn't done.

-----
Another handy resource for Tinderbox is the Tinderbox Cookbook.  For example, we find a variety of examples of using any() here:

    http://www.eastgate.com/Tinderbox/cookbook/Expressions.html
Back to top
 
« Last Edit: Jan 28th, 2013, 10:08am by Mark Bernstein »  
WWW   IP Logged
J Fallows
Full Member
*
Offline



Posts: 418

Re: Doing a conditional count of container
Reply #4 - Jan 28th, 2013, 11:18am
 
Thanks for this, too, and the pointer to the Cookbook. I had looked at those "any"/"every"- type models before, but not recently.

Interestingly, when I add either of these two statements as a $Rule for my container prototypes:

Quote:
if( any(children,$Done==false) ) {$NameBold=true} else {$NameBold=false}

or, more concisely:

    $NameBold=  any(children,$Done==false)


The first-round effect is as intended. It makes container names bold, or not, depending on whether they have any un-done child notes.

The second-round effect is the interesting one. For debugging purposes, I have this TBX set up for manual rather than automatic agent-updates. And when I update the agents, the next effect is to mark every parent-container note $Done (indicated by strike-through of its $Name), if any of its child notes is done. [And, to clarify, that is NOT the behavior I want.]  Obviously there is some other agent kicking in here. I will check that out to see what I can find.
Back to top
 
« Last Edit: Jan 28th, 2013, 12:58pm by J Fallows »  
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Doing a conditional count of container
Reply #5 - Jan 28th, 2013, 12:49pm
 
$Rule for a container of tasks:

$NameStrike = (any("children",$Done==true))

$NameStrike is a Boolean, false by default (i.e. no strike-through). Any returns true/false. Above it returns true as soon as it processes a child whose $Done is 'true'.

In an agent, processing task containers, the same can be used (tested in v5.12.0), as in this case testing the alias tests the original's children. We can write a more terse version of the above  for the agent action, by using the short Boolean test of '$Done':

$NameStrike = (any("children",$Done))

Were the agent to be gathering tasks, rather than their parent containers, then you could use the action:

if($Done){$NameStrike(parent(original))=true;}else{$NameStrike=;}

You don't have to use the 'else' part if you never want a parent that is 'done' to reverse it's mark-up.  However, we sometimes tick boxes by mistake so making the setting a toggle rather than one way seems a better choice.

Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
J Fallows
Full Member
*
Offline



Posts: 418

Re: Doing a conditional count of container
Reply #6 - Jan 28th, 2013, 1:40pm
 
Again, thanks. By inverting one of the formulations you proposed, so that I have

   $NameStrike = (every("children",$Done))

instead of

   $NameStrike = (any("children",$Done))

I end up with the behavior I am looking for. That is, a project's name is struck-out if all of its child items are completed. So thanks for this guidance.

I recognize that an "every" rule takes more processing time than an "any" rule; that I will want to add "else" provisions for resetting a toggle; and so on. But this gives me additional traction.
__

And to close the loop, here is the $Rule code that handles the bolding, and non-bolding, of container names depending on the $Done-ness of their children:

  $NameBold = (any("children",!$Done)) else !$NameBold

Thanks for guidance.
Back to top
 
« Last Edit: Jan 28th, 2013, 5:32pm by J Fallows »  
  IP Logged
Mark Bernstein
YaBB Administrator
*
Offline

designer of
Tinderbox

Posts: 2871
Eastgate Systems, Inc.
Re: Doing a conditional count of container
Reply #7 - Jan 30th, 2013, 11:16am
 
Two details:

  • Don't quote keywords like "children" and "parent".  It's not necessary, and while it's harmless in the current version, the quotes might mean something else in the future.  So:   $NameStrike = (every(children,$Done)) is better.
  • Notice that every(children,$Done) is exactly the same as any(children,(!$Done) ).  That is, if you have done everything then there is nothing left to do, and if you have any thing to do then you have not yet done everything.  So it’s easy to move from every to any/


As a rule, don’t worry too much or too soon about efficiencies like "every" vs "any".  Most of the time, either will be fast enough. But it's good to keep this every/any trick in mind, since it sometimes can save a lot of time and at other times it can take a tangled expression and make it much simpler.
Back to top
 
 
WWW   IP Logged
Pages: 1
Send Topic Print