Display tag combinations

Hello all,

I’ve been stuck on a problem for a while that I’m not sure how to solve. I would like to have a TW5 code that displays the tag combinations to each other. For this purpose all tiddlers of my wiki should be scanned.

Suppose we have these tiddlers with the tags as the initial state:

Tiddler1:
Tags: tag_A; tag_B

Tiddler2:
Tags: tag_A; tag_B; tag_C

Tiddler3:
Tags: tag_A; tag_B; tag_C

I would now like to have the following output in another tiddler:

occurred 3 times | tag_A <> tag_B
occurred 2 times | tag_A <> tag_C
occurred 2 times | tag_B <> tag_C

Means I would have liked to output tag combinations sorted by occurrence. Is there a simple solution for this without Java Script?

I use the version 5.2.5…

I would be very happy if I could help me.

Many thanks in advance!

Welcome @Ransche to the community;

The simplex form, not sorted by the count, and ignoring other tags would be;

a/b {{{ [tag[a]tag[b]count[]] }}}

a/c {{{ [tag[a]tag[c]count[]] }}}

b/c {{{ [tag[b]tag[c]count[]] }}}
  • I doubt you want links to the numbers so use this for each;
b/c <$text text={{{ [tag[b]tag[c]count[]] }}}/>

But do you want to do something else?

But I expect the reason you asked is you want to sort by the count?

  • I have done it before but it is not so straightforward.
  • I’ll be back if no one else answers;

Here is one way, need to test over 9 in the count

<$list filter="[tag[a]tag[b]count[]addsuffix[ a/b]] [tag[a]tag[c]count[]addsuffix[ a/c]] [tag[b]tag[c]count[]addsuffix[ b/c]] +[!nsort[]]">

</$list>

My Test data

Hello TW_Tones,

thank you for your quick response. I would like to implement it in a dynamic way. Means that if I add for example “Tag_D”, I don`t want to extend the filter. My actual state is this:

\define handle(regStr)
    <$set name="count" filter="[all[]tags[]regexp[$regStr$]count[]]">
        <$set name="combinationCount" value="0">

            <$list filter="[all[]tags[]regexp[$regStr$]]" variable="element1"  counter="i">
                <<element1>><br>====<br><br>
                <$set name="lastCount" filter="[<count>subtract<i>]">
                    <$list filter="[<lastCount>compare:number:ne[0]]">
                        <$list filter="[all[]tags[]regexp[$regStr$]!is[tiddler]last<lastCount>]" variable="element2" >
                                occurred {{{[tag<element1>tag<element2>count[]]}}} times | <<element1>> <> <<element2>><br>
                        </$list>
                    </$list>
                </$set>
                <br>
            </$list>
        </$set>
    </$set>
\end

<<handle "^tag_">>

The output for the given tags would be this:

tag_A
====

occurred 3 times | tag_A <> tag_B
occurred 2 times | tag_A <> tag_C

tag_B
====

occurred 2 times | tag_B <> tag_C

tag_C
====

The only problem I still have is the sort problem. In this case the sort is correct by accident. Do you have an idea how I can sort the output in the innermost list loop?

Ransche,

If you want to consider ALL tags in your wiki, looking for all combos, that’s a potentially very calculation-intensive task. Still, it’s simple-enough in structure… Perhaps you’re going about it from an overly complex direction.

The following (surely not as concise as possible, but functional) considers every combination of 2 non-system tags, and returns a count whenever the count of tiddlers with that combo is more than zero:

<$list filter="[tags[]!is[system]sort[]]" variable="first">
<$list filter="[tags[]!is[system]sort[]]" variable="second">

<$reveal type="lt" default={{{ [<first>] }}} text={{{ [<second>] }}}>
<$reveal type="gt" default={{{ [tag<first>tag<second>count[]] }}} text="0">
{{{ [tag<first>tag<second>count[]] }}} occurrences of <$tiddler tiddler=<<first>> > {{||$:/core/ui/TagTemplate}} </$tiddler> • <$tiddler tiddler=<<second>>  >{{||$:/core/ui/TagTemplate}} </$tiddler> <br>
</$reveal>
</$reveal>

</$list>
</$list>

Checking that the first tag is “less than” the second, alphabetically, serves to remove TagA—TagA pseudo-pairs, and also prevents TagA—TagB count from showing up again as TagB—TagA count.

If you want to add a drop-down button to list all tiddlers at each said intersection:

<$list filter="[tags[]!is[system]sort[]]" variable="first"><$list filter="[tags[]!is[system]sort[]]" variable="second">
<$reveal type="lt" default={{{ [<first>] }}} text={{{ [<second>] }}}>
<$reveal type="gt" default={{{ [tag<first>tag<second>count[]] }}} text="0">
<$tiddler tiddler=<<first>> > {{||$:/core/ui/TagTemplate}} </$tiddler> • <$tiddler tiddler=<<second>>  >{{||$:/core/ui/TagTemplate}} </$tiddler>
<$button popup={{{ [<first>addprefix[$:/]addsuffix<second>] }}}> <$text text={{{ [tag<first>tag<second>count[]] }}}/> occurrences  </$button>
<$reveal type="popup" state={{{ [<first>addprefix[$:/]addsuffix<second>] }}}><div class="tc-drop-down"><$list filter="[tag<first>tag<second>]"/></div></$reveal><br>
</$reveal></$reveal></$list></$list>

Last: I see you wanted a header for each tag. But presumably you would not want the header if there are no occupied intersections (At least, on large projects, that would be my preference; if you do want headers for tags not involved in combos, remove the <$reveal...> and </$reveal> tags near top.)

So, below is the code for something like that. First, preview of what it looks like at tiddlywiki.com:

<$list filter="[tags[]!is[system]sort[]]" variable="first">

<$reveal type="gt" default={{{ [<first>tagging[]tags[]!is[system]count[]] }}} text="1">
<h2><<first>></h2>
</$reveal>

<$list filter="[tags[]!is[system]sort[]]" variable="second">

<$reveal type="nomatch" default={{{ [<first>] }}} text={{{ [<second>] }}}>
<$reveal type="gt" default={{{ [tag<first>tag<second>count[]] }}} text="0">
@@margin-left:2em; 
<$tiddler tiddler=<<first>> > {{||$:/core/ui/TagTemplate}} </$tiddler> • <$tiddler tiddler=<<second>>  >{{||$:/core/ui/TagTemplate}} </$tiddler>
<$button popup={{{ [<first>addprefix[$:/]addsuffix<second>] }}}> <$text text={{{ [tag<first>tag<second>count[]] }}}/> at intersection  </$button>
<$reveal type="popup" state={{{ [<first>addprefix[$:/]addsuffix<second>] }}}><div class="tc-drop-down">
<$list filter="[tag<first>tag<second>]"/></div>
</$reveal><br>@@

</$reveal></$reveal>
</$list></$list>

Perhaps if you want to see all tags the idea of combinations does not make sense.

  • Have a look at the various Tag Cloud Solutions
  • I Imagin you want non system tags only
  • Think about your data, the current tags and ask yourself what is the best way to get an overview and why?
    • Sometimes we make these things then dont use them.
  • There was a tool called x link that helped review tag combinations but you must select which ones are involved.

Hi @Springer, just a side note: Each $reveal widget creates a DOM node, even when it is not “revealing” and the node is empty/hidden. With the doubly nested $lists and a wiki with a lot of tags that may be a lot of DOM nodes, slowing down the display.

Alternatively, you could use more $lists which do not create DOM nodes when they are empty.

Have a nice day
Yaisog

Hi @Springer,

very cool, thank you! Your are right, your code is less complex than mine. I will definetely use it for my topic.
But sorting by the count is also missing in your example. I would like to list the pairings chronologically by their combination count. The one with the highest on the top and so on. The highest in your picture would be this:
grafik
Do you have an solution for this?

Yaisog,

I feared that this kind of solution would be inherently computation-intensive with a large wiki, but I did not realize that the reveal widget is more of a culprit than nested lists.

Now I have at least one rule of thumb in trying to make my solutions less inefficient.

Thanks!

-Springer

:thinking: Perhaps you don’t really mean “chronologically” (since I’m not sure how a pair of tags would have a time assigned to it, as a pair), but just “sorted according to their combination count”?

Alas, sorting the all-encompassing set of tag-pairs — that is, sorting a set whose members are neither tiddlers nor tags (which TiddlyWiki happily slices, dices, and sorts), but rather all-distinct-pairs-of-tags-that-occur-together-in-at-least-some-tiddlers — is difficult (at least for me!). By the time I can display the list of tag-pairs, I find I’m already relying on a nested structure of simpler lists, and I’m not sure how to extract the pairs themselves as things with “meta-data” (as it were) according to which they can be sorted.

Perhaps someone with a level of skill far greater than mine would be interested. :wink:

Seriously, this more complex task is the kind of coding that someone would deserve to get paid for, imho. :slight_smile:

-Springer

@Springer I was afraid that it would not be so easy to solve. I was hoping that there is some function in tw5 that can solve the problem easily and I just don’t know it. Maybe someone else has an idea. I will continue to try to implement and let you know if I find a solution. If there is no other way i will change to java script.
Thanks for your effort!

@Ransche please make sure you consider my comments here;

  • And my other comment there.

Try and think this through, even do a mockup after developing some realistic example data.

@Ransche I also concur with @TW_Tones that it would be helpful to think through your imagined workflow — why you want this tag-intersection data (for every conceivable pair of tags?) and what purpose is served by the sort-by-count-of-tiddlers-at-intersection. With such things in mind, sometimes it turns out that there’s a simpler way to crack that egg, as it were.

Indeed, I would ask whether you’re using tags in the optimal way for your use-case. You might consider intersectional tags, or different fields for different parameters, if you recognize patterns of intersection (place-and-time, agent-and-client, etc.) that are especially typical. … I often use tags until/unless I see the data patterns whereby tags should become field-structures, or where there should be a hierarchy-structure among tags (rather than a flat set of tags), etc.

One thing I could imagine is: using the “crude” solution above to scan for patterns, and setting a threshold (such as intersections with at least 6 tiddlers, or whatever) as an important break-point, so that you can then see all “busy” intersections.

I’ve implemented that busy tag-intersections tiddler at the google-fonts site.

(You may also be interested in the combined tag-filter there, which allows you to peek into any
intersection of tags.)

-Springer

P.S. I’m pretty sure you can accomplish what you’re trying to do – if you’re determined to do that – with a custom macro defining tag-intersections (such that you can then identify features of each intersection). I’m not up for doing it now, but I’m pretty it’s doable without resorting to javascript.

@TW_Tones @Springer Thank you for your effort :+1: Unfortunately, I am very busy at the moment. I will try to answer you today or tomorrow with a detail description. @Springer I will check out your examples too…

Take your time, I have raised a related question here Find common tag(s) in list from filter, a TiddlyWiki Challenge that may prove interesting.

I have a similar case to display tiddlers with a set of tags.

My literature is tagged several Tag/Domain (e.g. Crop Model, Machine Learning)

image

Then I develop Doc tiddler (e.g. Crop Model - Machine Learning) for a combination of Domains (e.g. Crop Model and Machine Learning).

Now I want to list all literature tagged with proper domains (e.g. Crop Model and Machine Learning).

My method is attached and is a viewtemplate for tag Doc

$__bangyou_viewtemplate_doc-literature.json (1.4 KB)

This method also applies for any literatures tagged with Descendants which I assume they belong to same topic.

image

In this case, any literature tagged with Random Forest and Crop Model will list in the Doc tiddler.

My plan is following:
I want to create a tiddlywiki for my wardrobe aims. I want to create an Tiddler with a picture of an outfit I like. After that I want to add tags to this tiddler to classify the different outfit parts.
The tags which are used to classify should have a tags in following format:

grafik

A simplified example of the tiddlers could be:

Outfit A
   tags:
      Type/Trousers/Color/Blue
      Type/Trousers/Subclass/Jeans
      Type/TShirt/Color/White
      Type/TShirt/Subclass/Polo
      Type/Belt/Color/Brown
      Type/Belt/Subclass/Woven
Outfit B
   tags:
      Type/Trousers/Color/Grey
      Type/Trousers/Subclass/Chino
      Type/Shirt/Color/Brown
      Type/Shirt/Subclass/Business
      Type/Belt/Color/Brown
      Type/Belt/Subclass/Plain

Now I want to create a tiddler with a buying list which is sorted by the descripted combination count (in this example “Type/Belt/Color/Brown” has the most combinations). By this list I know which part I should buy next to complete my desire wardrobe.
Another example for a useful tiddler would be one which shows the color which should be combined with another to get the desired wardrobe style.

To list the tiddlers uses Regexes like this:

^Type\/(.*)\/Color\/(.*)$
^Type\/(.*)\/Subclass\/(.*)$

So I don’t want to list all combinations but only the ones that match with a certain regex. This might put the performance concerns into perspective a bit.

@Springer

Your “busy tag-intersections” is already very close to the solution of my problem. But if there is any possibility to list the combinations sorted by the count, I would prefer this solution. I think if the list will get long the sorted count solution has advantages.

The “Combined Tag Filter” is very cool and I think i will use a modified version of it in my wiki because with this I have the possibility to create outfit quickly. The only thing i would add is again a count after each unselected tag which shows how many outfits are possible with the already selected tags (but that’s another task :grin:)

@TW_Tones

  • Have a look at the various Tag Cloud Solutions
    → which do you mean exactly
  • I Imagine you want non system tags only
    → I want to filter with the regex formulas
  • Think about your data, the current tags and ask yourself what is the best way to get an overview and why?
    • Sometimes we make these things then don’t use them.
      → For the buying list
  • There was a tool called x link that helped review tag combinations but you must select which ones are involved.
    → I will have a look, but for my buying list there I do not want to select the tags

For the problem I currently have only the following impractical solution:

  • Use another list around the existing list which are used to iterate a variable backwards from for example 1000 to 1 and use this variable to show the output if the variable matches the count. But that would mean that the existing code would be run 1000 times. This would be a performance explosion!

For me that looks like “the wrong tool for the task”. … I would go with fields instead of “namespaced” tags.

You could have a field named: x-type with a value eg: Trousers … (type is used by TW)
A second field name: x-color value: blue … (color is used by TW )
subclass : Polo

Eg a filter to list all Polo’s would be [subclass[Polo]] … done.

OR [x-type[Trousers]x-color[blue]] :or[x-color[green]] … would show every thing typed: Trousers and where it’s x-color is green :or any other thing which has a x-color field green

If you want to count your Trousers use: [x-type[Trousers]count[]] … The filters that can be used are so much more flexible

just my thoughts.

This looks like what I would call a compound tag, just as I have posted about avoiding “compound tiddler titles” I advise against this because it forces you to decompose the “compound value” everytime you use it.

All you need is separate tags;

  Type Trousers Color Blue
  Subclass Jeans TShirt White
  Polo Belt Brown Woven

In fact you would only add Trousers / TShirt / Belt - because they are tagged with “Type”.