Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/drawing/nx_pylab.py: 6%
297 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""
2**********
3Matplotlib
4**********
6Draw networks with matplotlib.
8Examples
9--------
10>>> G = nx.complete_graph(5)
11>>> nx.draw(G)
13See Also
14--------
15 - :doc:`matplotlib <matplotlib:index>`
16 - :func:`matplotlib.pyplot.scatter`
17 - :obj:`matplotlib.patches.FancyArrowPatch`
18"""
19from numbers import Number
21import networkx as nx
22from networkx.drawing.layout import (
23 circular_layout,
24 kamada_kawai_layout,
25 planar_layout,
26 random_layout,
27 shell_layout,
28 spectral_layout,
29 spring_layout,
30)
32__all__ = [
33 "draw",
34 "draw_networkx",
35 "draw_networkx_nodes",
36 "draw_networkx_edges",
37 "draw_networkx_labels",
38 "draw_networkx_edge_labels",
39 "draw_circular",
40 "draw_kamada_kawai",
41 "draw_random",
42 "draw_spectral",
43 "draw_spring",
44 "draw_planar",
45 "draw_shell",
46]
49def draw(G, pos=None, ax=None, **kwds):
50 """Draw the graph G with Matplotlib.
52 Draw the graph as a simple representation with no node
53 labels or edge labels and using the full Matplotlib figure area
54 and no axis labels by default. See draw_networkx() for more
55 full-featured drawing that allows title, axis labels etc.
57 Parameters
58 ----------
59 G : graph
60 A networkx graph
62 pos : dictionary, optional
63 A dictionary with nodes as keys and positions as values.
64 If not specified a spring layout positioning will be computed.
65 See :py:mod:`networkx.drawing.layout` for functions that
66 compute node positions.
68 ax : Matplotlib Axes object, optional
69 Draw the graph in specified Matplotlib axes.
71 kwds : optional keywords
72 See networkx.draw_networkx() for a description of optional keywords.
74 Examples
75 --------
76 >>> G = nx.dodecahedral_graph()
77 >>> nx.draw(G)
78 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout
80 See Also
81 --------
82 draw_networkx
83 draw_networkx_nodes
84 draw_networkx_edges
85 draw_networkx_labels
86 draw_networkx_edge_labels
88 Notes
89 -----
90 This function has the same name as pylab.draw and pyplot.draw
91 so beware when using `from networkx import *`
93 since you might overwrite the pylab.draw function.
95 With pyplot use
97 >>> import matplotlib.pyplot as plt
98 >>> G = nx.dodecahedral_graph()
99 >>> nx.draw(G) # networkx draw()
100 >>> plt.draw() # pyplot draw()
102 Also see the NetworkX drawing examples at
103 https://networkx.org/documentation/latest/auto_examples/index.html
104 """
105 import matplotlib.pyplot as plt
107 if ax is None:
108 cf = plt.gcf()
109 else:
110 cf = ax.get_figure()
111 cf.set_facecolor("w")
112 if ax is None:
113 if cf.axes:
114 ax = cf.gca()
115 else:
116 ax = cf.add_axes((0, 0, 1, 1))
118 if "with_labels" not in kwds:
119 kwds["with_labels"] = "labels" in kwds
121 draw_networkx(G, pos=pos, ax=ax, **kwds)
122 ax.set_axis_off()
123 plt.draw_if_interactive()
124 return
127def draw_networkx(G, pos=None, arrows=None, with_labels=True, **kwds):
128 r"""Draw the graph G using Matplotlib.
130 Draw the graph with Matplotlib with options for node positions,
131 labeling, titles, and many other drawing features.
132 See draw() for simple drawing without labels or axes.
134 Parameters
135 ----------
136 G : graph
137 A networkx graph
139 pos : dictionary, optional
140 A dictionary with nodes as keys and positions as values.
141 If not specified a spring layout positioning will be computed.
142 See :py:mod:`networkx.drawing.layout` for functions that
143 compute node positions.
145 arrows : bool or None, optional (default=None)
146 If `None`, directed graphs draw arrowheads with
147 `~matplotlib.patches.FancyArrowPatch`, while undirected graphs draw edges
148 via `~matplotlib.collections.LineCollection` for speed.
149 If `True`, draw arrowheads with FancyArrowPatches (bendable and stylish).
150 If `False`, draw edges using LineCollection (linear and fast).
151 For directed graphs, if True draw arrowheads.
152 Note: Arrows will be the same color as edges.
154 arrowstyle : str (default='-\|>' for directed graphs)
155 For directed graphs, choose the style of the arrowsheads.
156 For undirected graphs default to '-'
158 See `matplotlib.patches.ArrowStyle` for more options.
160 arrowsize : int or list (default=10)
161 For directed graphs, choose the size of the arrow head's length and
162 width. A list of values can be passed in to assign a different size for arrow head's length and width.
163 See `matplotlib.patches.FancyArrowPatch` for attribute `mutation_scale`
164 for more info.
166 with_labels : bool (default=True)
167 Set to True to draw labels on the nodes.
169 ax : Matplotlib Axes object, optional
170 Draw the graph in the specified Matplotlib axes.
172 nodelist : list (default=list(G))
173 Draw only specified nodes
175 edgelist : list (default=list(G.edges()))
176 Draw only specified edges
178 node_size : scalar or array (default=300)
179 Size of nodes. If an array is specified it must be the
180 same length as nodelist.
182 node_color : color or array of colors (default='#1f78b4')
183 Node color. Can be a single color or a sequence of colors with the same
184 length as nodelist. Color can be string or rgb (or rgba) tuple of
185 floats from 0-1. If numeric values are specified they will be
186 mapped to colors using the cmap and vmin,vmax parameters. See
187 matplotlib.scatter for more details.
189 node_shape : string (default='o')
190 The shape of the node. Specification is as matplotlib.scatter
191 marker, one of 'so^>v<dph8'.
193 alpha : float or None (default=None)
194 The node and edge transparency
196 cmap : Matplotlib colormap, optional
197 Colormap for mapping intensities of nodes
199 vmin,vmax : float, optional
200 Minimum and maximum for node colormap scaling
202 linewidths : scalar or sequence (default=1.0)
203 Line width of symbol border
205 width : float or array of floats (default=1.0)
206 Line width of edges
208 edge_color : color or array of colors (default='k')
209 Edge color. Can be a single color or a sequence of colors with the same
210 length as edgelist. Color can be string or rgb (or rgba) tuple of
211 floats from 0-1. If numeric values are specified they will be
212 mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters.
214 edge_cmap : Matplotlib colormap, optional
215 Colormap for mapping intensities of edges
217 edge_vmin,edge_vmax : floats, optional
218 Minimum and maximum for edge colormap scaling
220 style : string (default=solid line)
221 Edge line style e.g.: '-', '--', '-.', ':'
222 or words like 'solid' or 'dashed'.
223 (See `matplotlib.patches.FancyArrowPatch`: `linestyle`)
225 labels : dictionary (default=None)
226 Node labels in a dictionary of text labels keyed by node
228 font_size : int (default=12 for nodes, 10 for edges)
229 Font size for text labels
231 font_color : color (default='k' black)
232 Font color string. Color can be string or rgb (or rgba) tuple of
233 floats from 0-1.
235 font_weight : string (default='normal')
236 Font weight
238 font_family : string (default='sans-serif')
239 Font family
241 label : string, optional
242 Label for graph legend
244 kwds : optional keywords
245 See networkx.draw_networkx_nodes(), networkx.draw_networkx_edges(), and
246 networkx.draw_networkx_labels() for a description of optional keywords.
248 Notes
249 -----
250 For directed graphs, arrows are drawn at the head end. Arrows can be
251 turned off with keyword arrows=False.
253 Examples
254 --------
255 >>> G = nx.dodecahedral_graph()
256 >>> nx.draw(G)
257 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout
259 >>> import matplotlib.pyplot as plt
260 >>> limits = plt.axis("off") # turn off axis
262 Also see the NetworkX drawing examples at
263 https://networkx.org/documentation/latest/auto_examples/index.html
265 See Also
266 --------
267 draw
268 draw_networkx_nodes
269 draw_networkx_edges
270 draw_networkx_labels
271 draw_networkx_edge_labels
272 """
273 from inspect import signature
275 import matplotlib.pyplot as plt
277 # Get all valid keywords by inspecting the signatures of draw_networkx_nodes,
278 # draw_networkx_edges, draw_networkx_labels
280 valid_node_kwds = signature(draw_networkx_nodes).parameters.keys()
281 valid_edge_kwds = signature(draw_networkx_edges).parameters.keys()
282 valid_label_kwds = signature(draw_networkx_labels).parameters.keys()
284 # Create a set with all valid keywords across the three functions and
285 # remove the arguments of this function (draw_networkx)
286 valid_kwds = (valid_node_kwds | valid_edge_kwds | valid_label_kwds) - {
287 "G",
288 "pos",
289 "arrows",
290 "with_labels",
291 }
293 if any(k not in valid_kwds for k in kwds):
294 invalid_args = ", ".join([k for k in kwds if k not in valid_kwds])
295 raise ValueError(f"Received invalid argument(s): {invalid_args}")
297 node_kwds = {k: v for k, v in kwds.items() if k in valid_node_kwds}
298 edge_kwds = {k: v for k, v in kwds.items() if k in valid_edge_kwds}
299 label_kwds = {k: v for k, v in kwds.items() if k in valid_label_kwds}
301 if pos is None:
302 pos = nx.drawing.spring_layout(G) # default to spring layout
304 draw_networkx_nodes(G, pos, **node_kwds)
305 draw_networkx_edges(G, pos, arrows=arrows, **edge_kwds)
306 if with_labels:
307 draw_networkx_labels(G, pos, **label_kwds)
308 plt.draw_if_interactive()
311def draw_networkx_nodes(
312 G,
313 pos,
314 nodelist=None,
315 node_size=300,
316 node_color="#1f78b4",
317 node_shape="o",
318 alpha=None,
319 cmap=None,
320 vmin=None,
321 vmax=None,
322 ax=None,
323 linewidths=None,
324 edgecolors=None,
325 label=None,
326 margins=None,
327):
328 """Draw the nodes of the graph G.
330 This draws only the nodes of the graph G.
332 Parameters
333 ----------
334 G : graph
335 A networkx graph
337 pos : dictionary
338 A dictionary with nodes as keys and positions as values.
339 Positions should be sequences of length 2.
341 ax : Matplotlib Axes object, optional
342 Draw the graph in the specified Matplotlib axes.
344 nodelist : list (default list(G))
345 Draw only specified nodes
347 node_size : scalar or array (default=300)
348 Size of nodes. If an array it must be the same length as nodelist.
350 node_color : color or array of colors (default='#1f78b4')
351 Node color. Can be a single color or a sequence of colors with the same
352 length as nodelist. Color can be string or rgb (or rgba) tuple of
353 floats from 0-1. If numeric values are specified they will be
354 mapped to colors using the cmap and vmin,vmax parameters. See
355 matplotlib.scatter for more details.
357 node_shape : string (default='o')
358 The shape of the node. Specification is as matplotlib.scatter
359 marker, one of 'so^>v<dph8'.
361 alpha : float or array of floats (default=None)
362 The node transparency. This can be a single alpha value,
363 in which case it will be applied to all the nodes of color. Otherwise,
364 if it is an array, the elements of alpha will be applied to the colors
365 in order (cycling through alpha multiple times if necessary).
367 cmap : Matplotlib colormap (default=None)
368 Colormap for mapping intensities of nodes
370 vmin,vmax : floats or None (default=None)
371 Minimum and maximum for node colormap scaling
373 linewidths : [None | scalar | sequence] (default=1.0)
374 Line width of symbol border
376 edgecolors : [None | scalar | sequence] (default = node_color)
377 Colors of node borders. Can be a single color or a sequence of colors with the
378 same length as nodelist. Color can be string or rgb (or rgba) tuple of floats
379 from 0-1. If numeric values are specified they will be mapped to colors
380 using the cmap and vmin,vmax parameters. See `~matplotlib.pyplot.scatter` for more details.
382 label : [None | string]
383 Label for legend
385 margins : float or 2-tuple, optional
386 Sets the padding for axis autoscaling. Increase margin to prevent
387 clipping for nodes that are near the edges of an image. Values should
388 be in the range ``[0, 1]``. See :meth:`matplotlib.axes.Axes.margins`
389 for details. The default is `None`, which uses the Matplotlib default.
391 Returns
392 -------
393 matplotlib.collections.PathCollection
394 `PathCollection` of the nodes.
396 Examples
397 --------
398 >>> G = nx.dodecahedral_graph()
399 >>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G))
401 Also see the NetworkX drawing examples at
402 https://networkx.org/documentation/latest/auto_examples/index.html
404 See Also
405 --------
406 draw
407 draw_networkx
408 draw_networkx_edges
409 draw_networkx_labels
410 draw_networkx_edge_labels
411 """
412 from collections.abc import Iterable
414 import matplotlib as mpl
415 import matplotlib.collections # call as mpl.collections
416 import matplotlib.pyplot as plt
417 import numpy as np
419 if ax is None:
420 ax = plt.gca()
422 if nodelist is None:
423 nodelist = list(G)
425 if len(nodelist) == 0: # empty nodelist, no drawing
426 return mpl.collections.PathCollection(None)
428 try:
429 xy = np.asarray([pos[v] for v in nodelist])
430 except KeyError as err:
431 raise nx.NetworkXError(f"Node {err} has no position.") from err
433 if isinstance(alpha, Iterable):
434 node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax)
435 alpha = None
437 node_collection = ax.scatter(
438 xy[:, 0],
439 xy[:, 1],
440 s=node_size,
441 c=node_color,
442 marker=node_shape,
443 cmap=cmap,
444 vmin=vmin,
445 vmax=vmax,
446 alpha=alpha,
447 linewidths=linewidths,
448 edgecolors=edgecolors,
449 label=label,
450 )
451 ax.tick_params(
452 axis="both",
453 which="both",
454 bottom=False,
455 left=False,
456 labelbottom=False,
457 labelleft=False,
458 )
460 if margins is not None:
461 if isinstance(margins, Iterable):
462 ax.margins(*margins)
463 else:
464 ax.margins(margins)
466 node_collection.set_zorder(2)
467 return node_collection
470def draw_networkx_edges(
471 G,
472 pos,
473 edgelist=None,
474 width=1.0,
475 edge_color="k",
476 style="solid",
477 alpha=None,
478 arrowstyle=None,
479 arrowsize=10,
480 edge_cmap=None,
481 edge_vmin=None,
482 edge_vmax=None,
483 ax=None,
484 arrows=None,
485 label=None,
486 node_size=300,
487 nodelist=None,
488 node_shape="o",
489 connectionstyle="arc3",
490 min_source_margin=0,
491 min_target_margin=0,
492):
493 r"""Draw the edges of the graph G.
495 This draws only the edges of the graph G.
497 Parameters
498 ----------
499 G : graph
500 A networkx graph
502 pos : dictionary
503 A dictionary with nodes as keys and positions as values.
504 Positions should be sequences of length 2.
506 edgelist : collection of edge tuples (default=G.edges())
507 Draw only specified edges
509 width : float or array of floats (default=1.0)
510 Line width of edges
512 edge_color : color or array of colors (default='k')
513 Edge color. Can be a single color or a sequence of colors with the same
514 length as edgelist. Color can be string or rgb (or rgba) tuple of
515 floats from 0-1. If numeric values are specified they will be
516 mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters.
518 style : string or array of strings (default='solid')
519 Edge line style e.g.: '-', '--', '-.', ':'
520 or words like 'solid' or 'dashed'.
521 Can be a single style or a sequence of styles with the same
522 length as the edge list.
523 If less styles than edges are given the styles will cycle.
524 If more styles than edges are given the styles will be used sequentially
525 and not be exhausted.
526 Also, `(offset, onoffseq)` tuples can be used as style instead of a strings.
527 (See `matplotlib.patches.FancyArrowPatch`: `linestyle`)
529 alpha : float or array of floats (default=None)
530 The edge transparency. This can be a single alpha value,
531 in which case it will be applied to all specified edges. Otherwise,
532 if it is an array, the elements of alpha will be applied to the colors
533 in order (cycling through alpha multiple times if necessary).
535 edge_cmap : Matplotlib colormap, optional
536 Colormap for mapping intensities of edges
538 edge_vmin,edge_vmax : floats, optional
539 Minimum and maximum for edge colormap scaling
541 ax : Matplotlib Axes object, optional
542 Draw the graph in the specified Matplotlib axes.
544 arrows : bool or None, optional (default=None)
545 If `None`, directed graphs draw arrowheads with
546 `~matplotlib.patches.FancyArrowPatch`, while undirected graphs draw edges
547 via `~matplotlib.collections.LineCollection` for speed.
548 If `True`, draw arrowheads with FancyArrowPatches (bendable and stylish).
549 If `False`, draw edges using LineCollection (linear and fast).
551 Note: Arrowheads will be the same color as edges.
553 arrowstyle : str (default='-\|>' for directed graphs)
554 For directed graphs and `arrows==True` defaults to '-\|>',
555 For undirected graphs default to '-'.
557 See `matplotlib.patches.ArrowStyle` for more options.
559 arrowsize : int (default=10)
560 For directed graphs, choose the size of the arrow head's length and
561 width. See `matplotlib.patches.FancyArrowPatch` for attribute
562 `mutation_scale` for more info.
564 connectionstyle : string (default="arc3")
565 Pass the connectionstyle parameter to create curved arc of rounding
566 radius rad. For example, connectionstyle='arc3,rad=0.2'.
567 See `matplotlib.patches.ConnectionStyle` and
568 `matplotlib.patches.FancyArrowPatch` for more info.
570 node_size : scalar or array (default=300)
571 Size of nodes. Though the nodes are not drawn with this function, the
572 node size is used in determining edge positioning.
574 nodelist : list, optional (default=G.nodes())
575 This provides the node order for the `node_size` array (if it is an array).
577 node_shape : string (default='o')
578 The marker used for nodes, used in determining edge positioning.
579 Specification is as a `matplotlib.markers` marker, e.g. one of 'so^>v<dph8'.
581 label : None or string
582 Label for legend
584 min_source_margin : int (default=0)
585 The minimum margin (gap) at the beginning of the edge at the source.
587 min_target_margin : int (default=0)
588 The minimum margin (gap) at the end of the edge at the target.
590 Returns
591 -------
592 matplotlib.collections.LineCollection or a list of matplotlib.patches.FancyArrowPatch
593 If ``arrows=True``, a list of FancyArrowPatches is returned.
594 If ``arrows=False``, a LineCollection is returned.
595 If ``arrows=None`` (the default), then a LineCollection is returned if
596 `G` is undirected, otherwise returns a list of FancyArrowPatches.
598 Notes
599 -----
600 For directed graphs, arrows are drawn at the head end. Arrows can be
601 turned off with keyword arrows=False or by passing an arrowstyle without
602 an arrow on the end.
604 Be sure to include `node_size` as a keyword argument; arrows are
605 drawn considering the size of nodes.
607 Self-loops are always drawn with `~matplotlib.patches.FancyArrowPatch`
608 regardless of the value of `arrows` or whether `G` is directed.
609 When ``arrows=False`` or ``arrows=None`` and `G` is undirected, the
610 FancyArrowPatches corresponding to the self-loops are not explicitly
611 returned. They should instead be accessed via the ``Axes.patches``
612 attribute (see examples).
614 Examples
615 --------
616 >>> G = nx.dodecahedral_graph()
617 >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
619 >>> G = nx.DiGraph()
620 >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
621 >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
622 >>> alphas = [0.3, 0.4, 0.5]
623 >>> for i, arc in enumerate(arcs): # change alpha values of arcs
624 ... arc.set_alpha(alphas[i])
626 The FancyArrowPatches corresponding to self-loops are not always
627 returned, but can always be accessed via the ``patches`` attribute of the
628 `matplotlib.Axes` object.
630 >>> import matplotlib.pyplot as plt
631 >>> fig, ax = plt.subplots()
632 >>> G = nx.Graph([(0, 1), (0, 0)]) # Self-loop at node 0
633 >>> edge_collection = nx.draw_networkx_edges(G, pos=nx.circular_layout(G), ax=ax)
634 >>> self_loop_fap = ax.patches[0]
636 Also see the NetworkX drawing examples at
637 https://networkx.org/documentation/latest/auto_examples/index.html
639 See Also
640 --------
641 draw
642 draw_networkx
643 draw_networkx_nodes
644 draw_networkx_labels
645 draw_networkx_edge_labels
647 """
648 import matplotlib as mpl
649 import matplotlib.collections # call as mpl.collections
650 import matplotlib.colors # call as mpl.colors
651 import matplotlib.patches # call as mpl.patches
652 import matplotlib.path # call as mpl.path
653 import matplotlib.pyplot as plt
654 import numpy as np
656 # The default behavior is to use LineCollection to draw edges for
657 # undirected graphs (for performance reasons) and use FancyArrowPatches
658 # for directed graphs.
659 # The `arrows` keyword can be used to override the default behavior
660 use_linecollection = not G.is_directed()
661 if arrows in (True, False):
662 use_linecollection = not arrows
664 # Some kwargs only apply to FancyArrowPatches. Warn users when they use
665 # non-default values for these kwargs when LineCollection is being used
666 # instead of silently ignoring the specified option
667 if use_linecollection and any(
668 [
669 arrowstyle is not None,
670 arrowsize != 10,
671 connectionstyle != "arc3",
672 min_source_margin != 0,
673 min_target_margin != 0,
674 ]
675 ):
676 import warnings
678 msg = (
679 "\n\nThe {0} keyword argument is not applicable when drawing edges\n"
680 "with LineCollection.\n\n"
681 "To make this warning go away, either specify `arrows=True` to\n"
682 "force FancyArrowPatches or use the default value for {0}.\n"
683 "Note that using FancyArrowPatches may be slow for large graphs.\n"
684 )
685 if arrowstyle is not None:
686 msg = msg.format("arrowstyle")
687 if arrowsize != 10:
688 msg = msg.format("arrowsize")
689 if connectionstyle != "arc3":
690 msg = msg.format("connectionstyle")
691 if min_source_margin != 0:
692 msg = msg.format("min_source_margin")
693 if min_target_margin != 0:
694 msg = msg.format("min_target_margin")
695 warnings.warn(msg, category=UserWarning, stacklevel=2)
697 if arrowstyle == None:
698 if G.is_directed():
699 arrowstyle = "-|>"
700 else:
701 arrowstyle = "-"
703 if ax is None:
704 ax = plt.gca()
706 if edgelist is None:
707 edgelist = list(G.edges())
709 if len(edgelist) == 0: # no edges!
710 return []
712 if nodelist is None:
713 nodelist = list(G.nodes())
715 # FancyArrowPatch handles color=None different from LineCollection
716 if edge_color is None:
717 edge_color = "k"
718 edgelist_tuple = list(map(tuple, edgelist))
720 # set edge positions
721 edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
723 # Check if edge_color is an array of floats and map to edge_cmap.
724 # This is the only case handled differently from matplotlib
725 if (
726 np.iterable(edge_color)
727 and (len(edge_color) == len(edge_pos))
728 and np.all([isinstance(c, Number) for c in edge_color])
729 ):
730 if edge_cmap is not None:
731 assert isinstance(edge_cmap, mpl.colors.Colormap)
732 else:
733 edge_cmap = plt.get_cmap()
734 if edge_vmin is None:
735 edge_vmin = min(edge_color)
736 if edge_vmax is None:
737 edge_vmax = max(edge_color)
738 color_normal = mpl.colors.Normalize(vmin=edge_vmin, vmax=edge_vmax)
739 edge_color = [edge_cmap(color_normal(e)) for e in edge_color]
741 def _draw_networkx_edges_line_collection():
742 edge_collection = mpl.collections.LineCollection(
743 edge_pos,
744 colors=edge_color,
745 linewidths=width,
746 antialiaseds=(1,),
747 linestyle=style,
748 alpha=alpha,
749 )
750 edge_collection.set_cmap(edge_cmap)
751 edge_collection.set_clim(edge_vmin, edge_vmax)
752 edge_collection.set_zorder(1) # edges go behind nodes
753 edge_collection.set_label(label)
754 ax.add_collection(edge_collection)
756 return edge_collection
758 def _draw_networkx_edges_fancy_arrow_patch():
759 # Note: Waiting for someone to implement arrow to intersection with
760 # marker. Meanwhile, this works well for polygons with more than 4
761 # sides and circle.
763 def to_marker_edge(marker_size, marker):
764 if marker in "s^>v<d": # `large` markers need extra space
765 return np.sqrt(2 * marker_size) / 2
766 else:
767 return np.sqrt(marker_size) / 2
769 # Draw arrows with `matplotlib.patches.FancyarrowPatch`
770 arrow_collection = []
772 if isinstance(arrowsize, list):
773 if len(arrowsize) != len(edge_pos):
774 raise ValueError("arrowsize should have the same length as edgelist")
775 else:
776 mutation_scale = arrowsize # scale factor of arrow head
778 base_connection_style = mpl.patches.ConnectionStyle(connectionstyle)
780 # Fallback for self-loop scale. Left outside of _connectionstyle so it is
781 # only computed once
782 max_nodesize = np.array(node_size).max()
784 def _connectionstyle(posA, posB, *args, **kwargs):
785 # check if we need to do a self-loop
786 if np.all(posA == posB):
787 # Self-loops are scaled by view extent, except in cases the extent
788 # is 0, e.g. for a single node. In this case, fall back to scaling
789 # by the maximum node size
790 selfloop_ht = 0.005 * max_nodesize if h == 0 else h
791 # this is called with _screen space_ values so convert back
792 # to data space
793 data_loc = ax.transData.inverted().transform(posA)
794 v_shift = 0.1 * selfloop_ht
795 h_shift = v_shift * 0.5
796 # put the top of the loop first so arrow is not hidden by node
797 path = [
798 # 1
799 data_loc + np.asarray([0, v_shift]),
800 # 4 4 4
801 data_loc + np.asarray([h_shift, v_shift]),
802 data_loc + np.asarray([h_shift, 0]),
803 data_loc,
804 # 4 4 4
805 data_loc + np.asarray([-h_shift, 0]),
806 data_loc + np.asarray([-h_shift, v_shift]),
807 data_loc + np.asarray([0, v_shift]),
808 ]
810 ret = mpl.path.Path(ax.transData.transform(path), [1, 4, 4, 4, 4, 4, 4])
811 # if not, fall back to the user specified behavior
812 else:
813 ret = base_connection_style(posA, posB, *args, **kwargs)
815 return ret
817 # FancyArrowPatch doesn't handle color strings
818 arrow_colors = mpl.colors.colorConverter.to_rgba_array(edge_color, alpha)
819 for i, (src, dst) in zip(fancy_edges_indices, edge_pos):
820 x1, y1 = src
821 x2, y2 = dst
822 shrink_source = 0 # space from source to tail
823 shrink_target = 0 # space from head to target
825 if isinstance(arrowsize, list):
826 # Scale each factor of each arrow based on arrowsize list
827 mutation_scale = arrowsize[i]
829 if np.iterable(node_size): # many node sizes
830 source, target = edgelist[i][:2]
831 source_node_size = node_size[nodelist.index(source)]
832 target_node_size = node_size[nodelist.index(target)]
833 shrink_source = to_marker_edge(source_node_size, node_shape)
834 shrink_target = to_marker_edge(target_node_size, node_shape)
835 else:
836 shrink_source = shrink_target = to_marker_edge(node_size, node_shape)
838 if shrink_source < min_source_margin:
839 shrink_source = min_source_margin
841 if shrink_target < min_target_margin:
842 shrink_target = min_target_margin
844 if len(arrow_colors) > i:
845 arrow_color = arrow_colors[i]
846 elif len(arrow_colors) == 1:
847 arrow_color = arrow_colors[0]
848 else: # Cycle through colors
849 arrow_color = arrow_colors[i % len(arrow_colors)]
851 if np.iterable(width):
852 if len(width) > i:
853 line_width = width[i]
854 else:
855 line_width = width[i % len(width)]
856 else:
857 line_width = width
859 if (
860 np.iterable(style)
861 and not isinstance(style, str)
862 and not isinstance(style, tuple)
863 ):
864 if len(style) > i:
865 linestyle = style[i]
866 else: # Cycle through styles
867 linestyle = style[i % len(style)]
868 else:
869 linestyle = style
871 arrow = mpl.patches.FancyArrowPatch(
872 (x1, y1),
873 (x2, y2),
874 arrowstyle=arrowstyle,
875 shrinkA=shrink_source,
876 shrinkB=shrink_target,
877 mutation_scale=mutation_scale,
878 color=arrow_color,
879 linewidth=line_width,
880 connectionstyle=_connectionstyle,
881 linestyle=linestyle,
882 zorder=1,
883 ) # arrows go behind nodes
885 arrow_collection.append(arrow)
886 ax.add_patch(arrow)
888 return arrow_collection
890 # compute initial view
891 minx = np.amin(np.ravel(edge_pos[:, :, 0]))
892 maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
893 miny = np.amin(np.ravel(edge_pos[:, :, 1]))
894 maxy = np.amax(np.ravel(edge_pos[:, :, 1]))
895 w = maxx - minx
896 h = maxy - miny
898 # Draw the edges
899 if use_linecollection:
900 edge_viz_obj = _draw_networkx_edges_line_collection()
901 # Make sure selfloop edges are also drawn
902 selfloops_to_draw = [loop for loop in nx.selfloop_edges(G) if loop in edgelist]
903 if selfloops_to_draw:
904 fancy_edges_indices = [
905 edgelist_tuple.index(loop) for loop in selfloops_to_draw
906 ]
907 edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in selfloops_to_draw])
908 arrowstyle = "-"
909 _draw_networkx_edges_fancy_arrow_patch()
910 else:
911 fancy_edges_indices = range(len(edgelist))
912 edge_viz_obj = _draw_networkx_edges_fancy_arrow_patch()
914 # update view after drawing
915 padx, pady = 0.05 * w, 0.05 * h
916 corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
917 ax.update_datalim(corners)
918 ax.autoscale_view()
920 ax.tick_params(
921 axis="both",
922 which="both",
923 bottom=False,
924 left=False,
925 labelbottom=False,
926 labelleft=False,
927 )
929 return edge_viz_obj
932def draw_networkx_labels(
933 G,
934 pos,
935 labels=None,
936 font_size=12,
937 font_color="k",
938 font_family="sans-serif",
939 font_weight="normal",
940 alpha=None,
941 bbox=None,
942 horizontalalignment="center",
943 verticalalignment="center",
944 ax=None,
945 clip_on=True,
946):
947 """Draw node labels on the graph G.
949 Parameters
950 ----------
951 G : graph
952 A networkx graph
954 pos : dictionary
955 A dictionary with nodes as keys and positions as values.
956 Positions should be sequences of length 2.
958 labels : dictionary (default={n: n for n in G})
959 Node labels in a dictionary of text labels keyed by node.
960 Node-keys in labels should appear as keys in `pos`.
961 If needed use: `{n:lab for n,lab in labels.items() if n in pos}`
963 font_size : int (default=12)
964 Font size for text labels
966 font_color : color (default='k' black)
967 Font color string. Color can be string or rgb (or rgba) tuple of
968 floats from 0-1.
970 font_weight : string (default='normal')
971 Font weight
973 font_family : string (default='sans-serif')
974 Font family
976 alpha : float or None (default=None)
977 The text transparency
979 bbox : Matplotlib bbox, (default is Matplotlib's ax.text default)
980 Specify text box properties (e.g. shape, color etc.) for node labels.
982 horizontalalignment : string (default='center')
983 Horizontal alignment {'center', 'right', 'left'}
985 verticalalignment : string (default='center')
986 Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
988 ax : Matplotlib Axes object, optional
989 Draw the graph in the specified Matplotlib axes.
991 clip_on : bool (default=True)
992 Turn on clipping of node labels at axis boundaries
994 Returns
995 -------
996 dict
997 `dict` of labels keyed on the nodes
999 Examples
1000 --------
1001 >>> G = nx.dodecahedral_graph()
1002 >>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G))
1004 Also see the NetworkX drawing examples at
1005 https://networkx.org/documentation/latest/auto_examples/index.html
1007 See Also
1008 --------
1009 draw
1010 draw_networkx
1011 draw_networkx_nodes
1012 draw_networkx_edges
1013 draw_networkx_edge_labels
1014 """
1015 import matplotlib.pyplot as plt
1017 if ax is None:
1018 ax = plt.gca()
1020 if labels is None:
1021 labels = {n: n for n in G.nodes()}
1023 text_items = {} # there is no text collection so we'll fake one
1024 for n, label in labels.items():
1025 (x, y) = pos[n]
1026 if not isinstance(label, str):
1027 label = str(label) # this makes "1" and 1 labeled the same
1028 t = ax.text(
1029 x,
1030 y,
1031 label,
1032 size=font_size,
1033 color=font_color,
1034 family=font_family,
1035 weight=font_weight,
1036 alpha=alpha,
1037 horizontalalignment=horizontalalignment,
1038 verticalalignment=verticalalignment,
1039 transform=ax.transData,
1040 bbox=bbox,
1041 clip_on=clip_on,
1042 )
1043 text_items[n] = t
1045 ax.tick_params(
1046 axis="both",
1047 which="both",
1048 bottom=False,
1049 left=False,
1050 labelbottom=False,
1051 labelleft=False,
1052 )
1054 return text_items
1057def draw_networkx_edge_labels(
1058 G,
1059 pos,
1060 edge_labels=None,
1061 label_pos=0.5,
1062 font_size=10,
1063 font_color="k",
1064 font_family="sans-serif",
1065 font_weight="normal",
1066 alpha=None,
1067 bbox=None,
1068 horizontalalignment="center",
1069 verticalalignment="center",
1070 ax=None,
1071 rotate=True,
1072 clip_on=True,
1073):
1074 """Draw edge labels.
1076 Parameters
1077 ----------
1078 G : graph
1079 A networkx graph
1081 pos : dictionary
1082 A dictionary with nodes as keys and positions as values.
1083 Positions should be sequences of length 2.
1085 edge_labels : dictionary (default=None)
1086 Edge labels in a dictionary of labels keyed by edge two-tuple.
1087 Only labels for the keys in the dictionary are drawn.
1089 label_pos : float (default=0.5)
1090 Position of edge label along edge (0=head, 0.5=center, 1=tail)
1092 font_size : int (default=10)
1093 Font size for text labels
1095 font_color : color (default='k' black)
1096 Font color string. Color can be string or rgb (or rgba) tuple of
1097 floats from 0-1.
1099 font_weight : string (default='normal')
1100 Font weight
1102 font_family : string (default='sans-serif')
1103 Font family
1105 alpha : float or None (default=None)
1106 The text transparency
1108 bbox : Matplotlib bbox, optional
1109 Specify text box properties (e.g. shape, color etc.) for edge labels.
1110 Default is {boxstyle='round', ec=(1.0, 1.0, 1.0), fc=(1.0, 1.0, 1.0)}.
1112 horizontalalignment : string (default='center')
1113 Horizontal alignment {'center', 'right', 'left'}
1115 verticalalignment : string (default='center')
1116 Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
1118 ax : Matplotlib Axes object, optional
1119 Draw the graph in the specified Matplotlib axes.
1121 rotate : bool (default=True)
1122 Rotate edge labels to lie parallel to edges
1124 clip_on : bool (default=True)
1125 Turn on clipping of edge labels at axis boundaries
1127 Returns
1128 -------
1129 dict
1130 `dict` of labels keyed by edge
1132 Examples
1133 --------
1134 >>> G = nx.dodecahedral_graph()
1135 >>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G))
1137 Also see the NetworkX drawing examples at
1138 https://networkx.org/documentation/latest/auto_examples/index.html
1140 See Also
1141 --------
1142 draw
1143 draw_networkx
1144 draw_networkx_nodes
1145 draw_networkx_edges
1146 draw_networkx_labels
1147 """
1148 import matplotlib.pyplot as plt
1149 import numpy as np
1151 if ax is None:
1152 ax = plt.gca()
1153 if edge_labels is None:
1154 labels = {(u, v): d for u, v, d in G.edges(data=True)}
1155 else:
1156 labels = edge_labels
1157 # Informative exception for multiedges
1158 try:
1159 (u, v) = next(iter(labels)) # ensures no edge key provided
1160 except ValueError as err:
1161 raise nx.NetworkXError(
1162 "draw_networkx_edge_labels does not support multiedges."
1163 ) from err
1164 except StopIteration:
1165 pass
1167 text_items = {}
1168 for (n1, n2), label in labels.items():
1169 (x1, y1) = pos[n1]
1170 (x2, y2) = pos[n2]
1171 (x, y) = (
1172 x1 * label_pos + x2 * (1.0 - label_pos),
1173 y1 * label_pos + y2 * (1.0 - label_pos),
1174 )
1176 if rotate:
1177 # in degrees
1178 angle = np.arctan2(y2 - y1, x2 - x1) / (2.0 * np.pi) * 360
1179 # make label orientation "right-side-up"
1180 if angle > 90:
1181 angle -= 180
1182 if angle < -90:
1183 angle += 180
1184 # transform data coordinate angle to screen coordinate angle
1185 xy = np.array((x, y))
1186 trans_angle = ax.transData.transform_angles(
1187 np.array((angle,)), xy.reshape((1, 2))
1188 )[0]
1189 else:
1190 trans_angle = 0.0
1191 # use default box of white with white border
1192 if bbox is None:
1193 bbox = {"boxstyle": "round", "ec": (1.0, 1.0, 1.0), "fc": (1.0, 1.0, 1.0)}
1194 if not isinstance(label, str):
1195 label = str(label) # this makes "1" and 1 labeled the same
1197 t = ax.text(
1198 x,
1199 y,
1200 label,
1201 size=font_size,
1202 color=font_color,
1203 family=font_family,
1204 weight=font_weight,
1205 alpha=alpha,
1206 horizontalalignment=horizontalalignment,
1207 verticalalignment=verticalalignment,
1208 rotation=trans_angle,
1209 transform=ax.transData,
1210 bbox=bbox,
1211 zorder=1,
1212 clip_on=clip_on,
1213 )
1214 text_items[(n1, n2)] = t
1216 ax.tick_params(
1217 axis="both",
1218 which="both",
1219 bottom=False,
1220 left=False,
1221 labelbottom=False,
1222 labelleft=False,
1223 )
1225 return text_items
1228def draw_circular(G, **kwargs):
1229 """Draw the graph `G` with a circular layout.
1231 This is a convenience function equivalent to::
1233 nx.draw(G, pos=nx.circular_layout(G), **kwargs)
1235 Parameters
1236 ----------
1237 G : graph
1238 A networkx graph
1240 kwargs : optional keywords
1241 See `draw_networkx` for a description of optional keywords.
1243 Notes
1244 -----
1245 The layout is computed each time this function is called. For
1246 repeated drawing it is much more efficient to call
1247 `~networkx.drawing.layout.circular_layout` directly and reuse the result::
1249 >>> G = nx.complete_graph(5)
1250 >>> pos = nx.circular_layout(G)
1251 >>> nx.draw(G, pos=pos) # Draw the original graph
1252 >>> # Draw a subgraph, reusing the same node positions
1253 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1255 Examples
1256 --------
1257 >>> G = nx.path_graph(5)
1258 >>> nx.draw_circular(G)
1260 See Also
1261 --------
1262 :func:`~networkx.drawing.layout.circular_layout`
1263 """
1264 draw(G, circular_layout(G), **kwargs)
1267def draw_kamada_kawai(G, **kwargs):
1268 """Draw the graph `G` with a Kamada-Kawai force-directed layout.
1270 This is a convenience function equivalent to::
1272 nx.draw(G, pos=nx.kamada_kawai_layout(G), **kwargs)
1274 Parameters
1275 ----------
1276 G : graph
1277 A networkx graph
1279 kwargs : optional keywords
1280 See `draw_networkx` for a description of optional keywords.
1282 Notes
1283 -----
1284 The layout is computed each time this function is called.
1285 For repeated drawing it is much more efficient to call
1286 `~networkx.drawing.layout.kamada_kawai_layout` directly and reuse the
1287 result::
1289 >>> G = nx.complete_graph(5)
1290 >>> pos = nx.kamada_kawai_layout(G)
1291 >>> nx.draw(G, pos=pos) # Draw the original graph
1292 >>> # Draw a subgraph, reusing the same node positions
1293 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1295 Examples
1296 --------
1297 >>> G = nx.path_graph(5)
1298 >>> nx.draw_kamada_kawai(G)
1300 See Also
1301 --------
1302 :func:`~networkx.drawing.layout.kamada_kawai_layout`
1303 """
1304 draw(G, kamada_kawai_layout(G), **kwargs)
1307def draw_random(G, **kwargs):
1308 """Draw the graph `G` with a random layout.
1310 This is a convenience function equivalent to::
1312 nx.draw(G, pos=nx.random_layout(G), **kwargs)
1314 Parameters
1315 ----------
1316 G : graph
1317 A networkx graph
1319 kwargs : optional keywords
1320 See `draw_networkx` for a description of optional keywords.
1322 Notes
1323 -----
1324 The layout is computed each time this function is called.
1325 For repeated drawing it is much more efficient to call
1326 `~networkx.drawing.layout.random_layout` directly and reuse the result::
1328 >>> G = nx.complete_graph(5)
1329 >>> pos = nx.random_layout(G)
1330 >>> nx.draw(G, pos=pos) # Draw the original graph
1331 >>> # Draw a subgraph, reusing the same node positions
1332 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1334 Examples
1335 --------
1336 >>> G = nx.lollipop_graph(4, 3)
1337 >>> nx.draw_random(G)
1339 See Also
1340 --------
1341 :func:`~networkx.drawing.layout.random_layout`
1342 """
1343 draw(G, random_layout(G), **kwargs)
1346def draw_spectral(G, **kwargs):
1347 """Draw the graph `G` with a spectral 2D layout.
1349 This is a convenience function equivalent to::
1351 nx.draw(G, pos=nx.spectral_layout(G), **kwargs)
1353 For more information about how node positions are determined, see
1354 `~networkx.drawing.layout.spectral_layout`.
1356 Parameters
1357 ----------
1358 G : graph
1359 A networkx graph
1361 kwargs : optional keywords
1362 See `draw_networkx` for a description of optional keywords.
1364 Notes
1365 -----
1366 The layout is computed each time this function is called.
1367 For repeated drawing it is much more efficient to call
1368 `~networkx.drawing.layout.spectral_layout` directly and reuse the result::
1370 >>> G = nx.complete_graph(5)
1371 >>> pos = nx.spectral_layout(G)
1372 >>> nx.draw(G, pos=pos) # Draw the original graph
1373 >>> # Draw a subgraph, reusing the same node positions
1374 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1376 Examples
1377 --------
1378 >>> G = nx.path_graph(5)
1379 >>> nx.draw_spectral(G)
1381 See Also
1382 --------
1383 :func:`~networkx.drawing.layout.spectral_layout`
1384 """
1385 draw(G, spectral_layout(G), **kwargs)
1388def draw_spring(G, **kwargs):
1389 """Draw the graph `G` with a spring layout.
1391 This is a convenience function equivalent to::
1393 nx.draw(G, pos=nx.spring_layout(G), **kwargs)
1395 Parameters
1396 ----------
1397 G : graph
1398 A networkx graph
1400 kwargs : optional keywords
1401 See `draw_networkx` for a description of optional keywords.
1403 Notes
1404 -----
1405 `~networkx.drawing.layout.spring_layout` is also the default layout for
1406 `draw`, so this function is equivalent to `draw`.
1408 The layout is computed each time this function is called.
1409 For repeated drawing it is much more efficient to call
1410 `~networkx.drawing.layout.spring_layout` directly and reuse the result::
1412 >>> G = nx.complete_graph(5)
1413 >>> pos = nx.spring_layout(G)
1414 >>> nx.draw(G, pos=pos) # Draw the original graph
1415 >>> # Draw a subgraph, reusing the same node positions
1416 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1418 Examples
1419 --------
1420 >>> G = nx.path_graph(20)
1421 >>> nx.draw_spring(G)
1423 See Also
1424 --------
1425 draw
1426 :func:`~networkx.drawing.layout.spring_layout`
1427 """
1428 draw(G, spring_layout(G), **kwargs)
1431def draw_shell(G, nlist=None, **kwargs):
1432 """Draw networkx graph `G` with shell layout.
1434 This is a convenience function equivalent to::
1436 nx.draw(G, pos=nx.shell_layout(G, nlist=nlist), **kwargs)
1438 Parameters
1439 ----------
1440 G : graph
1441 A networkx graph
1443 nlist : list of list of nodes, optional
1444 A list containing lists of nodes representing the shells.
1445 Default is `None`, meaning all nodes are in a single shell.
1446 See `~networkx.drawing.layout.shell_layout` for details.
1448 kwargs : optional keywords
1449 See `draw_networkx` for a description of optional keywords.
1451 Notes
1452 -----
1453 The layout is computed each time this function is called.
1454 For repeated drawing it is much more efficient to call
1455 `~networkx.drawing.layout.shell_layout` directly and reuse the result::
1457 >>> G = nx.complete_graph(5)
1458 >>> pos = nx.shell_layout(G)
1459 >>> nx.draw(G, pos=pos) # Draw the original graph
1460 >>> # Draw a subgraph, reusing the same node positions
1461 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1463 Examples
1464 --------
1465 >>> G = nx.path_graph(4)
1466 >>> shells = [[0], [1, 2, 3]]
1467 >>> nx.draw_shell(G, nlist=shells)
1469 See Also
1470 --------
1471 :func:`~networkx.drawing.layout.shell_layout`
1472 """
1473 draw(G, shell_layout(G, nlist=nlist), **kwargs)
1476def draw_planar(G, **kwargs):
1477 """Draw a planar networkx graph `G` with planar layout.
1479 This is a convenience function equivalent to::
1481 nx.draw(G, pos=nx.planar_layout(G), **kwargs)
1483 Parameters
1484 ----------
1485 G : graph
1486 A planar networkx graph
1488 kwargs : optional keywords
1489 See `draw_networkx` for a description of optional keywords.
1491 Raises
1492 ------
1493 NetworkXException
1494 When `G` is not planar
1496 Notes
1497 -----
1498 The layout is computed each time this function is called.
1499 For repeated drawing it is much more efficient to call
1500 `~networkx.drawing.layout.planar_layout` directly and reuse the result::
1502 >>> G = nx.path_graph(5)
1503 >>> pos = nx.planar_layout(G)
1504 >>> nx.draw(G, pos=pos) # Draw the original graph
1505 >>> # Draw a subgraph, reusing the same node positions
1506 >>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
1508 Examples
1509 --------
1510 >>> G = nx.path_graph(4)
1511 >>> nx.draw_planar(G)
1513 See Also
1514 --------
1515 :func:`~networkx.drawing.layout.planar_layout`
1516 """
1517 draw(G, planar_layout(G), **kwargs)
1520def apply_alpha(colors, alpha, elem_list, cmap=None, vmin=None, vmax=None):
1521 """Apply an alpha (or list of alphas) to the colors provided.
1523 Parameters
1524 ----------
1526 colors : color string or array of floats (default='r')
1527 Color of element. Can be a single color format string,
1528 or a sequence of colors with the same length as nodelist.
1529 If numeric values are specified they will be mapped to
1530 colors using the cmap and vmin,vmax parameters. See
1531 matplotlib.scatter for more details.
1533 alpha : float or array of floats
1534 Alpha values for elements. This can be a single alpha value, in
1535 which case it will be applied to all the elements of color. Otherwise,
1536 if it is an array, the elements of alpha will be applied to the colors
1537 in order (cycling through alpha multiple times if necessary).
1539 elem_list : array of networkx objects
1540 The list of elements which are being colored. These could be nodes,
1541 edges or labels.
1543 cmap : matplotlib colormap
1544 Color map for use if colors is a list of floats corresponding to points
1545 on a color mapping.
1547 vmin, vmax : float
1548 Minimum and maximum values for normalizing colors if a colormap is used
1550 Returns
1551 -------
1553 rgba_colors : numpy ndarray
1554 Array containing RGBA format values for each of the node colours.
1556 """
1557 from itertools import cycle, islice
1559 import matplotlib as mpl
1560 import matplotlib.cm # call as mpl.cm
1561 import matplotlib.colors # call as mpl.colors
1562 import numpy as np
1564 # If we have been provided with a list of numbers as long as elem_list,
1565 # apply the color mapping.
1566 if len(colors) == len(elem_list) and isinstance(colors[0], Number):
1567 mapper = mpl.cm.ScalarMappable(cmap=cmap)
1568 mapper.set_clim(vmin, vmax)
1569 rgba_colors = mapper.to_rgba(colors)
1570 # Otherwise, convert colors to matplotlib's RGB using the colorConverter
1571 # object. These are converted to numpy ndarrays to be consistent with the
1572 # to_rgba method of ScalarMappable.
1573 else:
1574 try:
1575 rgba_colors = np.array([mpl.colors.colorConverter.to_rgba(colors)])
1576 except ValueError:
1577 rgba_colors = np.array(
1578 [mpl.colors.colorConverter.to_rgba(color) for color in colors]
1579 )
1580 # Set the final column of the rgba_colors to have the relevant alpha values
1581 try:
1582 # If alpha is longer than the number of colors, resize to the number of
1583 # elements. Also, if rgba_colors.size (the number of elements of
1584 # rgba_colors) is the same as the number of elements, resize the array,
1585 # to avoid it being interpreted as a colormap by scatter()
1586 if len(alpha) > len(rgba_colors) or rgba_colors.size == len(elem_list):
1587 rgba_colors = np.resize(rgba_colors, (len(elem_list), 4))
1588 rgba_colors[1:, 0] = rgba_colors[0, 0]
1589 rgba_colors[1:, 1] = rgba_colors[0, 1]
1590 rgba_colors[1:, 2] = rgba_colors[0, 2]
1591 rgba_colors[:, 3] = list(islice(cycle(alpha), len(rgba_colors)))
1592 except TypeError:
1593 rgba_colors[:, -1] = alpha
1594 return rgba_colors