Shaping a map into an outline

Forum searches on the theme of convert map to outline do already harvest several hits, and I am struck (from a non-fiction perspective) that a tool which brings outlines and diagrams so productively close to each other appears to lack a well-worn (or technically facilitated) path from a directed acyclic graph (a tree of of text tiles and links, in which no note has more than one incoming link) to an outline (and back).

Perhaps this is not such a busy autoroute/freeway in fiction work ?
Perhaps literary graphs are typically cyclic, to some extent ?

As it happens, building tree structures which represent claims or arguments, flipping back and forth between graphic and outline representations of these, is the core of my work (underpinning key points with supporting points, spanning separate trees with logical connectives, and building on top of those conjunctions, choosing narrative/rhetorical routes, etc)

What is current best practice if one tries to do this in Tinderbox 8 ? (
Directed acyclic graphic representation ⇄ text outline
)

Forum discussions that I have seen appear to treat expressions of interest in map to outline conversions rather warily, as if counselling against departure from some other beaten track …


Re scripted routes to help with this:

In the JavaScript / Applescript interface, to which I turned by reflex, I can see no route to listing the outgoing and incoming links of a note (though we are offered counts of each).

Does it look feasible to equip the (osascript) scripting interface with something like an evaluate function through which it could harvest results from action code, e.g. evaluating link-related functions ?

Or perhaps to expose the incoming and outgoing links of notes (and the sources+targets) of those links ?

Rob

PS it seems a pity to have to use things like Scapple (link below) which makes for rather one-way traffic from map to outline.

A really productive thinking-space in my context needs an auto-route in both directions (map ⇄ outline), and Tinderbox seems so close …

OK, my understanding is this is a Directed Acyclic Graph:

So if we turn this into an outline, does 5 come under 2 or 6. If we use 2 and an alias of 2 for the two previous possibilities, which is the original and which the alias.

There seem to be a lot of unsurfaced assumptions here.

Thanks ! I should add, ‘in which no node has two parents’.

In short, a tree :slight_smile:

You are probably looking for something more direct but here is a simple way to harvest results from action code.

1 Like

Thanks ! That’s a very good idea …

A couple of questions following Gerard’s very helpful suggestion

  • is the double dot syntax particular to links, or might I find some more general uses or documentation of it ?
  • should I assume that the semicolon separator for the generated name lists is more or less immutable ?

(It looks, at first glance, as if I should avoid or automatically prune out any semi-colons in note names to avoid ambiguity)

Dipping in/out as busy just now. But, in pseudocode and not tested what about running this in the map container:

Get paths of all map objects with exactly one in- or out-bound link

$MapList = collect_if(children,$InboundLinks==1&$Container(current)==$Container(that),$Path)

Assumption - no links start outside the map in question. Extra code on the above could ensure the link source/destination note has the same container as the note being tested - i.e. both are in the same map.

Now, iterate the list of paths and for each note set the source of the (single!) inbound link as the container of the note, i.e. make the note the child of the note the note linking to it

MapList.each(aPath){
   $Container = links.inbound..$Path;
}

Assumption: There is only one inbound link, i.e. links() can only return one path.

Assumption: As we work through the $MapList list, some reassigned notes’ new parent may itself be re-assigned a new parent but as we only iterate the list once, Tinderbox will take care of the eventual outline paths.

To go the other way, you tell the Map container to make all descendants into direct children of the current container.

BUT, this all rests on the user making sure there is only a single path from the map ‘root’ to each eventual leaf note. Otherwise, the process fails. By using a discrete link type only for mapping the outline, and using link type filers above, links for other purposes can be supported.

This sort of thing might become a feature, with the app doing the work, but it’s up to someone with the need to write in to Eastgate making the case for it.

Still, I hope that helps. As I think on this, using a discrete link type just for this task will likely make it much easier to test if the correct linkages exist.

1 Like

So generous of you to pause to do that.

I look forward to experimenting.

So here is my start point:

We will use only links of type ‘outline’ to make our new outline. I will use a stamp:

$MapList= find(linkedFrom("*","outline"));
$MapList.each(aPath){
    $Container(aPath)= (links(aPath).inbound."outline".$Path );
   }
};
$MapList=;

on the map’s container (which here is /Test). The outcome is:

Untitled%202019-05-20%2020-52-48

The only fail is I’ve not found a simple way to avoid ‘Edge case 4’ being moved. There is no simple way, on the flay, to test if the source of the link to the current note lies outside the container being acted upon.

To rebuild the map, we apply this stamp to the map container:

$Container(descendants)=$Path;

Note, the items do not return to their original map position - but that’s a whole other issue!

Anyway, here’s a TBX that shows the above: MapToOutline.tbx (91.7 KB)

So it’s not a complete fix, but it does get you some of the way.

3 Likes

Thank you ! That’s looking very encouraging :slight_smile:

(and it has shown me stamps, which I had somehow missed …)

I think I might have understood some of this. And if the general thrust is that it would be nice to have some way of rendering the map as an outline, I heartily concur, having asked something similar (without the technical additions). ComplexPoint might seem a well chosen name, to some of us! But I still owe you something for all the remarkable scripts you have given to the public over the years. Thank you.

1 Like

Thanks. If this seems a bit convoluted, bear in mind this task wasn’t (nor is now) a design intent of map view. Indeed optimising the map for this task might break other long-standing behaviours needed by other users.

To me, a bigger issue is if I, as the user, assert “of course, I won’t try this with notes not linked appropriately”. For, eventually I’ll forget, at best with no outcome and at worst perhaps a crash and I’ll blame the app. Ergo, making this behaviour a feature means the app would have to trap all sorts of ambiguities. Plus, if found what should it do… etc. IOW, I don’t think this is a simple feature to ‘just’ add as might be assumed. As regards Scapple, it doesn’t do nesting in the way Tinderbox does. Indeed, it draws inspiration from Tinderbox maps, whilst deliberately being much more simple in design/function. As such, if is easier to support the behaviour you decide.

Clearly, once the design encompasses cyclical graphs, trees become a special case.

When I have scripted this kind of thing in OmniGraffle etc, the first pass has always been a test for cyclicality, leading either to:

  • a tree operation (if the graph turns out to be a tree) or
  • an explanatory message, (if the graph turns out to contain cycles).

(But while trees/outlines are a particular case, they are also, for the structure of discourses, a common and arguably fairly central case - hence, perhaps, the periodic queries which one sees in the log of this forum).

Another fascinating example from Mark A!

On the more mundane points raised here, which perhaps should be split off into a separate topic, though not sure how or where and thus leave that to the moderators …

(It looks, at first glance, as if I should avoid or automatically prune out any semi-colons in note names to avoid ambiguity)

Semicolons have a special meaning as I found out (again) the hard way here. Easy enough to handle as long as one doesn’t forget!

(and it has shown me stamps, which I had somehow missed …)

Stamps are great. I am more comfortable running action code in stamps more than in agents or rules. I showed a rule in the simple example above as that was easier to include in the screenshot.

If you do a lot of your work in scripts outside Tinderbox (a reasonable assumption!) then stamps give you an off-label way to run action code from a script.

First you select the notes in Tinderbox. You can do that manually of course. But also (despite the statement in Tinderbox Help to the contrary) you can easily select multiple notes from a script, with something like this (an example that selects all notes with 1 in their name):

## select multiple Tinderbox notes

tell application "Tinderbox 8"
	tell front document
		set notes1 to notes whose name contains "1"
		repeat with i from 1 to length of notes1
			set selection i to item i of notes1
		end repeat
	end tell
end tell

Then you can run a stamp on those notes from a script with something like this.

## apply Stamp to selected Tinderbox notes

-- http://www.macosxautomation.com/applescript/uiscripting/index.html

my do_menu("Tinderbox 8", "Stamps", "MyStampName")

on do_menu(app_name, menu_name, menu_item)
	try
		tell application app_name to activate --must bring to front		
		tell application "System Events"
			tell process app_name
				tell menu bar 1
					tell menu bar item menu_name
						tell menu menu_name
							click menu item menu_item
						end tell
					end tell
				end tell
			end tell
		end tell
		return true
	on error error_message
		return false
	end try
end do_menu

Stamps need to be set up in Tinderbox manually first. But you can also run action code from a script with no prior manual prep in Tinderbox by creating an agent from the script and having the script set the value for its AgentAction, something like this:

tell application "Tinderbox 8"
	tell front document
		set myAgent to make new agent
		tell myAgent
			set name to "MyNewAgent"
			set value of attribute "AgentQuery" to "$Name.contains(" & quote & "1" & quote & ")"
			set value of attribute "AgentAction" to "$Color=" & quote & "red" & quote
		end tell
	end tell
end tell

Or create a note from a script and set a value for its Rule…

Lots of new possibilities with the new scripting support!

1 Like

Ha ! Excellent … I hadn’t spotted the scope for scripting the value of the AgentQuery and AgentAction attributes.

Thank you !

(extraordinary forum …)

1 Like

Hi Rob,

Very interesting thread you started. Now that we have 9.1 with new features and ability to have functions, I was curious if you have any updates in how you might be using Tinderbox as it pertains to Directed Acyclic Graphs? Have any of the new features helped? I am very new to Graph Theory and am asking more as a question to learn from rather than from experience.

Lastly, I found a program that seems to be built with DAG’s in mind. It is called Flying Logic. Flying Logic: Just Another Outliner? - Flying Logic | Software for TOC and Complex Problems
Have you heard of it?

Thanks in advance,
Tom

1 Like