-
Notifications
You must be signed in to change notification settings - Fork 65
feat: new interactive graph visualization #609
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
Conversation
for more information, see https://pre-commit.ci
|
Looks really cool! Thanks for the contribution @frazane |
|
@frazane this is really cool! Are you still planning to add more features? I'd be happy to review or test this if it helps! |
Thanks! I think for this PR I would only make sure that this works for arbitrary graphs, including stretched grid graphs with many nodes (let's see how well this scales) and hierarchical graphs. In subsequent PRs I see a few additional features we might add:
It would be great if you could test it (you can simply run the module with the temporary CLI and provide the path to a graph). Generally, the more graphs we throw at it, the better. Feedback is also very welcome! :) |
|
Hi @frazane , is this always plotting things on a globe? LAM graphs for example cover only a limited area, would they get rendered (on part of the globe?) in the current implementation? (Don't have time to test now, can send you a LAM graph in case you would have time, in any case this comment should not stop you merging/developping this PR) |
Yes, it should work on arbitrary graphs. I tried with the stretched grid graph and it also worked. Can you send me a small LAM graph that I can test? |
|
Very nice feature! Just a quick note: I had to adapt the script slightly on my system. @@ -82,14 +82,14 @@ if __name__ == "__main__":
nodes, edges = load_graph(args.path, nodes=args.nodes, edges=args.edges)
for node_set in nodes:
- node_lats, node_lons = coords_to_latlon(nodes[node_set].numpy())
+ node_lats, node_lons = coords_to_latlon(nodes[node_set].to('cpu').numpy())
nodes[node_set] = to_nodes_json(node_lats, node_lons, prefix=node_set)
for edge_set in edges:
src_nodes, dst_nodes = edge_set.split("_to_")
src_names = [f"{src_nodes}_{i}" for i in range(len(nodes[src_nodes]))]
dst_names = [f"{dst_nodes}_{i}" for i in range(len(nodes[dst_nodes]))]
- edges[edge_set] = to_edges_json(src_names, dst_names, edges[edge_set].numpy().T)
+ edges[edge_set] = to_edges_json(src_names, dst_names, edges[edge_set].to('cpu').numpy().T)
|
Tested and works correctly 👍
|
a602409 to
920824d
Compare
|
Thanks @anaprietonem and @jlcasador for the feedback! ana:
jlcasador:
|
|
Hi Francesco, sorry for the delayed review. I just have one minor comment about the location: could we put it in Also, I would set the default edges to 'None' and iterate over 'graph.edge_types', which will return all the edges already defined in the graphs. Thanks for the contribution, really cool! Looking forward to have it merged |
9309143 to
920824d
Compare
|
@ecmwf/anemoisecurity please ignore the review request, It was created by mistake during a merge with main. Note to self: "do not use VSCode git UI ever again" :) |
dd7739d to
28be0cb
Compare
b1cfa5a to
ccce692
Compare
for more information, see https://pre-commit.ci
JPXKQX
left a comment
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.
Brilliant! Thanks for the great contribution Francesco!
|
Hi @frazane — this looks awesome, thanks a lot for implementing it!
|
|
Hi @matschreiner, I think it makes more sense to just directly open PRs with the proposed improvements. Both of the first two points seem sensible to me! And to answer to your question, the nodes are technically spheres: just with a very small number of vertices so the rendering is faster. |
🤖 Automated Release PR This PR was created by `release-please` to prepare the next release. Once merged: 1. A new version tag will be created 2. A GitHub release will be published 3. The changelog will be updated Changes to be included in the next release: --- <details><summary>training: 0.7.0</summary> ## [0.7.0](training-0.6.7...training-0.7.0) (2025-11-17) ### ⚠ BREAKING CHANGES * **training:** remove support for EDA ([#651](#651)) ### Features * Callbacks for GraphEnsForecaster. ([#449](#449)) ([39c2bfc](39c2bfc)) * Mlflow azure ([#646](#646)) ([27bd3dd](27bd3dd)) * **training:** Remove support for EDA ([#651](#651)) ([921e108](921e108)) ### Bug Fixes * Anemoi-datasets import ([#626](#626)) ([65c8901](65c8901)) * Bug for mlflow offline logging ([#675](#675)) ([fdce0f6](fdce0f6)) * Bug in sample plots. ([#632](#632)) ([9e024f3](9e024f3)) * Incorrect test for variable mask scaler ([#649](#649)) ([d0f775e](d0f775e)) * Integration tests and drop missed reference for profiler ([#630](#630)) ([f352e17](f352e17)) * **training:** Provide more informative error when user specifies inexistent node attribute ([#663](#663)) ([dde3cb6](dde3cb6)) * Update readmes ([#655](#655)) ([a58aa64](a58aa64)) </details> <details><summary>graphs: 0.7.2</summary> ## [0.7.2](graphs-0.7.1...graphs-0.7.2) (2025-11-17) ### Features * **graphs:** Add LimitedAreaMask for stretched hidden nodes ([#671](#671)) ([f155f3c](f155f3c)) * **graphs:** New edge attributes and faster graph cleaning ([#617](#617)) ([8659de9](8659de9)) * New interactive graph visualization ([#609](#609)) ([5b5ede4](5b5ede4)) ### Bug Fixes * **graphs,normalisation:** Add assert when dividing by 0 ([#676](#676)) ([01b7034](01b7034)) * **graphs,schemas:** Missing type for mask_attr_name in schema ([#664](#664)) ([f021017](f021017)) * **graphs,tests:** New test and fix anemoi-graphs tests with gpu ([#637](#637)) ([ca1b542](ca1b542)) * **graphs:** Remove wrong argument from og.Figure ([#616](#616)) ([abd37eb](abd37eb)) * **graphs:** Unit-range normalisation ([#665](#665)) ([6de4778](6de4778)) * Update readmes ([#655](#655)) ([a58aa64](a58aa64)) </details> <details><summary>models: 0.10.0</summary> ## [0.10.0](models-0.9.7...models-0.10.0) (2025-11-17) ### ⚠ BREAKING CHANGES * **training:** remove support for EDA ([#651](#651)) ### Features * **training:** Remove support for EDA ([#651](#651)) ([921e108](921e108)) ### Bug Fixes * Basemodel.predict_step ([#672](#672)) ([0c830e9](0c830e9)) * **models:** Assert no dropout ([#638](#638)) ([c1bbcec](c1bbcec)) * Shard shape type hints ([#625](#625)) ([fb201fd](fb201fd)) * Update readmes ([#655](#655)) ([a58aa64](a58aa64)) </details> --- > [!IMPORTANT] > Please do not change the PR title, manifest file, or any other automatically generated content in this PR unless you understand the implications. Changes here can break the release process. > >⚠️ Merging this PR will: > - Create a new release > - Trigger deployment pipelines > - Update package versions **Before merging:** - Ensure all tests pass - Review the changelog carefully - Get required approvals [Release-please documentation](https://github.com/googleapis/release-please)





Description
Adds a new lightweight way to visualize graphs interactively. No added dependencies (the javascript code runs entirely in the broswer and sources libraries via CDN). The way this is implemented is quite simple: the data is embedded directly in the HTML in json format using a jinja template. Then javascript code does the rest (yes, definitely with the help of coding assistants).
The largest graph on which this was tested was a cutout graph with n320 grid globally and a 2km grid over central Europe (the one we currently have at MeteoSwiss). Loaded in about 6s and then still runs relatively smoothly. Still, we might be reaching a limit with >1'500'000 nodes with lots of connections - we might need to find some optimizations to the code at some point as I am sure there are some left.
Nothing changes in terms of interface - this will simply add another output to the command:
Features
Graphs tested
📚 Documentation preview 📚: https://anemoi-training--609.org.readthedocs.build/en/609/
📚 Documentation preview 📚: https://anemoi-graphs--609.org.readthedocs.build/en/609/
📚 Documentation preview 📚: https://anemoi-models--609.org.readthedocs.build/en/609/