Clean Graph layouts and increase flexibility
Overview: What does this pull request change?
This pull request changes the way _determine_graph_layout functions. It allows for user-supplied layout functions to be used in both the __init__ and the change_layout function. Each of the customized layouts provided by Manim has been moved to a separate function that adheres to the new LayoutFunction interface. I have done my best to ensure backward compatibility.
- standardizes layout function interfaces
- adds support for user-supplied graph layout functions
- improves the specificity of type hints in graph.py
Motivation and Explanation: Why and how do your changes improve the library?
This pull request standardizes the interface of the various supported graph layouts to make code more consistent and simplify the introduction of future layout options. It provides an option for users to supply their own custom layout function to programmatically arrange graphs using change_layout or the __init__.
Links to added or changed documentation pages
Reviewer Checklist
- [ ] The PR title is descriptive enough for the changelog, and the PR is labeled correctly
- [ ] If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section
- [ ] If applicable: newly added functions and classes are tested
Sooo it would've been a good idea to make an issue for this first, before creating a PR with a lot of changes discussing the applications and changes to the code. Because it seems like a change that will affect a lot of the behavior of the current codebase.
So if you could provide some examples on cases where this is useful and how exactly it improves the consistency that would make reviewing this a lot easier. Because discussing ideas is a lot easier than figuring out the functionality of written code and discussing about the interpretation of that.
I am all for improving consistency and making the usage of the manim easier, but still examples are needed!
@MrDiver The Graph Mobject provides the Graph.change_layout method for arranging nodes. The user can currently specify the graph layout in 2 different ways: by name as a str, or by dict[Hashable, np.ndarray[3]]. The Graph._determine_layout function is used by manim to 'parse' the provided layout parameter and return a dictionary that maps nodes to positions. If the user supplied a dict, it is simply returned. If the user supplied a str name ("tree", "spring", etc.) then there is some extra work that goes on.
Of the supported named layouts, most are implemented by the underlying graph library NetworkX. If this is the case then the appropriate function is invoked and the results are cleaned up a little bit before returning. The "tree" and "partite" layouts are special cases. The "tree" layout is not implemented by NetworkX so it was implemented ad hoc in the graph.py file. The "partite" layout is implemented by NetworkX but there are extra steps before and after calling to NetworkX. These cases are checked in a large if-else block. Also, the "tree" and "partite" layouts require additional arguments which are passed as optional keyword arguments to the Graph.__init__ and Graph.change_layout.
This pull request standardizes the interface of these layout functions by creating the LayoutFunction type (only statically-checked). It also allows the user to supply any function conforming to the LayoutFunction type to allow for new layouts at runtime. I also converted the "tree" and "partite" layouts to conform with LayoutFunction.
I tried to make all public interfaces fully backwards compatible, but in the future we can look at deprecating the root_vertex and partitions parameters instead requiring these arguments to be passed through the layout_config parameter thus decoupling the Graph constructor from the layout implementation.
@MrDiver Please let me know if there's anything I should improve.
I think it would be nice to have an Example for each of the layouts in the docs! (Not animated) ++
It would be nice if you could add your comment to the docs which explains how to use the layouts additionally to the example scenes.
Sorry, it’s finals week for me right now so I haven’t had much free time 💀. I can get it done by this weekend but if you have the bandwidth feel free to do it earlier.
Then just do your things! If we find the time we can do it! No stress!
@MrDiver would you mind reviewing this MR