123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- """Unit tests for matplotlib drawing functions."""
- import itertools
- import os
- import warnings
- import pytest
- mpl = pytest.importorskip("matplotlib")
- np = pytest.importorskip("numpy")
- mpl.use("PS")
- plt = pytest.importorskip("matplotlib.pyplot")
- plt.rcParams["text.usetex"] = False
- import networkx as nx
- barbell = nx.barbell_graph(4, 6)
- def test_draw():
- try:
- functions = [
- nx.draw_circular,
- nx.draw_kamada_kawai,
- nx.draw_planar,
- nx.draw_random,
- nx.draw_spectral,
- nx.draw_spring,
- nx.draw_shell,
- ]
- options = [{"node_color": "black", "node_size": 100, "width": 3}]
- for function, option in itertools.product(functions, options):
- function(barbell, **option)
- plt.savefig("test.ps")
- finally:
- try:
- os.unlink("test.ps")
- except OSError:
- pass
- def test_draw_shell_nlist():
- try:
- nlist = [list(range(4)), list(range(4, 10)), list(range(10, 14))]
- nx.draw_shell(barbell, nlist=nlist)
- plt.savefig("test.ps")
- finally:
- try:
- os.unlink("test.ps")
- except OSError:
- pass
- def test_edge_colormap():
- colors = range(barbell.number_of_edges())
- nx.draw_spring(
- barbell, edge_color=colors, width=4, edge_cmap=plt.cm.Blues, with_labels=True
- )
- # plt.show()
- def test_arrows():
- nx.draw_spring(barbell.to_directed())
- # plt.show()
- @pytest.mark.parametrize(
- ("edge_color", "expected"),
- (
- (None, "black"), # Default
- ("r", "red"), # Non-default color string
- (["r"], "red"), # Single non-default color in a list
- ((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple
- ([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list
- ((0, 1, 0, 1), "lime"), # single color as rgba tuple
- ([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list
- ("#0000ff", "blue"), # single color hex code
- (["#0000ff"], "blue"), # hex code in list
- ),
- )
- @pytest.mark.parametrize("edgelist", (None, [(0, 1)]))
- def test_single_edge_color_undirected(edge_color, expected, edgelist):
- """Tests ways of specifying all edges have a single color for edges
- drawn with a LineCollection"""
- G = nx.path_graph(3)
- drawn_edges = nx.draw_networkx_edges(
- G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color
- )
- assert mpl.colors.same_color(drawn_edges.get_color(), expected)
- @pytest.mark.parametrize(
- ("edge_color", "expected"),
- (
- (None, "black"), # Default
- ("r", "red"), # Non-default color string
- (["r"], "red"), # Single non-default color in a list
- ((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple
- ([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list
- ((0, 1, 0, 1), "lime"), # single color as rgba tuple
- ([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list
- ("#0000ff", "blue"), # single color hex code
- (["#0000ff"], "blue"), # hex code in list
- ),
- )
- @pytest.mark.parametrize("edgelist", (None, [(0, 1)]))
- def test_single_edge_color_directed(edge_color, expected, edgelist):
- """Tests ways of specifying all edges have a single color for edges drawn
- with FancyArrowPatches"""
- G = nx.path_graph(3, create_using=nx.DiGraph)
- drawn_edges = nx.draw_networkx_edges(
- G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color
- )
- for fap in drawn_edges:
- assert mpl.colors.same_color(fap.get_edgecolor(), expected)
- def test_edge_color_tuple_interpretation():
- """If edge_color is a sequence with the same length as edgelist, then each
- value in edge_color is mapped onto each edge via colormap."""
- G = nx.path_graph(6, create_using=nx.DiGraph)
- pos = {n: (n, n) for n in range(len(G))}
- # num edges != 3 or 4 --> edge_color interpreted as rgb(a)
- for ec in ((0, 0, 1), (0, 0, 1, 1)):
- # More than 4 edges
- drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=ec)
- for fap in drawn_edges:
- assert mpl.colors.same_color(fap.get_edgecolor(), ec)
- # Fewer than 3 edges
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edgelist=[(0, 1), (1, 2)], edge_color=ec
- )
- for fap in drawn_edges:
- assert mpl.colors.same_color(fap.get_edgecolor(), ec)
- # num edges == 3, len(edge_color) == 4: interpreted as rgba
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1, 1)
- )
- for fap in drawn_edges:
- assert mpl.colors.same_color(fap.get_edgecolor(), "blue")
- # num edges == 4, len(edge_color) == 3: interpreted as rgb
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1)
- )
- for fap in drawn_edges:
- assert mpl.colors.same_color(fap.get_edgecolor(), "blue")
- # num edges == len(edge_color) == 3: interpreted with cmap, *not* as rgb
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1)
- )
- assert mpl.colors.same_color(
- drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor()
- )
- for fap in drawn_edges:
- assert not mpl.colors.same_color(fap.get_edgecolor(), "blue")
- # num edges == len(edge_color) == 4: interpreted with cmap, *not* as rgba
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1, 1)
- )
- assert mpl.colors.same_color(
- drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor()
- )
- assert mpl.colors.same_color(
- drawn_edges[2].get_edgecolor(), drawn_edges[3].get_edgecolor()
- )
- for fap in drawn_edges:
- assert not mpl.colors.same_color(fap.get_edgecolor(), "blue")
- def test_fewer_edge_colors_than_num_edges_directed():
- """Test that the edge colors are cycled when there are fewer specified
- colors than edges."""
- G = barbell.to_directed()
- pos = nx.random_layout(barbell)
- edgecolors = ("r", "g", "b")
- drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors)
- for fap, expected in zip(drawn_edges, itertools.cycle(edgecolors)):
- assert mpl.colors.same_color(fap.get_edgecolor(), expected)
- def test_more_edge_colors_than_num_edges_directed():
- """Test that extra edge colors are ignored when there are more specified
- colors than edges."""
- G = nx.path_graph(4, create_using=nx.DiGraph) # 3 edges
- pos = nx.random_layout(barbell)
- edgecolors = ("r", "g", "b", "c") # 4 edge colors
- drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors)
- for fap, expected in zip(drawn_edges, edgecolors[:-1]):
- assert mpl.colors.same_color(fap.get_edgecolor(), expected)
- def test_edge_color_string_with_global_alpha_undirected():
- edge_collection = nx.draw_networkx_edges(
- barbell,
- pos=nx.random_layout(barbell),
- edgelist=[(0, 1), (1, 2)],
- edge_color="purple",
- alpha=0.2,
- )
- ec = edge_collection.get_color().squeeze() # as rgba tuple
- assert len(edge_collection.get_paths()) == 2
- assert mpl.colors.same_color(ec[:-1], "purple")
- assert ec[-1] == 0.2
- def test_edge_color_string_with_global_alpha_directed():
- drawn_edges = nx.draw_networkx_edges(
- barbell.to_directed(),
- pos=nx.random_layout(barbell),
- edgelist=[(0, 1), (1, 2)],
- edge_color="purple",
- alpha=0.2,
- )
- assert len(drawn_edges) == 2
- for fap in drawn_edges:
- ec = fap.get_edgecolor() # As rgba tuple
- assert mpl.colors.same_color(ec[:-1], "purple")
- assert ec[-1] == 0.2
- @pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
- def test_edge_width_default_value(graph_type):
- """Test the default linewidth for edges drawn either via LineCollection or
- FancyArrowPatches."""
- G = nx.path_graph(2, create_using=graph_type)
- pos = {n: (n, n) for n in range(len(G))}
- drawn_edges = nx.draw_networkx_edges(G, pos)
- if isinstance(drawn_edges, list): # directed case: list of FancyArrowPatch
- drawn_edges = drawn_edges[0]
- assert drawn_edges.get_linewidth() == 1
- @pytest.mark.parametrize(
- ("edgewidth", "expected"),
- (
- (3, 3), # single-value, non-default
- ([3], 3), # Single value as a list
- ),
- )
- def test_edge_width_single_value_undirected(edgewidth, expected):
- G = nx.path_graph(4)
- pos = {n: (n, n) for n in range(len(G))}
- drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth)
- assert len(drawn_edges.get_paths()) == 3
- assert drawn_edges.get_linewidth() == expected
- @pytest.mark.parametrize(
- ("edgewidth", "expected"),
- (
- (3, 3), # single-value, non-default
- ([3], 3), # Single value as a list
- ),
- )
- def test_edge_width_single_value_directed(edgewidth, expected):
- G = nx.path_graph(4, create_using=nx.DiGraph)
- pos = {n: (n, n) for n in range(len(G))}
- drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth)
- assert len(drawn_edges) == 3
- for fap in drawn_edges:
- assert fap.get_linewidth() == expected
- @pytest.mark.parametrize(
- "edgelist",
- (
- [(0, 1), (1, 2), (2, 3)], # one width specification per edge
- None, # fewer widths than edges - widths cycle
- [(0, 1), (1, 2)], # More widths than edges - unused widths ignored
- ),
- )
- def test_edge_width_sequence(edgelist):
- G = barbell.to_directed()
- pos = nx.random_layout(G)
- widths = (0.5, 2.0, 12.0)
- drawn_edges = nx.draw_networkx_edges(G, pos, edgelist=edgelist, width=widths)
- for fap, expected_width in zip(drawn_edges, itertools.cycle(widths)):
- assert fap.get_linewidth() == expected_width
- def test_edge_color_with_edge_vmin_vmax():
- """Test that edge_vmin and edge_vmax properly set the dynamic range of the
- color map when num edges == len(edge_colors)."""
- G = nx.path_graph(3, create_using=nx.DiGraph)
- pos = nx.random_layout(G)
- # Extract colors from the original (unscaled) colormap
- drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=[0, 1.0])
- orig_colors = [e.get_edgecolor() for e in drawn_edges]
- # Colors from scaled colormap
- drawn_edges = nx.draw_networkx_edges(
- G, pos, edge_color=[0.2, 0.8], edge_vmin=0.2, edge_vmax=0.8
- )
- scaled_colors = [e.get_edgecolor() for e in drawn_edges]
- assert mpl.colors.same_color(orig_colors, scaled_colors)
- def test_directed_edges_linestyle_default():
- """Test default linestyle for edges drawn with FancyArrowPatches."""
- G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
- pos = {n: (n, n) for n in range(len(G))}
- # edge with default style
- drawn_edges = nx.draw_networkx_edges(G, pos)
- assert len(drawn_edges) == 3
- for fap in drawn_edges:
- assert fap.get_linestyle() == "solid"
- @pytest.mark.parametrize(
- "style",
- (
- "dashed", # edge with string style
- "--", # edge with simplified string style
- (1, (1, 1)), # edge with (offset, onoffseq) style
- ),
- )
- def test_directed_edges_linestyle_single_value(style):
- """Tests support for specifying linestyles with a single value to be applied to
- all edges in ``draw_networkx_edges`` for FancyArrowPatch outputs
- (e.g. directed edges)."""
- G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
- pos = {n: (n, n) for n in range(len(G))}
- drawn_edges = nx.draw_networkx_edges(G, pos, style=style)
- assert len(drawn_edges) == 3
- for fap in drawn_edges:
- assert fap.get_linestyle() == style
- @pytest.mark.parametrize(
- "style_seq",
- (
- ["dashed"], # edge with string style in list
- ["--"], # edge with simplified string style in list
- [(1, (1, 1))], # edge with (offset, onoffseq) style in list
- ["--", "-", ":"], # edges with styles for each edge
- ["--", "-"], # edges with fewer styles than edges (styles cycle)
- ["--", "-", ":", "-."], # edges with more styles than edges (extra unused)
- ),
- )
- def test_directed_edges_linestyle_sequence(style_seq):
- """Tests support for specifying linestyles with sequences in
- ``draw_networkx_edges`` for FancyArrowPatch outputs (e.g. directed edges)."""
- G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
- pos = {n: (n, n) for n in range(len(G))}
- drawn_edges = nx.draw_networkx_edges(G, pos, style=style_seq)
- assert len(drawn_edges) == 3
- for fap, style in zip(drawn_edges, itertools.cycle(style_seq)):
- assert fap.get_linestyle() == style
- def test_labels_and_colors():
- G = nx.cubical_graph()
- pos = nx.spring_layout(G) # positions for all nodes
- # nodes
- nx.draw_networkx_nodes(
- G, pos, nodelist=[0, 1, 2, 3], node_color="r", node_size=500, alpha=0.75
- )
- nx.draw_networkx_nodes(
- G,
- pos,
- nodelist=[4, 5, 6, 7],
- node_color="b",
- node_size=500,
- alpha=[0.25, 0.5, 0.75, 1.0],
- )
- # edges
- nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5)
- nx.draw_networkx_edges(
- G,
- pos,
- edgelist=[(0, 1), (1, 2), (2, 3), (3, 0)],
- width=8,
- alpha=0.5,
- edge_color="r",
- )
- nx.draw_networkx_edges(
- G,
- pos,
- edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)],
- width=8,
- alpha=0.5,
- edge_color="b",
- )
- nx.draw_networkx_edges(
- G,
- pos,
- edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)],
- arrows=True,
- min_source_margin=0.5,
- min_target_margin=0.75,
- width=8,
- edge_color="b",
- )
- # some math labels
- labels = {}
- labels[0] = r"$a$"
- labels[1] = r"$b$"
- labels[2] = r"$c$"
- labels[3] = r"$d$"
- labels[4] = r"$\alpha$"
- labels[5] = r"$\beta$"
- labels[6] = r"$\gamma$"
- labels[7] = r"$\delta$"
- nx.draw_networkx_labels(G, pos, labels, font_size=16)
- nx.draw_networkx_edge_labels(G, pos, edge_labels=None, rotate=False)
- nx.draw_networkx_edge_labels(G, pos, edge_labels={(4, 5): "4-5"})
- # plt.show()
- @pytest.mark.mpl_image_compare
- def test_house_with_colors():
- G = nx.house_graph()
- # explicitly set positions
- fig, ax = plt.subplots()
- pos = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0.5, 2.0)}
- # Plot nodes with different properties for the "wall" and "roof" nodes
- nx.draw_networkx_nodes(
- G,
- pos,
- node_size=3000,
- nodelist=[0, 1, 2, 3],
- node_color="tab:blue",
- )
- nx.draw_networkx_nodes(
- G, pos, node_size=2000, nodelist=[4], node_color="tab:orange"
- )
- nx.draw_networkx_edges(G, pos, alpha=0.5, width=6)
- # Customize axes
- ax.margins(0.11)
- plt.tight_layout()
- plt.axis("off")
- return fig
- def test_axes():
- fig, ax = plt.subplots()
- nx.draw(barbell, ax=ax)
- nx.draw_networkx_edge_labels(barbell, nx.circular_layout(barbell), ax=ax)
- def test_empty_graph():
- G = nx.Graph()
- nx.draw(G)
- def test_draw_empty_nodes_return_values():
- # See Issue #3833
- import matplotlib.collections # call as mpl.collections
- G = nx.Graph([(1, 2), (2, 3)])
- DG = nx.DiGraph([(1, 2), (2, 3)])
- pos = nx.circular_layout(G)
- assert isinstance(
- nx.draw_networkx_nodes(G, pos, nodelist=[]), mpl.collections.PathCollection
- )
- assert isinstance(
- nx.draw_networkx_nodes(DG, pos, nodelist=[]), mpl.collections.PathCollection
- )
- # drawing empty edges used to return an empty LineCollection or empty list.
- # Now it is always an empty list (because edges are now lists of FancyArrows)
- assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=True) == []
- assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=False) == []
- assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=False) == []
- assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=True) == []
- def test_multigraph_edgelist_tuples():
- # See Issue #3295
- G = nx.path_graph(3, create_using=nx.MultiDiGraph)
- nx.draw_networkx(G, edgelist=[(0, 1, 0)])
- nx.draw_networkx(G, edgelist=[(0, 1, 0)], node_size=[10, 20, 0])
- def test_alpha_iter():
- pos = nx.random_layout(barbell)
- fig = plt.figure()
- # with fewer alpha elements than nodes
- fig.add_subplot(131) # Each test in a new axis object
- nx.draw_networkx_nodes(barbell, pos, alpha=[0.1, 0.2])
- # with equal alpha elements and nodes
- num_nodes = len(barbell.nodes)
- alpha = [x / num_nodes for x in range(num_nodes)]
- colors = range(num_nodes)
- fig.add_subplot(132)
- nx.draw_networkx_nodes(barbell, pos, node_color=colors, alpha=alpha)
- # with more alpha elements than nodes
- alpha.append(1)
- fig.add_subplot(133)
- nx.draw_networkx_nodes(barbell, pos, alpha=alpha)
- def test_error_invalid_kwds():
- with pytest.raises(ValueError, match="Received invalid argument"):
- nx.draw(barbell, foo="bar")
- def test_draw_networkx_arrowsize_incorrect_size():
- G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 3)])
- arrowsize = [1, 2, 3]
- with pytest.raises(
- ValueError, match="arrowsize should have the same length as edgelist"
- ):
- nx.draw(G, arrowsize=arrowsize)
- @pytest.mark.parametrize("arrowsize", (30, [10, 20, 30]))
- def test_draw_edges_arrowsize(arrowsize):
- G = nx.DiGraph([(0, 1), (0, 2), (1, 2)])
- pos = {0: (0, 0), 1: (0, 1), 2: (1, 0)}
- edges = nx.draw_networkx_edges(G, pos=pos, arrowsize=arrowsize)
- arrowsize = itertools.repeat(arrowsize) if isinstance(arrowsize, int) else arrowsize
- for fap, expected in zip(edges, arrowsize):
- assert isinstance(fap, mpl.patches.FancyArrowPatch)
- assert fap.get_mutation_scale() == expected
- def test_np_edgelist():
- # see issue #4129
- nx.draw_networkx(barbell, edgelist=np.array([(0, 2), (0, 3)]))
- def test_draw_nodes_missing_node_from_position():
- G = nx.path_graph(3)
- pos = {0: (0, 0), 1: (1, 1)} # No position for node 2
- with pytest.raises(nx.NetworkXError, match="has no position"):
- nx.draw_networkx_nodes(G, pos)
- # NOTE: parametrizing on marker to test both branches of internal
- # nx.draw_networkx_edges.to_marker_edge function
- @pytest.mark.parametrize("node_shape", ("o", "s"))
- def test_draw_edges_min_source_target_margins(node_shape):
- """Test that there is a wider gap between the node and the start of an
- incident edge when min_source_margin is specified.
- This test checks that the use of min_{source/target}_margin kwargs result
- in shorter (more padding) between the edges and source and target nodes.
- As a crude visual example, let 's' and 't' represent source and target
- nodes, respectively:
- Default:
- s-----------------------------t
- With margins:
- s ----------------------- t
- """
- # Create a single axis object to get consistent pixel coords across
- # multiple draws
- fig, ax = plt.subplots()
- G = nx.DiGraph([(0, 1)])
- pos = {0: (0, 0), 1: (1, 0)} # horizontal layout
- # Get leftmost and rightmost points of the FancyArrowPatch object
- # representing the edge between nodes 0 and 1 (in pixel coordinates)
- default_patch = nx.draw_networkx_edges(G, pos, ax=ax, node_shape=node_shape)[0]
- default_extent = default_patch.get_extents().corners()[::2, 0]
- # Now, do the same but with "padding" for the source and target via the
- # min_{source/target}_margin kwargs
- padded_patch = nx.draw_networkx_edges(
- G,
- pos,
- ax=ax,
- node_shape=node_shape,
- min_source_margin=100,
- min_target_margin=100,
- )[0]
- padded_extent = padded_patch.get_extents().corners()[::2, 0]
- # With padding, the left-most extent of the edge should be further to the
- # right
- assert padded_extent[0] > default_extent[0]
- # And the rightmost extent of the edge, further to the left
- assert padded_extent[1] < default_extent[1]
- def test_nonzero_selfloop_with_single_node():
- """Ensure that selfloop extent is non-zero when there is only one node."""
- # Create explicit axis object for test
- fig, ax = plt.subplots()
- # Graph with single node + self loop
- G = nx.DiGraph()
- G.add_node(0)
- G.add_edge(0, 0)
- # Draw
- patch = nx.draw_networkx_edges(G, {0: (0, 0)})[0]
- # The resulting patch must have non-zero extent
- bbox = patch.get_extents()
- assert bbox.width > 0 and bbox.height > 0
- # Cleanup
- plt.delaxes(ax)
- def test_nonzero_selfloop_with_single_edge_in_edgelist():
- """Ensure that selfloop extent is non-zero when only a single edge is
- specified in the edgelist.
- """
- # Create explicit axis object for test
- fig, ax = plt.subplots()
- # Graph with selfloop
- G = nx.path_graph(2, create_using=nx.DiGraph)
- G.add_edge(1, 1)
- pos = {n: (n, n) for n in G.nodes}
- # Draw only the selfloop edge via the `edgelist` kwarg
- patch = nx.draw_networkx_edges(G, pos, edgelist=[(1, 1)])[0]
- # The resulting patch must have non-zero extent
- bbox = patch.get_extents()
- assert bbox.width > 0 and bbox.height > 0
- # Cleanup
- plt.delaxes(ax)
- def test_apply_alpha():
- """Test apply_alpha when there is a mismatch between the number of
- supplied colors and elements.
- """
- nodelist = [0, 1, 2]
- colorlist = ["r", "g", "b"]
- alpha = 0.5
- rgba_colors = nx.drawing.nx_pylab.apply_alpha(colorlist, alpha, nodelist)
- assert all(rgba_colors[:, -1] == alpha)
- def test_draw_edges_toggling_with_arrows_kwarg():
- """
- The `arrows` keyword argument is used as a 3-way switch to select which
- type of object to use for drawing edges:
- - ``arrows=None`` -> default (FancyArrowPatches for directed, else LineCollection)
- - ``arrows=True`` -> FancyArrowPatches
- - ``arrows=False`` -> LineCollection
- """
- import matplotlib.collections
- import matplotlib.patches
- UG = nx.path_graph(3)
- DG = nx.path_graph(3, create_using=nx.DiGraph)
- pos = {n: (n, n) for n in UG}
- # Use FancyArrowPatches when arrows=True, regardless of graph type
- for G in (UG, DG):
- edges = nx.draw_networkx_edges(G, pos, arrows=True)
- assert len(edges) == len(G.edges)
- assert isinstance(edges[0], mpl.patches.FancyArrowPatch)
- # Use LineCollection when arrows=False, regardless of graph type
- for G in (UG, DG):
- edges = nx.draw_networkx_edges(G, pos, arrows=False)
- assert isinstance(edges, mpl.collections.LineCollection)
- # Default behavior when arrows=None: FAPs for directed, LC's for undirected
- edges = nx.draw_networkx_edges(UG, pos)
- assert isinstance(edges, mpl.collections.LineCollection)
- edges = nx.draw_networkx_edges(DG, pos)
- assert len(edges) == len(G.edges)
- assert isinstance(edges[0], mpl.patches.FancyArrowPatch)
- @pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx))
- def test_draw_networkx_arrows_default_undirected(drawing_func):
- import matplotlib.collections
- G = nx.path_graph(3)
- fig, ax = plt.subplots()
- drawing_func(G, ax=ax)
- assert any(isinstance(c, mpl.collections.LineCollection) for c in ax.collections)
- assert not ax.patches
- plt.delaxes(ax)
- @pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx))
- def test_draw_networkx_arrows_default_directed(drawing_func):
- import matplotlib.collections
- G = nx.path_graph(3, create_using=nx.DiGraph)
- fig, ax = plt.subplots()
- drawing_func(G, ax=ax)
- assert not any(
- isinstance(c, mpl.collections.LineCollection) for c in ax.collections
- )
- assert ax.patches
- plt.delaxes(ax)
- def test_edgelist_kwarg_not_ignored():
- # See gh-4994
- G = nx.path_graph(3)
- G.add_edge(0, 0)
- fig, ax = plt.subplots()
- nx.draw(G, edgelist=[(0, 1), (1, 2)], ax=ax) # Exclude self-loop from edgelist
- assert not ax.patches
- plt.delaxes(ax)
- def test_draw_networkx_edge_label_multiedge_exception():
- """
- draw_networkx_edge_labels should raise an informative error message when
- the edge label includes keys
- """
- exception_msg = "draw_networkx_edge_labels does not support multiedges"
- G = nx.MultiGraph()
- G.add_edge(0, 1, weight=10)
- G.add_edge(0, 1, weight=20)
- edge_labels = nx.get_edge_attributes(G, "weight") # Includes edge keys
- pos = {n: (n, n) for n in G}
- with pytest.raises(nx.NetworkXError, match=exception_msg):
- nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
- def test_draw_networkx_edge_label_empty_dict():
- """Regression test for draw_networkx_edge_labels with empty dict. See
- gh-5372."""
- G = nx.path_graph(3)
- pos = {n: (n, n) for n in G.nodes}
- assert nx.draw_networkx_edge_labels(G, pos, edge_labels={}) == {}
- def test_draw_networkx_edges_undirected_selfloop_colors():
- """When an edgelist is supplied along with a sequence of colors, check that
- the self-loops have the correct colors."""
- fig, ax = plt.subplots()
- # Edge list and corresponding colors
- edgelist = [(1, 3), (1, 2), (2, 3), (1, 1), (3, 3), (2, 2)]
- edge_colors = ["pink", "cyan", "black", "red", "blue", "green"]
- G = nx.Graph(edgelist)
- pos = {n: (n, n) for n in G.nodes}
- nx.draw_networkx_edges(G, pos, ax=ax, edgelist=edgelist, edge_color=edge_colors)
- # Verify that there are three fancy arrow patches (1 per self loop)
- assert len(ax.patches) == 3
- # These are points that should be contained in the self loops. For example,
- # sl_points[0] will be (1, 1.1), which is inside the "path" of the first
- # self-loop but outside the others
- sl_points = np.array(edgelist[-3:]) + np.array([0, 0.1])
- # Check that the mapping between self-loop locations and their colors is
- # correct
- for fap, clr, slp in zip(ax.patches, edge_colors[-3:], sl_points):
- assert fap.get_path().contains_point(slp)
- assert mpl.colors.same_color(fap.get_edgecolor(), clr)
- plt.delaxes(ax)
- @pytest.mark.parametrize(
- "fap_only_kwarg", # Non-default values for kwargs that only apply to FAPs
- (
- {"arrowstyle": "-"},
- {"arrowsize": 20},
- {"connectionstyle": "arc3,rad=0.2"},
- {"min_source_margin": 10},
- {"min_target_margin": 10},
- ),
- )
- def test_user_warnings_for_unused_edge_drawing_kwargs(fap_only_kwarg):
- """Users should get a warning when they specify a non-default value for
- one of the kwargs that applies only to edges drawn with FancyArrowPatches,
- but FancyArrowPatches aren't being used under the hood."""
- G = nx.path_graph(3)
- pos = {n: (n, n) for n in G}
- fig, ax = plt.subplots()
- # By default, an undirected graph will use LineCollection to represent
- # the edges
- kwarg_name = list(fap_only_kwarg.keys())[0]
- with pytest.warns(
- UserWarning, match=f"\n\nThe {kwarg_name} keyword argument is not applicable"
- ):
- nx.draw_networkx_edges(G, pos, ax=ax, **fap_only_kwarg)
- # FancyArrowPatches are always used when `arrows=True` is specified.
- # Check that warnings are *not* raised in this case
- with warnings.catch_warnings():
- # Escalate warnings -> errors so tests fail if warnings are raised
- warnings.simplefilter("error")
- nx.draw_networkx_edges(G, pos, ax=ax, arrows=True, **fap_only_kwarg)
- plt.delaxes(ax)
|