Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 # Copyright (C) 2004-2019 by | |
| 2 # Aric Hagberg <hagberg@lanl.gov> | |
| 3 # Dan Schult <dschult@colgate.edu> | |
| 4 # Pieter Swart <swart@lanl.gov> | |
| 5 # All rights reserved. | |
| 6 # BSD license. | |
| 7 # | |
| 8 # Author: Aric Hagberg (hagberg@lanl.gov) | |
| 9 """ | |
| 10 ********** | |
| 11 Matplotlib | |
| 12 ********** | |
| 13 | |
| 14 Draw networks with matplotlib. | |
| 15 | |
| 16 See Also | |
| 17 -------- | |
| 18 | |
| 19 matplotlib: http://matplotlib.org/ | |
| 20 | |
| 21 pygraphviz: http://pygraphviz.github.io/ | |
| 22 | |
| 23 """ | |
| 24 from numbers import Number | |
| 25 import networkx as nx | |
| 26 from networkx.utils import is_string_like | |
| 27 from networkx.drawing.layout import shell_layout, \ | |
| 28 circular_layout, kamada_kawai_layout, spectral_layout, \ | |
| 29 spring_layout, random_layout, planar_layout | |
| 30 | |
| 31 __all__ = ['draw', | |
| 32 'draw_networkx', | |
| 33 'draw_networkx_nodes', | |
| 34 'draw_networkx_edges', | |
| 35 'draw_networkx_labels', | |
| 36 'draw_networkx_edge_labels', | |
| 37 'draw_circular', | |
| 38 'draw_kamada_kawai', | |
| 39 'draw_random', | |
| 40 'draw_spectral', | |
| 41 'draw_spring', | |
| 42 'draw_planar', | |
| 43 'draw_shell'] | |
| 44 | |
| 45 | |
| 46 def draw(G, pos=None, ax=None, **kwds): | |
| 47 """Draw the graph G with Matplotlib. | |
| 48 | |
| 49 Draw the graph as a simple representation with no node | |
| 50 labels or edge labels and using the full Matplotlib figure area | |
| 51 and no axis labels by default. See draw_networkx() for more | |
| 52 full-featured drawing that allows title, axis labels etc. | |
| 53 | |
| 54 Parameters | |
| 55 ---------- | |
| 56 G : graph | |
| 57 A networkx graph | |
| 58 | |
| 59 pos : dictionary, optional | |
| 60 A dictionary with nodes as keys and positions as values. | |
| 61 If not specified a spring layout positioning will be computed. | |
| 62 See :py:mod:`networkx.drawing.layout` for functions that | |
| 63 compute node positions. | |
| 64 | |
| 65 ax : Matplotlib Axes object, optional | |
| 66 Draw the graph in specified Matplotlib axes. | |
| 67 | |
| 68 kwds : optional keywords | |
| 69 See networkx.draw_networkx() for a description of optional keywords. | |
| 70 | |
| 71 Examples | |
| 72 -------- | |
| 73 >>> G = nx.dodecahedral_graph() | |
| 74 >>> nx.draw(G) | |
| 75 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout | |
| 76 | |
| 77 See Also | |
| 78 -------- | |
| 79 draw_networkx() | |
| 80 draw_networkx_nodes() | |
| 81 draw_networkx_edges() | |
| 82 draw_networkx_labels() | |
| 83 draw_networkx_edge_labels() | |
| 84 | |
| 85 Notes | |
| 86 ----- | |
| 87 This function has the same name as pylab.draw and pyplot.draw | |
| 88 so beware when using `from networkx import *` | |
| 89 | |
| 90 since you might overwrite the pylab.draw function. | |
| 91 | |
| 92 With pyplot use | |
| 93 | |
| 94 >>> import matplotlib.pyplot as plt | |
| 95 >>> import networkx as nx | |
| 96 >>> G = nx.dodecahedral_graph() | |
| 97 >>> nx.draw(G) # networkx draw() | |
| 98 >>> plt.draw() # pyplot draw() | |
| 99 | |
| 100 Also see the NetworkX drawing examples at | |
| 101 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 102 """ | |
| 103 try: | |
| 104 import matplotlib.pyplot as plt | |
| 105 except ImportError: | |
| 106 raise ImportError("Matplotlib required for draw()") | |
| 107 except RuntimeError: | |
| 108 print("Matplotlib unable to open display") | |
| 109 raise | |
| 110 | |
| 111 if ax is None: | |
| 112 cf = plt.gcf() | |
| 113 else: | |
| 114 cf = ax.get_figure() | |
| 115 cf.set_facecolor('w') | |
| 116 if ax is None: | |
| 117 if cf._axstack() is None: | |
| 118 ax = cf.add_axes((0, 0, 1, 1)) | |
| 119 else: | |
| 120 ax = cf.gca() | |
| 121 | |
| 122 if 'with_labels' not in kwds: | |
| 123 kwds['with_labels'] = 'labels' in kwds | |
| 124 | |
| 125 draw_networkx(G, pos=pos, ax=ax, **kwds) | |
| 126 ax.set_axis_off() | |
| 127 plt.draw_if_interactive() | |
| 128 return | |
| 129 | |
| 130 | |
| 131 def draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds): | |
| 132 """Draw the graph G using Matplotlib. | |
| 133 | |
| 134 Draw the graph with Matplotlib with options for node positions, | |
| 135 labeling, titles, and many other drawing features. | |
| 136 See draw() for simple drawing without labels or axes. | |
| 137 | |
| 138 Parameters | |
| 139 ---------- | |
| 140 G : graph | |
| 141 A networkx graph | |
| 142 | |
| 143 pos : dictionary, optional | |
| 144 A dictionary with nodes as keys and positions as values. | |
| 145 If not specified a spring layout positioning will be computed. | |
| 146 See :py:mod:`networkx.drawing.layout` for functions that | |
| 147 compute node positions. | |
| 148 | |
| 149 arrows : bool, optional (default=True) | |
| 150 For directed graphs, if True draw arrowheads. | |
| 151 Note: Arrows will be the same color as edges. | |
| 152 | |
| 153 arrowstyle : str, optional (default='-|>') | |
| 154 For directed graphs, choose the style of the arrowsheads. | |
| 155 See :py:class: `matplotlib.patches.ArrowStyle` for more | |
| 156 options. | |
| 157 | |
| 158 arrowsize : int, optional (default=10) | |
| 159 For directed graphs, choose the size of the arrow head head's length and | |
| 160 width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute | |
| 161 `mutation_scale` for more info. | |
| 162 | |
| 163 with_labels : bool, optional (default=True) | |
| 164 Set to True to draw labels on the nodes. | |
| 165 | |
| 166 ax : Matplotlib Axes object, optional | |
| 167 Draw the graph in the specified Matplotlib axes. | |
| 168 | |
| 169 nodelist : list, optional (default G.nodes()) | |
| 170 Draw only specified nodes | |
| 171 | |
| 172 edgelist : list, optional (default=G.edges()) | |
| 173 Draw only specified edges | |
| 174 | |
| 175 node_size : scalar or array, optional (default=300) | |
| 176 Size of nodes. If an array is specified it must be the | |
| 177 same length as nodelist. | |
| 178 | |
| 179 node_color : color or array of colors (default='#1f78b4') | |
| 180 Node color. Can be a single color or a sequence of colors with the same | |
| 181 length as nodelist. Color can be string, or rgb (or rgba) tuple of | |
| 182 floats from 0-1. If numeric values are specified they will be | |
| 183 mapped to colors using the cmap and vmin,vmax parameters. See | |
| 184 matplotlib.scatter for more details. | |
| 185 | |
| 186 node_shape : string, optional (default='o') | |
| 187 The shape of the node. Specification is as matplotlib.scatter | |
| 188 marker, one of 'so^>v<dph8'. | |
| 189 | |
| 190 alpha : float, optional (default=None) | |
| 191 The node and edge transparency | |
| 192 | |
| 193 cmap : Matplotlib colormap, optional (default=None) | |
| 194 Colormap for mapping intensities of nodes | |
| 195 | |
| 196 vmin,vmax : float, optional (default=None) | |
| 197 Minimum and maximum for node colormap scaling | |
| 198 | |
| 199 linewidths : [None | scalar | sequence] | |
| 200 Line width of symbol border (default =1.0) | |
| 201 | |
| 202 width : float, optional (default=1.0) | |
| 203 Line width of edges | |
| 204 | |
| 205 edge_color : color or array of colors (default='k') | |
| 206 Edge color. Can be a single color or a sequence of colors with the same | |
| 207 length as edgelist. Color can be string, or rgb (or rgba) tuple of | |
| 208 floats from 0-1. If numeric values are specified they will be | |
| 209 mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. | |
| 210 | |
| 211 edge_cmap : Matplotlib colormap, optional (default=None) | |
| 212 Colormap for mapping intensities of edges | |
| 213 | |
| 214 edge_vmin,edge_vmax : floats, optional (default=None) | |
| 215 Minimum and maximum for edge colormap scaling | |
| 216 | |
| 217 style : string, optional (default='solid') | |
| 218 Edge line style (solid|dashed|dotted,dashdot) | |
| 219 | |
| 220 labels : dictionary, optional (default=None) | |
| 221 Node labels in a dictionary keyed by node of text labels | |
| 222 | |
| 223 font_size : int, optional (default=12) | |
| 224 Font size for text labels | |
| 225 | |
| 226 font_color : string, optional (default='k' black) | |
| 227 Font color string | |
| 228 | |
| 229 font_weight : string, optional (default='normal') | |
| 230 Font weight | |
| 231 | |
| 232 font_family : string, optional (default='sans-serif') | |
| 233 Font family | |
| 234 | |
| 235 label : string, optional | |
| 236 Label for graph legend | |
| 237 | |
| 238 Notes | |
| 239 ----- | |
| 240 For directed graphs, arrows are drawn at the head end. Arrows can be | |
| 241 turned off with keyword arrows=False. | |
| 242 | |
| 243 Examples | |
| 244 -------- | |
| 245 >>> G = nx.dodecahedral_graph() | |
| 246 >>> nx.draw(G) | |
| 247 >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout | |
| 248 | |
| 249 >>> import matplotlib.pyplot as plt | |
| 250 >>> limits = plt.axis('off') # turn of axis | |
| 251 | |
| 252 Also see the NetworkX drawing examples at | |
| 253 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 254 | |
| 255 See Also | |
| 256 -------- | |
| 257 draw() | |
| 258 draw_networkx_nodes() | |
| 259 draw_networkx_edges() | |
| 260 draw_networkx_labels() | |
| 261 draw_networkx_edge_labels() | |
| 262 """ | |
| 263 try: | |
| 264 import matplotlib.pyplot as plt | |
| 265 except ImportError: | |
| 266 raise ImportError("Matplotlib required for draw()") | |
| 267 except RuntimeError: | |
| 268 print("Matplotlib unable to open display") | |
| 269 raise | |
| 270 | |
| 271 if pos is None: | |
| 272 pos = nx.drawing.spring_layout(G) # default to spring layout | |
| 273 | |
| 274 node_collection = draw_networkx_nodes(G, pos, **kwds) | |
| 275 edge_collection = draw_networkx_edges(G, pos, arrows=arrows, **kwds) | |
| 276 if with_labels: | |
| 277 draw_networkx_labels(G, pos, **kwds) | |
| 278 plt.draw_if_interactive() | |
| 279 | |
| 280 | |
| 281 def draw_networkx_nodes(G, pos, | |
| 282 nodelist=None, | |
| 283 node_size=300, | |
| 284 node_color='#1f78b4', | |
| 285 node_shape='o', | |
| 286 alpha=None, | |
| 287 cmap=None, | |
| 288 vmin=None, | |
| 289 vmax=None, | |
| 290 ax=None, | |
| 291 linewidths=None, | |
| 292 edgecolors=None, | |
| 293 label=None, | |
| 294 **kwds): | |
| 295 """Draw the nodes of the graph G. | |
| 296 | |
| 297 This draws only the nodes of the graph G. | |
| 298 | |
| 299 Parameters | |
| 300 ---------- | |
| 301 G : graph | |
| 302 A networkx graph | |
| 303 | |
| 304 pos : dictionary | |
| 305 A dictionary with nodes as keys and positions as values. | |
| 306 Positions should be sequences of length 2. | |
| 307 | |
| 308 ax : Matplotlib Axes object, optional | |
| 309 Draw the graph in the specified Matplotlib axes. | |
| 310 | |
| 311 nodelist : list, optional | |
| 312 Draw only specified nodes (default G.nodes()) | |
| 313 | |
| 314 node_size : scalar or array | |
| 315 Size of nodes (default=300). If an array is specified it must be the | |
| 316 same length as nodelist. | |
| 317 | |
| 318 node_color : color or array of colors (default='#1f78b4') | |
| 319 Node color. Can be a single color or a sequence of colors with the same | |
| 320 length as nodelist. Color can be string, or rgb (or rgba) tuple of | |
| 321 floats from 0-1. If numeric values are specified they will be | |
| 322 mapped to colors using the cmap and vmin,vmax parameters. See | |
| 323 matplotlib.scatter for more details. | |
| 324 | |
| 325 node_shape : string | |
| 326 The shape of the node. Specification is as matplotlib.scatter | |
| 327 marker, one of 'so^>v<dph8' (default='o'). | |
| 328 | |
| 329 alpha : float or array of floats | |
| 330 The node transparency. This can be a single alpha value (default=None), | |
| 331 in which case it will be applied to all the nodes of color. Otherwise, | |
| 332 if it is an array, the elements of alpha will be applied to the colors | |
| 333 in order (cycling through alpha multiple times if necessary). | |
| 334 | |
| 335 cmap : Matplotlib colormap | |
| 336 Colormap for mapping intensities of nodes (default=None) | |
| 337 | |
| 338 vmin,vmax : floats | |
| 339 Minimum and maximum for node colormap scaling (default=None) | |
| 340 | |
| 341 linewidths : [None | scalar | sequence] | |
| 342 Line width of symbol border (default =1.0) | |
| 343 | |
| 344 edgecolors : [None | scalar | sequence] | |
| 345 Colors of node borders (default = node_color) | |
| 346 | |
| 347 label : [None| string] | |
| 348 Label for legend | |
| 349 | |
| 350 min_source_margin : int, optional (default=0) | |
| 351 The minimum margin (gap) at the begining of the edge at the source. | |
| 352 | |
| 353 min_target_margin : int, optional (default=0) | |
| 354 The minimum margin (gap) at the end of the edge at the target. | |
| 355 | |
| 356 Returns | |
| 357 ------- | |
| 358 matplotlib.collections.PathCollection | |
| 359 `PathCollection` of the nodes. | |
| 360 | |
| 361 Examples | |
| 362 -------- | |
| 363 >>> G = nx.dodecahedral_graph() | |
| 364 >>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G)) | |
| 365 | |
| 366 Also see the NetworkX drawing examples at | |
| 367 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 368 | |
| 369 See Also | |
| 370 -------- | |
| 371 draw() | |
| 372 draw_networkx() | |
| 373 draw_networkx_edges() | |
| 374 draw_networkx_labels() | |
| 375 draw_networkx_edge_labels() | |
| 376 """ | |
| 377 from collections.abc import Iterable | |
| 378 try: | |
| 379 import matplotlib.pyplot as plt | |
| 380 import numpy as np | |
| 381 except ImportError: | |
| 382 raise ImportError("Matplotlib required for draw()") | |
| 383 except RuntimeError: | |
| 384 print("Matplotlib unable to open display") | |
| 385 raise | |
| 386 | |
| 387 if ax is None: | |
| 388 ax = plt.gca() | |
| 389 | |
| 390 if nodelist is None: | |
| 391 nodelist = list(G) | |
| 392 | |
| 393 if len(nodelist) == 0: # empty nodelist, no drawing | |
| 394 return | |
| 395 | |
| 396 try: | |
| 397 xy = np.asarray([pos[v] for v in nodelist]) | |
| 398 except KeyError as e: | |
| 399 raise nx.NetworkXError('Node %s has no position.' % e) | |
| 400 except ValueError: | |
| 401 raise nx.NetworkXError('Bad value in node positions.') | |
| 402 | |
| 403 if isinstance(alpha, Iterable): | |
| 404 node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax) | |
| 405 alpha = None | |
| 406 | |
| 407 node_collection = ax.scatter(xy[:, 0], xy[:, 1], | |
| 408 s=node_size, | |
| 409 c=node_color, | |
| 410 marker=node_shape, | |
| 411 cmap=cmap, | |
| 412 vmin=vmin, | |
| 413 vmax=vmax, | |
| 414 alpha=alpha, | |
| 415 linewidths=linewidths, | |
| 416 edgecolors=edgecolors, | |
| 417 label=label) | |
| 418 ax.tick_params( | |
| 419 axis='both', | |
| 420 which='both', | |
| 421 bottom=False, | |
| 422 left=False, | |
| 423 labelbottom=False, | |
| 424 labelleft=False) | |
| 425 | |
| 426 node_collection.set_zorder(2) | |
| 427 return node_collection | |
| 428 | |
| 429 | |
| 430 def draw_networkx_edges(G, pos, | |
| 431 edgelist=None, | |
| 432 width=1.0, | |
| 433 edge_color='k', | |
| 434 style='solid', | |
| 435 alpha=None, | |
| 436 arrowstyle='-|>', | |
| 437 arrowsize=10, | |
| 438 edge_cmap=None, | |
| 439 edge_vmin=None, | |
| 440 edge_vmax=None, | |
| 441 ax=None, | |
| 442 arrows=True, | |
| 443 label=None, | |
| 444 node_size=300, | |
| 445 nodelist=None, | |
| 446 node_shape="o", | |
| 447 connectionstyle=None, | |
| 448 min_source_margin=0, | |
| 449 min_target_margin=0, | |
| 450 **kwds): | |
| 451 """Draw the edges of the graph G. | |
| 452 | |
| 453 This draws only the edges of the graph G. | |
| 454 | |
| 455 Parameters | |
| 456 ---------- | |
| 457 G : graph | |
| 458 A networkx graph | |
| 459 | |
| 460 pos : dictionary | |
| 461 A dictionary with nodes as keys and positions as values. | |
| 462 Positions should be sequences of length 2. | |
| 463 | |
| 464 edgelist : collection of edge tuples | |
| 465 Draw only specified edges(default=G.edges()) | |
| 466 | |
| 467 width : float, or array of floats | |
| 468 Line width of edges (default=1.0) | |
| 469 | |
| 470 edge_color : color or array of colors (default='k') | |
| 471 Edge color. Can be a single color or a sequence of colors with the same | |
| 472 length as edgelist. Color can be string, or rgb (or rgba) tuple of | |
| 473 floats from 0-1. If numeric values are specified they will be | |
| 474 mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. | |
| 475 | |
| 476 style : string | |
| 477 Edge line style (default='solid') (solid|dashed|dotted,dashdot) | |
| 478 | |
| 479 alpha : float | |
| 480 The edge transparency (default=None) | |
| 481 | |
| 482 edge_ cmap : Matplotlib colormap | |
| 483 Colormap for mapping intensities of edges (default=None) | |
| 484 | |
| 485 edge_vmin,edge_vmax : floats | |
| 486 Minimum and maximum for edge colormap scaling (default=None) | |
| 487 | |
| 488 ax : Matplotlib Axes object, optional | |
| 489 Draw the graph in the specified Matplotlib axes. | |
| 490 | |
| 491 arrows : bool, optional (default=True) | |
| 492 For directed graphs, if True draw arrowheads. | |
| 493 Note: Arrows will be the same color as edges. | |
| 494 | |
| 495 arrowstyle : str, optional (default='-|>') | |
| 496 For directed graphs, choose the style of the arrow heads. | |
| 497 See :py:class: `matplotlib.patches.ArrowStyle` for more | |
| 498 options. | |
| 499 | |
| 500 arrowsize : int, optional (default=10) | |
| 501 For directed graphs, choose the size of the arrow head head's length and | |
| 502 width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute | |
| 503 `mutation_scale` for more info. | |
| 504 | |
| 505 connectionstyle : str, optional (default=None) | |
| 506 Pass the connectionstyle parameter to create curved arc of rounding | |
| 507 radius rad. For example, connectionstyle='arc3,rad=0.2'. | |
| 508 See :py:class: `matplotlib.patches.ConnectionStyle` and | |
| 509 :py:class: `matplotlib.patches.FancyArrowPatch` for more info. | |
| 510 | |
| 511 label : [None| string] | |
| 512 Label for legend | |
| 513 | |
| 514 min_source_margin : int, optional (default=0) | |
| 515 The minimum margin (gap) at the begining of the edge at the source. | |
| 516 | |
| 517 min_target_margin : int, optional (default=0) | |
| 518 The minimum margin (gap) at the end of the edge at the target. | |
| 519 | |
| 520 Returns | |
| 521 ------- | |
| 522 matplotlib.collection.LineCollection | |
| 523 `LineCollection` of the edges | |
| 524 | |
| 525 list of matplotlib.patches.FancyArrowPatch | |
| 526 `FancyArrowPatch` instances of the directed edges | |
| 527 | |
| 528 Depending whether the drawing includes arrows or not. | |
| 529 | |
| 530 Notes | |
| 531 ----- | |
| 532 For directed graphs, arrows are drawn at the head end. Arrows can be | |
| 533 turned off with keyword arrows=False. Be sure to include `node_size` as a | |
| 534 keyword argument; arrows are drawn considering the size of nodes. | |
| 535 | |
| 536 Examples | |
| 537 -------- | |
| 538 >>> G = nx.dodecahedral_graph() | |
| 539 >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) | |
| 540 | |
| 541 >>> G = nx.DiGraph() | |
| 542 >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)]) | |
| 543 >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) | |
| 544 >>> alphas = [0.3, 0.4, 0.5] | |
| 545 >>> for i, arc in enumerate(arcs): # change alpha values of arcs | |
| 546 ... arc.set_alpha(alphas[i]) | |
| 547 | |
| 548 Also see the NetworkX drawing examples at | |
| 549 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 550 | |
| 551 See Also | |
| 552 -------- | |
| 553 draw() | |
| 554 draw_networkx() | |
| 555 draw_networkx_nodes() | |
| 556 draw_networkx_labels() | |
| 557 draw_networkx_edge_labels() | |
| 558 """ | |
| 559 try: | |
| 560 import matplotlib | |
| 561 import matplotlib.pyplot as plt | |
| 562 from matplotlib.colors import colorConverter, Colormap, Normalize | |
| 563 from matplotlib.collections import LineCollection | |
| 564 from matplotlib.patches import FancyArrowPatch | |
| 565 import numpy as np | |
| 566 except ImportError: | |
| 567 raise ImportError("Matplotlib required for draw()") | |
| 568 except RuntimeError: | |
| 569 print("Matplotlib unable to open display") | |
| 570 raise | |
| 571 | |
| 572 if ax is None: | |
| 573 ax = plt.gca() | |
| 574 | |
| 575 if edgelist is None: | |
| 576 edgelist = list(G.edges()) | |
| 577 | |
| 578 if not edgelist or len(edgelist) == 0: # no edges! | |
| 579 return None | |
| 580 | |
| 581 if nodelist is None: | |
| 582 nodelist = list(G.nodes()) | |
| 583 | |
| 584 # FancyArrowPatch handles color=None different from LineCollection | |
| 585 if edge_color is None: | |
| 586 edge_color = 'k' | |
| 587 | |
| 588 # set edge positions | |
| 589 edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) | |
| 590 | |
| 591 # Check if edge_color is an array of floats and map to edge_cmap. | |
| 592 # This is the only case handled differently from matplotlib | |
| 593 if np.iterable(edge_color) and (len(edge_color) == len(edge_pos)) \ | |
| 594 and np.alltrue([isinstance(c, Number) for c in edge_color]): | |
| 595 if edge_cmap is not None: | |
| 596 assert(isinstance(edge_cmap, Colormap)) | |
| 597 else: | |
| 598 edge_cmap = plt.get_cmap() | |
| 599 if edge_vmin is None: | |
| 600 edge_vmin = min(edge_color) | |
| 601 if edge_vmax is None: | |
| 602 edge_vmax = max(edge_color) | |
| 603 color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax) | |
| 604 edge_color = [edge_cmap(color_normal(e)) for e in edge_color] | |
| 605 | |
| 606 if (not G.is_directed() or not arrows): | |
| 607 edge_collection = LineCollection(edge_pos, | |
| 608 colors=edge_color, | |
| 609 linewidths=width, | |
| 610 antialiaseds=(1,), | |
| 611 linestyle=style, | |
| 612 transOffset=ax.transData, | |
| 613 alpha=alpha | |
| 614 ) | |
| 615 | |
| 616 edge_collection.set_zorder(1) # edges go behind nodes | |
| 617 edge_collection.set_label(label) | |
| 618 ax.add_collection(edge_collection) | |
| 619 | |
| 620 return edge_collection | |
| 621 | |
| 622 arrow_collection = None | |
| 623 | |
| 624 if G.is_directed() and arrows: | |
| 625 # Note: Waiting for someone to implement arrow to intersection with | |
| 626 # marker. Meanwhile, this works well for polygons with more than 4 | |
| 627 # sides and circle. | |
| 628 | |
| 629 def to_marker_edge(marker_size, marker): | |
| 630 if marker in "s^>v<d": # `large` markers need extra space | |
| 631 return np.sqrt(2 * marker_size) / 2 | |
| 632 else: | |
| 633 return np.sqrt(marker_size) / 2 | |
| 634 | |
| 635 # Draw arrows with `matplotlib.patches.FancyarrowPatch` | |
| 636 arrow_collection = [] | |
| 637 mutation_scale = arrowsize # scale factor of arrow head | |
| 638 | |
| 639 # FancyArrowPatch doesn't handle color strings | |
| 640 arrow_colors = colorConverter.to_rgba_array(edge_color, alpha) | |
| 641 for i, (src, dst) in enumerate(edge_pos): | |
| 642 x1, y1 = src | |
| 643 x2, y2 = dst | |
| 644 shrink_source = 0 # space from source to tail | |
| 645 shrink_target = 0 # space from head to target | |
| 646 if np.iterable(node_size): # many node sizes | |
| 647 src_node, dst_node = edgelist[i][:2] | |
| 648 index_node = nodelist.index(dst_node) | |
| 649 marker_size = node_size[index_node] | |
| 650 shrink_target = to_marker_edge(marker_size, node_shape) | |
| 651 else: | |
| 652 shrink_target = to_marker_edge(node_size, node_shape) | |
| 653 | |
| 654 if shrink_source < min_source_margin: | |
| 655 shrink_source = min_source_margin | |
| 656 | |
| 657 if shrink_target < min_target_margin: | |
| 658 shrink_target = min_target_margin | |
| 659 | |
| 660 if len(arrow_colors) == len(edge_pos): | |
| 661 arrow_color = arrow_colors[i] | |
| 662 elif len(arrow_colors) == 1: | |
| 663 arrow_color = arrow_colors[0] | |
| 664 else: # Cycle through colors | |
| 665 arrow_color = arrow_colors[i % len(arrow_colors)] | |
| 666 | |
| 667 if np.iterable(width): | |
| 668 if len(width) == len(edge_pos): | |
| 669 line_width = width[i] | |
| 670 else: | |
| 671 line_width = width[i % len(width)] | |
| 672 else: | |
| 673 line_width = width | |
| 674 | |
| 675 arrow = FancyArrowPatch((x1, y1), (x2, y2), | |
| 676 arrowstyle=arrowstyle, | |
| 677 shrinkA=shrink_source, | |
| 678 shrinkB=shrink_target, | |
| 679 mutation_scale=mutation_scale, | |
| 680 color=arrow_color, | |
| 681 linewidth=line_width, | |
| 682 connectionstyle=connectionstyle, | |
| 683 zorder=1) # arrows go behind nodes | |
| 684 | |
| 685 # There seems to be a bug in matplotlib to make collections of | |
| 686 # FancyArrowPatch instances. Until fixed, the patches are added | |
| 687 # individually to the axes instance. | |
| 688 arrow_collection.append(arrow) | |
| 689 ax.add_patch(arrow) | |
| 690 | |
| 691 # update view | |
| 692 minx = np.amin(np.ravel(edge_pos[:, :, 0])) | |
| 693 maxx = np.amax(np.ravel(edge_pos[:, :, 0])) | |
| 694 miny = np.amin(np.ravel(edge_pos[:, :, 1])) | |
| 695 maxy = np.amax(np.ravel(edge_pos[:, :, 1])) | |
| 696 | |
| 697 w = maxx - minx | |
| 698 h = maxy - miny | |
| 699 padx, pady = 0.05 * w, 0.05 * h | |
| 700 corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady) | |
| 701 ax.update_datalim(corners) | |
| 702 ax.autoscale_view() | |
| 703 | |
| 704 ax.tick_params( | |
| 705 axis='both', | |
| 706 which='both', | |
| 707 bottom=False, | |
| 708 left=False, | |
| 709 labelbottom=False, | |
| 710 labelleft=False) | |
| 711 | |
| 712 return arrow_collection | |
| 713 | |
| 714 | |
| 715 def draw_networkx_labels(G, pos, | |
| 716 labels=None, | |
| 717 font_size=12, | |
| 718 font_color='k', | |
| 719 font_family='sans-serif', | |
| 720 font_weight='normal', | |
| 721 alpha=None, | |
| 722 bbox=None, | |
| 723 ax=None, | |
| 724 **kwds): | |
| 725 """Draw node labels on the graph G. | |
| 726 | |
| 727 Parameters | |
| 728 ---------- | |
| 729 G : graph | |
| 730 A networkx graph | |
| 731 | |
| 732 pos : dictionary | |
| 733 A dictionary with nodes as keys and positions as values. | |
| 734 Positions should be sequences of length 2. | |
| 735 | |
| 736 labels : dictionary, optional (default=None) | |
| 737 Node labels in a dictionary keyed by node of text labels | |
| 738 Node-keys in labels should appear as keys in `pos`. | |
| 739 If needed use: `{n:lab for n,lab in labels.items() if n in pos}` | |
| 740 | |
| 741 font_size : int | |
| 742 Font size for text labels (default=12) | |
| 743 | |
| 744 font_color : string | |
| 745 Font color string (default='k' black) | |
| 746 | |
| 747 font_family : string | |
| 748 Font family (default='sans-serif') | |
| 749 | |
| 750 font_weight : string | |
| 751 Font weight (default='normal') | |
| 752 | |
| 753 alpha : float or None | |
| 754 The text transparency (default=None) | |
| 755 | |
| 756 ax : Matplotlib Axes object, optional | |
| 757 Draw the graph in the specified Matplotlib axes. | |
| 758 | |
| 759 Returns | |
| 760 ------- | |
| 761 dict | |
| 762 `dict` of labels keyed on the nodes | |
| 763 | |
| 764 Examples | |
| 765 -------- | |
| 766 >>> G = nx.dodecahedral_graph() | |
| 767 >>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G)) | |
| 768 | |
| 769 Also see the NetworkX drawing examples at | |
| 770 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 771 | |
| 772 See Also | |
| 773 -------- | |
| 774 draw() | |
| 775 draw_networkx() | |
| 776 draw_networkx_nodes() | |
| 777 draw_networkx_edges() | |
| 778 draw_networkx_edge_labels() | |
| 779 """ | |
| 780 try: | |
| 781 import matplotlib.pyplot as plt | |
| 782 except ImportError: | |
| 783 raise ImportError("Matplotlib required for draw()") | |
| 784 except RuntimeError: | |
| 785 print("Matplotlib unable to open display") | |
| 786 raise | |
| 787 | |
| 788 if ax is None: | |
| 789 ax = plt.gca() | |
| 790 | |
| 791 if labels is None: | |
| 792 labels = dict((n, n) for n in G.nodes()) | |
| 793 | |
| 794 # set optional alignment | |
| 795 horizontalalignment = kwds.get('horizontalalignment', 'center') | |
| 796 verticalalignment = kwds.get('verticalalignment', 'center') | |
| 797 | |
| 798 text_items = {} # there is no text collection so we'll fake one | |
| 799 for n, label in labels.items(): | |
| 800 (x, y) = pos[n] | |
| 801 if not is_string_like(label): | |
| 802 label = str(label) # this makes "1" and 1 labeled the same | |
| 803 t = ax.text(x, y, | |
| 804 label, | |
| 805 size=font_size, | |
| 806 color=font_color, | |
| 807 family=font_family, | |
| 808 weight=font_weight, | |
| 809 alpha=alpha, | |
| 810 horizontalalignment=horizontalalignment, | |
| 811 verticalalignment=verticalalignment, | |
| 812 transform=ax.transData, | |
| 813 bbox=bbox, | |
| 814 clip_on=True, | |
| 815 ) | |
| 816 text_items[n] = t | |
| 817 | |
| 818 ax.tick_params( | |
| 819 axis='both', | |
| 820 which='both', | |
| 821 bottom=False, | |
| 822 left=False, | |
| 823 labelbottom=False, | |
| 824 labelleft=False) | |
| 825 | |
| 826 return text_items | |
| 827 | |
| 828 | |
| 829 def draw_networkx_edge_labels(G, pos, | |
| 830 edge_labels=None, | |
| 831 label_pos=0.5, | |
| 832 font_size=10, | |
| 833 font_color='k', | |
| 834 font_family='sans-serif', | |
| 835 font_weight='normal', | |
| 836 alpha=None, | |
| 837 bbox=None, | |
| 838 ax=None, | |
| 839 rotate=True, | |
| 840 **kwds): | |
| 841 """Draw edge labels. | |
| 842 | |
| 843 Parameters | |
| 844 ---------- | |
| 845 G : graph | |
| 846 A networkx graph | |
| 847 | |
| 848 pos : dictionary | |
| 849 A dictionary with nodes as keys and positions as values. | |
| 850 Positions should be sequences of length 2. | |
| 851 | |
| 852 ax : Matplotlib Axes object, optional | |
| 853 Draw the graph in the specified Matplotlib axes. | |
| 854 | |
| 855 alpha : float or None | |
| 856 The text transparency (default=None) | |
| 857 | |
| 858 edge_labels : dictionary | |
| 859 Edge labels in a dictionary keyed by edge two-tuple of text | |
| 860 labels (default=None). Only labels for the keys in the dictionary | |
| 861 are drawn. | |
| 862 | |
| 863 label_pos : float | |
| 864 Position of edge label along edge (0=head, 0.5=center, 1=tail) | |
| 865 | |
| 866 font_size : int | |
| 867 Font size for text labels (default=12) | |
| 868 | |
| 869 font_color : string | |
| 870 Font color string (default='k' black) | |
| 871 | |
| 872 font_weight : string | |
| 873 Font weight (default='normal') | |
| 874 | |
| 875 font_family : string | |
| 876 Font family (default='sans-serif') | |
| 877 | |
| 878 bbox : Matplotlib bbox | |
| 879 Specify text box shape and colors. | |
| 880 | |
| 881 clip_on : bool | |
| 882 Turn on clipping at axis boundaries (default=True) | |
| 883 | |
| 884 Returns | |
| 885 ------- | |
| 886 dict | |
| 887 `dict` of labels keyed on the edges | |
| 888 | |
| 889 Examples | |
| 890 -------- | |
| 891 >>> G = nx.dodecahedral_graph() | |
| 892 >>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G)) | |
| 893 | |
| 894 Also see the NetworkX drawing examples at | |
| 895 https://networkx.github.io/documentation/latest/auto_examples/index.html | |
| 896 | |
| 897 See Also | |
| 898 -------- | |
| 899 draw() | |
| 900 draw_networkx() | |
| 901 draw_networkx_nodes() | |
| 902 draw_networkx_edges() | |
| 903 draw_networkx_labels() | |
| 904 """ | |
| 905 try: | |
| 906 import matplotlib.pyplot as plt | |
| 907 import numpy as np | |
| 908 except ImportError: | |
| 909 raise ImportError("Matplotlib required for draw()") | |
| 910 except RuntimeError: | |
| 911 print("Matplotlib unable to open display") | |
| 912 raise | |
| 913 | |
| 914 if ax is None: | |
| 915 ax = plt.gca() | |
| 916 if edge_labels is None: | |
| 917 labels = {(u, v): d for u, v, d in G.edges(data=True)} | |
| 918 else: | |
| 919 labels = edge_labels | |
| 920 text_items = {} | |
| 921 for (n1, n2), label in labels.items(): | |
| 922 (x1, y1) = pos[n1] | |
| 923 (x2, y2) = pos[n2] | |
| 924 (x, y) = (x1 * label_pos + x2 * (1.0 - label_pos), | |
| 925 y1 * label_pos + y2 * (1.0 - label_pos)) | |
| 926 | |
| 927 if rotate: | |
| 928 # in degrees | |
| 929 angle = np.arctan2(y2 - y1, x2 - x1) / (2.0 * np.pi) * 360 | |
| 930 # make label orientation "right-side-up" | |
| 931 if angle > 90: | |
| 932 angle -= 180 | |
| 933 if angle < - 90: | |
| 934 angle += 180 | |
| 935 # transform data coordinate angle to screen coordinate angle | |
| 936 xy = np.array((x, y)) | |
| 937 trans_angle = ax.transData.transform_angles(np.array((angle,)), | |
| 938 xy.reshape((1, 2)))[0] | |
| 939 else: | |
| 940 trans_angle = 0.0 | |
| 941 # use default box of white with white border | |
| 942 if bbox is None: | |
| 943 bbox = dict(boxstyle='round', | |
| 944 ec=(1.0, 1.0, 1.0), | |
| 945 fc=(1.0, 1.0, 1.0), | |
| 946 ) | |
| 947 if not is_string_like(label): | |
| 948 label = str(label) # this makes "1" and 1 labeled the same | |
| 949 | |
| 950 # set optional alignment | |
| 951 horizontalalignment = kwds.get('horizontalalignment', 'center') | |
| 952 verticalalignment = kwds.get('verticalalignment', 'center') | |
| 953 | |
| 954 t = ax.text(x, y, | |
| 955 label, | |
| 956 size=font_size, | |
| 957 color=font_color, | |
| 958 family=font_family, | |
| 959 weight=font_weight, | |
| 960 alpha=alpha, | |
| 961 horizontalalignment=horizontalalignment, | |
| 962 verticalalignment=verticalalignment, | |
| 963 rotation=trans_angle, | |
| 964 transform=ax.transData, | |
| 965 bbox=bbox, | |
| 966 zorder=1, | |
| 967 clip_on=True, | |
| 968 ) | |
| 969 text_items[(n1, n2)] = t | |
| 970 | |
| 971 ax.tick_params( | |
| 972 axis='both', | |
| 973 which='both', | |
| 974 bottom=False, | |
| 975 left=False, | |
| 976 labelbottom=False, | |
| 977 labelleft=False) | |
| 978 | |
| 979 return text_items | |
| 980 | |
| 981 | |
| 982 def draw_circular(G, **kwargs): | |
| 983 """Draw the graph G with a circular layout. | |
| 984 | |
| 985 Parameters | |
| 986 ---------- | |
| 987 G : graph | |
| 988 A networkx graph | |
| 989 | |
| 990 kwargs : optional keywords | |
| 991 See networkx.draw_networkx() for a description of optional keywords, | |
| 992 with the exception of the pos parameter which is not used by this | |
| 993 function. | |
| 994 """ | |
| 995 draw(G, circular_layout(G), **kwargs) | |
| 996 | |
| 997 | |
| 998 def draw_kamada_kawai(G, **kwargs): | |
| 999 """Draw the graph G with a Kamada-Kawai force-directed layout. | |
| 1000 | |
| 1001 Parameters | |
| 1002 ---------- | |
| 1003 G : graph | |
| 1004 A networkx graph | |
| 1005 | |
| 1006 kwargs : optional keywords | |
| 1007 See networkx.draw_networkx() for a description of optional keywords, | |
| 1008 with the exception of the pos parameter which is not used by this | |
| 1009 function. | |
| 1010 """ | |
| 1011 draw(G, kamada_kawai_layout(G), **kwargs) | |
| 1012 | |
| 1013 | |
| 1014 def draw_random(G, **kwargs): | |
| 1015 """Draw the graph G with a random layout. | |
| 1016 | |
| 1017 Parameters | |
| 1018 ---------- | |
| 1019 G : graph | |
| 1020 A networkx graph | |
| 1021 | |
| 1022 kwargs : optional keywords | |
| 1023 See networkx.draw_networkx() for a description of optional keywords, | |
| 1024 with the exception of the pos parameter which is not used by this | |
| 1025 function. | |
| 1026 """ | |
| 1027 draw(G, random_layout(G), **kwargs) | |
| 1028 | |
| 1029 | |
| 1030 def draw_spectral(G, **kwargs): | |
| 1031 """Draw the graph G with a spectral 2D layout. | |
| 1032 | |
| 1033 Using the unnormalized Laplacion, the layout shows possible clusters of | |
| 1034 nodes which are an approximation of the ratio cut. The positions are the | |
| 1035 entries of the second and third eigenvectors corresponding to the | |
| 1036 ascending eigenvalues starting from the second one. | |
| 1037 | |
| 1038 Parameters | |
| 1039 ---------- | |
| 1040 G : graph | |
| 1041 A networkx graph | |
| 1042 | |
| 1043 kwargs : optional keywords | |
| 1044 See networkx.draw_networkx() for a description of optional keywords, | |
| 1045 with the exception of the pos parameter which is not used by this | |
| 1046 function. | |
| 1047 """ | |
| 1048 draw(G, spectral_layout(G), **kwargs) | |
| 1049 | |
| 1050 | |
| 1051 def draw_spring(G, **kwargs): | |
| 1052 """Draw the graph G with a spring layout. | |
| 1053 | |
| 1054 Parameters | |
| 1055 ---------- | |
| 1056 G : graph | |
| 1057 A networkx graph | |
| 1058 | |
| 1059 kwargs : optional keywords | |
| 1060 See networkx.draw_networkx() for a description of optional keywords, | |
| 1061 with the exception of the pos parameter which is not used by this | |
| 1062 function. | |
| 1063 """ | |
| 1064 draw(G, spring_layout(G), **kwargs) | |
| 1065 | |
| 1066 | |
| 1067 def draw_shell(G, **kwargs): | |
| 1068 """Draw networkx graph with shell layout. | |
| 1069 | |
| 1070 Parameters | |
| 1071 ---------- | |
| 1072 G : graph | |
| 1073 A networkx graph | |
| 1074 | |
| 1075 kwargs : optional keywords | |
| 1076 See networkx.draw_networkx() for a description of optional keywords, | |
| 1077 with the exception of the pos parameter which is not used by this | |
| 1078 function. | |
| 1079 """ | |
| 1080 nlist = kwargs.get('nlist', None) | |
| 1081 if nlist is not None: | |
| 1082 del(kwargs['nlist']) | |
| 1083 draw(G, shell_layout(G, nlist=nlist), **kwargs) | |
| 1084 | |
| 1085 | |
| 1086 def draw_planar(G, **kwargs): | |
| 1087 """Draw a planar networkx graph with planar layout. | |
| 1088 | |
| 1089 Parameters | |
| 1090 ---------- | |
| 1091 G : graph | |
| 1092 A planar networkx graph | |
| 1093 | |
| 1094 kwargs : optional keywords | |
| 1095 See networkx.draw_networkx() for a description of optional keywords, | |
| 1096 with the exception of the pos parameter which is not used by this | |
| 1097 function. | |
| 1098 """ | |
| 1099 draw(G, planar_layout(G), **kwargs) | |
| 1100 | |
| 1101 | |
| 1102 def apply_alpha(colors, alpha, elem_list, cmap=None, vmin=None, vmax=None): | |
| 1103 """Apply an alpha (or list of alphas) to the colors provided. | |
| 1104 | |
| 1105 Parameters | |
| 1106 ---------- | |
| 1107 | |
| 1108 colors : color string, or array of floats | |
| 1109 Color of element. Can be a single color format string (default='r'), | |
| 1110 or a sequence of colors with the same length as nodelist. | |
| 1111 If numeric values are specified they will be mapped to | |
| 1112 colors using the cmap and vmin,vmax parameters. See | |
| 1113 matplotlib.scatter for more details. | |
| 1114 | |
| 1115 alpha : float or array of floats | |
| 1116 Alpha values for elements. This can be a single alpha value, in | |
| 1117 which case it will be applied to all the elements of color. Otherwise, | |
| 1118 if it is an array, the elements of alpha will be applied to the colors | |
| 1119 in order (cycling through alpha multiple times if necessary). | |
| 1120 | |
| 1121 elem_list : array of networkx objects | |
| 1122 The list of elements which are being colored. These could be nodes, | |
| 1123 edges or labels. | |
| 1124 | |
| 1125 cmap : matplotlib colormap | |
| 1126 Color map for use if colors is a list of floats corresponding to points | |
| 1127 on a color mapping. | |
| 1128 | |
| 1129 vmin, vmax : float | |
| 1130 Minimum and maximum values for normalizing colors if a color mapping is | |
| 1131 used. | |
| 1132 | |
| 1133 Returns | |
| 1134 ------- | |
| 1135 | |
| 1136 rgba_colors : numpy ndarray | |
| 1137 Array containing RGBA format values for each of the node colours. | |
| 1138 | |
| 1139 """ | |
| 1140 from itertools import islice, cycle | |
| 1141 | |
| 1142 try: | |
| 1143 import numpy as np | |
| 1144 from matplotlib.colors import colorConverter | |
| 1145 import matplotlib.cm as cm | |
| 1146 except ImportError: | |
| 1147 raise ImportError("Matplotlib required for draw()") | |
| 1148 | |
| 1149 # If we have been provided with a list of numbers as long as elem_list, | |
| 1150 # apply the color mapping. | |
| 1151 if len(colors) == len(elem_list) and isinstance(colors[0], Number): | |
| 1152 mapper = cm.ScalarMappable(cmap=cmap) | |
| 1153 mapper.set_clim(vmin, vmax) | |
| 1154 rgba_colors = mapper.to_rgba(colors) | |
| 1155 # Otherwise, convert colors to matplotlib's RGB using the colorConverter | |
| 1156 # object. These are converted to numpy ndarrays to be consistent with the | |
| 1157 # to_rgba method of ScalarMappable. | |
| 1158 else: | |
| 1159 try: | |
| 1160 rgba_colors = np.array([colorConverter.to_rgba(colors)]) | |
| 1161 except ValueError: | |
| 1162 rgba_colors = np.array([colorConverter.to_rgba(color) | |
| 1163 for color in colors]) | |
| 1164 # Set the final column of the rgba_colors to have the relevant alpha values | |
| 1165 try: | |
| 1166 # If alpha is longer than the number of colors, resize to the number of | |
| 1167 # elements. Also, if rgba_colors.size (the number of elements of | |
| 1168 # rgba_colors) is the same as the number of elements, resize the array, | |
| 1169 # to avoid it being interpreted as a colormap by scatter() | |
| 1170 if len(alpha) > len(rgba_colors) or rgba_colors.size == len(elem_list): | |
| 1171 rgba_colors = np.resize(rgba_colors, (len(elem_list), 4)) | |
| 1172 rgba_colors[1:, 0] = rgba_colors[0, 0] | |
| 1173 rgba_colors[1:, 1] = rgba_colors[0, 1] | |
| 1174 rgba_colors[1:, 2] = rgba_colors[0, 2] | |
| 1175 rgba_colors[:, 3] = list(islice(cycle(alpha), len(rgba_colors))) | |
| 1176 except TypeError: | |
| 1177 rgba_colors[:, -1] = alpha | |
| 1178 return rgba_colors | |
| 1179 | |
| 1180 | |
| 1181 # fixture for pytest | |
| 1182 def setup_module(module): | |
| 1183 import pytest | |
| 1184 mpl = pytest.importorskip('matplotlib') | |
| 1185 mpl.use('PS', warn=False) | |
| 1186 plt = pytest.importorskip('matplotlib.pyplot') |
