"""
**********
Matplotlib
**********
使用 Matplotlib 绘制网络图。
Examples
--------
>>> G = nx.complete_graph(5)
>>> nx.draw(G)
See Also
--------
- :doc:`matplotlib <matplotlib:index>`
- :func:`matplotlib.pyplot.scatter`
- :obj:`matplotlib.patches.FancyArrowPatch`
"""
import collections
import itertools
from numbers import Number
import networkx as nx
from networkx.drawing.layout import (
circular_layout,
kamada_kawai_layout,
planar_layout,
random_layout,
shell_layout,
spectral_layout,
spring_layout,
)
__all__ = [
"draw",
"draw_networkx",
"draw_networkx_nodes",
"draw_networkx_edges",
"draw_networkx_labels",
"draw_networkx_edge_labels",
"draw_circular",
"draw_kamada_kawai",
"draw_random",
"draw_spectral",
"draw_spring",
"draw_planar",
"draw_shell",
]
[docs]
def draw(G, pos=None, ax=None, **kwds):
"""使用 Matplotlib 绘制图 G。
将图绘制为一个简单的表示形式,不包含节点标签或边标签,默认使用 Matplotlib 的整个图形区域且不显示轴标签。更多功能丰富的绘制选项,如标题、轴标签等,请参见 `draw_networkx()` 。
Parameters
----------
G : graph
一个 networkx 图
pos : dictionary, 可选
一个以节点为键、位置为值的字典。如果未指定,将计算弹簧布局位置。
请参见 :py:mod:`networkx.drawing.layout` 中的函数来计算节点位置。
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴中绘制图。
kwds : 可选关键字
请参见 `networkx.draw_networkx()` 以了解可选关键字的描述。
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> nx.draw(G)
>>> nx.draw(G, pos=nx.spring_layout(G)) # 使用弹簧布局
See Also
--------
draw_networkx
draw_networkx_nodes
draw_networkx_edges
draw_networkx_labels
draw_networkx_edge_labels
Notes
-----
此函数与 `pylab.draw` 和 `pyplot.draw` 同名,因此在使用 `from networkx import *` 时需注意,
可能会覆盖 `pylab.draw` 函数。
使用 pyplot 时:
>>> import matplotlib.pyplot as plt
>>> G = nx.dodecahedral_graph()
>>> nx.draw(G) # networkx 的 draw()
>>> plt.draw() # pyplot 的 draw()
另请参见 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
"""
import matplotlib.pyplot as plt
if ax is None:
cf = plt.gcf()
else:
cf = ax.get_figure()
cf.set_facecolor("w")
if ax is None:
if cf.axes:
ax = cf.gca()
else:
ax = cf.add_axes((0, 0, 1, 1))
if "with_labels" not in kwds:
kwds["with_labels"] = "labels" in kwds
draw_networkx(G, pos=pos, ax=ax, **kwds)
ax.set_axis_off()
plt.draw_if_interactive()
return
[docs]
def draw_networkx(G, pos=None, arrows=None, with_labels=True, **kwds):
r"""使用 Matplotlib 绘制图 G。
使用 Matplotlib 绘制图,并提供节点位置、标签、标题和许多其他绘图功能的选项。
参见 draw() 以进行简单的无标签或坐标轴的绘图。
Parameters
----------
G : graph
一个 networkx 图
pos : dictionary, 可选
一个以节点为键、位置为值的字典。
如果未指定,将计算弹簧布局位置。
参见 :py:mod:`networkx.drawing.layout` 以获取计算节点位置的函数。
arrows : bool 或 None, 可选 (默认=None)
如果为 `None` ,有向图使用 `~matplotlib.patches.FancyArrowPatch` 绘制箭头,无向图使用 `~matplotlib.collections.LineCollection` 绘制边以提高速度。
如果为 `True` ,使用 FancyArrowPatches 绘制箭头(可弯曲且时尚)。
如果为 `False` ,使用 LineCollection 绘制边(线性且快速)。
对于有向图,如果为 True 则绘制箭头。
注意:箭头将与边颜色相同。
arrowstyle : str (有向图默认='-\|>')
对于有向图,选择箭头的样式。
对于无向图默认为 '-'
参见 `matplotlib.patches.ArrowStyle` 以获取更多选项。
arrowsize : int 或 list (默认=10)
对于有向图,选择箭头头部长度和宽度的尺寸。可以传递一个值列表来为箭头头部长度和宽度指定不同的尺寸。
参见 `matplotlib.patches.FancyArrowPatch` 的属性 `mutation_scale` 以获取更多信息。
with_labels : bool (默认=True)
设置为 True 以在节点上绘制标签。
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴上绘制图。
nodelist : list (默认=list(G))
仅绘制指定的节点
edgelist : list (默认=list(G.edges()))
仅绘制指定的边
node_size : 标量或数组 (默认=300)
节点的大小。如果指定数组,则必须与 nodelist 长度相同。
node_color : 颜色或颜色数组 (默认='#1f78b4')
节点的颜色。可以是单个颜色或与 nodelist 长度相同的颜色序列。颜色可以是字符串或 0-1 之间的浮点数的 rgb(或 rgba)元组。如果指定数值,它们将使用 cmap 和 vmin,vmax 参数映射到颜色。参见 matplotlib.scatter 以获取更多细节。
node_shape : 字符串 (默认='o')
节点的形状。规范与 matplotlib.scatter 标记相同,可以是 'so^>v<dph8' 之一。
alpha : float 或 None (默认=None)
节点和边的透明度
cmap : Matplotlib 颜色映射, 可选
用于映射节点强度的颜色映射
vmin,vmax : float, 可选
节点颜色映射的最小值和最大值
linewidths : 标量或序列 (默认=1.0)
符号边框的线宽
width : float 或 float 数组 (默认=1.0)
边的线宽
edge_color : 颜色或颜色数组 (默认='k')
边的颜色。可以是单个颜色或与 edgelist 长度相同的颜色序列。颜色可以是字符串或 0-1 之间的浮点数的 rgb(或 rgba)元组。如果指定数值,它们将使用 edge_cmap 和 edge_vmin,edge_vmax 参数映射到颜色。
edge_cmap : Matplotlib 颜色映射, 可选
用于映射边强度的颜色映射
edge_vmin,edge_vmax : float, 可选
边颜色映射的最小值和最大值
style : 字符串 (默认=实线)
边的线型,例如:'-', '--', '-.', ':'
或单词如 'solid' 或 'dashed'。
(参见 `matplotlib.patches.FancyArrowPatch` : `linestyle` )
labels : dictionary (默认=None)
节点标签,以节点为键的文本标签字典
font_size : int (节点默认=12,边默认=10)
文本标签的字体大小
font_color : 颜色 (默认='k' 黑色)
字体颜色字符串。颜色可以是字符串或 0-1 之间的浮点数的 rgb(或 rgba)元组。
font_weight : 字符串 (默认='normal')
字体粗细
font_family : 字符串 (默认='sans-serif')
字体系列
label : 字符串, 可选
图例的标签
hide_ticks : bool, 可选
隐藏坐标轴的刻度。当为 `True` (默认)时,刻度和刻度标签将从坐标轴中移除。要设置刻度和刻度标签为 pyplot 默认值,请使用 ``hide_ticks=False`` 。
kwds : 可选关键字
参见 networkx.draw_networkx_nodes(), networkx.draw_networkx_edges(), 和 networkx.draw_networkx_labels() 以获取可选关键字的描述。
Notes
-----
对于有向图,箭头绘制在头部末端。可以通过关键字 arrows=False 关闭箭头。
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> nx.draw(G)
>>> nx.draw(G, pos=nx.spring_layout(G)) # 使用弹簧布局
>>> import matplotlib.pyplot as plt
>>> limits = plt.axis("off") # 关闭坐标轴
另请参见 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
See Also
--------
draw
draw_networkx_nodes
draw_networkx_edges
draw_networkx_labels
draw_networkx_edge_labels
"""
from inspect import signature
import matplotlib.pyplot as plt
# Get all valid keywords by inspecting the signatures of draw_networkx_nodes,
# draw_networkx_edges, draw_networkx_labels
valid_node_kwds = signature(draw_networkx_nodes).parameters.keys()
valid_edge_kwds = signature(draw_networkx_edges).parameters.keys()
valid_label_kwds = signature(draw_networkx_labels).parameters.keys()
# Create a set with all valid keywords across the three functions and
# remove the arguments of this function (draw_networkx)
valid_kwds = (valid_node_kwds | valid_edge_kwds | valid_label_kwds) - {
"G",
"pos",
"arrows",
"with_labels",
}
if any(k not in valid_kwds for k in kwds):
invalid_args = ", ".join([k for k in kwds if k not in valid_kwds])
raise ValueError(f"Received invalid argument(s): {invalid_args}")
node_kwds = {k: v for k, v in kwds.items() if k in valid_node_kwds}
edge_kwds = {k: v for k, v in kwds.items() if k in valid_edge_kwds}
label_kwds = {k: v for k, v in kwds.items() if k in valid_label_kwds}
if pos is None:
pos = nx.drawing.spring_layout(G) # default to spring layout
draw_networkx_nodes(G, pos, **node_kwds)
draw_networkx_edges(G, pos, arrows=arrows, **edge_kwds)
if with_labels:
draw_networkx_labels(G, pos, **label_kwds)
plt.draw_if_interactive()
[docs]
def draw_networkx_nodes(
G,
pos,
nodelist=None,
node_size=300,
node_color="#1f78b4",
node_shape="o",
alpha=None,
cmap=None,
vmin=None,
vmax=None,
ax=None,
linewidths=None,
edgecolors=None,
label=None,
margins=None,
hide_ticks=True,
):
"""绘制图 G 的节点。
此函数仅绘制图 G 的节点。
Parameters
----------
G : 图
一个 networkx 图
pos : 字典
一个以节点为键、位置为值的字典。
位置应为长度为 2 的序列。
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴上绘制图。
nodelist : 列表 (默认 list(G))
仅绘制指定的节点
node_size : 标量或数组 (默认=300)
节点的大小。如果是一个数组,必须与 nodelist 长度相同。
node_color : 颜色或颜色数组 (默认='#1f78b4')
节点的颜色。可以是单一颜色或与 nodelist 长度相同的颜色序列。颜色可以是字符串或 0-1 之间的浮点数组成的 rgb(或 rgba)元组。如果指定数值,它们将使用 cmap 和 vmin,vmax 参数映射为颜色。详见 matplotlib.scatter。
node_shape : 字符串 (默认='o')
节点的形状。规范与 matplotlib.scatter 标记相同,可以是 'so^>v<dph8' 之一。
alpha : 浮点数或浮点数数组 (默认=None)
节点的透明度。可以是一个单一的 alpha 值,应用于所有节点颜色;或者是一个数组,数组元素按顺序应用于颜色(必要时循环应用 alpha 多次)。
cmap : Matplotlib 颜色映射 (默认=None)
用于映射节点强度的颜色映射
vmin,vmax : 浮点数或 None (默认=None)
节点颜色映射的最小值和最大值
linewidths : [None | 标量 | 序列] (默认=1.0)
符号边界的线宽
edgecolors : [None | 标量 | 序列] (默认 = node_color)
节点边界的颜色。可以是单一颜色或与 nodelist 长度相同的颜色序列。颜色可以是字符串或 0-1 之间的浮点数组成的 rgb(或 rgba)元组。如果指定数值,它们将使用 cmap 和 vmin,vmax 参数映射为颜色。详见 `~matplotlib.pyplot.scatter` 。
label : [None | 字符串]
图例标签
margins : 浮点数或 2-元组, 可选
设置轴自动缩放的填充。增加边距以防止节点靠近图像边缘时被裁剪。值应在 ``[0, 1]`` 范围内。详见 :meth:`matplotlib.axes.Axes.margins` 。默认是 `None` ,使用 Matplotlib 默认值。
hide_ticks : bool, 可选
隐藏轴的刻度。当 `True` (默认)时,刻度和刻度标签从轴上移除。要设置刻度和刻度标签为 pyplot 默认值,使用 ``hide_ticks=False`` 。
Returns
-------
matplotlib.collections.PathCollection
节点的 `PathCollection` 。
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G))
另请参见 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
See Also
--------
draw
draw_networkx
draw_networkx_edges
draw_networkx_labels
draw_networkx_edge_labels
"""
from collections.abc import Iterable
import matplotlib as mpl
import matplotlib.collections # call as mpl.collections
import matplotlib.pyplot as plt
import numpy as np
if ax is None:
ax = plt.gca()
if nodelist is None:
nodelist = list(G)
if len(nodelist) == 0: # empty nodelist, no drawing
return mpl.collections.PathCollection(None)
try:
xy = np.asarray([pos[v] for v in nodelist])
except KeyError as err:
raise nx.NetworkXError(f"Node {err} has no position.") from err
if isinstance(alpha, Iterable):
node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax)
alpha = None
node_collection = ax.scatter(
xy[:, 0],
xy[:, 1],
s=node_size,
c=node_color,
marker=node_shape,
cmap=cmap,
vmin=vmin,
vmax=vmax,
alpha=alpha,
linewidths=linewidths,
edgecolors=edgecolors,
label=label,
)
if hide_ticks:
ax.tick_params(
axis="both",
which="both",
bottom=False,
left=False,
labelbottom=False,
labelleft=False,
)
if margins is not None:
if isinstance(margins, Iterable):
ax.margins(*margins)
else:
ax.margins(margins)
node_collection.set_zorder(2)
return node_collection
class FancyArrowFactory:
"""使用 `matplotlib.patches.FancyArrowPatch` 绘制箭头"""
class ConnectionStyleFactory:
def __init__(self, connectionstyles, selfloop_height, ax=None):
import matplotlib as mpl
import matplotlib.path # call as mpl.path
import numpy as np
self.ax = ax
self.mpl = mpl
self.np = np
self.base_connection_styles = [
mpl.patches.ConnectionStyle(cs) for cs in connectionstyles
]
self.n = len(self.base_connection_styles)
self.selfloop_height = selfloop_height
def curved(self, edge_index):
return self.base_connection_styles[edge_index % self.n]
def self_loop(self, edge_index):
def self_loop_connection(posA, posB, *args, **kwargs):
if not self.np.all(posA == posB):
raise nx.NetworkXError(
"`self_loop` connection style method"
"is only to be used for self-loops"
)
# this is called with _screen space_ values
# so convert back to data space
data_loc = self.ax.transData.inverted().transform(posA)
v_shift = 0.1 * self.selfloop_height
h_shift = v_shift * 0.5
# put the top of the loop first so arrow is not hidden by node
path = self.np.asarray(
[
# 1
[0, v_shift],
# 4 4 4
[h_shift, v_shift],
[h_shift, 0],
[0, 0],
# 4 4 4
[-h_shift, 0],
[-h_shift, v_shift],
[0, v_shift],
]
)
# Rotate self loop 90 deg. if more than 1
# This will allow for maximum of 4 visible self loops
if edge_index % 4:
x, y = path.T
for _ in range(edge_index % 4):
x, y = y, -x
path = self.np.array([x, y]).T
return self.mpl.path.Path(
self.ax.transData.transform(data_loc + path), [1, 4, 4, 4, 4, 4, 4]
)
return self_loop_connection
def __init__(
self,
edge_pos,
edgelist,
nodelist,
edge_indices,
node_size,
selfloop_height,
connectionstyle="arc3",
node_shape="o",
arrowstyle="-",
arrowsize=10,
edge_color="k",
alpha=None,
linewidth=1.0,
style="solid",
min_source_margin=0,
min_target_margin=0,
ax=None,
):
import matplotlib as mpl
import matplotlib.patches # call as mpl.patches
import matplotlib.pyplot as plt
import numpy as np
if isinstance(connectionstyle, str):
connectionstyle = [connectionstyle]
elif np.iterable(connectionstyle):
connectionstyle = list(connectionstyle)
else:
msg = "ConnectionStyleFactory arg `connectionstyle` must be str or iterable"
raise nx.NetworkXError(msg)
self.ax = ax
self.mpl = mpl
self.np = np
self.edge_pos = edge_pos
self.edgelist = edgelist
self.nodelist = nodelist
self.node_shape = node_shape
self.min_source_margin = min_source_margin
self.min_target_margin = min_target_margin
self.edge_indices = edge_indices
self.node_size = node_size
self.connectionstyle_factory = self.ConnectionStyleFactory(
connectionstyle, selfloop_height, ax
)
self.arrowstyle = arrowstyle
self.arrowsize = arrowsize
self.arrow_colors = mpl.colors.colorConverter.to_rgba_array(edge_color, alpha)
self.linewidth = linewidth
self.style = style
if isinstance(arrowsize, list) and len(arrowsize) != len(edge_pos):
raise ValueError("arrowsize should have the same length as edgelist")
def __call__(self, i):
(x1, y1), (x2, y2) = self.edge_pos[i]
shrink_source = 0 # space from source to tail
shrink_target = 0 # space from head to target
if self.np.iterable(self.node_size): # many node sizes
source, target = self.edgelist[i][:2]
source_node_size = self.node_size[self.nodelist.index(source)]
target_node_size = self.node_size[self.nodelist.index(target)]
shrink_source = self.to_marker_edge(source_node_size, self.node_shape)
shrink_target = self.to_marker_edge(target_node_size, self.node_shape)
else:
shrink_source = self.to_marker_edge(self.node_size, self.node_shape)
shrink_target = shrink_source
shrink_source = max(shrink_source, self.min_source_margin)
shrink_target = max(shrink_target, self.min_target_margin)
# scale factor of arrow head
if isinstance(self.arrowsize, list):
mutation_scale = self.arrowsize[i]
else:
mutation_scale = self.arrowsize
if len(self.arrow_colors) > i:
arrow_color = self.arrow_colors[i]
elif len(self.arrow_colors) == 1:
arrow_color = self.arrow_colors[0]
else: # Cycle through colors
arrow_color = self.arrow_colors[i % len(self.arrow_colors)]
if self.np.iterable(self.linewidth):
if len(self.linewidth) > i:
linewidth = self.linewidth[i]
else:
linewidth = self.linewidth[i % len(self.linewidth)]
else:
linewidth = self.linewidth
if (
self.np.iterable(self.style)
and not isinstance(self.style, str)
and not isinstance(self.style, tuple)
):
if len(self.style) > i:
linestyle = self.style[i]
else: # Cycle through styles
linestyle = self.style[i % len(self.style)]
else:
linestyle = self.style
if x1 == x2 and y1 == y2:
connectionstyle = self.connectionstyle_factory.self_loop(
self.edge_indices[i]
)
else:
connectionstyle = self.connectionstyle_factory.curved(self.edge_indices[i])
return self.mpl.patches.FancyArrowPatch(
(x1, y1),
(x2, y2),
arrowstyle=self.arrowstyle,
shrinkA=shrink_source,
shrinkB=shrink_target,
mutation_scale=mutation_scale,
color=arrow_color,
linewidth=linewidth,
connectionstyle=connectionstyle,
linestyle=linestyle,
zorder=1, # arrows go behind nodes
)
def to_marker_edge(self, marker_size, marker):
if marker in "s^>v<d": # `large` markers need extra space
return self.np.sqrt(2 * marker_size) / 2
else:
return self.np.sqrt(marker_size) / 2
[docs]
def draw_networkx_edges(
G,
pos,
edgelist=None,
width=1.0,
edge_color="k",
style="solid",
alpha=None,
arrowstyle=None,
arrowsize=10,
edge_cmap=None,
edge_vmin=None,
edge_vmax=None,
ax=None,
arrows=None,
label=None,
node_size=300,
nodelist=None,
node_shape="o",
connectionstyle="arc3",
min_source_margin=0,
min_target_margin=0,
hide_ticks=True,
):
r"""绘制图 G 的边。
此函数仅绘制图 G 的边。
Parameters
----------
G : 图
一个 networkx 图
pos : 字典
一个以节点为键、位置为值的字典。
位置应为长度为 2 的序列。
edgelist : 边元组的集合 (默认=G.edges())
仅绘制指定的边
width : 浮点数或浮点数数组 (默认=1.0)
边的线宽
edge_color : 颜色或颜色数组 (默认='k')
边的颜色。可以是单一颜色或与 edgelist 长度相同的颜色序列。颜色可以是字符串或 0-1 之间的浮点数 rgb(或 rgba)元组。如果指定了数值,它们将使用 edge_cmap 和 edge_vmin、edge_vmax 参数映射为颜色。
style : 字符串或字符串数组 (默认='solid')
边的线型,例如:'-', '--', '-.', ':'
或单词如 'solid' 或 'dashed'。
可以是单一风格或与边列表长度相同的风格序列。
如果给定的风格少于边数,风格将循环使用。
如果给定的风格多于边数,风格将按顺序使用且不会耗尽。
此外,可以使用 `(offset, onoffseq)` 元组作为风格,而不是字符串。
(参见 `matplotlib.patches.FancyArrowPatch` : `linestyle` )
alpha : 浮点数或浮点数数组 (默认=None)
边的透明度。这可以是一个单一的 alpha 值,
在这种情况下,它将应用于所有指定的边。否则,如果它是一个数组,alpha 的元素将按顺序应用于颜色(如果需要,可以多次循环 alpha)。
edge_cmap : Matplotlib 颜色映射, 可选
用于映射边强度的颜色映射
edge_vmin, edge_vmax : 浮点数, 可选
边颜色映射的最小值和最大值
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴上绘制图
arrows : 布尔值或 None, 可选 (默认=None)
如果为 `None` ,有向图使用 `~matplotlib.patches.FancyArrowPatch` 绘制箭头,无向图使用 `~matplotlib.collections.LineCollection` 绘制边以提高速度。
如果为 `True` ,使用 FancyArrowPatches 绘制箭头(可弯曲且样式美观)。
如果为 `False` ,使用 LineCollection 绘制边(线性且快速)。
注意:箭头将与边颜色相同。
arrowstyle : 字符串 (默认='-\|>' 用于有向图)
对于有向图和 `arrows==True` 默认值为 '-\|>',
对于无向图默认值为 '-'。
参见 `matplotlib.patches.ArrowStyle` 了解更多选项。
arrowsize : 整数 (默认=10)
对于有向图,选择箭头头部的长度和宽度。参见 `matplotlib.patches.FancyArrowPatch` 的属性 `mutation_scale` 了解更多信息。
connectionstyle : 字符串或字符串可迭代 (默认="arc3")
传递 connectionstyle 参数以创建弯曲的圆弧和圆角半径 rad。例如,connectionstyle='arc3,rad=0.2'。
参见 `matplotlib.patches.ConnectionStyle` 和 `matplotlib.patches.FancyArrowPatch` 了解更多信息。
如果为可迭代对象,索引表示 MultiGraph 的第 i 条边键
node_size : 标量或数组 (默认=300)
节点的大小。尽管此函数不绘制节点,但节点大小用于确定边的位置。
nodelist : 列表, 可选 (默认=G.nodes())
这提供了 `node_size` 数组的节点顺序(如果它是数组)。
node_shape : 字符串 (默认='o')
用于节点的标记,用于确定边的位置。
规范为 `matplotlib.markers` 标记,例如 'so^>v<dph8' 之一。
label : None 或字符串
图例标签
min_source_margin : 整数 (默认=0)
边在源头的起始处的最小边距(间隙)。
min_target_margin : 整数 (默认=0)
边在目标的末端处的最小边距(间隙)。
hide_ticks : 布尔值, 可选
隐藏轴的刻度。当为 `True` (默认)时,刻度和刻度标签从轴上移除。要将刻度和刻度标签设置为 pyplot 默认值,请使用 ``hide_ticks=False`` 。
Returns
-------
matplotlib.collections.LineCollection 或 matplotlib.patches.FancyArrowPatch 列表
如果 ``arrows=True`` ,返回 FancyArrowPatch 列表。
如果 ``arrows=False`` ,返回 LineCollection。
如果 ``arrows=None`` (默认),如果 `G` 是无向图,返回 LineCollection,否则返回 FancyArrowPatch 列表。
Notes
-----
对于有向图,箭头绘制在头部末端。箭头可以通过关键字 arrows=False 或传递没有箭头的 arrowstyle 来关闭。
确保包含 `node_size` 作为关键字参数;箭头是根据节点大小绘制的。
自环始终使用 `~matplotlib.patches.FancyArrowPatch` 绘制,无论 `arrows` 的值或 `G` 是否为有向图。当 ``arrows=False`` 或 ``arrows=None`` 且 `G` 为无向图时,对应于自环的 FancyArrowPatches 不会显式返回。它们应通过 ``Axes.patches`` 属性访问(参见示例)。
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
>>> G = nx.DiGraph()
>>> G.add_edges_from([(1, 2), (1, 3), (2, 3)])
>>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G))
>>> alphas = [0.3, 0.4, 0.5]
>>> for i, arc in enumerate(arcs): # 更改弧的 alpha 值
... arc.set_alpha(alphas[i])
对应于自环的 FancyArrowPatches 并不总是返回,但始终可以通过 `matplotlib.Axes` 对象的 ``patches`` 属性访问。
>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots()
>>> G = nx.Graph([(0, 1), (0, 0)]) # 节点 0 的自环
>>> edge_collection = nx.draw_networkx_edges(G, pos=nx.circular_layout(G), ax=ax)
>>> self_loop_fap = ax.patches[0]
另请参见 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
See Also
--------
draw
draw_networkx
draw_networkx_nodes
draw_networkx_labels
draw_networkx_edge_labels
"""
import warnings
import matplotlib as mpl
import matplotlib.collections # call as mpl.collections
import matplotlib.colors # call as mpl.colors
import matplotlib.pyplot as plt
import numpy as np
# The default behavior is to use LineCollection to draw edges for
# undirected graphs (for performance reasons) and use FancyArrowPatches
# for directed graphs.
# The `arrows` keyword can be used to override the default behavior
if arrows is None:
use_linecollection = not (G.is_directed() or G.is_multigraph())
else:
if not isinstance(arrows, bool):
raise TypeError("Argument `arrows` must be of type bool or None")
use_linecollection = not arrows
if isinstance(connectionstyle, str):
connectionstyle = [connectionstyle]
elif np.iterable(connectionstyle):
connectionstyle = list(connectionstyle)
else:
msg = "draw_networkx_edges arg `connectionstyle` must be str or iterable"
raise nx.NetworkXError(msg)
# Some kwargs only apply to FancyArrowPatches. Warn users when they use
# non-default values for these kwargs when LineCollection is being used
# instead of silently ignoring the specified option
if use_linecollection:
msg = (
"\n\nThe {0} keyword argument is not applicable when drawing edges\n"
"with LineCollection.\n\n"
"To make this warning go away, either specify `arrows=True` to\n"
"force FancyArrowPatches or use the default values.\n"
"Note that using FancyArrowPatches may be slow for large graphs.\n"
)
if arrowstyle is not None:
warnings.warn(msg.format("arrowstyle"), category=UserWarning, stacklevel=2)
if arrowsize != 10:
warnings.warn(msg.format("arrowsize"), category=UserWarning, stacklevel=2)
if min_source_margin != 0:
warnings.warn(
msg.format("min_source_margin"), category=UserWarning, stacklevel=2
)
if min_target_margin != 0:
warnings.warn(
msg.format("min_target_margin"), category=UserWarning, stacklevel=2
)
if any(cs != "arc3" for cs in connectionstyle):
warnings.warn(
msg.format("connectionstyle"), category=UserWarning, stacklevel=2
)
# NOTE: Arrowstyle modification must occur after the warnings section
if arrowstyle is None:
arrowstyle = "-|>" if G.is_directed() else "-"
if ax is None:
ax = plt.gca()
if edgelist is None:
edgelist = list(G.edges) # (u, v, k) for multigraph (u, v) otherwise
if len(edgelist):
if G.is_multigraph():
key_count = collections.defaultdict(lambda: itertools.count(0))
edge_indices = [next(key_count[tuple(e[:2])]) for e in edgelist]
else:
edge_indices = [0] * len(edgelist)
else: # no edges!
return []
if nodelist is None:
nodelist = list(G.nodes())
# FancyArrowPatch handles color=None different from LineCollection
if edge_color is None:
edge_color = "k"
# set edge positions
edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
# Check if edge_color is an array of floats and map to edge_cmap.
# This is the only case handled differently from matplotlib
if (
np.iterable(edge_color)
and (len(edge_color) == len(edge_pos))
and np.all([isinstance(c, Number) for c in edge_color])
):
if edge_cmap is not None:
assert isinstance(edge_cmap, mpl.colors.Colormap)
else:
edge_cmap = plt.get_cmap()
if edge_vmin is None:
edge_vmin = min(edge_color)
if edge_vmax is None:
edge_vmax = max(edge_color)
color_normal = mpl.colors.Normalize(vmin=edge_vmin, vmax=edge_vmax)
edge_color = [edge_cmap(color_normal(e)) for e in edge_color]
# compute initial view
minx = np.amin(np.ravel(edge_pos[:, :, 0]))
maxx = np.amax(np.ravel(edge_pos[:, :, 0]))
miny = np.amin(np.ravel(edge_pos[:, :, 1]))
maxy = np.amax(np.ravel(edge_pos[:, :, 1]))
w = maxx - minx
h = maxy - miny
# Self-loops are scaled by view extent, except in cases the extent
# is 0, e.g. for a single node. In this case, fall back to scaling
# by the maximum node size
selfloop_height = h if h != 0 else 0.005 * np.array(node_size).max()
fancy_arrow_factory = FancyArrowFactory(
edge_pos,
edgelist,
nodelist,
edge_indices,
node_size,
selfloop_height,
connectionstyle,
node_shape,
arrowstyle,
arrowsize,
edge_color,
alpha,
width,
style,
min_source_margin,
min_target_margin,
ax=ax,
)
# Draw the edges
if use_linecollection:
edge_collection = mpl.collections.LineCollection(
edge_pos,
colors=edge_color,
linewidths=width,
antialiaseds=(1,),
linestyle=style,
alpha=alpha,
)
edge_collection.set_cmap(edge_cmap)
edge_collection.set_clim(edge_vmin, edge_vmax)
edge_collection.set_zorder(1) # edges go behind nodes
edge_collection.set_label(label)
ax.add_collection(edge_collection)
edge_viz_obj = edge_collection
# Make sure selfloop edges are also drawn
# ---------------------------------------
selfloops_to_draw = [loop for loop in nx.selfloop_edges(G) if loop in edgelist]
if selfloops_to_draw:
edgelist_tuple = list(map(tuple, edgelist))
arrow_collection = []
for loop in selfloops_to_draw:
i = edgelist_tuple.index(loop)
arrow = fancy_arrow_factory(i)
arrow_collection.append(arrow)
ax.add_patch(arrow)
else:
edge_viz_obj = []
for i in range(len(edgelist)):
arrow = fancy_arrow_factory(i)
ax.add_patch(arrow)
edge_viz_obj.append(arrow)
# update view after drawing
padx, pady = 0.05 * w, 0.05 * h
corners = (minx - padx, miny - pady), (maxx + padx, maxy + pady)
ax.update_datalim(corners)
ax.autoscale_view()
if hide_ticks:
ax.tick_params(
axis="both",
which="both",
bottom=False,
left=False,
labelbottom=False,
labelleft=False,
)
return edge_viz_obj
[docs]
def draw_networkx_labels(
G,
pos,
labels=None,
font_size=12,
font_color="k",
font_family="sans-serif",
font_weight="normal",
alpha=None,
bbox=None,
horizontalalignment="center",
verticalalignment="center",
ax=None,
clip_on=True,
hide_ticks=True,
):
"""在图 G 上绘制节点标签。
Parameters
----------
G : 图
一个 networkx 图
pos : 字典
一个以节点为键、位置为值的字典。
位置应该是长度为 2 的序列。
labels : 字典 (默认={n: n for n in G})
节点标签的字典,以节点为键。
labels 中的节点键应出现在 `pos` 中。
如果需要,使用: `{n:lab for n,lab in labels.items() if n in pos}`
font_size : 整数 (默认=12)
文本标签的字体大小
font_color : 颜色 (默认='k' 黑色)
字体颜色字符串。颜色可以是字符串或浮点数从 0-1 的 rgb(或 rgba)元组。
font_weight : 字符串 (默认='normal')
字体粗细
font_family : 字符串 (默认='sans-serif')
字体系列
alpha : 浮点数或 None (默认=None)
文本透明度
bbox : Matplotlib bbox, (默认是 Matplotlib 的 ax.text 默认值)
指定节点标签的文本框属性(例如形状、颜色等)。
horizontalalignment : 字符串 (默认='center')
水平对齐方式 {'center', 'right', 'left'}
verticalalignment : 字符串 (默认='center')
垂直对齐方式 {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴上绘制图。
clip_on : 布尔值 (默认=True)
在轴边界处裁剪节点标签
hide_ticks : 布尔值, 可选
隐藏轴的刻度。当 `True` (默认)时,刻度和刻度标签从轴上移除。
要设置刻度和刻度标签为 pyplot 默认值,使用 ``hide_ticks=False`` 。
Returns
-------
字典
以节点为键的标签字典
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G))
另请参阅 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
See Also
--------
draw
draw_networkx
draw_networkx_nodes
draw_networkx_edges
draw_networkx_edge_labels
"""
import matplotlib.pyplot as plt
if ax is None:
ax = plt.gca()
if labels is None:
labels = {n: n for n in G.nodes()}
text_items = {} # there is no text collection so we'll fake one
for n, label in labels.items():
(x, y) = pos[n]
if not isinstance(label, str):
label = str(label) # this makes "1" and 1 labeled the same
t = ax.text(
x,
y,
label,
size=font_size,
color=font_color,
family=font_family,
weight=font_weight,
alpha=alpha,
horizontalalignment=horizontalalignment,
verticalalignment=verticalalignment,
transform=ax.transData,
bbox=bbox,
clip_on=clip_on,
)
text_items[n] = t
if hide_ticks:
ax.tick_params(
axis="both",
which="both",
bottom=False,
left=False,
labelbottom=False,
labelleft=False,
)
return text_items
[docs]
def draw_networkx_edge_labels(
G,
pos,
edge_labels=None,
label_pos=0.5,
font_size=10,
font_color="k",
font_family="sans-serif",
font_weight="normal",
alpha=None,
bbox=None,
horizontalalignment="center",
verticalalignment="center",
ax=None,
rotate=True,
clip_on=True,
node_size=300,
nodelist=None,
connectionstyle="arc3",
hide_ticks=True,
):
"""绘制边标签。
Parameters
----------
G : 图
一个 networkx 图
pos : 字典
一个以节点为键、位置为值的字典。
位置应该是长度为 2 的序列。
edge_labels : 字典 (默认=None)
边标签的字典,以边的两个节点元组为键。
仅绘制字典中键对应的标签。
label_pos : 浮点数 (默认=0.5)
边标签在边上的位置(0=头部,0.5=中心,1=尾部)
font_size : 整数 (默认=10)
文本标签的字体大小
font_color : 颜色 (默认='k' 黑色)
字体颜色字符串。颜色可以是字符串或浮点数从 0-1 的 rgb(或 rgba)元组。
font_weight : 字符串 (默认='normal')
字体粗细
font_family : 字符串 (默认='sans-serif')
字体系列
alpha : 浮点数或 None (默认=None)
文本透明度
bbox : Matplotlib bbox, 可选
指定边标签文本框的属性(例如形状、颜色等)。
默认是 {boxstyle='round', ec=(1.0, 1.0, 1.0), fc=(1.0, 1.0, 1.0)}。
horizontalalignment : 字符串 (默认='center')
水平对齐方式 {'center', 'right', 'left'}
verticalalignment : 字符串 (默认='center')
垂直对齐方式 {'center', 'top', 'bottom', 'baseline', 'center_baseline'}
ax : Matplotlib Axes 对象, 可选
在指定的 Matplotlib 轴上绘制图。
rotate : 布尔值 (默认=True)
旋转边标签以使其与边平行
clip_on : 布尔值 (默认=True)
在轴边界处裁剪边标签
node_size : 标量或数组 (默认=300)
节点的大小。如果是一个数组,必须与 nodelist 的长度相同。
nodelist : 列表, 可选 (默认=G.nodes())
这为 `node_size` 数组(如果它是数组)提供节点顺序。
connectionstyle : 字符串或可迭代字符串 (默认="arc3")
传递 connectionstyle 参数以创建具有指定半径的弯曲弧。例如,connectionstyle='arc3,rad=0.2'。
更多信息请参见 `matplotlib.patches.ConnectionStyle` 和 `matplotlib.patches.FancyArrowPatch` 。
如果是可迭代对象,索引表示 MultiGraph 的第 i 条边键。
hide_ticks : 布尔值, 可选
隐藏轴的刻度。当 `True` (默认)时,刻度和刻度标签从轴上移除。
要设置刻度和刻度标签为 pyplot 默认值,请使用 ``hide_ticks=False`` 。
Returns
-------
字典
`字典` 以边为键的标签
Examples
--------
>>> G = nx.dodecahedral_graph()
>>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G))
另请参阅 NetworkX 绘图示例:
https://networkx.org/documentation/latest/auto_examples/index.html
See Also
--------
draw
draw_networkx
draw_networkx_nodes
draw_networkx_edges
draw_networkx_labels
"""
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
class CurvedArrowText(mpl.text.Text):
def __init__(
self,
arrow,
*args,
label_pos=0.5,
labels_horizontal=False,
ax=None,
**kwargs,
):
# Bind to FancyArrowPatch
self.arrow = arrow
# how far along the text should be on the curve,
# 0 is at start, 1 is at end etc.
self.label_pos = label_pos
self.labels_horizontal = labels_horizontal
if ax is None:
ax = plt.gca()
self.ax = ax
self.x, self.y, self.angle = self._update_text_pos_angle(arrow)
# Create text object
super().__init__(self.x, self.y, *args, rotation=self.angle, **kwargs)
# Bind to axis
self.ax.add_artist(self)
def _get_arrow_path_disp(self, arrow):
"""这是FancyArrowPatch._get_path_in_displaycoord方法的一部分
它省略了方法的第二部分,即路径根据宽度转换为多边形的过程
变换是从ax获取的,而不是从对象获取的,因为对象尚未添加,并且没有变换
"""
dpi_cor = arrow._dpi_cor
# trans_data = arrow.get_transform()
trans_data = self.ax.transData
if arrow._posA_posB is not None:
posA = arrow._convert_xy_units(arrow._posA_posB[0])
posB = arrow._convert_xy_units(arrow._posA_posB[1])
(posA, posB) = trans_data.transform((posA, posB))
_path = arrow.get_connectionstyle()(
posA,
posB,
patchA=arrow.patchA,
patchB=arrow.patchB,
shrinkA=arrow.shrinkA * dpi_cor,
shrinkB=arrow.shrinkB * dpi_cor,
)
else:
_path = trans_data.transform_path(arrow._path_original)
# Return is in display coordinates
return _path
def _update_text_pos_angle(self, arrow):
# Fractional label position
path_disp = self._get_arrow_path_disp(arrow)
(x1, y1), (cx, cy), (x2, y2) = path_disp.vertices
# Text position at a proportion t along the line in display coords
# default is 0.5 so text appears at the halfway point
t = self.label_pos
tt = 1 - t
x = tt**2 * x1 + 2 * t * tt * cx + t**2 * x2
y = tt**2 * y1 + 2 * t * tt * cy + t**2 * y2
if self.labels_horizontal:
# Horizontal text labels
angle = 0
else:
# Labels parallel to curve
change_x = 2 * tt * (cx - x1) + 2 * t * (x2 - cx)
change_y = 2 * tt * (cy - y1) + 2 * t * (y2 - cy)
angle = (np.arctan2(change_y, change_x) / (2 * np.pi)) * 360
# Text is "right way up"
if angle > 90:
angle -= 180
if angle < -90:
angle += 180
(x, y) = self.ax.transData.inverted().transform((x, y))
return x, y, angle
def draw(self, renderer):
# recalculate the text position and angle
self.x, self.y, self.angle = self._update_text_pos_angle(self.arrow)
self.set_position((self.x, self.y))
self.set_rotation(self.angle)
# redraw text
super().draw(renderer)
# use default box of white with white border
if bbox is None:
bbox = {"boxstyle": "round", "ec": (1.0, 1.0, 1.0), "fc": (1.0, 1.0, 1.0)}
if isinstance(connectionstyle, str):
connectionstyle = [connectionstyle]
elif np.iterable(connectionstyle):
connectionstyle = list(connectionstyle)
else:
raise nx.NetworkXError(
"draw_networkx_edges arg `connectionstyle` must be"
"string or iterable of strings"
)
if ax is None:
ax = plt.gca()
if edge_labels is None:
kwds = {"keys": True} if G.is_multigraph() else {}
edge_labels = {tuple(edge): d for *edge, d in G.edges(data=True, **kwds)}
# NOTHING TO PLOT
if not edge_labels:
return {}
edgelist, labels = zip(*edge_labels.items())
if nodelist is None:
nodelist = list(G.nodes())
# set edge positions
edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
if G.is_multigraph():
key_count = collections.defaultdict(lambda: itertools.count(0))
edge_indices = [next(key_count[tuple(e[:2])]) for e in edgelist]
else:
edge_indices = [0] * len(edgelist)
# Used to determine self loop mid-point
# Note, that this will not be accurate,
# if not drawing edge_labels for all edges drawn
h = 0
if edge_labels:
miny = np.amin(np.ravel(edge_pos[:, :, 1]))
maxy = np.amax(np.ravel(edge_pos[:, :, 1]))
h = maxy - miny
selfloop_height = h if h != 0 else 0.005 * np.array(node_size).max()
fancy_arrow_factory = FancyArrowFactory(
edge_pos,
edgelist,
nodelist,
edge_indices,
node_size,
selfloop_height,
connectionstyle,
ax=ax,
)
text_items = {}
for i, (edge, label) in enumerate(zip(edgelist, labels)):
if not isinstance(label, str):
label = str(label) # this makes "1" and 1 labeled the same
n1, n2 = edge[:2]
arrow = fancy_arrow_factory(i)
if n1 == n2:
connectionstyle_obj = arrow.get_connectionstyle()
posA = ax.transData.transform(pos[n1])
path_disp = connectionstyle_obj(posA, posA)
path_data = ax.transData.inverted().transform_path(path_disp)
x, y = path_data.vertices[0]
text_items[edge] = ax.text(
x,
y,
label,
size=font_size,
color=font_color,
family=font_family,
weight=font_weight,
alpha=alpha,
horizontalalignment=horizontalalignment,
verticalalignment=verticalalignment,
rotation=0,
transform=ax.transData,
bbox=bbox,
zorder=1,
clip_on=clip_on,
)
else:
text_items[edge] = CurvedArrowText(
arrow,
label,
size=font_size,
color=font_color,
family=font_family,
weight=font_weight,
alpha=alpha,
horizontalalignment=horizontalalignment,
verticalalignment=verticalalignment,
transform=ax.transData,
bbox=bbox,
zorder=1,
clip_on=clip_on,
label_pos=label_pos,
labels_horizontal=not rotate,
ax=ax,
)
if hide_ticks:
ax.tick_params(
axis="both",
which="both",
bottom=False,
left=False,
labelbottom=False,
labelleft=False,
)
return text_items
[docs]
def draw_circular(G, **kwargs):
"""绘制图 `G` 并使用圆形布局。
这是一个便捷函数,等效于::
nx.draw(G, pos=nx.circular_layout(G), **kwargs)
Parameters
----------
G : 图
一个 networkx 图
kwargs : 可选关键字参数
参见 `draw_networkx` 以了解可选关键字参数的描述。
Notes
-----
每次调用此函数时都会计算布局。对于重复绘图,直接调用
`~networkx.drawing.layout.circular_layout` 并重用结果会更加高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.circular_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(5)
>>> nx.draw_circular(G)
See Also
--------
:func:`~networkx.drawing.layout.circular_layout`
"""
draw(G, circular_layout(G), **kwargs)
[docs]
def draw_kamada_kawai(G, **kwargs):
"""绘制图 `G` 使用 Kamada-Kawai 力导向布局。
这是一个便捷函数,等同于::
nx.draw(G, pos=nx.kamada_kawai_layout(G), **kwargs)
Parameters
----------
G : graph
一个 networkx 图
kwargs : 可选关键字参数
参见 `draw_networkx` 以了解可选关键字参数的描述。
Notes
-----
每次调用此函数时都会计算布局。
对于重复绘图,直接调用 `~networkx.drawing.layout.kamada_kawai_layout` 并重用结果更为高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.kamada_kawai_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(5)
>>> nx.draw_kamada_kawai(G)
See Also
--------
:func:`~networkx.drawing.layout.kamada_kawai_layout`
"""
draw(G, kamada_kawai_layout(G), **kwargs)
[docs]
def draw_random(G, **kwargs):
"""绘制图 `G` 并使用随机布局。
这是一个便捷函数,等效于::
nx.draw(G, pos=nx.random_layout(G), **kwargs)
Parameters
----------
G : 图
一个 networkx 图
kwargs : 可选关键字参数
关于可选关键字参数的描述,请参见 `draw_networkx` 。
Notes
-----
每次调用此函数时都会计算布局。
对于重复绘图,直接调用 `~networkx.drawing.layout.random_layout` 并重用结果更为高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.random_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.lollipop_graph(4, 3)
>>> nx.draw_random(G)
See Also
--------
:func:`~networkx.drawing.layout.random_layout`
"""
draw(G, random_layout(G), **kwargs)
[docs]
def draw_spectral(G, **kwargs):
"""绘制图 `G` 使用谱二维布局。
这是一个便捷函数,等价于::
nx.draw(G, pos=nx.spectral_layout(G), **kwargs)
关于节点位置如何确定的更多信息,请参阅 `~networkx.drawing.layout.spectral_layout` 。
Parameters
----------
G : 图
一个 networkx 图
kwargs : 可选关键字
关于可选关键字的描述,请参阅 `draw_networkx` 。
Notes
-----
每次调用此函数时都会计算布局。
对于重复绘图,直接调用 `~networkx.drawing.layout.spectral_layout` 并重用结果更为高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.spectral_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(5)
>>> nx.draw_spectral(G)
See Also
--------
:func:`~networkx.drawing.layout.spectral_layout`
"""
draw(G, spectral_layout(G), **kwargs)
[docs]
def draw_spring(G, **kwargs):
"""绘制图 `G` 使用弹簧布局。
这是一个便捷函数,等同于::
nx.draw(G, pos=nx.spring_layout(G), **kwargs)
Parameters
----------
G : 图
一个 networkx 图
kwargs : 可选关键字参数
参见 `draw_networkx` 以了解可选关键字参数的描述。
Notes
-----
`~networkx.drawing.layout.spring_layout` 也是 `draw` 的默认布局,因此此函数等同于 `draw` 。
每次调用此函数时都会计算布局。对于重复绘图,直接调用 `~networkx.drawing.layout.spring_layout` 并重用结果更为高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.spring_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(20)
>>> nx.draw_spring(G)
See Also
--------
draw
:func:`~networkx.drawing.layout.spring_layout`
"""
draw(G, spring_layout(G), **kwargs)
[docs]
def draw_shell(G, nlist=None, **kwargs):
"""绘制带有壳布局的 networkx 图 `G` 。
这是一个便捷函数,等效于::
nx.draw(G, pos=nx.shell_layout(G, nlist=nlist), **kwargs)
Parameters
----------
G : 图
一个 networkx 图
nlist : 节点列表的列表,可选
包含表示壳的节点列表的列表。
默认值为 `None` ,表示所有节点都在一个壳中。
详情请参见 `~networkx.drawing.layout.shell_layout` 。
kwargs : 可选关键字
有关可选关键字的描述,请参见 `draw_networkx` 。
Notes
-----
每次调用此函数时都会计算布局。
对于重复绘图,直接调用 `~networkx.drawing.layout.shell_layout` 并重用结果更为高效::
>>> G = nx.complete_graph(5)
>>> pos = nx.shell_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(4)
>>> shells = [[0], [1, 2, 3]]
>>> nx.draw_shell(G, nlist=shells)
See Also
--------
:func:`~networkx.drawing.layout.shell_layout`
"""
draw(G, shell_layout(G, nlist=nlist), **kwargs)
[docs]
def draw_planar(G, **kwargs):
"""绘制具有平面布局的平面网络x图 `G` 。
这是一个便捷函数,等效于::
nx.draw(G, pos=nx.planar_layout(G), **kwargs)
Parameters
----------
G : 图
一个平面网络x图
kwargs : 可选关键字
参见 `draw_networkx` 以了解可选关键字的描述。
Raises
------
NetworkXException
当 `G` 不是平面图时
Notes
-----
每次调用此函数时都会计算布局。
对于重复绘图,直接调用 `~networkx.drawing.layout.planar_layout` 并重用结果更为高效::
>>> G = nx.path_graph(5)
>>> pos = nx.planar_layout(G)
>>> nx.draw(G, pos=pos) # 绘制原始图
>>> # 绘制子图,重用相同的节点位置
>>> nx.draw(G.subgraph([0, 1, 2]), pos=pos, node_color="red")
Examples
--------
>>> G = nx.path_graph(4)
>>> nx.draw_planar(G)
See Also
--------
:func:`~networkx.drawing.layout.planar_layout`
"""
draw(G, planar_layout(G), **kwargs)
def apply_alpha(colors, alpha, elem_list, cmap=None, vmin=None, vmax=None):
"""应用一个alpha值(或alpha值列表)到提供的颜色上。
Parameters
----------
colors : 颜色字符串或浮点数数组(默认='r')
元素的颜色。可以是单个颜色格式字符串,
或与nodelist长度相同的颜色序列。
如果指定数值,它们将使用cmap和vmin,vmax参数映射到
颜色。详见matplotlib.scatter。
alpha : 浮点数或浮点数数组
元素的alpha值。这可以是一个单一的alpha值,
在这种情况下,它将应用于所有颜色元素。否则,
如果是一个数组,alpha的元素将按顺序应用于颜色
(如有必要,循环多次)。
elem_list : networkx对象数组
正在着色的元素列表。这些可以是节点、
边或标签。
cmap : matplotlib颜色映射
如果colors是与颜色映射上的点对应的浮点数列表,
则使用的颜色映射。
vmin, vmax : 浮点数
如果使用颜色映射,用于标准化颜色的最小值和最大值
Returns
-------
rgba_colors : numpy ndarray
包含每个节点颜色的RGBA格式值的数组。
"""
from itertools import cycle, islice
import matplotlib as mpl
import matplotlib.cm # call as mpl.cm
import matplotlib.colors # call as mpl.colors
import numpy as np
# If we have been provided with a list of numbers as long as elem_list,
# apply the color mapping.
if len(colors) == len(elem_list) and isinstance(colors[0], Number):
mapper = mpl.cm.ScalarMappable(cmap=cmap)
mapper.set_clim(vmin, vmax)
rgba_colors = mapper.to_rgba(colors)
# Otherwise, convert colors to matplotlib's RGB using the colorConverter
# object. These are converted to numpy ndarrays to be consistent with the
# to_rgba method of ScalarMappable.
else:
try:
rgba_colors = np.array([mpl.colors.colorConverter.to_rgba(colors)])
except ValueError:
rgba_colors = np.array(
[mpl.colors.colorConverter.to_rgba(color) for color in colors]
)
# Set the final column of the rgba_colors to have the relevant alpha values
try:
# If alpha is longer than the number of colors, resize to the number of
# elements. Also, if rgba_colors.size (the number of elements of
# rgba_colors) is the same as the number of elements, resize the array,
# to avoid it being interpreted as a colormap by scatter()
if len(alpha) > len(rgba_colors) or rgba_colors.size == len(elem_list):
rgba_colors = np.resize(rgba_colors, (len(elem_list), 4))
rgba_colors[1:, 0] = rgba_colors[0, 0]
rgba_colors[1:, 1] = rgba_colors[0, 1]
rgba_colors[1:, 2] = rgba_colors[0, 2]
rgba_colors[:, 3] = list(islice(cycle(alpha), len(rgba_colors)))
except TypeError:
rgba_colors[:, -1] = alpha
return rgba_colors