Depedencies

Depedencies#

By collecting data on the projects within the WETO portfolio that use other tools within the portfolio, we can get a sense for the software projects that are at the “core” of the capabilities.

This network is divided into two types of connectivity:

  1. Direct connections are software that are connected within the code, so they may communicate directly through API’s, share memory, and be distributed as a bundle.

  2. Indirect connections are software that require the outputs of other tools in order to construct their inputs. These are connected through workflows rather than code.

Hide code cell content
from pathlib import Path
import yaml
import networkx as nx

software_attr_dir = Path("..", "..", "software_attributes")
software_database_dir = software_attr_dir / "database"

model_list_inputs = yaml.safe_load( open(software_attr_dir / "database_list.yaml", "r") )
models = model_list_inputs["active"] + model_list_inputs["partial"]

model_attributes_map = {
    model: yaml.safe_load( open( software_database_dir / f"{model}.yaml", "r") )
    for model in models
}
Hide code cell content
model_connectivity = {}
for model in models:
    model_attributes = model_attributes_map[model]
    if "dependencies" not in model_attributes:
        continue
    model_connectivity[model] = model_attributes["dependencies"]

network_graph = nx.DiGraph()
for model, connections in model_connectivity.items():
    for c in connections:
        weight = 1 if c[1] == "direct" else 2
        network_graph.add_edge(model, c[0], weight=weight)
Hide code cell source
import matplotlib.pyplot as plt

edges_direct = [(u, v) for (u, v, d) in network_graph.edges(data=True) if d["weight"] == 1]
edges_indirect = [(u, v) for (u, v, d) in network_graph.edges(data=True) if d["weight"] == 2]

# layout = nx.nx_pydot.graphviz_layout(network_graph, prog="neato")
layout = nx.nx_agraph.graphviz_layout(
    network_graph,
    prog="sfdp",
    # args="-Gnormalize=true"
    # args="-GK=0.5"
)
# layout = nx.spring_layout(network_graph, k=2)

# nodes
nx.draw_networkx_nodes(
    network_graph,
    layout,
    # node_size=1000
)

# edges
nx.draw_networkx_edges(
    network_graph,
    layout,
    edgelist=edges_direct,
    width=1,
    # edge_color="b"
)

nx.draw_networkx_edges(
    network_graph,
    layout,
    edgelist=edges_indirect,
    width=1,
    # alpha=0.5,
    # edge_color="b",
    style=":"
    # edge_color="r"
)

# node labels
label_options = {"ec": "k", "fc": "white", "alpha": 0.7}
nx.draw_networkx_labels(
    network_graph,
    layout,
    font_size=8,
    bbox=label_options,
    # font_family="sans-serif"
)
# edge weight labels
# edge_labels = nx.get_edge_attributes(network_graph, "weight")
# nx.draw_networkx_edge_labels(network_graph, layout, edge_labels)

# Title/legend
ax = plt.gca()
font = {"fontname": "Helvetica", "color": "k", "fontweight": "bold", "fontsize": 14}
ax.set_title("WETO Software Portfolio Connectivity", font)

# Change font color for legend
font["color"] = "k"
ax.text(
    0.80,
    0.10,
    "------- Direct",
    horizontalalignment="left",
    transform=ax.transAxes,
    fontdict=font,
)
ax.text(
    0.80,
    0.06,
    "........ Indirect",
    horizontalalignment="left",
    transform=ax.transAxes,
    fontdict=font,
)

ax = plt.gca()
ax.margins(0.08)
plt.axis("off")
plt.tight_layout()
plt.show()
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py:301, in pygraphviz_layout(G, prog, root, args)
    300 try:
--> 301     import pygraphviz
    302 except ImportError as err:

ModuleNotFoundError: No module named 'pygraphviz'

The above exception was the direct cause of the following exception:

ImportError                               Traceback (most recent call last)
Cell In[3], line 7
      4 edges_indirect = [(u, v) for (u, v, d) in network_graph.edges(data=True) if d["weight"] == 2]
      6 # layout = nx.nx_pydot.graphviz_layout(network_graph, prog="neato")
----> 7 layout = nx.nx_agraph.graphviz_layout(
      8     network_graph,
      9     prog="sfdp",
     10     # args="-Gnormalize=true"
     11     # args="-GK=0.5"
     12 )
     13 # layout = nx.spring_layout(network_graph, k=2)
     14 
     15 # nodes
     16 nx.draw_networkx_nodes(
     17     network_graph,
     18     layout,
     19     # node_size=1000
     20 )

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py:257, in graphviz_layout(G, prog, root, args)
    226 def graphviz_layout(G, prog="neato", root=None, args=""):
    227     """Create node positions for G using Graphviz.
    228 
    229     Parameters
   (...)
    255     see https://gitlab.com/graphviz/graphviz/-/issues/1767 for more info.
    256     """
--> 257     return pygraphviz_layout(G, prog=prog, root=root, args=args)

File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/networkx/drawing/nx_agraph.py:303, in pygraphviz_layout(G, prog, root, args)
    301     import pygraphviz
    302 except ImportError as err:
--> 303     raise ImportError("requires pygraphviz http://pygraphviz.github.io/") from err
    304 if root is not None:
    305     args += f"-Groot={root}"

ImportError: requires pygraphviz http://pygraphviz.github.io/
Hide code cell source
import squarify

# Count the number of projects depending on each project
depending = {model: 0 for model in models}
for model, dependents in model_connectivity.items():
    for d in dependents:
        depending[d[0]] = depending[d[0]] + 1

non_zero = {k:v for k,v in depending.items() if v > 0}
squarify.plot(list(non_zero.values()), label=list(non_zero.keys()))
plt.axis("off")
(0.0, 100.0, 0.0, 100.0)
../_images/6b7e919f73541741478edfe5ae34e6b8c0062fcc9e6def31cb876ab167bebc2d.png