-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
addded family grouping with subgraphs #1810
base: master
Are you sure you want to change the base?
Conversation
Still to do (in order of priority).
|
name | ||
cyclePoint | ||
state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the only thing we need to request from the task's parent is its ID.
We can then use that ID to find the "FamilyProxy" entry for the family to get the other data.
name | ||
cyclePoint | ||
state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
parents { | ||
name | ||
} | ||
childTasks { | ||
name | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only need parents
to determine the family hierarchy.
src/views/Graph.vue
Outdated
const targetName = edgeCheck[0].node.target.split('/')[edgeCheck[0].node.target.split('/').length - 1] | ||
const targetCycle = edgeCheck[0].node.target.split('/')[edgeCheck[0].node.target.split('/').length - 2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an interface for parsing/formatting Cylc IDs called Tokens
. The ids of all nodes in the store are pre-parsed ready for use.
src_tokens = node.tokens.edge[0]
tgt_tokens = node.tokens.edge[1]
> tokens = Tokens('w//c/t/j')
> tokens.workflow
'w'
> tokens.cycle
'c'
> tokens.task
't'
> tokens.job
'j'
src/views/Graph.vue
Outdated
createNode (nodeName, cyclePoint) { | ||
// const abc = this.workflows[0].tokens.clone({cycle: "20240624T1200Z", workflow: "consolidate_observations"}) | ||
// adds a new node object to 'nodes' array | ||
const nodePath = this.workflowIDs[0] | ||
const nodeId = `${nodePath}//${cyclePoint}/${nodeName}` | ||
const nodeParent = `${nodePath}//${cyclePoint}` | ||
const newNode = { | ||
children: [], | ||
familyTree: undefined, | ||
id: nodeId, | ||
name: nodeName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cycle/family node should already be present in the store. So rather than creating a new one, we should be able to pull out the existing one with all the status information already filled in.
It should work something like this:
getNode(id) {
return this.cylcTree.$index[id]
}
src/views/Graph.vue
Outdated
createEdge (sourceName, targetName, sourceCyclePoint, targetCyclePoint) { | ||
// adds a new edge object to 'edges' array | ||
const edgePath = this.workflowIDs[0] | ||
const edgeId = `${edgePath}//$edge|${sourceCyclePoint}/${sourceName}|${targetCyclePoint}/${targetName}` | ||
const sourceObject = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edges to or from cycles or families will still need to be generated by this method because they do not exist in the store.
src/views/Graph.vue
Outdated
createEdge (sourceName, targetName, sourceCyclePoint, targetCyclePoint) { | ||
// adds a new edge object to 'edges' array | ||
const edgePath = this.workflowIDs[0] | ||
const edgeId = `${edgePath}//$edge|${sourceCyclePoint}/${sourceName}|${targetCyclePoint}/${targetName}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can pass this function the source and target tokens rather than their IDs, then this becomes a lot eaisier.
I think we can do it like this:
// untested
const edge_tokens = src_tokens.clone(cycle=`\$edge|${src_tokens.relativeID}|${tgt_tokens.relativeID}`, task=null, job=null)
const edge_tokens.edge = [src_tokens, tgt_tokens]
const edge_id = edge_tokens.id
I think this is a problem that warrants recursion as it's tricky to unroll as an iterative loop. Here's an idea of what that could look like (Python syntax):
from random import random
TASKS = {
'foo': {
'name': 'foo',
'parent': 'FOO',
},
'FOO': {
'name': 'FOO',
'parent': 'root'
},
'bar': {
'name': 'bar',
'parent': 'BAR1',
},
'baz': {
'name': 'baz',
'parent': 'BAR2',
},
'BAR1': {
'name': 'BAR1',
'parent': 'BAR',
},
'BAR2': {
'name': 'BAR2',
'parent': 'BAR',
},
'root': {
'name': 'root',
'parent': None,
},
}
TREE = {
'root': {
'FOO': None,
'BAR': {
'BAR1': None,
'BAR2': None,
},
},
}
def add_subgraph(dotcode, pointer, graph_sections):
for key, value in pointer.items():
dotcode.append(
f'subgraph cluster_{str(random())[2:]} {{'
f'\nlabel = "{key}"'
)
if value:
add_subgraph(dotcode, value, graph_sections)
if key in graph_sections:
dotcode.extend(graph_sections[key])
dotcode.append('}')
return dotcode
def get_dotcode(tasks):
graph_sections = {}
for task in tasks.values():
parent = task['parent']
if not parent:
continue
section = graph_sections.setdefault(parent, [])
section.append(f'{task["name"]} [title="{task["name"]}"]')
dotcode = ['digraph {']
add_subgraph(dotcode, TREE['root'], graph_sections)
return dotcode
for item in get_dotcode(TASKS):
print(item) digraph {
subgraph cluster_23300787190407446 {
label = "FOO"
foo [title="foo"]
}
subgraph cluster_5025488657295563 {
label = "BAR"
subgraph cluster_2135762450670372 {
label = "BAR1"
bar [title="bar"]
}
subgraph cluster_4413670667138756 {
label = "BAR2"
baz [title="baz"]
}
BAR1 [title="BAR1"]
BAR2 [title="BAR2"]
} I haven't taken cycles into account in this solution, you'll need to add a This solution will also add entries for families which have no tasks, so, you'll need some fancy logic for removing empty families, and any families that contain only empty families. |
21472f9
to
e45ccec
Compare
Partly addresses issue #1130
The grouping of nodes by cycle point is completed in this pr #1763
----Notes on work----
Some ideas for a unified approach to grouping/collapsing cycles/families. I'm suggesting unifying the handling of cycles and families (note, cycles represent the "root" family so they are essentially the same thing).
Grouping/Ungrouping - Drawing dashed boxes around a cycle/family.
Collapsing/Expanding - Reducing a family down to a single node.
Limitations of the Cylc 7 approach:
Note, for simplicity, this approach groups/collapses all instances of selected families rather than managing this at a per-cycle level. I think this is probably more aligned with expectations, but does represent a minor limitation, e.g. there's no ability to collapse all but one cycle. The ability to expand/collapse specific cycle instances would be a reasonable enhancement.
Design Sketch
Had a quick discussion on this (more to come):
Check List
CONTRIBUTING.md
and added my name as a Code Contributor.setup.cfg
(andconda-environment.yml
if present).CHANGES.md
entry included if this is a change that can affect users?.?.x
branch.