adapted originally from https://gist.github.com/ericdill/9942ac55c2c9f6a550973dd2dc3653a4 and then later from https://gist.github.com/msarahan/f425082c67bd985cb4edd0edb4d50de0
updated for repodata format changes
import copy
import json
import glob
from itertools import chain
from pathlib import Path
from matplotlib import pyplot as plt
import networkx as nx
import requests_cache
requests_cache.install_cache()
import requests
channels = [
"conda-forge/linux-64",
"conda-forge/noarch",
]
dg = nx.DiGraph()
for channel in channels:
url = f"https://conda.anaconda.org/{channel}/repodata.json"
r = requests.get(url)
assert r.status_code == 200, r.status_code
repodata = json.loads(r.text)
for meta in chain(repodata['packages'].values(), repodata['packages.conda'].values()):
dg.add_node(meta['name'])
for dep in meta.get('depends', []):
dg.add_edge(meta['name'], dep.partition(' ')[0])
dg.number_of_nodes()
22998
[name for name in dg if ('dolfin' in name or 'fenics' in name)]
['fenics', 'dolfin-adjoint', 'fenics-dijitso', 'fenics-dolfin', 'fenics-ffc', 'fenics-fiat', 'fenics-ufl', 'fenics-basix', 'fenics-libbasix', 'fenics-libdolfin', 'fenics-dolfinx', 'fenics-ffcx', 'fenics-libdolfinx', 'fenics-ufcx', 'dolfinx_mpc', 'fenics-basix-pybind11-abi', 'libdolfinx_mpc', 'fenicsprecice']
def dependents(G: nx.DiGraph, roots: str | list[str], steps: int=10) -> nx.DiGraph:
"""compute dependent packages, given one or more root packages"""
if isinstance(roots, str):
roots = [roots]
neighbors = set(roots)
for n in range(steps):
immediate_neighbors = copy.copy(neighbors)
for neighbor in immediate_neighbors:
neighbors.update(G.predecessors(neighbor))
return nx.subgraph(G, neighbors)
sg = dependents(dg, ['fenics-ufl', 'fenics-ufcx'])
def topo_pos(G: nx.DiGraph) -> dict:
"""Display in topological order, with simple offsetting for legibility"""
pos_dict = {}
for i, node_list in enumerate(nx.topological_generations(G)):
x_offset = len(node_list) / 2
y_offset = 0.5 / len(node_list)
for j, name in enumerate(node_list):
pos_dict[name] = (j - x_offset, -i)
return pos_dict
sgr = sg.reverse()
nx.draw(sgr, topo_pos(sgr), with_labels=True, node_color='#A0CBE2', edge_color='#FFCBE2')
nx.write_network_text(sgr)
╟── fenics-ufcx ╎ └─╼ fenics-libdolfinx ╎ ├─╼ dolfinx_mpc ╾ fenics-dolfinx, libdolfinx_mpc ╎ ├─╼ fenics-dolfinx ╾ fenics-ffcx, fenics-ufl ╎ │ └─╼ ... ╎ └─╼ libdolfinx_mpc ╎ └─╼ ... ╙── fenics-ufl ├─╼ fenics ╾ fenics-dolfin, fenics-ffc, fenics-libdolfin │ ├─╼ dolfin-adjoint │ │ ├─╼ windse ╾ fenics, mshr │ │ └─╼ gyptis ╾ fenics │ ├─╼ cashocs │ ├─╼ bvpy │ ├─╼ ldrb ╾ mshr │ ├─╼ mshr ╾ fenics-dolfin, fenics-libdolfin │ │ └─╼ ... │ ├─╼ turtlefsi │ ├─╼ fenicsprecice │ ├─╼ pulse │ └─╼ ... ├─╼ fenics-dolfin ╾ fenics-ffc, fenics-libdolfin │ ├─╼ puma │ ├─╼ fish2eod │ └─╼ ... ├─╼ fenics-ffc │ ├─╼ fenics-libdolfin │ │ └─╼ ... │ └─╼ ... ├─╼ fenics-ffcx │ └─╼ ... └─╼ ...