Skip to content
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

Consolidate network components #1052

Merged
merged 21 commits into from
May 9, 2024
Merged

Conversation

asizemore
Copy link
Member

@asizemore asizemore commented Apr 25, 2024

Resolves #996

The goal here is to simplify our network plot components. The approach I've taken here deviates slightly from the original proposal, mostly because cramming all the logic into NetworkPlot became overwhelming. So we'll see what others think!

Left to do:

  • Create NetworkPlot
  • Handle svg styling and overrides
  • Pass empty network data
  • Handle default layouts
  • Move partition titles into bp net styles
  • Possibly remove partitions from NetworkPlot. That prop is only used to set node positions, and if BipartiteNetworkPlot does that already...
  • Possibly setting a max height so that the network scrolls
  • Add more network stories

Left for later because they're more feature-upgrade types:

  1. Allow NodeWithLabel to take a label position, rotation, etc.

Other notes:

  • I'm not really happy with how the svgStyles handles the containerSyles height and width. It assumes the input is a number, and anything else provided gets the boot (the default boot, here). I don't have a much better way to handle this right now, but just wanted to state my frustration
  • I moved the css around for sake of organization. I didn't change styles, just class names when appropriate.

@asizemore asizemore marked this pull request as draft April 25, 2024 17:46
@asizemore asizemore marked this pull request as ready for review May 1, 2024 10:14
@asizemore asizemore requested a review from dmfalke May 1, 2024 10:14
@dmfalke
Copy link
Member

dmfalke commented May 1, 2024

@asizemore I will start to review this in the next day or two. Let me know if you want me to take a look sooner!

@asizemore
Copy link
Member Author

No problem, thanks @dmfalke ! This isn't for b68 so can definitely wait

Copy link
Member

@dmfalke dmfalke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks great. I like the direction you went with this.

Have you given any thought into how various layout algorithms will be applied, in the future? And would a bipartite network be considered a layout? I don't really have any strong opinions on this, but I think it's an interesting thing to consider.

Comment on lines 82 to 121
// In order to assign coordinates to each node, we'll separate the
// nodes based on their partition, then will use their order in the partition
// (given by partitionXNodeIDs) to finally assign the coordinates.
const nodesByPartition: NodeData[][] = useMemo(
() =>
partition(nodes, (node) => {
return partitions[0].nodeIds.includes(node.id);
}),
[nodes, partitions]
);

const nodesByPartitionWithCoordinates = useMemo(
() =>
nodesByPartition.map((partition, partitionIndex) => {
const partitionWithCoordinates = partition.map((node) => {
// Find the index of the node in the partition
const indexInPartition = partitions[partitionIndex].nodeIds.findIndex(
(id) => id === node.id
);

return {
// partitionIndex of 0 refers to the left-column nodes whereas 1 refers to right-column nodes
x: partitionIndex === 0 ? column1Position : column2Position,
y: svgStyles.topPadding + svgStyles.nodeSpacing * indexInPartition,
labelPosition:
partitionIndex === 0 ? 'left' : ('right' as LabelPosition),
...node,
};
});
return partitionWithCoordinates;
}),
[
column1Position,
column2Position,
partitions,
nodesByPartition,
svgStyles.nodeSpacing,
svgStyles.topPadding,
]
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is potential to make this a little more efficient. In my quick reading, it appears we don't really need to partition the nodes, since we just concatenate the arrays below. What would happen if you got rid of nodesByPartition? You would still need to know which partition the node is in--currently this is done with partitionIndex, which could be replaced with a lookup in partitions.

If we anticipate a large number of nodes (say, in the neighborhood of 1000), this change might be worth considering.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Done and done

Comment on lines 126 to 132
nodes.map((node, index) => ({
labelPosition: 'right' as LabelPosition,
...node,
x: node.x ?? 230 + 200 * Math.cos(2 * Math.PI * (index / nodes.length)),
y: node.y ?? 230 + 200 * Math.sin(2 * Math.PI * (index / nodes.length)),
actions: getNodeActions?.(node.id),
})),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is conditionally applying a default layout. What do you think about having this component assume that the nodes it receives already have a layout applied, and then we can skip this traversal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipped in the latest commits

@asizemore
Copy link
Member Author

@dmfalke ready for another look!

I let NetworkPlot assume it's getting node coordinates, but to totally remove the traversal i also have it assuming it's receiving node actions as well. Not a bad thing since we can totally remove a loop over the nodes. I think when it comes time for the network plot, it's possible we create a LayoutNetwork or LayoutedNetwork or not sure how to say it yet :) but some component that does what BipartiteNetworkPlot does now that lays out the network and processes nodes and edges in a way that nicely preps them for NetworkPlot.

Your point about the bipartite network being a layout is a good one. Mathematically it's much more than a layout because it carries a bunch of assumptions and rules about the network. But for this codebase, how much does that matter? Is it really anything more than a nice layout of the network when special data is given? I've been asking myself this a lot.

But anyways to get back to your question about layouts, yes I have given that a bunch of thought lately. Right now I'd like the backend to do it and to send x/y coordinates back to the frontend. I also want the backend to (someday) include node labels in that layout calculation and send us those coordinates as well so that we don't have a bunch of overlapping labels. The frontend could do a lot of layouts, but I think the backend would be faster and more easily expanded to specialized layouts if we go that direction in the future.

@asizemore asizemore requested a review from dmfalke May 8, 2024 11:34
@dmfalke
Copy link
Member

dmfalke commented May 8, 2024

This all sounds great!

@asizemore asizemore merged commit 05d427a into main May 9, 2024
2 checks passed
@asizemore asizemore deleted the feature-996-consolidate-networks branch May 9, 2024 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consolidate network components into one
2 participants