Menu

How to filter using linked node?

2015-12-31
2016-12-15
  • Rami Sedhom

    Rami Sedhom - 2015-12-31

    I've some nodes that's linked together. Is there a way to filter (or only show) the nodes that's linked to current node.

    For example, in attached map screenshot, "Marital" and "Parental" nodes are linked to "this week" node. My question is how filter the nodes ("Marital" and "Parental") as they are linked to "this week" node?

    map screenshot

    Result should be like the result screenshot.

    result screenshot

     

    Last edit: Rami Sedhom 2015-12-31
    • Rami Sedhom

      Rami Sedhom - 2015-12-31
       

      Last edit: Rami Sedhom 2015-12-31
  • Ken Hill

    Ken Hill - 2015-12-31

    From your map and your question, you seem to be an experienced user, so you may already know this manual work-around.

    click on one of the nodes
    hold (and keep holding) ctrl
    click on other nodes
    Filter > Filter selected nodes

     
  • Milavon

    Milavon - 2015-12-31

    Hi Ikhnaton2,
    First:
    I Really liked your map, I'm asking you if you can share it with us.
    I'm always interested in (Organizing Tasks) & Your Map looks interesting.

    Second:
    For Filtering the Connected Nodes:
    From the filter toolbar: Connecter > Exists > Quick Filter

     

    Last edit: Milavon 2015-12-31
    • Ken Hill

      Ken Hill - 2015-12-31

      I agree on the map sharing. This one does look interesting, but maybe there is personal stuff in the folded nodes?

      Thanks for this tip. All such little gems (and tips to them) make FP that much more useful.

      btw - is there a way, using this technique, to restrict the filter to a particular connection, without seeing all connections? <edit> I see now you can filter by connector label. That might do what I am thinking about, but maybe there is another way too?

       

      Last edit: Ken Hill 2015-12-31
  • Milavon

    Milavon - 2015-12-31

    The personal stuff can be removed (I'm interested in the main branches with the categories)

    For the filtering issue:
    there is a way, but not in the filter options,

    there is a script in the (Script Collection) Page:
    http://freeplane.sourceforge.net/wiki/index.php/Scripts_collection
    but it has a limitation: it can only filter the (outgoing connections) not the (incoming connections)

    Find all connected nodes
    This script will find all nodes below the current node that have connections and list them under a new node created to hold the results called "connected nodes". I found this extremely useful when I have multiple connections reaching across subtrees in a large map.
    listConnectedNodes.groovy

    // @ExecutionModes({ON_SELECTED_NODE})
    
    def resultNode = node.createChild("Connected Nodes")
    resultNode.style.backgroundColorCode = '#FFFF00'
    resultNode.link.node = node
    node.findAll().each {
        it.connectorsOut.each {
            def target = it.target
            def child = resultNode.createChild("${it.source.text} --> ${target.text}")
            child.link.setNode(target)
        }
    }
    
     

    Last edit: Milavon 2015-12-31
    • Ken Hill

      Ken Hill - 2015-12-31

      Thanks. Looks to be very useful.

      Someday I'm going to have to break down and try to learn scripting.

       
  • Rami Sedhom

    Rami Sedhom - 2015-12-31

    The point is the map contain a lot of links as I use links to connect my tasks to different prospective and I would like at a moment to filter tasks related to one prospective only.

    So using "Filter selected nodes" or "Connector" or "Connector Label" didn't fulfill my need.

    I didn't try groove scripting before. I'll try the given script in comment by Milavon.

    Attached is the mindmap for people interested. The idea is using different tasks management systems to correctly categorize my tasks and then find what I want to do in the correct time with correct role/goal/priority/...

     
  • Milavon

    Milavon - 2015-12-31

    thanks for sharing your map.
    I understand your point about connecting the tasks.
    but using the links & connections is not the perfect solution.

    I use another different approach, to connect my tasks to (different prospectives), it is Tags.
    based on some experience from the popular software (Evernote), I can use them effectively.

    I have adopted list of tags / words that can describe any task: (each tag is preceded by the character "#" to identify it).. I usually put them inside the (Note section) of the target nodes. since I don't use (Note) for any other purpose

    these tags are very similar to the words / categories used in your map.
    For Example: #Urgent #Important #Family #Work #Project_X #Project_Y #File #Task......etc

    I can later filter the nodes based on single or several tags.
    so these tags can connect between nodes without having to draw alot of connections

    there is also another solution that is similar to (Tags) Solution: you use (Icons) in different ways to tag / mark your tasks, if you are not satisfied with the built-in icons, you can add additional icons to the program & give them (Special Meaning) & use them to categorize your tasks.
    (For Example: The Built-in (Star) Icon stands for (#Excellent), the (Yellow Triangle) stands for (#Important)..and so on.

     

    Last edit: Milavon 2015-12-31
    • Ken Hill

      Ken Hill - 2015-12-31

      @Milavon - any chance of a generic version of your map?

       
  • Rami Sedhom

    Rami Sedhom - 2016-01-01

    Thanks @Milavon for advice. I use already Evernote too as well as Toodledo, however I think visualizing my task management in mindmap will take it for the next level :)

    I beleive I can do it. For start I modified the script you shared to be like below:

    // @ExecutionModes({ON_SELECTED_NODE})
    
    node.findAll().each {
        it.connectorsIn.each {
            def source = it.source
            def id = source.getId()
            def child = node.createChild("${source.text} : ${id}")
        }
    }
    

    Using this, I could get the source (linked) node IDs. I didn't find filter method in groove scripting yet. Not sure if groove can do filtering programtically.

    So, I then thought of using the "Script filter" to filter by node ID, like following example:

    def id = node.getId()
    id == "ID_1191996445" || id == "ID_1367036193"
    

    The above Script filter could constructed use Java into clipboard and then paste it in the "Script filter" -> Script Edit -> Quick filter, and that's it.

    I think I could use AutoHotkey to do the 2 steps with 1 keyboard shortcut:
    1. Run script to get node ID (I need to add java statement to construct the 2nd script in clipboard).
    2. Use "Script filter" using the constructed script in step #1 (and which should be in clipboard).

    I'll continue evolving the solution tomorrow. Your advices are welcome.

     

    Last edit: Rami Sedhom 2016-01-01
    • Volker Börchers

      I didn't find filter method in groove scripting yet. Not sure if groove can do filtering programtically.

      No problem: instead of node.findAll() use node.find(Closure) like this

      node.find{ it.text.contains("sometext") }
      node.find{ it.isLeaf() }
      

      The type of "it" is Proxy.Node, see Help -> Scripting API http://freeplane.sourceforge.net/doc/api/

      Volker

       
  • Rami Sedhom

    Rami Sedhom - 2016-01-02

    I did it using 2 steps:
    1- Add this script which get liked nodes and copy them into clipboard:

    // @ExecutionModes({ON_SELECTED_NODE})
    
    import java.awt.Toolkit;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Clipboard;
    
    def id = node.getId()
    String str = new String('def id = node.getId()\r\nid == "'+"${id}"+'"');
    
    node.findAll().each {
        it.connectorsIn.each {
            def source = it.source
            def id1 = source.getId()
            str = str + ' || id == "' + "${id1}" + '"'
        }
    }
    StringSelection selection = new StringSelection(str);
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    clipboard.setContents(selection, selection);
    

    2- Using Filters, choose Script filter and paste what's already copied into clipboard in step #1 into the script of the filter. Apply Quick Filter and you will see only the linked nodes.

     

    Last edit: Rami Sedhom 2016-01-02
  • Milavon

    Milavon - 2016-01-03

    I tested it. It is a very nice idea, Rami

    but I suggest 2 modifications:

    1- to filter the selected node only (no need Niether to find / filter all the connected nodes in the maps, Nor the connected descendants of the selected node)

    2- this script can filter only the (Incoming Connections), other than the first one wich filter the (Outgoing Connections), I think you need to develop a new script to filter / include both types of connections (Outgoing & Incoming) for the selected node(s).
    it would be amazing idea.

    Thanks

     

    Last edit: Milavon 2016-01-03
  • Rami Sedhom

    Rami Sedhom - 2016-01-03

    @Milavon, I did modify the script for your 2nd suggestion

    // @ExecutionModes({ON_SELECTED_NODE})
    
    import java.awt.Toolkit;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Clipboard;
    
    //Get current node ID
    def id = node.getId()
    String strClipboard = new String('def id = node.getId()\r\nid == "'+"${id}"+'"');
    
    // Get all nodes linked with IN connection 
    node.findAll().each {
        it.connectorsIn.each {
            def source = it.source
            def id1 = source.getId()
            strClipboard = strClipboard + ' || id == "' + "${id1}" + '"'
        }
    }
    
    // Get all nodes linked with OUT connection
    node.findAll().each {
        it.connectorsOut.each {
            def target = it.target
            def id2 = target.getId()
            strClipboard = strClipboard + ' || id == "' + "${id2}" + '"'
        }
    }
    
    //Copy all node IDs to clipboard
    StringSelection selection = new StringSelection(strClipboard);
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    clipboard.setContents(selection, selection);
    

    I didn't get much what's meant in suggesstion #1, would you elaborate more (may be with screenshot)?

     
  • Milavon

    Milavon - 2016-01-03

    Great Work @Rami

    What I mean in the suggestion 1:

    The script should not search the entire map looking for connections, but it should filter only the nodes that are (selected by the user) at the moment of executing the script.

    That means if the selected node has direct connections with other nodes, then the script should display all the connected nodes, but if the (selected node) has no connections at all, then the script should Return (Nothing). because the selected node has no connections.

    I uploaded a small map to explain this point: (Look at the attatchments)

    as you see in the map, there

    (AAA) & (RRR) & (bbb) are connected to each other

    (ddd) & (SSS) & (TTT) are connected to each other

    (ddd) is a descendant of (AAA): a grand child of (AAA)

    The problem with the script:
    When I select the (Root) node and execute the script: the result will be all the connected nodes in the map (RRR TTT, AAA, SSS, bbb, ddd). However,it should return nothing, because the (Root) Node has no connections with any other node.

    Also when I select the node (AAA) and execute the script: the script the show the nodes (SSS) & (TTT) which are not connected to the selected node (AAA), but connected to another node (ddd).
    (The Right behaviour should be: is to show only (RRR & bbb) which are connected to (AAA))

    Also if I select 2 nodes together: for example: (AAA) & (ddd), the script should display all the nodes connected with them (TTT,SSS,BBB,RRR)

    My point is: the script should only work on the selected nodes, if they have connections, show them & if not, display Nothing. (the execution should be based on selection / selected nodes)

    Freeplane already has a function to filter all the connections in the map (Connector > Exists), So, the script need to focus on the selected node(s) only.

    Thanks

     

    Last edit: Milavon 2016-01-03
  • Milavon

    Milavon - 2016-01-04

    HI, I found an old script that can help (can be used / modified)

    It will select (filter) the nodes connected to the currently selected node
    (By Outgoing Connections only)
    & But Unfortunately, it can be only executed on 1 single node, not working if the user select multi-nodes together (to show / select their connected nodes)

    // a set is unique
    def toSelect = new HashSet(c.selecteds)
    toSelect.each {
        toSelect.addAll(it.connectorsOut.collect { it.target })
    }
    c.selectMultipleNodes(toSelect.toList())
    
     

    Last edit: Milavon 2016-01-04
  • Rami Sedhom

    Rami Sedhom - 2016-01-04

    Got your point, feel free to modify the script to get only selected node as I don't full understand the script shared. We can see later how to adapt to make it works with multiple selection.

     
  • Rami Sedhom

    Rami Sedhom - 2016-01-04

    I've tried to modify the script to resolve the point you highlighted. Here it's:

    // @ExecutionModes({ON_SELECTED_NODE})
    
    import java.awt.Toolkit;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Clipboard;
    
    //Get current node ID
    def id = node.getId()
    String strClipboard = new String('def id = node.getId()\r\nid == "'+"${id}"+'"');
    
    def toSelect = new HashSet(c.selecteds)
    toSelect.each {
        // Get all nodes linked to current node with IN connection
        it.connectorsIn.each {
            def source = it.source
            def id1 = source.getId()
            strClipboard = strClipboard + ' || id == "' + "${id1}" + '"'
        }
        // Get all nodes linked to current node with OUT connection
        it.connectorsOut.each {
            def target = it.target
            def id2 = target.getId()
            strClipboard = strClipboard + ' || id == "' + "${id2}" + '"'
        }
    }
    
    //Copy all node IDs to clipboard
    StringSelection selection = new StringSelection(strClipboard);
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    clipboard.setContents(selection, selection);
    

    I tested in differnt scenarios on Example-Connections.mm and it works fine. Only issue with multiple-node selection.

     

    Last edit: Rami Sedhom 2016-01-04
    • Luigi Kang

      Luigi Kang - 2016-12-15

      Only issue with multiple-node selection.

      I tested the script above and it indeed only get one ID when the script runs on multi-selection of nodes, though it got the incoming and outgoing nodes, they would appear floating because the original selection (central node) is missing. I modified your code so that the script below now gets all the IDs of original multi-selection of nodes as well.

      // @ExecutionModes({ON_SELECTED_NODE})
      
      import java.awt.Toolkit;
      import java.awt.datatransfer.StringSelection;
      import java.awt.datatransfer.Clipboard;
      
      //set the first line and CRLF for pasting into script filter
      
          String str = new String('def id = node.getId()\r\n');
      
      //get node ID(s)--
      //--of current selection
      
          c.selecteds.each {
          str = str + 'id == "' + "${it.getId()}" + '"'
      
      //--of incoming nodes linked to current selection
      
              it.connectorsIn.each {
              str = str + 'id == "' + "${it.source.getId()}" + '"'
              }
      
      //--of outgoing nodes linked to current selection
      
              it.connectorsOut.each {
              str = str + 'id == "' + "${it.target.getId()}" + '"'
              }
          }
      
      //plumber adding pipes
      
          str = str.replace('"id =','" || id =')
      
      //set the above result to clipboard for pasting into script filter
      
          StringSelection selection = new StringSelection(str);
          Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
          clipboard.setContents(selection, selection);
      
       
  • Milavon

    Milavon - 2016-01-04

    Yes, Very Nice Work @Rami, No need to bother yourself about (multiple node selection) anyway. this script is more than enough.

    I think that the connectors can be very useful, They can take Freeplane a step forward to be
    (Concept Mapping Tool, Alongside with Mindmapping),
    But, they need some development & Improvements. to make using them more easy & productive.
    I have some ideas about that. (Ideas to develop working with connectors)
    maybe I will post them later.

    Thanks.

     
    • Miguel Boyer

      Miguel Boyer - 2016-01-05

      Personally, I prefer connectors rather than clones. Any improvement here
      seems right to me.
      Milavon, what are those ideas?

       
  • Pieter van Oostrum

    Here is a script that does the filtering. No need to go through the clipboard pasting.

    // This script filters the selected nodes
    // and those that are directly connected to them
    // (no transitive closure)
    // Use 'Undo Filter Action' to remove the filter
    
    // @ExecutionModes({ON_SELECTED_NODE})
    
    // Initialize
    
        def showAncestors = true
        def showDescendants = false
        def nodeList = [ ]
    
    // Get nodes--
    // --of current selection
    
        c.selecteds.each {
            nodeList.add(it)
    
    // --of incoming nodes linked to current selection
    
            it.connectorsIn.each {
            nodeList.add(it.source)
            }
    
    // --of outgoing nodes linked to current selection
    
            it.connectorsOut.each {
            nodeList.add(it.target)
            }
        }
    
    // Apply filter
    
        map.filter(showAncestors, showDescendants, {it in nodeList})