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

1""" 

2********** 

3Matplotlib 

4********** 

5 

6Draw networks with matplotlib. 

7 

8Examples 

9-------- 

10>>> G = nx.complete_graph(5) 

11>>> nx.draw(G) 

12 

13See Also 

14-------- 

15 - :doc:`matplotlib <matplotlib:index>` 

16 - :func:`matplotlib.pyplot.scatter` 

17 - :obj:`matplotlib.patches.FancyArrowPatch` 

18""" 

19from numbers import Number 

20 

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) 

31 

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] 

47 

48 

49def draw(G, pos=None, ax=None, **kwds): 

50 """Draw the graph G with Matplotlib. 

51 

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. 

56 

57 Parameters 

58 ---------- 

59 G : graph 

60 A networkx graph 

61 

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. 

67 

68 ax : Matplotlib Axes object, optional 

69 Draw the graph in specified Matplotlib axes. 

70 

71 kwds : optional keywords 

72 See networkx.draw_networkx() for a description of optional keywords. 

73 

74 Examples 

75 -------- 

76 >>> G = nx.dodecahedral_graph() 

77 >>> nx.draw(G) 

78 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout 

79 

80 See Also 

81 -------- 

82 draw_networkx 

83 draw_networkx_nodes 

84 draw_networkx_edges 

85 draw_networkx_labels 

86 draw_networkx_edge_labels 

87 

88 Notes 

89 ----- 

90 This function has the same name as pylab.draw and pyplot.draw 

91 so beware when using `from networkx import *` 

92 

93 since you might overwrite the pylab.draw function. 

94 

95 With pyplot use 

96 

97 >>> import matplotlib.pyplot as plt 

98 >>> G = nx.dodecahedral_graph() 

99 >>> nx.draw(G) # networkx draw() 

100 >>> plt.draw() # pyplot draw() 

101 

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 

106 

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)) 

117 

118 if "with_labels" not in kwds: 

119 kwds["with_labels"] = "labels" in kwds 

120 

121 draw_networkx(G, pos=pos, ax=ax, **kwds) 

122 ax.set_axis_off() 

123 plt.draw_if_interactive() 

124 return 

125 

126 

127def draw_networkx(G, pos=None, arrows=None, with_labels=True, **kwds): 

128 r"""Draw the graph G using Matplotlib. 

129 

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. 

133 

134 Parameters 

135 ---------- 

136 G : graph 

137 A networkx graph 

138 

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. 

144 

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. 

153 

154 arrowstyle : str (default='-\|>' for directed graphs) 

155 For directed graphs, choose the style of the arrowsheads. 

156 For undirected graphs default to '-' 

157 

158 See `matplotlib.patches.ArrowStyle` for more options. 

159 

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. 

165 

166 with_labels : bool (default=True) 

167 Set to True to draw labels on the nodes. 

168 

169 ax : Matplotlib Axes object, optional 

170 Draw the graph in the specified Matplotlib axes. 

171 

172 nodelist : list (default=list(G)) 

173 Draw only specified nodes 

174 

175 edgelist : list (default=list(G.edges())) 

176 Draw only specified edges 

177 

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. 

181 

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. 

188 

189 node_shape : string (default='o') 

190 The shape of the node. Specification is as matplotlib.scatter 

191 marker, one of 'so^>v<dph8'. 

192 

193 alpha : float or None (default=None) 

194 The node and edge transparency 

195 

196 cmap : Matplotlib colormap, optional 

197 Colormap for mapping intensities of nodes 

198 

199 vmin,vmax : float, optional 

200 Minimum and maximum for node colormap scaling 

201 

202 linewidths : scalar or sequence (default=1.0) 

203 Line width of symbol border 

204 

205 width : float or array of floats (default=1.0) 

206 Line width of edges 

207 

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. 

213 

214 edge_cmap : Matplotlib colormap, optional 

215 Colormap for mapping intensities of edges 

216 

217 edge_vmin,edge_vmax : floats, optional 

218 Minimum and maximum for edge colormap scaling 

219 

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`) 

224 

225 labels : dictionary (default=None) 

226 Node labels in a dictionary of text labels keyed by node 

227 

228 font_size : int (default=12 for nodes, 10 for edges) 

229 Font size for text labels 

230 

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. 

234 

235 font_weight : string (default='normal') 

236 Font weight 

237 

238 font_family : string (default='sans-serif') 

239 Font family 

240 

241 label : string, optional 

242 Label for graph legend 

243 

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. 

247 

248 Notes 

249 ----- 

250 For directed graphs, arrows are drawn at the head end. Arrows can be 

251 turned off with keyword arrows=False. 

252 

253 Examples 

254 -------- 

255 >>> G = nx.dodecahedral_graph() 

256 >>> nx.draw(G) 

257 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout 

258 

259 >>> import matplotlib.pyplot as plt 

260 >>> limits = plt.axis("off") # turn off axis 

261 

262 Also see the NetworkX drawing examples at 

263 https://networkx.org/documentation/latest/auto_examples/index.html 

264 

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 

274 

275 import matplotlib.pyplot as plt 

276 

277 # Get all valid keywords by inspecting the signatures of draw_networkx_nodes, 

278 # draw_networkx_edges, draw_networkx_labels 

279 

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() 

283 

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 } 

292 

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}") 

296 

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} 

300 

301 if pos is None: 

302 pos = nx.drawing.spring_layout(G) # default to spring layout 

303 

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() 

309 

310 

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. 

329 

330 This draws only the nodes of the graph G. 

331 

332 Parameters 

333 ---------- 

334 G : graph 

335 A networkx graph 

336 

337 pos : dictionary 

338 A dictionary with nodes as keys and positions as values. 

339 Positions should be sequences of length 2. 

340 

341 ax : Matplotlib Axes object, optional 

342 Draw the graph in the specified Matplotlib axes. 

343 

344 nodelist : list (default list(G)) 

345 Draw only specified nodes 

346 

347 node_size : scalar or array (default=300) 

348 Size of nodes. If an array it must be the same length as nodelist. 

349 

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. 

356 

357 node_shape : string (default='o') 

358 The shape of the node. Specification is as matplotlib.scatter 

359 marker, one of 'so^>v<dph8'. 

360 

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). 

366 

367 cmap : Matplotlib colormap (default=None) 

368 Colormap for mapping intensities of nodes 

369 

370 vmin,vmax : floats or None (default=None) 

371 Minimum and maximum for node colormap scaling 

372 

373 linewidths : [None | scalar | sequence] (default=1.0) 

374 Line width of symbol border 

375 

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. 

381 

382 label : [None | string] 

383 Label for legend 

384 

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. 

390 

391 Returns 

392 ------- 

393 matplotlib.collections.PathCollection 

394 `PathCollection` of the nodes. 

395 

396 Examples 

397 -------- 

398 >>> G = nx.dodecahedral_graph() 

399 >>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G)) 

400 

401 Also see the NetworkX drawing examples at 

402 https://networkx.org/documentation/latest/auto_examples/index.html 

403 

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 

413 

414 import matplotlib as mpl 

415 import matplotlib.collections # call as mpl.collections 

416 import matplotlib.pyplot as plt 

417 import numpy as np 

418 

419 if ax is None: 

420 ax = plt.gca() 

421 

422 if nodelist is None: 

423 nodelist = list(G) 

424 

425 if len(nodelist) == 0: # empty nodelist, no drawing 

426 return mpl.collections.PathCollection(None) 

427 

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 

432 

433 if isinstance(alpha, Iterable): 

434 node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax) 

435 alpha = None 

436 

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 ) 

459 

460 if margins is not None: 

461 if isinstance(margins, Iterable): 

462 ax.margins(*margins) 

463 else: 

464 ax.margins(margins) 

465 

466 node_collection.set_zorder(2) 

467 return node_collection 

468 

469 

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. 

494 

495 This draws only the edges of the graph G. 

496 

497 Parameters 

498 ---------- 

499 G : graph 

500 A networkx graph 

501 

502 pos : dictionary 

503 A dictionary with nodes as keys and positions as values. 

504 Positions should be sequences of length 2. 

505 

506 edgelist : collection of edge tuples (default=G.edges()) 

507 Draw only specified edges 

508 

509 width : float or array of floats (default=1.0) 

510 Line width of edges 

511 

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. 

517 

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`) 

528 

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). 

534 

535 edge_cmap : Matplotlib colormap, optional 

536 Colormap for mapping intensities of edges 

537 

538 edge_vmin,edge_vmax : floats, optional 

539 Minimum and maximum for edge colormap scaling 

540 

541 ax : Matplotlib Axes object, optional 

542 Draw the graph in the specified Matplotlib axes. 

543 

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). 

550 

551 Note: Arrowheads will be the same color as edges. 

552 

553 arrowstyle : str (default='-\|>' for directed graphs) 

554 For directed graphs and `arrows==True` defaults to '-\|>', 

555 For undirected graphs default to '-'. 

556 

557 See `matplotlib.patches.ArrowStyle` for more options. 

558 

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. 

563 

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. 

569 

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. 

573 

574 nodelist : list, optional (default=G.nodes()) 

575 This provides the node order for the `node_size` array (if it is an array). 

576 

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'. 

580 

581 label : None or string 

582 Label for legend 

583 

584 min_source_margin : int (default=0) 

585 The minimum margin (gap) at the beginning of the edge at the source. 

586 

587 min_target_margin : int (default=0) 

588 The minimum margin (gap) at the end of the edge at the target. 

589 

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. 

597 

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. 

603 

604 Be sure to include `node_size` as a keyword argument; arrows are 

605 drawn considering the size of nodes. 

606 

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). 

613 

614 Examples 

615 -------- 

616 >>> G = nx.dodecahedral_graph() 

617 >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) 

618 

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]) 

625 

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. 

629 

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] 

635 

636 Also see the NetworkX drawing examples at 

637 https://networkx.org/documentation/latest/auto_examples/index.html 

638 

639 See Also 

640 -------- 

641 draw 

642 draw_networkx 

643 draw_networkx_nodes 

644 draw_networkx_labels 

645 draw_networkx_edge_labels 

646 

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 

655 

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 

663 

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 

677 

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) 

696 

697 if arrowstyle == None: 

698 if G.is_directed(): 

699 arrowstyle = "-|>" 

700 else: 

701 arrowstyle = "-" 

702 

703 if ax is None: 

704 ax = plt.gca() 

705 

706 if edgelist is None: 

707 edgelist = list(G.edges()) 

708 

709 if len(edgelist) == 0: # no edges! 

710 return [] 

711 

712 if nodelist is None: 

713 nodelist = list(G.nodes()) 

714 

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)) 

719 

720 # set edge positions 

721 edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) 

722 

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] 

740 

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) 

755 

756 return edge_collection 

757 

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. 

762 

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 

768 

769 # Draw arrows with `matplotlib.patches.FancyarrowPatch` 

770 arrow_collection = [] 

771 

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 

777 

778 base_connection_style = mpl.patches.ConnectionStyle(connectionstyle) 

779 

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() 

783 

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 ] 

809 

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) 

814 

815 return ret 

816 

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 

824 

825 if isinstance(arrowsize, list): 

826 # Scale each factor of each arrow based on arrowsize list 

827 mutation_scale = arrowsize[i] 

828 

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) 

837 

838 if shrink_source < min_source_margin: 

839 shrink_source = min_source_margin 

840 

841 if shrink_target < min_target_margin: 

842 shrink_target = min_target_margin 

843 

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)] 

850 

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 

858 

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 

870 

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 

884 

885 arrow_collection.append(arrow) 

886 ax.add_patch(arrow) 

887 

888 return arrow_collection 

889 

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 

897 

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() 

913 

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() 

919 

920 ax.tick_params( 

921 axis="both", 

922 which="both", 

923 bottom=False, 

924 left=False, 

925 labelbottom=False, 

926 labelleft=False, 

927 ) 

928 

929 return edge_viz_obj 

930 

931 

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. 

948 

949 Parameters 

950 ---------- 

951 G : graph 

952 A networkx graph 

953 

954 pos : dictionary 

955 A dictionary with nodes as keys and positions as values. 

956 Positions should be sequences of length 2. 

957 

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}` 

962 

963 font_size : int (default=12) 

964 Font size for text labels 

965 

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. 

969 

970 font_weight : string (default='normal') 

971 Font weight 

972 

973 font_family : string (default='sans-serif') 

974 Font family 

975 

976 alpha : float or None (default=None) 

977 The text transparency 

978 

979 bbox : Matplotlib bbox, (default is Matplotlib's ax.text default) 

980 Specify text box properties (e.g. shape, color etc.) for node labels. 

981 

982 horizontalalignment : string (default='center') 

983 Horizontal alignment {'center', 'right', 'left'} 

984 

985 verticalalignment : string (default='center') 

986 Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'} 

987 

988 ax : Matplotlib Axes object, optional 

989 Draw the graph in the specified Matplotlib axes. 

990 

991 clip_on : bool (default=True) 

992 Turn on clipping of node labels at axis boundaries 

993 

994 Returns 

995 ------- 

996 dict 

997 `dict` of labels keyed on the nodes 

998 

999 Examples 

1000 -------- 

1001 >>> G = nx.dodecahedral_graph() 

1002 >>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G)) 

1003 

1004 Also see the NetworkX drawing examples at 

1005 https://networkx.org/documentation/latest/auto_examples/index.html 

1006 

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 

1016 

1017 if ax is None: 

1018 ax = plt.gca() 

1019 

1020 if labels is None: 

1021 labels = {n: n for n in G.nodes()} 

1022 

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 

1044 

1045 ax.tick_params( 

1046 axis="both", 

1047 which="both", 

1048 bottom=False, 

1049 left=False, 

1050 labelbottom=False, 

1051 labelleft=False, 

1052 ) 

1053 

1054 return text_items 

1055 

1056 

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. 

1075 

1076 Parameters 

1077 ---------- 

1078 G : graph 

1079 A networkx graph 

1080 

1081 pos : dictionary 

1082 A dictionary with nodes as keys and positions as values. 

1083 Positions should be sequences of length 2. 

1084 

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. 

1088 

1089 label_pos : float (default=0.5) 

1090 Position of edge label along edge (0=head, 0.5=center, 1=tail) 

1091 

1092 font_size : int (default=10) 

1093 Font size for text labels 

1094 

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. 

1098 

1099 font_weight : string (default='normal') 

1100 Font weight 

1101 

1102 font_family : string (default='sans-serif') 

1103 Font family 

1104 

1105 alpha : float or None (default=None) 

1106 The text transparency 

1107 

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)}. 

1111 

1112 horizontalalignment : string (default='center') 

1113 Horizontal alignment {'center', 'right', 'left'} 

1114 

1115 verticalalignment : string (default='center') 

1116 Vertical alignment {'center', 'top', 'bottom', 'baseline', 'center_baseline'} 

1117 

1118 ax : Matplotlib Axes object, optional 

1119 Draw the graph in the specified Matplotlib axes. 

1120 

1121 rotate : bool (default=True) 

1122 Rotate edge labels to lie parallel to edges 

1123 

1124 clip_on : bool (default=True) 

1125 Turn on clipping of edge labels at axis boundaries 

1126 

1127 Returns 

1128 ------- 

1129 dict 

1130 `dict` of labels keyed by edge 

1131 

1132 Examples 

1133 -------- 

1134 >>> G = nx.dodecahedral_graph() 

1135 >>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G)) 

1136 

1137 Also see the NetworkX drawing examples at 

1138 https://networkx.org/documentation/latest/auto_examples/index.html 

1139 

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 

1150 

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 

1166 

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 ) 

1175 

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 

1196 

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 

1215 

1216 ax.tick_params( 

1217 axis="both", 

1218 which="both", 

1219 bottom=False, 

1220 left=False, 

1221 labelbottom=False, 

1222 labelleft=False, 

1223 ) 

1224 

1225 return text_items 

1226 

1227 

1228def draw_circular(G, **kwargs): 

1229 """Draw the graph `G` with a circular layout. 

1230 

1231 This is a convenience function equivalent to:: 

1232 

1233 nx.draw(G, pos=nx.circular_layout(G), **kwargs) 

1234 

1235 Parameters 

1236 ---------- 

1237 G : graph 

1238 A networkx graph 

1239 

1240 kwargs : optional keywords 

1241 See `draw_networkx` for a description of optional keywords. 

1242 

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:: 

1248 

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") 

1254 

1255 Examples 

1256 -------- 

1257 >>> G = nx.path_graph(5) 

1258 >>> nx.draw_circular(G) 

1259 

1260 See Also 

1261 -------- 

1262 :func:`~networkx.drawing.layout.circular_layout` 

1263 """ 

1264 draw(G, circular_layout(G), **kwargs) 

1265 

1266 

1267def draw_kamada_kawai(G, **kwargs): 

1268 """Draw the graph `G` with a Kamada-Kawai force-directed layout. 

1269 

1270 This is a convenience function equivalent to:: 

1271 

1272 nx.draw(G, pos=nx.kamada_kawai_layout(G), **kwargs) 

1273 

1274 Parameters 

1275 ---------- 

1276 G : graph 

1277 A networkx graph 

1278 

1279 kwargs : optional keywords 

1280 See `draw_networkx` for a description of optional keywords. 

1281 

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:: 

1288 

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") 

1294 

1295 Examples 

1296 -------- 

1297 >>> G = nx.path_graph(5) 

1298 >>> nx.draw_kamada_kawai(G) 

1299 

1300 See Also 

1301 -------- 

1302 :func:`~networkx.drawing.layout.kamada_kawai_layout` 

1303 """ 

1304 draw(G, kamada_kawai_layout(G), **kwargs) 

1305 

1306 

1307def draw_random(G, **kwargs): 

1308 """Draw the graph `G` with a random layout. 

1309 

1310 This is a convenience function equivalent to:: 

1311 

1312 nx.draw(G, pos=nx.random_layout(G), **kwargs) 

1313 

1314 Parameters 

1315 ---------- 

1316 G : graph 

1317 A networkx graph 

1318 

1319 kwargs : optional keywords 

1320 See `draw_networkx` for a description of optional keywords. 

1321 

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:: 

1327 

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") 

1333 

1334 Examples 

1335 -------- 

1336 >>> G = nx.lollipop_graph(4, 3) 

1337 >>> nx.draw_random(G) 

1338 

1339 See Also 

1340 -------- 

1341 :func:`~networkx.drawing.layout.random_layout` 

1342 """ 

1343 draw(G, random_layout(G), **kwargs) 

1344 

1345 

1346def draw_spectral(G, **kwargs): 

1347 """Draw the graph `G` with a spectral 2D layout. 

1348 

1349 This is a convenience function equivalent to:: 

1350 

1351 nx.draw(G, pos=nx.spectral_layout(G), **kwargs) 

1352 

1353 For more information about how node positions are determined, see 

1354 `~networkx.drawing.layout.spectral_layout`. 

1355 

1356 Parameters 

1357 ---------- 

1358 G : graph 

1359 A networkx graph 

1360 

1361 kwargs : optional keywords 

1362 See `draw_networkx` for a description of optional keywords. 

1363 

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:: 

1369 

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") 

1375 

1376 Examples 

1377 -------- 

1378 >>> G = nx.path_graph(5) 

1379 >>> nx.draw_spectral(G) 

1380 

1381 See Also 

1382 -------- 

1383 :func:`~networkx.drawing.layout.spectral_layout` 

1384 """ 

1385 draw(G, spectral_layout(G), **kwargs) 

1386 

1387 

1388def draw_spring(G, **kwargs): 

1389 """Draw the graph `G` with a spring layout. 

1390 

1391 This is a convenience function equivalent to:: 

1392 

1393 nx.draw(G, pos=nx.spring_layout(G), **kwargs) 

1394 

1395 Parameters 

1396 ---------- 

1397 G : graph 

1398 A networkx graph 

1399 

1400 kwargs : optional keywords 

1401 See `draw_networkx` for a description of optional keywords. 

1402 

1403 Notes 

1404 ----- 

1405 `~networkx.drawing.layout.spring_layout` is also the default layout for 

1406 `draw`, so this function is equivalent to `draw`. 

1407 

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:: 

1411 

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") 

1417 

1418 Examples 

1419 -------- 

1420 >>> G = nx.path_graph(20) 

1421 >>> nx.draw_spring(G) 

1422 

1423 See Also 

1424 -------- 

1425 draw 

1426 :func:`~networkx.drawing.layout.spring_layout` 

1427 """ 

1428 draw(G, spring_layout(G), **kwargs) 

1429 

1430 

1431def draw_shell(G, nlist=None, **kwargs): 

1432 """Draw networkx graph `G` with shell layout. 

1433 

1434 This is a convenience function equivalent to:: 

1435 

1436 nx.draw(G, pos=nx.shell_layout(G, nlist=nlist), **kwargs) 

1437 

1438 Parameters 

1439 ---------- 

1440 G : graph 

1441 A networkx graph 

1442 

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. 

1447 

1448 kwargs : optional keywords 

1449 See `draw_networkx` for a description of optional keywords. 

1450 

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:: 

1456 

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") 

1462 

1463 Examples 

1464 -------- 

1465 >>> G = nx.path_graph(4) 

1466 >>> shells = [[0], [1, 2, 3]] 

1467 >>> nx.draw_shell(G, nlist=shells) 

1468 

1469 See Also 

1470 -------- 

1471 :func:`~networkx.drawing.layout.shell_layout` 

1472 """ 

1473 draw(G, shell_layout(G, nlist=nlist), **kwargs) 

1474 

1475 

1476def draw_planar(G, **kwargs): 

1477 """Draw a planar networkx graph `G` with planar layout. 

1478 

1479 This is a convenience function equivalent to:: 

1480 

1481 nx.draw(G, pos=nx.planar_layout(G), **kwargs) 

1482 

1483 Parameters 

1484 ---------- 

1485 G : graph 

1486 A planar networkx graph 

1487 

1488 kwargs : optional keywords 

1489 See `draw_networkx` for a description of optional keywords. 

1490 

1491 Raises 

1492 ------ 

1493 NetworkXException 

1494 When `G` is not planar 

1495 

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:: 

1501 

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") 

1507 

1508 Examples 

1509 -------- 

1510 >>> G = nx.path_graph(4) 

1511 >>> nx.draw_planar(G) 

1512 

1513 See Also 

1514 -------- 

1515 :func:`~networkx.drawing.layout.planar_layout` 

1516 """ 

1517 draw(G, planar_layout(G), **kwargs) 

1518 

1519 

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. 

1522 

1523 Parameters 

1524 ---------- 

1525 

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. 

1532 

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). 

1538 

1539 elem_list : array of networkx objects 

1540 The list of elements which are being colored. These could be nodes, 

1541 edges or labels. 

1542 

1543 cmap : matplotlib colormap 

1544 Color map for use if colors is a list of floats corresponding to points 

1545 on a color mapping. 

1546 

1547 vmin, vmax : float 

1548 Minimum and maximum values for normalizing colors if a colormap is used 

1549 

1550 Returns 

1551 ------- 

1552 

1553 rgba_colors : numpy ndarray 

1554 Array containing RGBA format values for each of the node colours. 

1555 

1556 """ 

1557 from itertools import cycle, islice 

1558 

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 

1563 

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