Skip to content

Commit

Permalink
Fix drawing (#142)
Browse files Browse the repository at this point in the history
This fixes #137 and #140. Among other things, user can specify
* node size, node line color, node face color, node line width, edge line width, and edge color as dictionaries, iterables, or strings.
* edge face color as a colormap, dictionary, iterable or string.

The `draw` function is now modularized into `draw_xgi_nodes`, `draw_xgi_hyperedges`, and `draw_xgi_complexes` as well as a few helper functions. In addition, nodes are now drawn with `scatter` not `Circle` objects.
  • Loading branch information
nwlandry authored Jul 26, 2022
1 parent fb7d956 commit 6e33613
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 153 deletions.
6 changes: 5 additions & 1 deletion tests/generators/test_classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ def test_empty_hypergraph():
assert (H.num_nodes, H.num_edges) == (0, 0)


def test_star_clique():
def test_empty_hypergraph():
SC = xgi.empty_simplicial_complex()
assert (SC.num_nodes, SC.num_edges) == (0, 0)


def test_star_clique():
with pytest.raises(ValueError):
H = xgi.star_clique(-1, 7, 3)
with pytest.raises(ValueError):
Expand Down
62 changes: 50 additions & 12 deletions tutorials/Tutorial 5 - Plotting.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@
"cmap = plt.cm.Blues\n",
"\n",
"ax = plt.subplot(1,2,1)\n",
"xgi.draw(H, pos, cmap=cmap, ax=ax)\n",
"xgi.draw(H, pos, edge_fc=cmap, ax=ax)\n",
"\n",
"#Qualitative colormap\n",
"cmap = plt.cm.Set1\n",
"\n",
"ax = plt.subplot(1,2,2)\n",
"xgi.draw(H, pos, cmap=cmap, ax=ax)"
"xgi.draw(H, pos, edge_fc=cmap, ax=ax)"
]
},
{
Expand All @@ -136,9 +136,9 @@
"node_fc = 'black'\n",
"node_ec = 'white'\n",
"node_lw = 2\n",
"node_size = 0.07\n",
"node_size = 20\n",
"\n",
"xgi.draw(H, pos, cmap=cmap, edge_lc=edge_lc, edge_lw=edge_lw,\n",
"xgi.draw(H, pos, edge_fc=cmap, edge_lc=edge_lc, edge_lw=edge_lw,\n",
" node_fc=node_fc, node_ec=node_ec, node_lw=node_lw, node_size=node_size)"
]
},
Expand Down Expand Up @@ -201,7 +201,7 @@
"metadata": {},
"source": [
"# Example: generative model\n",
"We generate and visualize a [Chung-Lu hypergraph](https://doi.org/10.1093/comnet/cnx001)."
"We generate and visualize a [random hypergraph](https://doi.org/10.1093/comnet/cnx001)."
]
},
{
Expand All @@ -211,10 +211,8 @@
"metadata": {},
"outputs": [],
"source": [
"n = 500\n",
"k1 = {i : random.randint(10, 30) for i in range(n)}\n",
"k2 = {i : sorted(k1.values())[i] for i in range(n)}\n",
"H = xgi.chung_lu_hypergraph(k1, k2)"
"n = 100\n",
"H = xgi.random_hypergraph(100, [0.03, 0.0002, 0.00001])"
]
},
{
Expand Down Expand Up @@ -244,7 +242,42 @@
"source": [
"plt.figure(figsize=(10,10))\n",
"ax = plt.subplot(111)\n",
"xgi.draw(H, pos, node_size = 0.01, ax=ax)"
"xgi.draw(H, pos, node_size = 5, ax=ax)"
]
},
{
"cell_type": "markdown",
"id": "39e2d438",
"metadata": {},
"source": [
"We can even size/color the nodes by their degree!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d741e39e",
"metadata": {},
"outputs": [],
"source": [
"d = H.nodes.degree\n",
"s = 10\n",
"node_size = {id: np.sqrt((val+1)*s) for id, val in d.asdict().items()}\n",
"c = plt.cm.Blues\n",
"cmap = [c(i) for i in np.linspace(0.1, 0.9, d.max() + 1)]\n",
"node_fc = {id: np.array(cmap[val]).reshape(1, -1) for id, val in d.asdict().items()}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "03902a8e",
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,10))\n",
"ax = plt.subplot(111)\n",
"xgi.draw(H, pos, node_size = node_size, node_fc=node_fc, ax=ax)"
]
},
{
Expand Down Expand Up @@ -277,7 +310,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "Python 3.10.4 ('hypergraph')",
"language": "python",
"name": "python3"
},
Expand All @@ -291,7 +324,12 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.9"
"version": "3.10.4"
},
"vscode": {
"interpreter": {
"hash": "fdeb83b6e5b2333358b6ba79181fac315f1a722b4574d7079c134c9ae27f7c53"
}
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion xgi/drawing/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def weighted_barycenter_spring_layout(H, return_phantom_graph=False):
except ValueError:
# The list of node-labels has no integers, so I start from 0
phantom_node_id = 0

# Looping over the hyperedges of different order (from triples up)
for d in range(2, max_edge_order(H) + 1):
# Hyperedges of order d (d=2: triplets, etc.)
Expand Down
Loading

0 comments on commit 6e33613

Please sign in to comment.