Recursive filter operators to show all tiddlers beneath a tag and all tags above a tiddler

Hi,

i am sorry ,but what is the alternative to to a text widget when doing sums,

because i used to do this

[kin::to<currentTiddler>get[field]sum[]]

then show it in a text widget

now

[<currentTiddler>taggingtree[]get[field]sum[]]">

doesnt work with a text widget and only sums one level down

Hi @paulgilbert2000, difficult to say what the problem is without a live example. Filters generally don’t depend on the widget they’re used in.
You could try debugging the filter with the debug-log operator from here:
https://yaisog.tiddlyhost.com/#%24%3A%2Fplugins%2Fyaisog%2Fdebug-log-filter

You might first want to check if the list of tiddlers after kin[] and after taggingtree[] are the same.

My bad , i got myself all confused , the only difference is that kin filter in sum operations counts the current tiddler ,where as tag tree doesn’t .

Thank you very much for the filter, its way way faster than kin filter!!

@linonetwo would it be possible for you to publish and English version of your revised plugin?. I am keen to make extensive use of it. Sorry I can read Chinese :frowning:

I’m currently making heavy usage of kin:list:to[] and kin:list:from[] to return the whole list of related tiddlers using the list fields. If I’m reading this correctly, I’m not able to take advantage of these improved performance versions as I’m using list fields intead of tags - is that correct?

@TW_Tones Recently @dongrentianyu add the translated content with the help of deepl, you can switch to it using this drop down!

The PR is in docs: 借助deepl翻译文档 by dongrentianyu · Pull Request #4 · tiddly-gittly/in-tagtree-of · GitHub , If you find any misspell or place that is not fluent, don’t hesitate to make a PR to improve it. We are translating doc site in this way until we have a better solution to How to translate 3rd party plugin demo website?

1 Like

Yes, I use $tw.wiki.getTiddlersWithTag so only support tags. But you can try add new logic, or just fork to create a new operator. I fork most of the code from @Yaisog 's version too.

I think in your examples, “child” should be “descendant”.

It probably doesn’t matter to you per se, but to anyone in Europe or North America who wants to contribute, the use of Simpsons images is probably not fair use and may violate trademarks. Large companies will sometimes pursue even small infractions of their copyrights. It’s just tidier if you can avoid those complications.

What’s the difference?

I just copy them from elsewhere, maybe kin-filter’s doc? I don’t really like this kind of cartoon, I hope someone or I can have time to turn them into waifu using stable difussion.

A child is the direct descendant of a parent. A descendant is anyone, no matter how many generations, who is a descendant.

I am not the child of my grandfather, but I am a descendant of my grandfather.

To use CSS as a comparison, it’s like the difference between

div.level1 div.level2 { }

and

div.level1 > div.level2 { }

They are rather unattractive characters, aren’t they? But they are part of one of the longest running broadcast series. They are owned by Fo x Broadcasting, which is worth an estimated $18 billion.

That is why I would urge caution in using their images.

@Yaisog I was using the taggingtree operator for a path or route through all items in the tiddlywiki.com TableOfContents and realise the output of taggingtree does not maintain, or flatten the structure. Imagin you were to step through the top level items first, starting at the top one, now follow all its children, and their children in the order they are found until exhausted now move onto the next item in the top level.

  • The output of taggingtree is not in the above order, making it less useful navigating trees.

I don’t know if this achievable in your code but if you could output the list of titles in the “natural” and “flattened” order, it will have even more uses. The current order is not of much use, so the new order can be default and not need any switches.

Here’s my TiddlyTools <<toc-list>> macro (see https://tiddlytools.com/#TiddlyTools%2FTOC), which walks a TOC tree structure in the manner you have described (“depth-first traversal”) and produces a “flat list” output of links to all tiddlers in the TOC:

\define toc-list(here,max,exclude,level:"1",field:"tags")
<!-- SHOW FLAT LIST -->
<$list filter="""[contains:$field$[$here$]sortby{$here$!!list}] -[subfilter<__exclude__>] -[[$here$]]""">
   <$text text="[["/><<currentTiddler>><$text text="]]"/><br>
   <$reveal default="$level$" type="nomatch" text="$max$">
      <$macrocall $name="toc-list" here=<<currentTiddler>> max="$max$" exclude="""$exclude$ [[$here$]]""" level={{{ [[$level$]add[1]] }}} field=<<__field__>>/>
   </$reveal>
</$list>
\end

Notes:

  • Only the here parameter is required, where here is the top-level starting tag.
    Example: <<toc-list "TableOfContents">>
  • max (optional) allows you to limit the depth of traversal.
    Example: <<toc-list here:"TableOfContents" max:3>>
  • exclude (optional) can be used to provide a filter that ignores specified tiddlers. It is also used internally to prevent infinite recursive loops by ignoring any tiddlers that have already been visited in the current TOC tree branch.
  • level is used internally (along with max) to track the current depth.
  • field:fieldname (optional, default=“tags”) allows you to define the tree structure using a field other than “tags” (e.g., field:parent)
  • You can use <$wikify name="flatlist" text="<<toc-list TableOfContents>>">...</$wikify> to capture the output into a variable that can then be used via [enlist<flatlist>] to perform operations on the resultant tiddler list (e.g., previous/next navigation via <$link to={{{ [enlist<flatlist>before<currentTiddler>] }}}>previous</$link> and <$link to={{{ [enlist<flatlist>after<currentTiddler>] }}}>next</$link>

The macro can also be simplified a bit by removing the handling for max, level and field parameters, like this:

\define toc-list(here,exclude)
<$list filter="""[tag[$here$]sortby{$here$!!list}] -[subfilter<__exclude__>] -[[$here$]]""">
   <$text text="[["/><<currentTiddler>><$text text="]]"/><br>
   <$macrocall $name="toc-list" here=<<currentTiddler>> exclude="""$exclude$ [[$here$]]"""/>
</$list>
\end

enjoy,
-e

2 Likes

Thanks @EricShulman you have documented how to achieve what I was asking for, however I was aware of this approach, and was wondering if the taggingtree filter operator could return the flat list, making it a lot simpler. It is so close to doing this already and with 5.3.0 it could be used in a function.

  • Until taggingtree has this output order, the way you show is the only way to achive this so I am sure it will help others finding this thread by search.

Thank you @TW_Tones for the suggestion. It makes sense to have a returned tiddler order that itself has a use. I had a quick look at the code, and I think one only needs to change

$tw.utils.pushTop(results,intermediate);
intermediate.forEach(function(title) {
	gettagsrecursively(title,results,options);
});

to

intermediate.forEach(function(title) {
	$tw.utils.pushTop(results,title);
	gettagsrecursively(title,results,options);
});

so that the hierarchy is “logged” into the results array as it’s traversed. The traversal already happens “depth first”.
One thing to consider – before I test and change this – is that duplicates are removed. So, when you have tiddlers with multiple parent tags within the hierarchy, they will only show up once when they are encountered first.
Also, how do you plan to make use of this? The returned tiddlers carry no information about where within the hierarchy they are located or at what level, regardless of their ordering, so you would have to have some additional machinery in place to figure this out, which will probably kill the performance gains you get from using taggingtree[].
On the other hand, @EricShulman’s solution will let you easily and selectively perform additional operations while traversing the hierarchy, without necessarily operating on a whole family of tiddlers at once.

Have a nice day
Yaisog

If they list is in the order of traversal, depth first, you can step through the list and visit every tiddler is in its structured order and guarentees you visit every tiddler.

  • the first thing we can determin is position in the list.
  • but lets not forget while navigating this the user will be at a position in the list and we can retrieve additional info from the current tiddler in addition to next and previous.
    • thus we can find parents and siblings etc… Of the current tiddler
  • another key value of the heirachy list counting or computing something for all tiddlers in the heirachy. With the tiddlers in order I may be able determin some subtotals whilst retaining whole of heirachy totals. Such as sum the current tiddlers children

With time I am confident we can achive more, simply by ensuring we flatten the list into a deterministic depth first list. But perhaps there is value having a width first option.

Hi @TW_Tones, even with a depth-first list you wouldn’t know when you reach the end of the hierachy of one parent and the hierarchy of that parent’s sibling starts, would you? It’s all still just one long list of tiddlers, just sorted differently. There is no information in that list about the level within the hierarchy that the current tiddler is located at…
Anyway, I suggest you try changing the code in taggingtree.js as outlined above and see if that’s what you are looking for. If you can, give us a code example or two of how you would use the depth-first list. I’d be happy to add a suffix that controls sorting if it proves useful.

Have a nice day
Yaisog

PS: In the * taggingtree and tagstree Example* at https://yaisog.tiddlyhost.com/, the current-version output list for Jackie is
Marge Patty Selma Bart Lisa Maggie Ling
while with depth-first it would be
Marge Bart Lisa Maggie Patty Selma Ling
How would you know – just from this list – whether Patty is a another child or sibling of Marge?

1 Like

Thanks I have some code patterns I will share. For any given tiddler in a list you can go back to that actual tiddler and discover or count its children and parent, even siblings all over again, and this can just in time.

However the key value of a flat depth first list is you can step through every tiddler exhastivly in that heirachy in an appropriate order.

  • my argument is the current order is even less useful.

I will look at that modification thanks. If I get it working I will share and example.

@Yaisog thanks for your help here, I replaced the code all at the top to all the code in the bottom, however it throws a red error;

After reload this happens

Internal JavaScript Error

Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser

ReferenceError: gettagsrecursively is not defined

Unfortunately my JavaScript is not strong enough to resolve, yet.

And I had to edit the wiki and remove module-type value “filteroperator”

Once I have the depth first order, it will be more practical but here is an example of obtaining additional info;

<ol>
<$list filter="[[TableOfContents]taggingtree[]!has[draft.of]]">
   <$list filter="[<currentTiddler>is[tag]]">
       <li><$link/></li>
   </$list>
</$list>
</ol>

So in the inner list I can determine if the current tiddler has children or not, that is “is a leaf” on the tree, Just by using is[tag]] or !is[tag].

  • From here I could identify the last child and allow the user to move after that (in the full list) to the next sibling/parent/grandparent, without re-walking the tree, just working off the depth first list.
  • Similarly for any tiddler in the tree we can look to see if it has more than one tag, which may indicate a cross hierarchy relationship, or two parents etc…

Hi @TW_Tones, it works for me and it does what it should. Maybe you left out a semicolon somewhere?
Here is a link to a sharing edition TW from where you can drag-n-drop the modified taggingtree.js:
taggingtree.js

You wouldn’t know if it is a parent or grandparent, though.

Acting on this information (by using the current tiddler is the other parent’s tree) sounds rather complicated. I think that many of the edge cases will make taggingtree much harder to use (and to read!) than @EricShulman’s recursive macro above – especially if you want to do it all within a filter run.

Please keep us updated with the advances you make with its application while I contemplate how to best integrate an optional alternate ordering while keeping the filter operator codebase small.

Have a nice day
Yaisog

1 Like